36 Commits
Author SHA1 Message Date
Leonardo Vencovsky 99f08e2b6e Add clangd to project 2024-06-26 22:50:15 +02:00
Leonardo Vencovsky 47ece66520 Move everything out of src folder 2023-12-13 15:14:46 +01:00
Leonardo Vencovsky 2c1eb41280 Quickfix flags 2023-12-11 02:31:30 +01:00
Leonardo Vencovsky 53960a3bce List stabilization part 2 2023-12-10 20:44:17 +01:00
Leonardo Vencovsky e4dbeae46d List stabilization part 1 2023-12-10 20:44:17 +01:00
Leonardo Vencovsky 32deb8356c Add install dev deps target 2023-08-28 09:09:01 +02:00
Leonardo Vencovsky 3593957bb8 add phony targets 2023-08-21 08:56:45 +02:00
Leonardo Vencovsky a8735889c7 Quickfix for ALLOC_NODE 2023-03-09 16:51:48 +01:00
Leonardo Vencovsky 655b7fa825 Added FTABLE flag 2023-03-03 21:28:04 +01:00
Leonardo Vencovsky 78fe5c2b09 Libray 2023-02-28 16:42:49 +01:00
Leonardo Vencovsky 015d14216f Callbacks redone 2023-02-28 16:42:02 +01:00
Leonardo Vencovsky a46ba1f255 Add CNAME 2023-02-24 11:15:45 +01:00
Leonardo Vencovsky feb5dab0ce v0.26.0 2023-02-22 16:06:58 +01:00
Leonardo Vencovsky 6f8496d39e Last changes 2023-02-22 15:09:16 +01:00
Leonardo Vencovsky b330790bf9 Added list SAC and examples 2023-02-02 09:57:15 +01:00
Leonardo Vencovsky 82ac5a4748 Added CMC_DEV and an example 2023-02-01 11:56:16 +01:00
Leonardo Vencovsky 9a5e5d3aa7 Fix readme 2023-02-01 11:53:22 +01:00
Leonardo Vencovsky bd338f2fe3 Examples and fixing stuff 2023-01-25 13:35:16 +01:00
Leonardo Vencovsky a8c1619be6 More examples 2023-01-24 22:23:33 +01:00
Leonardo Vencovsky 301f080713 Refactored types test 2023-01-24 13:54:32 +01:00
Leonardo Vencovsky 84f73ab623 Fixing benchmark 2023-01-23 10:08:14 +01:00
Leonardo Vencovsky 1802771546 lcov for tests 2023-01-19 16:24:34 +01:00
Leonardo Vencovsky 71fd0b8ad5 More refactoring 2023-01-19 15:37:44 +01:00
Leonardo Vencovsky e4d58db474 More refactoring 2023-01-19 13:06:40 +01:00
Leonardo Vencovsky c1070c4858 More refactoring 2023-01-19 10:38:54 +01:00
Leonardo Vencovsky f6bc58a3d7 More refactoring 2023-01-17 17:09:48 +01:00
Leonardo Vencovsky 0e6c44ac46 Preparing pipeline 2023-01-17 11:32:23 +01:00
Leonardo Vencovsky bf02cede2b Refactored tests 2023-01-17 10:48:42 +01:00
Leonardo Vencovsky 2c9759e5ec Basic structure for V2 2023-01-06 21:56:35 +01:00
Leonardo Vencovsky 9cadaeea85 Merge pull request #17 from pxeger/patch-1
Fix colour blocks in README
2021-05-29 11:22:27 -03:00
Patrick Reader 26175688bd fix colour blocks in README
`placehold.it` has an expired SSL certificate, so the coloured blocks weren't rendering correctly in the README. It seems to have been replaced by `via.placeholder.com`.
2021-05-29 13:08:08 +01:00
Leonardo Vencovsky b58ff6a656 Merge branch 'dev' 2020-10-07 15:04:16 -03:00
Leonardo Vencovsky 0226b91d81 Merge pull request #15 from timgates42/bugfix_typo_beginning
docs: Fix simple typo, beggining -> beginning
2020-09-26 09:17:28 -03:00
Tim Gates 1e16bc1c77 docs: Fix simple typo, beggining -> beginning
There is a small typo in src/utl/assert.h.

Should read `beginning` rather than `beggining`.
2020-09-26 21:09:23 +10:00
Leonardo Vencovsky 4d8d49019d Merge branch 'dev' 2020-06-26 00:02:51 -03:00
Leonardo Vencovsky 7d4abfb66b Update issue templates 2020-06-25 22:30:36 -03:00
450 changed files with 29204 additions and 55211 deletions

No files matched your search

+2
View File
@@ -0,0 +1,2 @@
CompileFlags:
CompilationDatabase: "cmake"
+42
View File
@@ -0,0 +1,42 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: bug
assignees: ''
---
# Bug Report template
### Describe the bug
A clear and concise description of what the bug is.
### How to Reproduce
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
### Expected behavior
A clear and concise description of what you expected to happen.
### Screenshots
If applicable, add screenshots to help explain your problem.
### Please complete the following information:
- Type: [e.g. src, tests, examples, benchmarks]
- OS: [e.g. linux, win32]
- Compiler [e.g. gcc, clang]
- Compiler Version [e.g. 8.1.0]
### Additional context
Add any other context about the problem here.
+32
View File
@@ -0,0 +1,32 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: feature request
assignees: ''
---
# Feature Request Template
### What is the nature of this request?
* New functionalities
* Change in standards
* Change in source code details (names of variables, functions, parameters, etc)
### Is your feature request related to a problem? Please describe.
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
### Describe the solution you'd like
A clear and concise description of what you want to happen.
### Describe alternatives you've considered
A clear and concise description of any alternative solutions or features you've considered.
### Additional context
Add any other context or screenshots about the feature request here.
+8 -6
View File
@@ -2,7 +2,7 @@ name: Test Suit
on:
push:
branches: [ master ]
branches: [ master, dev ]
jobs:
main:
@@ -10,14 +10,16 @@ jobs:
steps:
- uses: actions/checkout@v2
- name: Setup Environment
run: sudo apt install make valgrind gcc python3.8
run: sudo apt install make valgrind gcc
- name: Versions
run: |
gcc --version \
make --version \
valgrind --version \
python --version \
- name: Test Suite
run: python autogen.py -e -b -r -nf
# - name: Valgrind Test
# run: make -C ./tests/main valgrind
run: make tests --always-make
- name: Upload Coverage
uses: codecov/codecov-action@v3
with:
directory: ./tests
verbose: true
+5
View File
@@ -59,3 +59,8 @@ experimental/
# Test / Code Coverage build folder
build
tests/coverage
tests/out
cmake
-24
View File
@@ -1,24 +0,0 @@
dist: xenial
os: linux
language: c
compiler: gcc
addons:
apt:
sources:
- deadsnakes
- ubuntu-toolchain-r-test
packages:
- gcc-9
- cmake
- python3.8
script:
- sudo rm -f /usr/bin/gcc /usr/bin/gcov /usr/bin/python
- sudo ln -s /usr/bin/gcc-9 /usr/bin/gcc
- sudo ln -s /usr/bin/gcov-9 /usr/bin/gcov
- sudo ln -s /usr/bin/python3.8 /usr/bin/python
- gcc --version
- gcov --version
- python --version
- python autogen.py -e -b -cv -r -nf -nt
after_success:
- bash <(curl -s https://codecov.io/bash)
+3
View File
@@ -1,5 +1,8 @@
# RELEASE.MAJOR.MINOR
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
+18
View File
@@ -0,0 +1,18 @@
cmake_minimum_required(VERSION 3.8)
project(cmc)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
file(GLOB_RECURSE sources
"./tests/main.c"
)
add_definitions(-DCMC_CALLBACKS)
add_executable(cmc ${sources})
target_include_directories(cmc PUBLIC
"./"
)
+38
View File
@@ -0,0 +1,38 @@
help:
@echo Welcome to the C Macro Collections Library. Targets:
@echo
@echo - tests: run tests
@echo - tests_dev: run tests for dev
@echo - format: formats the entire project
@echo - bench: runs benchmarks
@echo - docbuild: builds documentation to ./docs
@echo - docserve: serves mdbook docs
@echo - install_dev_deps: install dev dependencies
tests:
make -C ./tests
tests_dev:
make -C ./tests dev
format:
- find ./ -name *.h -type f | xargs clang-format --style=file --verbose -i
bench:
make -C ./benchmarks benchmark
docbuild:
mdbook build -d ../docs documentation
docserve:
mdbook serve documentation
install_dev_deps:
sudo apt install gcc make valgrind lcov clang-format hyperfine clangd cmake
cargo install mdbook
build_clangd:
cmake -S . -G "Unix Makefiles" -B cmake
.PHONY: tests tests_dev format bench docbuild docserve install_dev_deps
+64 -106
View File
@@ -4,22 +4,27 @@
<img src="https://leoven.github.io/C-Macro-Collections/img/logo.png" alt="C Macro Collections Logo" width="300"/>
</p>
<p align="center">Easy to use, header only, macro generated, generic and type-safe Data Structures 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-2195F3.svg?logo=github" alt="LinkToRepo"/></a>
<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://leoven.github.io/C-Macro-Collections/"><img style="color: #ffffff;" src="https://img.shields.io/badge/Read%20the%20Docs-D13636.svg?logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHN0eWxlPSIiPjxyZWN0IGlkPSJiYWNrZ3JvdW5kcmVjdCIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgeD0iMCIgeT0iMCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSJub25lIi8%2BPHRpdGxlPmljbi9kb2MtdGV4dDwvdGl0bGU%2BPGcgY2xhc3M9ImN1cnJlbnRMYXllciIgc3R5bGU9IiI%2BPHRpdGxlPkxheWVyIDE8L3RpdGxlPjxwYXRoIGQ9Ik01IDFoNC4yNDRhMiAyIDAgMCAxIDEuNDM0LjYwNmwyLjc1NiAyLjgzNEEyIDIgMCAwIDEgMTQgNS44MzVWMTJhMyAzIDAgMCAxLTMgM0g1YTMgMyAwIDAgMS0zLTNWNGEzIDMgMCAwIDEgMy0zem0wIDJhMSAxIDAgMCAwLTEgMXY4YTEgMSAwIDAgMCAxIDFoNmExIDEgMCAwIDAgMS0xVjUuODM1TDkuMjQ0IDNINXptMS41IDdoM2EuNS41IDAgMSAxIDAgMWgtM2EuNS41IDAgMSAxIDAtMXptMC0yaDJhLjUuNSAwIDAgMSAwIDFoLTJhLjUuNSAwIDAgMSAwLTF6TTggMmwzIDEuOTk1TDEzIDdIOWExIDEgMCAwIDEtMS0xVjJ6IiBpZD0iYSIgY2xhc3M9IiIgZmlsbD0iI2ZmZmZmZiIgZmlsbC1vcGFjaXR5PSIxIi8%2BPC9nPjwvc3ZnPg%3D%3D" alt="LinkToDocs"/></a>
</p>
<p align="center">
<a href="https://github.com/LeoVen/C-Macro-Collections/blob/master/LICENSE"><img src="https://img.shields.io/badge/License-MIT-blue.svg" alt="License"/></a>
<a href="https://github.com/LeoVen/C-Macro-Collections/releases"><img src="https://img.shields.io/badge/Version-v0.25.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
* [Installation](#installation)
@@ -30,8 +35,6 @@
* [Available Collections](#available-collections)
* [Other Features](#other-features)
* [Design Decisions](#design-decisions)
* [What to use](#what-to-use)
* [Code Review](#code-review)
## Installation
@@ -39,30 +42,28 @@ No installation is required. The entire library is made of header files and can
## 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. Also check out the `STATUS` file for the status on the development of the library.
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
The header `macro_collections.h` includes every feature from the library and comes with higher level APIs that help you generate collections from specific sub-libraries with specific extensions.
Below is a minimal example that makes use of some core functionalities. And a lot of explanation too!
```c
// This is the master header. This will include every feature of the library.
// This comes with many helper macros (high level API) and utility functions.
#include "macro_collections.h"
// 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"
// A PARAM is a standard way to pass required parameters to the lower level API.
// It is a tuple of form (PFX, SNAME, SIZE, K, V). In this case, not all of them
// are used, so we can leave them empty. We are creating a list of value int.
#define MY_LIST_PARAMS (intl, int_list, , , int)
// High level API. Generate a LIST from the CMC library with the STR extension
// using our previously defined PARAMs. Every collections has a CORE part that
// needs to be generated first. Then, we can add other parts after. This macro
// does all of that for us. The STR part will provide us with a function that
// will be used later.
C_MACRO_COLLECTIONS_EXTENDED(CMC, LIST, MY_LIST_PARAMS, (STR))
// 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)
{
@@ -78,8 +79,8 @@ int main(void)
// 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 /utl/futils.h header file.
// 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
@@ -98,7 +99,8 @@ int main(void)
if (!intl_push_back(list, i))
{
enum cmc_flags flag = intl_flag(list);
// Use cmc_flags_to_str to map the enum error to a string.
// 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]);
}
}
@@ -107,13 +109,11 @@ int main(void)
// '.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 usefull and can
// print a data structure very nicely.
// 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");
// You should see a nicely printed list in your terminal.
// Free all of its resources
intl_free(list);
}
@@ -129,28 +129,11 @@ The C Macro Collections library is organized into many other sub-libraries. The
| :-----: | -------------------------------- | ------------------------------------------------------------------------------------------- |
| 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 from CMC, SAC and TSC libraries |
| INT | Integrations | Macros that facilitate the creation of code that involves more than one type of collection |
| 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 |
Every macro that generates code for a certain collection can be found with the following template. Some exceptions exist as certain collections don't have or can't have some features. One big example is the `UTL` library, which does not follow this pattern.
```
macro_name := CMC_[ lib ]_[ collection ]_[ part ]_[ access ]_[ file ]
lib := CMC | COR | DEV | EXT | INT | SAC | TSC
collection := BITSET | DEQUE | HASHBIDIMAP | ... | TREEMULTISET | TREESET
part := CORE | ITER | INIT | ... | SETF | NODE
access := PUBLIC | PRIVATE
file := HEADER | SOURCE
```
__Some `collection`s might not be present in a certain `lib`. Check the documentation.__
Every macro is suffixed by `CMC` and each section is separated by an underscore (`_`). The first section is the library (`lib`). The second is the collection name in all uppercase. Then the `part` (or which module) that you wish to generate. And last, if it is code that should belong to a header file or code that should belong to a source file.
## Project Structure
* __benchmarks__ - Where all benchmarks are hosted
@@ -158,13 +141,10 @@ Every macro is suffixed by `CMC` and each section is separated by an underscore
* __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
* __macro\_collections.h__ - Master header containing all collections and utilities
* __tests__ - Where all tests are hosted
## Available Collections
Check out the STATUS file at the root of the project for more information.
__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 |
@@ -194,21 +174,21 @@ __The following table is an overview of all the currently available or upcoming
These are some features within the library that are implemented by all collections.
### Two-way iterators
## 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
@@ -244,31 +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 |
| ------------ | :------------------------------------------------------: | :------------------------------------------------------: | :------------------------------------------------------: | :------------------------------------------------------: | :------------------------------------------------------: | :------------------------------------------------------: |
| Deque | ![#9f3b94](https://placehold.it/20/9f3b94/000000?text=+) | ![#9f3b94](https://placehold.it/20/9f3b94/000000?text=+) | ![#497edd](https://placehold.it/20/497edd/000000?text=+) | ![#00d3eb](https://placehold.it/20/00d3eb/000000?text=+) | ![#2ef625](https://placehold.it/20/2ef625/000000?text=+) | ![#2ef625](https://placehold.it/20/2ef625/000000?text=+) |
| HashMap | ![#b82b28](https://placehold.it/20/b82b28/000000?text=+) | ![#9f3b94](https://placehold.it/20/9f3b94/000000?text=+) | ![#497edd](https://placehold.it/20/497edd/000000?text=+) | ![#00d3eb](https://placehold.it/20/00d3eb/000000?text=+) | ![#b82b28](https://placehold.it/20/b82b28/000000?text=+) | ![#2ef625](https://placehold.it/20/2ef625/000000?text=+) |
| HashBidiMap | ![#b82b28](https://placehold.it/20/b82b28/000000?text=+) | ![#9f3b94](https://placehold.it/20/9f3b94/000000?text=+) | ![#497edd](https://placehold.it/20/497edd/000000?text=+) | ![#00d3eb](https://placehold.it/20/00d3eb/000000?text=+) | ![#b82b28](https://placehold.it/20/b82b28/000000?text=+) | ![#2ef625](https://placehold.it/20/2ef625/000000?text=+) |
| HashMultiMap | ![#b82b28](https://placehold.it/20/b82b28/000000?text=+) | ![#9f3b94](https://placehold.it/20/9f3b94/000000?text=+) | ![#497edd](https://placehold.it/20/497edd/000000?text=+) | ![#00d3eb](https://placehold.it/20/00d3eb/000000?text=+) | ![#b82b28](https://placehold.it/20/b82b28/000000?text=+) | ![#2ef625](https://placehold.it/20/2ef625/000000?text=+) |
| HashMultiSet | ![#b82b28](https://placehold.it/20/b82b28/000000?text=+) | ![#9f3b94](https://placehold.it/20/9f3b94/000000?text=+) | ![#497edd](https://placehold.it/20/497edd/000000?text=+) | ![#00d3eb](https://placehold.it/20/00d3eb/000000?text=+) | ![#b82b28](https://placehold.it/20/b82b28/000000?text=+) | ![#2ef625](https://placehold.it/20/2ef625/000000?text=+) |
| HashSet | ![#b82b28](https://placehold.it/20/b82b28/000000?text=+) | ![#9f3b94](https://placehold.it/20/9f3b94/000000?text=+) | ![#497edd](https://placehold.it/20/497edd/000000?text=+) | ![#00d3eb](https://placehold.it/20/00d3eb/000000?text=+) | ![#b82b28](https://placehold.it/20/b82b28/000000?text=+) | ![#2ef625](https://placehold.it/20/2ef625/000000?text=+) |
| Heap | ![#9f3b94](https://placehold.it/20/9f3b94/000000?text=+) | ![#9f3b94](https://placehold.it/20/9f3b94/000000?text=+) | ![#497edd](https://placehold.it/20/497edd/000000?text=+) | ![#00d3eb](https://placehold.it/20/00d3eb/000000?text=+) | ![#2ef625](https://placehold.it/20/2ef625/000000?text=+) | ![#b82b28](https://placehold.it/20/b82b28/000000?text=+) |
| IntervalHeap | ![#9f3b94](https://placehold.it/20/9f3b94/000000?text=+) | ![#9f3b94](https://placehold.it/20/9f3b94/000000?text=+) | ![#497edd](https://placehold.it/20/497edd/000000?text=+) | ![#00d3eb](https://placehold.it/20/00d3eb/000000?text=+) | ![#2ef625](https://placehold.it/20/2ef625/000000?text=+) | ![#b82b28](https://placehold.it/20/b82b28/000000?text=+) |
| List | ![#9f3b94](https://placehold.it/20/9f3b94/000000?text=+) | ![#9f3b94](https://placehold.it/20/9f3b94/000000?text=+) | ![#497edd](https://placehold.it/20/497edd/000000?text=+) | ![#00d3eb](https://placehold.it/20/00d3eb/000000?text=+) | ![#2ef625](https://placehold.it/20/2ef625/000000?text=+) | ![#2ef625](https://placehold.it/20/2ef625/000000?text=+) |
| LinkedList | ![#9f3b94](https://placehold.it/20/9f3b94/000000?text=+) | ![#9f3b94](https://placehold.it/20/9f3b94/000000?text=+) | ![#497edd](https://placehold.it/20/497edd/000000?text=+) | ![#00d3eb](https://placehold.it/20/00d3eb/000000?text=+) | ![#2ef625](https://placehold.it/20/2ef625/000000?text=+) | ![#2ef625](https://placehold.it/20/2ef625/000000?text=+) |
| Queue | ![#9f3b94](https://placehold.it/20/9f3b94/000000?text=+) | ![#9f3b94](https://placehold.it/20/9f3b94/000000?text=+) | ![#497edd](https://placehold.it/20/497edd/000000?text=+) | ![#00d3eb](https://placehold.it/20/00d3eb/000000?text=+) | ![#2ef625](https://placehold.it/20/2ef625/000000?text=+) | ![#2ef625](https://placehold.it/20/2ef625/000000?text=+) |
| SortedList | ![#b82b28](https://placehold.it/20/b82b28/000000?text=+) | ![#9f3b94](https://placehold.it/20/9f3b94/000000?text=+) | ![#497edd](https://placehold.it/20/497edd/000000?text=+) | ![#00d3eb](https://placehold.it/20/00d3eb/000000?text=+) | ![#2ef625](https://placehold.it/20/2ef625/000000?text=+) | ![#2ef625](https://placehold.it/20/2ef625/000000?text=+) |
| Stack | ![#9f3b94](https://placehold.it/20/9f3b94/000000?text=+) | ![#9f3b94](https://placehold.it/20/9f3b94/000000?text=+) | ![#497edd](https://placehold.it/20/497edd/000000?text=+) | ![#00d3eb](https://placehold.it/20/00d3eb/000000?text=+) | ![#2ef625](https://placehold.it/20/2ef625/000000?text=+) | ![#2ef625](https://placehold.it/20/2ef625/000000?text=+) |
| TreeMap | ![#b82b28](https://placehold.it/20/b82b28/000000?text=+) | ![#9f3b94](https://placehold.it/20/9f3b94/000000?text=+) | ![#497edd](https://placehold.it/20/497edd/000000?text=+) | ![#00d3eb](https://placehold.it/20/00d3eb/000000?text=+) | ![#2ef625](https://placehold.it/20/2ef625/000000?text=+) | ![#2ef625](https://placehold.it/20/2ef625/000000?text=+) |
| TreeSet | ![#b82b28](https://placehold.it/20/b82b28/000000?text=+) | ![#9f3b94](https://placehold.it/20/9f3b94/000000?text=+) | ![#497edd](https://placehold.it/20/497edd/000000?text=+) | ![#00d3eb](https://placehold.it/20/00d3eb/000000?text=+) | ![#2ef625](https://placehold.it/20/2ef625/000000?text=+) | ![#2ef625](https://placehold.it/20/2ef625/000000?text=+) |
| Collection | CMP | CPY | STR | FREE | HASH | PRI |
| ------------ | :-------------------------------------------------------------: | :-------------------------------------------------------------: | :-------------------------------------------------------------: | :-------------------------------------------------------------: | :-------------------------------------------------------------: | :-------------------------------------------------------------: |
| BitSet | ![#2ef625](https://via.placeholder.com/20/2ef625/000000?text=+) | ![#2ef625](https://via.placeholder.com/20/2ef625/000000?text=+) | ![#2ef625](https://via.placeholder.com/20/2ef625/000000?text=+) | ![#2ef625](https://via.placeholder.com/20/2ef625/000000?text=+) | ![#2ef625](https://via.placeholder.com/20/2ef625/000000?text=+) | ![#2ef625](https://via.placeholder.com/20/2ef625/000000?text=+) |
| Deque | ![#9f3b94](https://via.placeholder.com/20/9f3b94/000000?text=+) | ![#9f3b94](https://via.placeholder.com/20/9f3b94/000000?text=+) | ![#497edd](https://via.placeholder.com/20/497edd/000000?text=+) | ![#00d3eb](https://via.placeholder.com/20/00d3eb/000000?text=+) | ![#2ef625](https://via.placeholder.com/20/2ef625/000000?text=+) | ![#2ef625](https://via.placeholder.com/20/2ef625/000000?text=+) |
| HashMap | ![#b82b28](https://via.placeholder.com/20/b82b28/000000?text=+) | ![#9f3b94](https://via.placeholder.com/20/9f3b94/000000?text=+) | ![#497edd](https://via.placeholder.com/20/497edd/000000?text=+) | ![#00d3eb](https://via.placeholder.com/20/00d3eb/000000?text=+) | ![#b82b28](https://via.placeholder.com/20/b82b28/000000?text=+) | ![#2ef625](https://via.placeholder.com/20/2ef625/000000?text=+) |
| HashBidiMap | ![#b82b28](https://via.placeholder.com/20/b82b28/000000?text=+) | ![#9f3b94](https://via.placeholder.com/20/9f3b94/000000?text=+) | ![#497edd](https://via.placeholder.com/20/497edd/000000?text=+) | ![#00d3eb](https://via.placeholder.com/20/00d3eb/000000?text=+) | ![#b82b28](https://via.placeholder.com/20/b82b28/000000?text=+) | ![#2ef625](https://via.placeholder.com/20/2ef625/000000?text=+) |
| HashMultiMap | ![#b82b28](https://via.placeholder.com/20/b82b28/000000?text=+) | ![#9f3b94](https://via.placeholder.com/20/9f3b94/000000?text=+) | ![#497edd](https://via.placeholder.com/20/497edd/000000?text=+) | ![#00d3eb](https://via.placeholder.com/20/00d3eb/000000?text=+) | ![#b82b28](https://via.placeholder.com/20/b82b28/000000?text=+) | ![#2ef625](https://via.placeholder.com/20/2ef625/000000?text=+) |
| HashMultiSet | ![#b82b28](https://via.placeholder.com/20/b82b28/000000?text=+) | ![#9f3b94](https://via.placeholder.com/20/9f3b94/000000?text=+) | ![#497edd](https://via.placeholder.com/20/497edd/000000?text=+) | ![#00d3eb](https://via.placeholder.com/20/00d3eb/000000?text=+) | ![#b82b28](https://via.placeholder.com/20/b82b28/000000?text=+) | ![#2ef625](https://via.placeholder.com/20/2ef625/000000?text=+) |
| HashSet | ![#b82b28](https://via.placeholder.com/20/b82b28/000000?text=+) | ![#9f3b94](https://via.placeholder.com/20/9f3b94/000000?text=+) | ![#497edd](https://via.placeholder.com/20/497edd/000000?text=+) | ![#00d3eb](https://via.placeholder.com/20/00d3eb/000000?text=+) | ![#b82b28](https://via.placeholder.com/20/b82b28/000000?text=+) | ![#2ef625](https://via.placeholder.com/20/2ef625/000000?text=+) |
| Heap | ![#9f3b94](https://via.placeholder.com/20/9f3b94/000000?text=+) | ![#9f3b94](https://via.placeholder.com/20/9f3b94/000000?text=+) | ![#497edd](https://via.placeholder.com/20/497edd/000000?text=+) | ![#00d3eb](https://via.placeholder.com/20/00d3eb/000000?text=+) | ![#2ef625](https://via.placeholder.com/20/2ef625/000000?text=+) | ![#b82b28](https://via.placeholder.com/20/b82b28/000000?text=+) |
| IntervalHeap | ![#9f3b94](https://via.placeholder.com/20/9f3b94/000000?text=+) | ![#9f3b94](https://via.placeholder.com/20/9f3b94/000000?text=+) | ![#497edd](https://via.placeholder.com/20/497edd/000000?text=+) | ![#00d3eb](https://via.placeholder.com/20/00d3eb/000000?text=+) | ![#2ef625](https://via.placeholder.com/20/2ef625/000000?text=+) | ![#b82b28](https://via.placeholder.com/20/b82b28/000000?text=+) |
| List | ![#9f3b94](https://via.placeholder.com/20/9f3b94/000000?text=+) | ![#9f3b94](https://via.placeholder.com/20/9f3b94/000000?text=+) | ![#497edd](https://via.placeholder.com/20/497edd/000000?text=+) | ![#00d3eb](https://via.placeholder.com/20/00d3eb/000000?text=+) | ![#2ef625](https://via.placeholder.com/20/2ef625/000000?text=+) | ![#2ef625](https://via.placeholder.com/20/2ef625/000000?text=+) |
| LinkedList | ![#9f3b94](https://via.placeholder.com/20/9f3b94/000000?text=+) | ![#9f3b94](https://via.placeholder.com/20/9f3b94/000000?text=+) | ![#497edd](https://via.placeholder.com/20/497edd/000000?text=+) | ![#00d3eb](https://via.placeholder.com/20/00d3eb/000000?text=+) | ![#2ef625](https://via.placeholder.com/20/2ef625/000000?text=+) | ![#2ef625](https://via.placeholder.com/20/2ef625/000000?text=+) |
| Queue | ![#9f3b94](https://via.placeholder.com/20/9f3b94/000000?text=+) | ![#9f3b94](https://via.placeholder.com/20/9f3b94/000000?text=+) | ![#497edd](https://via.placeholder.com/20/497edd/000000?text=+) | ![#00d3eb](https://via.placeholder.com/20/00d3eb/000000?text=+) | ![#2ef625](https://via.placeholder.com/20/2ef625/000000?text=+) | ![#2ef625](https://via.placeholder.com/20/2ef625/000000?text=+) |
| SortedList | ![#b82b28](https://via.placeholder.com/20/b82b28/000000?text=+) | ![#9f3b94](https://via.placeholder.com/20/9f3b94/000000?text=+) | ![#497edd](https://via.placeholder.com/20/497edd/000000?text=+) | ![#00d3eb](https://via.placeholder.com/20/00d3eb/000000?text=+) | ![#2ef625](https://via.placeholder.com/20/2ef625/000000?text=+) | ![#2ef625](https://via.placeholder.com/20/2ef625/000000?text=+) |
| Stack | ![#9f3b94](https://via.placeholder.com/20/9f3b94/000000?text=+) | ![#9f3b94](https://via.placeholder.com/20/9f3b94/000000?text=+) | ![#497edd](https://via.placeholder.com/20/497edd/000000?text=+) | ![#00d3eb](https://via.placeholder.com/20/00d3eb/000000?text=+) | ![#2ef625](https://via.placeholder.com/20/2ef625/000000?text=+) | ![#2ef625](https://via.placeholder.com/20/2ef625/000000?text=+) |
| TreeMap | ![#b82b28](https://via.placeholder.com/20/b82b28/000000?text=+) | ![#9f3b94](https://via.placeholder.com/20/9f3b94/000000?text=+) | ![#497edd](https://via.placeholder.com/20/497edd/000000?text=+) | ![#00d3eb](https://via.placeholder.com/20/00d3eb/000000?text=+) | ![#2ef625](https://via.placeholder.com/20/2ef625/000000?text=+) | ![#2ef625](https://via.placeholder.com/20/2ef625/000000?text=+) |
| TreeSet | ![#b82b28](https://via.placeholder.com/20/b82b28/000000?text=+) | ![#9f3b94](https://via.placeholder.com/20/9f3b94/000000?text=+) | ![#497edd](https://via.placeholder.com/20/497edd/000000?text=+) | ![#00d3eb](https://via.placeholder.com/20/00d3eb/000000?text=+) | ![#2ef625](https://via.placeholder.com/20/2ef625/000000?text=+) | ![#2ef625](https://via.placeholder.com/20/2ef625/000000?text=+) |
| Color | Label |
| :------------------------------------------------------: | ----------------------------------------- |
| ![#b82b28](https://placehold.it/20/b82b28/000000?text=+) | Required for basic functionality. |
| ![#9f3b94](https://placehold.it/20/9f3b94/000000?text=+) | Required for specific functions. |
| ![#497edd](https://placehold.it/20/497edd/000000?text=+) | Required for non-core specific functions. |
| ![#00d3eb](https://placehold.it/20/00d3eb/000000?text=+) | Optional. |
| ![#2ef625](https://placehold.it/20/2ef625/000000?text=+) | Not Used. |
| Color | Label |
| :-------------------------------------------------------------: | ----------------------------------------- |
| ![#b82b28](https://via.placeholder.com/20/b82b28/000000?text=+) | Required for basic functionality. |
| ![#9f3b94](https://via.placeholder.com/20/9f3b94/000000?text=+) | Required for specific functions. |
| ![#497edd](https://via.placeholder.com/20/497edd/000000?text=+) | Required for non-core specific functions. |
| ![#00d3eb](https://via.placeholder.com/20/00d3eb/000000?text=+) | Optional. |
| ![#2ef625](https://via.placeholder.com/20/2ef625/000000?text=+) | Not Used. |
## Design Decisions
@@ -294,30 +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
(Outdated)
The following table shows how each collection is implemented and how well they do when using as common [abstract data types](https://en.wikipedia.org/wiki/Abstract_data_type).
* **Ideal** - The collection implements correctly the abstract data type;
* **Not Ideal** - The implementation is fulfilled but some functionalities are either not part of the ADT or not present;
* **Bad** - It can be done, but its a bad idea.
![DataStructuresDiagram](https://i.imgur.com/hFqBSlC.png)
![GoodColor](https://img.shields.io/badge/Ideal_Implementation-%236abf69.svg)
![AverageColor](https://img.shields.io/badge/Not_Ideal_Implementation-%2363a4ff.svg)
![BadColor](https://img.shields.io/badge/Bad_Implementation-%23ff6659.svg)
## Code Review
Check out some code reviews that covers some parts the project. Most of them were posted a long time ago and are probably outdated.
| About | Link |
| ------------------------------------ | ------------------------------------------------------------------------------------------------------------------------- |
| Unit Test *./utl/test.h* | [![Code Review](http://www.zomis.net/codereview/shield/?qid=222954)](http://codereview.stackexchange.com/q/222954/178948) |
| Interval Heap *./cmc/intervalheap.h* | [![Code Review](http://www.zomis.net/codereview/shield/?qid=223595)](http://codereview.stackexchange.com/q/223595/178948) |
| Hash Set *./cmc/hashset.h* | [![Code Review](http://www.zomis.net/codereview/shield/?qid=217333)](http://codereview.stackexchange.com/q/217333/178948) |
| Linked List *./cmc/linkedlist.h* | [![Code Review](http://www.zomis.net/codereview/shield/?qid=216737)](http://codereview.stackexchange.com/q/216737/178948) |
| Others | [![Code Review](http://www.zomis.net/codereview/shield/?qid=213553)](http://codereview.stackexchange.com/q/213553/178948) |
* `CMC_NO_ALLOC` - disables `"cor/alloc.h"`, useful for statically allocated collections (SAC)
* `CMC_NO_IMPORTS` - disables all imports from the standard library at `"cor/core.h"`
-72
View File
@@ -1,72 +0,0 @@
Approximate completion of the library
[ 99 ][ 99 ][ 99 ] %
[source][tests][docs]
## - Finished
[30][15][01] Library
[91][45][01] CMC
[40][40][05] BitSet
[##][##][10] Deque
[80][70][00] HashBidiMap
[##][##][00] HashMap
[##][20][00] HashMultiMap
[##][20][00] HashMultiSet
[##][40][00] HashSet
[##][30][00] Heap
[##][40][00] IntervalHeap
[90][20][00] LinkedList
[90][30][00] List
[##][60][00] Queue
[00][00][00] SkipList
[80][20][00] SortedList
[95][90][00] Stack
[00][00][00] TreeBidiMap
[95][20][00] TreeMap
[00][00][00] TreeMultiMap
[00][00][00] TreeMultiSet
[95][20][00] TreeSet
[00][00][00] SAC
[00][00][00] BitSet
[00][00][00] Deque
[00][00][00] HashBidiMap
[00][00][00] HashMap
[00][00][00] HashMultiMap
[00][00][00] HashMultiSet
[00][00][00] HashSet
[00][00][00] Heap
[00][00][00] IntervalHeap
[00][00][00] LinkedList
[00][00][00] List
[00][00][00] Queue
[00][00][00] SkipList
[00][00][00] SortedList
[00][00][00] Stack
[00][00][00] TreeBidiMap
[00][00][00] TreeMap
[00][00][00] TreeMultiMap
[00][00][00] TreeMultiSet
[00][00][00] TreeSet
[00][00][00] TSC
[00][00][00] BitSet
[00][00][00] Deque
[00][00][00] HashBidiMap
[00][00][00] HashMap
[00][00][00] HashMultiMap
[00][00][00] HashMultiSet
[00][00][00] HashSet
[00][00][00] Heap
[00][00][00] IntervalHeap
[00][00][00] LinkedList
[00][00][00] List
[00][00][00] Queue
[00][00][00] SkipList
[00][00][00] SortedList
[00][00][00] Stack
[00][00][00] TreeBidiMap
[00][00][00] TreeMap
[00][00][00] TreeMultiMap
[00][00][00] TreeMultiSet
[00][00][00] TreeSet
+3 -5
View File
@@ -13,14 +13,11 @@ Check out CHANGELOG
#!! Next Patch -----------------------------------------------------------------
[ ] Fix BitSet, using capacity vs. counter
[ ] #12 - Fix the collections that depend on ITER
#!! Major ----------------------------------------------------------------------
[ ] Stabilize the library
[ ] Add INT library
[ ] Add SAC library
[ ] Add TSC library
[ ] Separate inner Data Structure implementation from the Collection's one
@@ -31,8 +28,8 @@ Check out CHANGELOG
#!! Minor ----------------------------------------------------------------------
[ ] Fix BitSet, using capacity vs. counter
[ ] #13 - Properly implement HashBidiMap iterator
[ ] #10 - Fix Benchmarks and Examples
[ ] More SortedList functions
[ ] BidiMap's _is_mapping() to check if a mapping K <=> V exists
[ ] New asserts - _array_int(), _array_not_in() and str
@@ -44,7 +41,6 @@ Check out CHANGELOG
#!! Patch ----------------------------------------------------------------------
[ ] MultiSets replace existing value with the new added one
[ ] Fix PUBLIC and PRIVATE incompatibility between CMC and EXT
#!! Considerations -------------------------------------------------------------
@@ -104,3 +100,5 @@ Check out CHANGELOG
[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
-502
View File
@@ -1,502 +0,0 @@
# A script for automation
import argparse
import os
import pathlib
import re
import shutil
import subprocess
import sys
from typing import List, Text
# Config Script Configuration
# Directories Names for directories
# Files Names for files
# Compiler Compiler Configurations
# Macro Expansion Configuration for the code expansion
# Collections All collections
#
# Variables marked as const are to not be modified
# Directories
# Output directory
# In this directory it is assumed that the following files and directories are
# included: main.c, codecov.c, unt folder
OUTPUT_DIR = './tests'
# Where the unit test files are
UNT_DIR = f'{OUTPUT_DIR}/unt'
# Directory mapping
DIR_MAP = {'HEADER': 'include', 'SOURCE': 'src'}
# File extension mapping
EXT_MAP = {'HEADER': 'h', 'SOURCE': 'c'}
# Where compilation objects will be outputted
BUILD_DIR = f'{OUTPUT_DIR}/build'
# const
INCLUDE_DIR = f"{OUTPUT_DIR}/{DIR_MAP['HEADER']}"
# const
SRC_DIR = f"{OUTPUT_DIR}/{DIR_MAP['SOURCE']}"
# Where executables go
BIN_DIR = f'{BUILD_DIR}/bin'
# Where object files .o go
OBJ_DIR = BUILD_DIR
# Where .gcov files should go
GCOV_DIR = f'{BUILD_DIR}/gcov'
# Files
# All const
# The name of the main test
MAIN = 'main'
# The name of the code coverage file
CODECOV = 'codecov'
# The name of the single test file
SINGLE = 'single'
# Compiler
# Compiler to be used
CC = 'gcc'
# Compilation Flags
CFLAGS = ['-Wall', '-Werror', '-O3']
# Link flags
LFLAGS = []
# Coverage Flags
CVFLAGS = ['--coverage', '-O0']
# gcov flags
GCOV_FLAGS = []
# Include of the main library
# const
INCLUDE = ['-I', './src']
# Include to the test file headers
# const
TINCLUDE = ['-I', f'{INCLUDE_DIR}', '-I', f'{UNT_DIR}']
# Include to code coverage
# const
CVINCLUDE = ['-I', INCLUDE_DIR, '-I', SRC_DIR, '-I', f'{UNT_DIR}']
# Macro Expansion
# -E Only preprocessor
# -P No linemarkers
# -C Keep comments, except those inside macros (for UNIQUE_FLAG)
# const
EXPAND_FLAGS = '-E -P -C'
# Used to delimiter where the actual code starts and ends. Used by regex.
# Needs to be a valid C comment.
UNIQUE_FLAG = '// C_MACRO_COLLECTIONS_CODE'
# Temporary file used to expand the macros
TMP_FILE = './main.c'
# All collections that can be used for testing
COLLECTIONS = [
# header, library, collection, pfx, sname, size, key, val
{'h': '"cmc_bitset.h"', 'LIB': 'CMC', 'COLLECTION': 'BITSET', 'PFX': 'bs', 'SNAME': 'bitset', 'SIZE': '', 'K': '', 'V': '' },
{'h': '"cmc_deque.h"', 'LIB': 'CMC', 'COLLECTION': 'DEQUE', 'PFX': 'd', 'SNAME': 'deque', 'SIZE': '', 'K': '', 'V': 'size_t'},
{'h': '"cmc_hashbidimap.h"', 'LIB': 'CMC', 'COLLECTION': 'HASHBIDIMAP', 'PFX': 'hbm', 'SNAME': 'hashbidimap', 'SIZE': '', 'K': 'size_t', 'V': 'size_t'},
{'h': '"cmc_hashmap.h"', 'LIB': 'CMC', 'COLLECTION': 'HASHMAP', 'PFX': 'hm', 'SNAME': 'hashmap', 'SIZE': '', 'K': 'size_t', 'V': 'size_t'},
{'h': '"cmc_hashmultimap.h"', 'LIB': 'CMC', 'COLLECTION': 'HASHMULTIMAP', 'PFX': 'hmm', 'SNAME': 'hashmultimap', 'SIZE': '', 'K': 'size_t', 'V': 'size_t'},
{'h': '"cmc_hashmultiset.h"', 'LIB': 'CMC', 'COLLECTION': 'HASHMULTISET', 'PFX': 'hms', 'SNAME': 'hashmultiset', 'SIZE': '', 'K': '', 'V': 'size_t'},
{'h': '"cmc_hashset.h"', 'LIB': 'CMC', 'COLLECTION': 'HASHSET', 'PFX': 'hs', 'SNAME': 'hashset', 'SIZE': '', 'K': '', 'V': 'size_t'},
{'h': '"cmc_heap.h"', 'LIB': 'CMC', 'COLLECTION': 'HEAP', 'PFX': 'h', 'SNAME': 'heap', 'SIZE': '', 'K': '', 'V': 'size_t'},
{'h': '"cmc_intervalheap.h"', 'LIB': 'CMC', 'COLLECTION': 'INTERVALHEAP', 'PFX': 'ih', 'SNAME': 'intervalheap', 'SIZE': '', 'K': '', 'V': 'size_t'},
{'h': '"cmc_linkedlist.h"', 'LIB': 'CMC', 'COLLECTION': 'LINKEDLIST', 'PFX': 'll', 'SNAME': 'linkedlist', 'SIZE': '', 'K': '', 'V': 'size_t'},
{'h': '"cmc_list.h"', 'LIB': 'CMC', 'COLLECTION': 'LIST', 'PFX': 'l', 'SNAME': 'list', 'SIZE': '', 'K': '', 'V': 'size_t'},
{'h': '"cmc_queue.h"', 'LIB': 'CMC', 'COLLECTION': 'QUEUE', 'PFX': 'q', 'SNAME': 'queue', 'SIZE': '', 'K': '', 'V': 'size_t'},
{'h': '"cmc_sortedlist.h"', 'LIB': 'CMC', 'COLLECTION': 'SORTEDLIST', 'PFX': 'sl', 'SNAME': 'sortedlist', 'SIZE': '', 'K': '', 'V': 'size_t'},
{'h': '"cmc_stack.h"', 'LIB': 'CMC', 'COLLECTION': 'STACK', 'PFX': 's', 'SNAME': 'stack', 'SIZE': '', 'K': '', 'V': 'size_t'},
{'h': '"cmc_treemap.h"', 'LIB': 'CMC', 'COLLECTION': 'TREEMAP', 'PFX': 'tm', 'SNAME': 'treemap', 'SIZE': '', 'K': 'size_t', 'V': 'size_t'},
{'h': '"cmc_treeset.h"', 'LIB': 'CMC', 'COLLECTION': 'TREESET', 'PFX': 'ts', 'SNAME': 'treeset', 'SIZE': '', 'K': '', 'V': 'size_t'}
]
# Just a realy helpfull overview
CONFIG = f'''Directory Settings
OUTPUT_DIR = {OUTPUT_DIR}
UNT_DIR = {UNT_DIR}
DIR_MAP = {DIR_MAP}
EXT_MAP = {EXT_MAP}
BUILD_DIR = {BUILD_DIR}
INCLUDE_DIR = {INCLUDE_DIR}
SRC_DIR = {SRC_DIR}
OBJ_DIR = {OBJ_DIR}
GCOV_DIR = {GCOV_DIR}
File Settings
MAIN = {MAIN}
CODECOV = {CODECOV}
SINGLE = {SINGLE}
Compiler Settings
CC = {CC}
CFLAGS = {CFLAGS}
LFLAGS = {LFLAGS}
CVFLAGS = {CVFLAGS}
GCOV_FLAGS = {GCOV_FLAGS}
INCLUDE = {INCLUDE}
TINCLUDE = {TINCLUDE}
CVINCLUDE = {CVINCLUDE}
Macro Expansion
EXPAND_FLAGS = {EXPAND_FLAGS}
UNIQUE_FLAG = {UNIQUE_FLAG}
TMP_FILE = {TMP_FILE}'''
def full_path(path: Text) -> Text:
'''
Returns the full path of a 'path' with ralative paths, e.g. './' or '../'
'''
return str(pathlib.Path(path).resolve())
def execute_command(commands: List[Text]):
cmd = ' '.join(commands)
print(cmd)
subprocess.check_call(cmd, shell=True)
# if cp.returncode != 0:
# print('Error when executing the last command')
# exit(1)
def require_executable(program: Text):
'''
Asserts that a given program is installed and available in PATH. Raises an exception if it doesn't.
'''
if shutil.which(program) is None:
raise Exception(f'The required executable {program} was not found in your path')
def require_file(file: Text):
'''
Asserts that a given file exists. Raises an exception if it doesn't.
'''
f = pathlib.Path(file).resolve()
if not f.is_file():
raise Exception(f'The required file {str(f)} was not found')
def assert_dir(directory: Text):
'''
Given a string 'directory' that is a path to a directory, make sure that it exists.
'''
# TODO change this to use pathlib ?
if not os.path.exists(directory):
os.makedirs(directory)
def assert_structure():
'''
Git might not commit some required directories. This function asserts that they exist.
'''
assert_dir(OUTPUT_DIR)
# include and src
for directory in DIR_MAP.values():
assert_dir(f'{OUTPUT_DIR}/{directory}')
assert_dir(BUILD_DIR)
assert_dir(OBJ_DIR)
assert_dir(BIN_DIR)
assert_dir(GCOV_DIR)
def format_code(source: bool, tests: bool):
'''
Format all source files from the main library or test files.
'''
if source:
execute_command(['find', './src/', '-name', '*.h', '|', 'xargs', 'clang-format', '--style=file', '--verbose', '-i'])
if tests:
execute_command(['find', './tests/', '-name', '*.c', '-o', '-name', '*.h', '|', 'xargs', 'clang-format', '--style=file', '--verbose', '-i'])
def clean_build(cleanfull: bool):
'''
Removes all files generated by compilation and code coverage along with folders.
'''
# -f prevents 'rm' from failing
execute_command(['rm', '-r', '-f', f'./*.gcov'])
execute_command(['rm', '-r', '-f', f'{OUTPUT_DIR}/*.exe'])
execute_command(['rm', '-r', '-f', BUILD_DIR])
execute_command(['rm', '-f', './*.gcda'])
execute_command(['rm', '-f', './*.gcno'])
if cleanfull:
execute_command(['rm', '-r', SRC_DIR])
execute_command(['rm', '-r', INCLUDE_DIR])
def expand_code():
'''
Expands code to be used in tests. This is necessary because code coverage doesn't work with macros.
'''
# Generate Header and Source separately
for ftype in ['HEADER', 'SOURCE']:
for data in COLLECTIONS:
file = open(TMP_FILE, 'w')
file.write(
f'''
#include "macro_collections.h"
{UNIQUE_FLAG}
C_MACRO_COLLECTIONS_ALL_{ftype}({data['LIB']}, {data['COLLECTION']}, PUBLIC, ({', '.join([data['PFX'], data['SNAME'], data['SIZE'], data['K'], data['V']])}))
{UNIQUE_FLAG}
''')
file.flush()
file.close()
result = subprocess.getoutput(f'{CC} {EXPAND_FLAGS} {" ".join(INCLUDE)} {TMP_FILE}')
# (?s) makes '.' match anything, even '\n'
match = re.search(fr'(?s){UNIQUE_FLAG}(?P<code>.+){UNIQUE_FLAG}', result)
if match is None:
os.remove(TMP_FILE)
print('Didn\'t match FLAG. Probably because compilation failed.', file=sys.stderr)
exit(1)
file = open(f'{OUTPUT_DIR}/{DIR_MAP[ftype]}/tst_{data["LIB"].lower()}_{data["SNAME"]}.{EXT_MAP[ftype]}', 'w')
if ftype == 'HEADER':
file.write(
f'''
#ifndef CMC_{data['LIB']}_{data['COLLECTION']}_TEST_H
#define CMC_{data['LIB']}_{data['COLLECTION']}_TEST_H
#include "macro_collections.h"
{match.group('code')}
#endif /* CMC_{data['LIB']}_{data['COLLECTION']}_TEST_H */
''')
else:
file.write(
f'''
#include {'"tst_' + data["h"][1:]}
{match.group("code")}
''')
file.flush()
file.close()
print(f'''Generated {'"tst_' + data["h"][1:]: >24} -> {OUTPUT_DIR}/{DIR_MAP[ftype]}/tst_{data["LIB"].lower()}_{data["SNAME"]}.{EXT_MAP[ftype]}''')
os.remove(TMP_FILE)
def format_expand():
'''
Format the files outputted by 'expand_code'.
'''
cmd = ['clang-format', '--style=file', '--verbose', '-i']
dirs_to_format = [f'{OUTPUT_DIR}/{DIR_MAP[ftype]}/*.{EXT_MAP[ftype]}' for ftype in DIR_MAP.keys()]
cmd.extend(dirs_to_format)
execute_command(cmd)
def build_main():
'''
Build all object files and main.c for tests.
'''
for data in COLLECTIONS:
cmd = [CC]
cmd += TINCLUDE # This one needs to go first
cmd += INCLUDE
cmd += ['-c', f"{SRC_DIR}/tst_{data['LIB'].lower()}_{data['SNAME']}.c"]
cmd += ['-o', f"{OBJ_DIR}/tst_{data['LIB'].lower()}_{data['SNAME']}.o"]
execute_command(cmd)
# Build OUTPUT_DIR/main.c
cmd = [CC]
cmd += TINCLUDE # This one needs to go first
cmd += INCLUDE
cmd += ['-c', f'{OUTPUT_DIR}/{MAIN}.c']
cmd += ['-o', f'{OBJ_DIR}/{MAIN}.o']
execute_command(cmd)
# Link everything producing OUTPUT_DIR/main.exe
cmd = [CC]
cmd += LFLAGS
cmd += ['-o', f'{BIN_DIR}/{MAIN}.exe']
cmd += [f'{OBJ_DIR}/main.o']
cmd += [f'{OBJ_DIR}/tst_{data["LIB"].lower()}_{data["SNAME"]}.o' for data in COLLECTIONS]
execute_command(cmd)
def run_main():
'''
Runs main.exe
'''
execute_command([full_path(f'{BIN_DIR}/{MAIN}.exe')])
def build_codecov():
'''
Builds codecov.c for code coverage.
'''
cmd = [CC]
cmd += CVFLAGS
cmd += CVINCLUDE # This one needs to go first
cmd += INCLUDE
cmd += [f'{OUTPUT_DIR}/{CODECOV}.c']
cmd += ['-o', f'{BIN_DIR}/{CODECOV}.exe']
execute_command(cmd)
def run_codecov():
'''
Runs codecov.exe and then gcov on the generated gcda files. All gcov files then go to GCOV_DIR.
'''
execute_command([full_path(f'{BIN_DIR}/{CODECOV}.exe')])
execute_command(['gcov'] + GCOV_FLAGS + [f'{CODECOV}.gcda'])
execute_command(['rm', '*.h.gcov'])
def tidy():
'''
Places files to their respective directory.
'''
execute_command(['mv', '*.gcov', GCOV_DIR])
if __name__ == '__main__':
p = argparse.ArgumentParser('autogen.py', usage='%(prog)s [options]')
p.add_argument('-sc', '--show-config',
help='Displays the current configuration',
default=False,
action='store_true',
dest='config')
source = p.add_argument_group('source', 'For dealing with the source files and formatting')
expand = p.add_argument_group('expand', 'For dealing with code generation and formatting for tests')
task = p.add_argument_group('task', 'Specify a task (mutually exclusive)')
task_ = task.add_mutually_exclusive_group()
action = p.add_argument_group('action', 'Actions on task')
task_.add_argument('-cv', '--codecov',
help='Designates task as code coverage (uses codecov.c)',
default=False,
action='store_true',
dest='codecov')
task_.add_argument('-m', '--main',
help='Designates task as the main tests (uses main.c)',
default=False,
action='store_true',
dest='main')
task_.add_argument('-s', '--single',
help='Designates task as an individual test (uses single.c)',
dest='single')
expand.add_argument('-c', '--clean',
help='Cleans all build objects',
default=False,
action='store_true',
dest='clean')
expand.add_argument('-cf', '--clean-full',
help='Cleans all build objects, source and header files, and removes folders',
default=False,
action='store_true',
dest='cleanfull')
expand.add_argument('-e', '--expand',
help='Expands the header and source files',
default=False,
action='store_true',
dest='expand')
expand.add_argument('-nf', '--no-format',
help='Does not format the output of expand. Can be used when you might not have clang-format',
default=False,
action='store_true',
dest='noformat')
expand.add_argument('-nt', '--no-tidy',
help='Don\'t move files around',
default=False,
action='store_true',
dest='notidy')
action.add_argument('-b', '--build',
help='Build task',
default=False,
action='store_true',
dest='build')
action.add_argument('-r', '--run',
help='Run task',
default=False,
action='store_true',
dest='run')
source.add_argument('-fs', '--format-source',
help='Format the source code',
default=False,
action='store_true',
dest='fmt_source')
source.add_argument('-ft', '--format-tests',
help='Format tests files',
default=False,
action='store_true',
dest='fmt_tests')
args = p.parse_args()
has_target = args.main or args.codecov or args.single
if args.config:
print(CONFIG)
exit(0)
if args.fmt_source or args.fmt_tests:
require_executable('find')
require_executable('xargs')
format_code(args.fmt_source, args.fmt_tests)
# Prevent mixing code
exit(0)
if not args.cleanfull:
assert_structure()
if args.clean:
clean_build(False)
else:
clean_build(True)
# Nothing else will work, so just exit
exit(0)
if args.expand:
expand_code()
if not args.noformat:
require_executable('clang-format')
format_expand()
else:
# In case the next task is to build the code from source
# This warning is a very annoying one from gcc
CFLAGS += ['-Wno-misleading-indentation']
if args.build:
require_executable(CC)
if args.codecov:
require_executable('gcov')
if args.codecov:
require_file(f'{OUTPUT_DIR}/{CODECOV}.c')
if args.build:
build_codecov()
if args.run:
run_codecov()
elif args.main:
require_file(f'{OUTPUT_DIR}/{MAIN}.c')
if args.build:
build_main()
if args.run:
run_main()
elif args.single:
require_file(f'{OUTPUT_DIR}/{SINGLE}.c')
# TODO
if not args.notidy and args.codecov:
tidy()
@@ -1,57 +0,0 @@
import os
import sys
import time
import subprocess
ITERATIONS = 10
COUNT = 20000000
VERBOSE = False
NL = '\n'
INCLUDE = "../../../src"
CC = 'gcc'
CCPP = 'g++' # LoL
OPT = '-O3'
print(f'Using {CC} compiler')
def execute_command(commands):
print(' '.join(commands))
subprocess.run(commands, shell=True)
# Common args
args = ['-I', INCLUDE, OPT, f'-DCOUNT={COUNT}', '-DCMC_NO_CALLBACKS']
map_args = [CC, 'hashmap.c', '-o', 'hashmap.exe']
mmap_args = [CC, 'hashmultimap.c', '-o', 'hashmultimap.exe']
cpp_args = [CCPP, 'unorderedmap.cpp', '-I', INCLUDE, '-o', 'unorderedmap.exe', OPT, f'-DCOUNT={COUNT}']
map_args.extend(args)
mmap_args.extend(args)
cpp_args.extend(args)
execute_command(map_args)
execute_command(mmap_args)
execute_command(cpp_args)
programs = ['hashmap.exe', 'hashmultimap.exe', 'unorderedmap.exe']
for prog in programs:
total = 0
for i in range(ITERATIONS):
print(f'{i}...', end='')
sys.stdout.flush()
start_time = time.time()
subprocess.run(prog, shell=True)
delta = time.time() - start_time
total += delta
if VERBOSE:
print(f'({delta})')
avg = total / ITERATIONS
print(f'{"" if VERBOSE else NL}{avg} seconds for {COUNT} -> AVG[{int((avg * 1e9) / COUNT)} ns] [{prog}]{NL if VERBOSE else ""}')
+11
View File
@@ -0,0 +1,11 @@
CC=gcc
INCLUDE=-I ..
CFLAGS=-Wall -Wextra -Werror
benchmark: benchmark.c
$(CC) $(CFLAGS) $(INCLUDE) $< -o ./$@.exe -lm
./$@.exe
clean:
rm *.exe -f
rm *.txt -f
+191 -148
View File
@@ -12,13 +12,19 @@
* - Iteration
* - Output
*/
#include "macro_collections.h"
#include "util/twister.c"
#include <stdio.h>
#include <stdint.h>
#include <assert.h>
#include <math.h>
#include <inttypes.h>
#include <math.h>
#include <stdint.h>
#include <stdio.h>
#include "util/twister.c"
#include "cmc/cor/hashtable.h"
#include "cmc/cor/heap.h"
#include "cmc/utl/foreach.h"
#include "cmc/utl/futils.h"
#include "cmc/utl/timer.h"
#define NTOTAL UINT64_C(10000000)
#define NMIN UINT64_C(100)
@@ -26,23 +32,6 @@
// Percentage % macro
#define PC(x) x * 100.0
static int intcmp(int a, int b)
{
return a - b;
}
static size_t inthash(int t)
{
size_t a = t;
a += ~(a << 15);
a ^= (a >> 10);
a += (a << 3);
a ^= (a >> 6);
a += ~(a << 11);
a ^= (a >> 16);
return a;
}
size_t randsize(size_t min, size_t max, mt_state_ptr st)
{
return (size_t)floor(twist_real(st) * ((double)max - (double)min + 1.0) + (double)min);
@@ -59,136 +48,190 @@ void shuffle(int *array, mt_state_ptr st)
}
}
CMC_COLLECTION_GENERATE(DEQUE, d, deque, /* K */, int)
CMC_COLLECTION_GENERATE(HASHMAP, hm, hmap, int, int)
CMC_COLLECTION_GENERATE(HASHSET, hs, hset, /* K */, int)
CMC_COLLECTION_GENERATE(HEAP, h, heap, /* K */, int)
CMC_COLLECTION_GENERATE(LINKEDLIST, ll, linked, /* K */, int)
CMC_COLLECTION_GENERATE(LIST, l, list, /* K */, int)
CMC_COLLECTION_GENERATE(QUEUE, q, queue, /* K */, int)
CMC_COLLECTION_GENERATE(STACK, s, stack, /* K */, int)
CMC_COLLECTION_GENERATE(TREEMAP, tm, tmap, int, int)
CMC_COLLECTION_GENERATE(TREESET, ts, tset, /* K */, int)
struct
{
CMC_DEF_FTAB_CMP(size_t);
CMC_DEF_FTAB_CPY(size_t);
CMC_DEF_FTAB_STR(size_t);
CMC_DEF_FTAB_FREE(size_t);
CMC_DEF_FTAB_HASH(size_t);
CMC_DEF_FTAB_PRI(size_t);
} int_ftab = { cmc_size_cmp, NULL, cmc_size_str, NULL, cmc_size_hash, cmc_size_cmp };
CMC_COLLECTION_GENERATE(INTERVALHEAP, ih, iheap, /* k */, int)
CMC_COLLECTION_GENERATE(MULTIMAP, mm, mmap, int, int)
CMC_COLLECTION_GENERATE(MULTISET, ms, mset, /* K */, int)
#define CMC_ARGS_FALLTHROUGH
#define V int
#define K int
#define CMC_EXT_ITER
#define BENCHMARK(NAME, PFX, sname, initfunc, insertbody, removebody, searchbody) \
void NAME##_io_benchmark(int *array, int *sarray, size_t s) \
{ \
printf("+------------------------------------------------------------ %10s\n", #NAME); \
printf("+------------------------------------------------------------ \n"); \
struct cmc_timer timer, total; \
int r, k, v; \
size_t j; \
\
struct sname *coll = initfunc; \
\
cmc_timer_start(total); \
cmc_timer_start(timer); \
\
for (size_t i = 0; i < NTOTAL; i++) \
{ \
insertbody; \
} \
\
cmc_timer_stop(timer); \
\
cmc_timer_calc(timer); \
\
size_t s1 = PFX##_count(coll); \
\
#define SNAME bitset
#define PFX bs
#include "cmc/bitset.h"
#define SNAME deque
#define PFX d
#include "cmc/deque.h"
#define SNAME hashbidimap
#define PFX hbm
#include "cmc/hashbidimap.h"
#define SNAME hashmap
#define PFX hm
#include "cmc/hashmap.h"
#define SNAME hashmultimap
#define PFX hmm
#include "cmc/hashmultimap.h"
#define SNAME hashmultiset
#define PFX hms
#include "cmc/hashmultiset.h"
#define SNAME hashset
#define PFX hs
#include "cmc/hashset.h"
#define SNAME heap
#define PFX h
#include "cmc/heap.h"
#define SNAME intervalheap
#define PFX ih
#include "cmc/intervalheap.h"
#define SNAME linkedlist
#define PFX ll
#include "cmc/linkedlist.h"
#define SNAME list
#define PFX l
#include "cmc/list.h"
#define SNAME queue
#define PFX q
#include "cmc/queue.h"
#define SNAME sortedlist
#define PFX sl
#include "cmc/sortedlist.h"
#define SNAME stack
#define PFX s
#include "cmc/stack.h"
#define SNAME treemap
#define PFX tm
#include "cmc/treemap.h"
#define SNAME treeset
#define PFX ts
#include "cmc/treeset.h"
#undef CMC_ARGS_FALLTHROUGH
#include "cmc/cor/undef.h"
#define BENCHMARK(NAME, PFX, SNAME, initfunc, insertbody, removebody, searchbody) \
void NAME##_io_benchmark(int *array, int *sarray, size_t s) \
{ \
printf("+------------------------------------------------------------ %10s\n", #NAME); \
printf("+------------------------------------------------------------ \n"); \
struct cmc_timer timer, total; \
CMC_UNUSED int r; \
\
struct SNAME *coll = initfunc; \
\
cmc_timer_start(total); \
cmc_timer_start(timer); \
\
for (size_t i = 0; i < NTOTAL; i++) \
{ \
insertbody; \
} \
\
cmc_timer_stop(timer); \
\
size_t s1 = PFX##_count(coll); \
\
printf(" INPUT %10s TOOK %8.0lf milliseconds for %8" PRIuMAX " elements\n", #NAME, timer.result, s1); \
\
double input_time = timer.result; \
\
cmc_timer_start(timer); \
\
for (size_t i = 0; i < s; i++) \
{ \
searchbody; \
} \
\
cmc_timer_stop(timer); \
\
cmc_timer_calc(timer); \
\
printf(" SEARCH %10s TOOK %8.0lf milliseconds for %8" PRIuMAX " elements\n", #NAME, timer.result, s); \
\
double search_time = timer.result; \
\
struct sname##_iter iter; \
\
cmc_timer_start(timer); \
\
for (PFX##_iter_init(&iter, coll); !PFX##_iter_end(&iter); PFX##_iter_next(&iter)) \
{ \
} \
\
cmc_timer_stop(timer); \
\
cmc_timer_calc(timer); \
\
\
double input_time = timer.result; \
\
cmc_timer_start(timer); \
\
for (size_t i = 0; i < s; i++) \
{ \
searchbody; \
} \
\
cmc_timer_stop(timer); \
\
printf(" SEARCH %10s TOOK %8.0lf milliseconds for %8" PRIuMAX " elements\n", #NAME, timer.result, s); \
\
double search_time = timer.result; \
\
cmc_timer_start(timer); \
\
CMC_FOREACH (PFX, SNAME, iter, coll) \
{ \
} \
\
cmc_timer_stop(timer); \
\
printf("ITERATION %10s TOOK %8.0lf milliseconds for %8" PRIuMAX " elements\n", #NAME, timer.result, s1); \
\
double iter_time = timer.result; \
\
cmc_timer_start(timer); \
\
for (size_t i = 0; i < NTOTAL; i++) \
{ \
removebody; \
} \
\
cmc_timer_stop(timer); \
\
cmc_timer_calc(timer); \
\
size_t s2 = PFX##_count(coll); \
\
\
double iter_time = timer.result; \
\
cmc_timer_start(timer); \
\
for (size_t i = 0; i < NTOTAL; i++) \
{ \
removebody; \
} \
\
cmc_timer_stop(timer); \
\
size_t s2 = PFX##_count(coll); \
\
printf(" OUTPUT %10s TOOK %8.0lf milliseconds for %8" PRIuMAX " elements\n", #NAME, timer.result, s1); \
\
double output_time = timer.result; \
\
cmc_timer_stop(total); \
cmc_timer_calc(total); \
\
PFX##_free(coll, NULL); \
\
double adj_search_time = (total.result - search_time) + (search_time * (double)NTOTAL) / (double)s; \
double no_search = input_time + iter_time + output_time; \
\
printf("+------------------------------------------------------------ \n"); \
printf("TOTAL TIME : %.0lf milliseconds\n", total.result); \
printf("ADJUSTED TIME : %.0lf milliseconds\n", adj_search_time); \
\
printf("+------------------------------------------------------------ \n"); \
printf(" INPUT : %5.2lf%% (%5.2f%%)\n", PC(input_time / total.result), PC(input_time / no_search)); \
printf(" SEARCH : %5.2lf%%\n", PC(search_time / total.result)); \
printf("ITERATION : %5.2lf%% (%5.2f%%)\n", PC(iter_time / total.result), PC(iter_time / no_search)); \
\
double output_time = timer.result; \
\
cmc_timer_stop(total); \
\
PFX##_free(coll); \
\
double adj_search_time = (total.result - search_time) + (search_time * (double)NTOTAL) / (double)s; \
double no_search = input_time + iter_time + output_time; \
\
printf("+------------------------------------------------------------ \n"); \
printf("TOTAL TIME : %.0lf milliseconds\n", total.result); \
printf("ADJUSTED TIME : %.0lf milliseconds\n", adj_search_time); \
\
printf("+------------------------------------------------------------ \n"); \
printf(" INPUT : %5.2lf%% (%5.2f%%)\n", PC(input_time / total.result), PC(input_time / no_search)); \
printf(" SEARCH : %5.2lf%%\n", PC(search_time / total.result)); \
printf("ITERATION : %5.2lf%% (%5.2f%%)\n", PC(iter_time / total.result), PC(iter_time / no_search)); \
printf(" OUTPUT : %5.2lf%% (%5.2f%%)\n", PC(output_time / total.result), PC(output_time / no_search)); \
printf("+------------------------------------------------------------ \n"); \
\
assert(s1 == NTOTAL && s2 == 0); \
\
printf("+------------------------------------------------------------ %10s\n\n", #NAME); \
printf("+------------------------------------------------------------ \n"); \
\
assert(s1 == NTOTAL && s2 == 0); \
\
printf("+------------------------------------------------------------ %10s\n\n", #NAME); \
}
BENCHMARK(DEQUE, d, deque, d_new(NTOTAL), d_push_back(coll, array[i]), d_pop_back(coll), d_contains(coll, sarray[i], intcmp))
BENCHMARK(HASHMAP, hm, hmap, hm_new(NTOTAL, 0.6, intcmp, inthash), hm_insert(coll, array[i], array[i]), hm_remove(coll, array[i], &r), hm_contains(coll, sarray[i]))
BENCHMARK(HASHSET, hs, hset, hs_new(NTOTAL, 0.6, intcmp, inthash), hs_insert(coll, array[i]), hs_remove(coll, array[i]), hs_contains(coll, sarray[i]))
BENCHMARK(HEAP, h, heap, h_new(NTOTAL, cmc_min_heap, intcmp), h_insert(coll, array[i]), h_remove(coll, &r), h_contains(coll, sarray[i]))
BENCHMARK(LINKEDLIST, ll, linked, ll_new(), ll_push_back(coll, array[i]), ll_pop_back(coll), ll_contains(coll, sarray[i], intcmp))
BENCHMARK(LIST, l, list, l_new(NTOTAL), l_push_back(coll, array[i]), l_pop_back(coll), l_contains(coll, sarray[i], intcmp))
BENCHMARK(QUEUE, q, queue, q_new(NTOTAL), q_enqueue(coll, array[i]), q_dequeue(coll), q_contains(coll, sarray[i], intcmp))
BENCHMARK(STACK, s, stack, s_new(NTOTAL), s_push(coll, array[i]), s_pop(coll), s_contains(coll, sarray[i], intcmp))
BENCHMARK(TREEMAP, tm, tmap, tm_new(intcmp), tm_insert(coll, array[i], array[i]), tm_remove(coll, array[i], &r), tm_contains(coll, sarray[i]))
BENCHMARK(TREESET, ts, tset, ts_new(intcmp), ts_insert(coll, array[i]), ts_remove(coll, array[i]), ts_contains(coll, sarray[i]))
BENCHMARK(DEQUE, d, deque, d_new(NTOTAL, (struct deque_fval *)&int_ftab), d_push_back(coll, array[i]), d_pop_back(coll),
d_contains(coll, sarray[i]))
BENCHMARK(HASHMAP, hm, hashmap, hm_new(NTOTAL, 0.6, (struct hashmap_fkey *)&int_ftab, (struct hashmap_fval *)&int_ftab),
hm_insert(coll, array[i], array[i]), hm_remove(coll, array[i], &r), hm_contains(coll, sarray[i]))
BENCHMARK(HASHSET, hs, hashset, hs_new(NTOTAL, 0.6, (struct hashset_fval *)&int_ftab), hs_insert(coll, array[i]),
hs_remove(coll, array[i]), hs_contains(coll, sarray[i]))
BENCHMARK(HEAP, h, heap, h_new(NTOTAL, CMC_MIN_HEAP, (struct heap_fval *)&int_ftab), h_insert(coll, array[i]),
h_remove(coll), h_contains(coll, sarray[i]))
BENCHMARK(LINKEDLIST, ll, linkedlist, ll_new((struct linkedlist_fval *)&int_ftab), ll_push_back(coll, array[i]),
ll_pop_back(coll), ll_contains(coll, sarray[i]))
BENCHMARK(LIST, l, list, l_new(NTOTAL, (struct list_fval *)&int_ftab), l_push_back(coll, array[i]), l_pop_back(coll),
l_contains(coll, sarray[i]))
BENCHMARK(QUEUE, q, queue, q_new(NTOTAL, (struct queue_fval *)&int_ftab), q_enqueue(coll, array[i]), q_dequeue(coll),
q_contains(coll, sarray[i]))
BENCHMARK(STACK, s, stack, s_new(NTOTAL, (struct stack_fval *)&int_ftab), s_push(coll, array[i]), s_pop(coll),
s_contains(coll, sarray[i]))
BENCHMARK(TREEMAP, tm, treemap, tm_new((struct treemap_fkey *)&int_ftab, (struct treemap_fval *)&int_ftab),
tm_insert(coll, array[i], array[i]), tm_remove(coll, array[i], &r), tm_contains(coll, sarray[i]))
BENCHMARK(TREESET, ts, treeset, ts_new((struct treeset_fval *)&int_ftab), ts_insert(coll, array[i]),
ts_remove(coll, array[i]), ts_contains(coll, sarray[i]))
BENCHMARK(INTERVALHEAP, ih, iheap, ih_new(NTOTAL, intcmp), ih_insert(coll, array[i]), ih_remove_max(coll, &r), ih_contains(coll, sarray[i]))
BENCHMARK(MULTIMAP, mm, mmap, mm_new(NTOTAL, 0.8, intcmp, inthash), mm_insert(coll, array[i], array[i]), mm_remove(coll, array[i], &r), mm_contains(coll, sarray[i]))
BENCHMARK(MULTISET, ms, mset, ms_new(NTOTAL, 0.6, intcmp, inthash), ms_insert(coll, array[i]), ms_remove(coll, array[i]), ms_contains(coll, sarray[i]))
BENCHMARK(INTERVALHEAP, ih, intervalheap, ih_new(NTOTAL, (struct intervalheap_fval *)&int_ftab),
ih_insert(coll, array[i]), ih_remove_max(coll), ih_contains(coll, sarray[i]))
BENCHMARK(MULTIMAP, hmm, hashmultimap,
hmm_new(NTOTAL, 0.8, (struct hashmultimap_fkey *)&int_ftab, (struct hashmultimap_fval *)&int_ftab),
hmm_insert(coll, array[i], array[i]), hmm_remove(coll, array[i], &r), hmm_contains(coll, sarray[i]))
BENCHMARK(MULTISET, hms, hashmultiset, hms_new(NTOTAL, 0.6, (struct hashmultiset_fval *)&int_ftab),
hms_insert(coll, array[i]), hms_remove(coll, array[i]), hms_contains(coll, sarray[i]))
int main(void)
{
@@ -217,7 +260,8 @@ int main(void)
shuffle(sarray, &st);
printf("\nNote: Adjusted Time refers to if the container had done a search over all %" PRIuMAX " elements.\n\n", NTOTAL);
printf("\nNote: Adjusted Time refers to if the container had done a search over all %" PRIuMAX " elements.\n\n",
NTOTAL);
// Linear containers have to search for NMIN elements and non-linear (hash
// and tree) have to search for all elements.
@@ -235,12 +279,11 @@ int main(void)
TREEMAP_io_benchmark(array, sarray, NTOTAL);
TREESET_io_benchmark(array, sarray, NTOTAL);
INTERVALHEAP_io_benchmark(array, array, NMIN);
MULTIMAP_io_benchmark(array, array, NTOTAL);
MULTISET_io_benchmark(array, array, NTOTAL);
// INTERVALHEAP_io_benchmark(array, array, NMIN);
// MULTIMAP_io_benchmark(array, array, NTOTAL);
// MULTISET_io_benchmark(array, array, NTOTAL);
cmc_timer_stop(timer);
cmc_timer_calc(timer);
printf("+-----------------------------------------------------------+ \n");
printf("| Total Benchmark Running Time : %12.0lf seconds | \n", timer.result / 1000);
+19
View File
@@ -0,0 +1,19 @@
INCLUDE=-I ../../..
CFLAGS=-O3 -Wall -Wextra -Werror -DCOUNT=20000000 -DCMC_NO_CALLBACKS
# Install hyperfine
# https://github.com/sharkdp/hyperfine
run: build
hyperfine --warmup 2 --runs 5 './hashmap.exe'
hyperfine --warmup 2 --runs 5 './hashmultimap.exe'
hyperfine --warmup 2 --runs 5 './unorderedmap.exe'
build:
gcc hashmap.c -o hashmap.exe $(INCLUDE) $(CFLAGS)
gcc hashmultimap.c -o hashmultimap.exe $(INCLUDE) $(CFLAGS)
g++ unorderedmap.cpp $(INCLUDE) -o unorderedmap.exe $(CFLAGS)
clean:
rm *.exe -f
rm *.txt -f
@@ -4,12 +4,13 @@
#include "murmurhash.h"
#include "macro_collections.h"
#include "../../util/twister.c"
CMC_CMC_HASHMAP_CORE(PUBLIC, HEADER, (hm, hashmap, , uint64_t, uint64_t))
CMC_CMC_HASHMAP_CORE(PUBLIC, SOURCE, (hm, hashmap, , uint64_t, uint64_t))
#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)
{
@@ -31,17 +32,9 @@ size_t hash(uint64_t k)
return MurMurHash(&k, sizeof(k), seed);
}
struct hashmap_fkey *fkey = &(struct hashmap_fkey) {
.cmp = cmp,
.hash = hash,
NULL
};
struct hashmap_fkey *fkey = &(struct hashmap_fkey){ .cmp = cmp, .hash = hash, NULL };
struct hashmap_fval *fval = &(struct hashmap_fval) {
.cmp = cmp,
.hash = hash,
NULL
};
struct hashmap_fval *fval = &(struct hashmap_fval){ .cmp = cmp, .hash = hash, NULL };
int main(void)
{
@@ -4,12 +4,13 @@
#include "murmurhash.h"
#include "macro_collections.h"
#include "../../util/twister.c"
CMC_CMC_HASHMULTIMAP_CORE(PUBLIC, HEADER, (hmm, hashmultimap, , uint64_t, uint64_t))
CMC_CMC_HASHMULTIMAP_CORE(PUBLIC, SOURCE, (hmm, hashmultimap, , uint64_t, uint64_t))
#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)
{
@@ -31,17 +32,9 @@ size_t hash(uint64_t k)
return MurMurHash(&k, sizeof(k), seed);
}
struct hashmultimap_fkey *fkey = &(struct hashmultimap_fkey) {
.cmp = cmp,
.hash = hash,
NULL
};
struct hashmultimap_fkey *fkey = &(struct hashmultimap_fkey){ .cmp = cmp, .hash = hash, NULL };
struct hashmultimap_fval *fval = &(struct hashmultimap_fval) {
.cmp = cmp,
.hash = hash,
NULL
};
struct hashmultimap_fval *fval = &(struct hashmultimap_fval){ .cmp = cmp, .hash = hash, NULL };
int main(void)
{
@@ -10,7 +10,7 @@
struct IntHasher
{
std::size_t operator()(const uint64_t& k) const
std::size_t operator()(const uint64_t &k) const
{
static size_t seed = 211106232532969;
return MurMurHash(&k, sizeof(k), seed);
@@ -27,7 +27,7 @@ int main(void)
for (uint64_t i = 0; i < COUNT; i++)
{
uint64_t v = twist_uint64(&tw);
map.insert({v, v});
map.insert({ v, v });
}
return 0;
-2
View File
@@ -1,2 +0,0 @@
main:
gcc compile_time.c -c -O3 -ftime-report -I ../../src
-178
View File
@@ -1,178 +0,0 @@
/* Compilation time for over 90 collections */
#include <macro_collections.h>
struct imaginary
{
double real;
double imag;
};
enum app_state
{
TRACE = 1,
DEBUG = 2,
INFO = 3,
WARN = 4,
ERROR = 5,
FATAL = 6
};
CMC_COLLECTION_GENERATE(BIDIMAP, bd0, bidimap0, struct imaginary, struct imaginary)
CMC_COLLECTION_GENERATE(DEQUE, d0, deque0, /* K */, struct imaginary)
CMC_COLLECTION_GENERATE(HASHMAP, hm0, hmap0, struct imaginary, struct imaginary)
CMC_COLLECTION_GENERATE(HASHSET, hs0, hset0, /* K */, struct imaginary)
CMC_COLLECTION_GENERATE(HEAP, h0, heap0, /* K */, struct imaginary)
CMC_COLLECTION_GENERATE(INTERVALHEAP, ih0, iheap0, struct imaginary, struct imaginary)
CMC_COLLECTION_GENERATE(LINKEDLIST, ll0, linked0, /* K */, struct imaginary)
CMC_COLLECTION_GENERATE(LIST, l0, list0, /* K */, struct imaginary)
CMC_COLLECTION_GENERATE(MULTIMAP, mm0, mmap0, struct imaginary, struct imaginary)
CMC_COLLECTION_GENERATE(MULTISET, ms0, mset0, /* K */, struct imaginary)
CMC_COLLECTION_GENERATE(STACK, s0, stack0, /* K */, struct imaginary)
CMC_COLLECTION_GENERATE(SORTEDLIST, sl0, sotredlist0, /* K */, struct imaginary)
CMC_COLLECTION_GENERATE(QUEUE, q0, queue0, /* K */, struct imaginary)
CMC_COLLECTION_GENERATE(TREESET, ts0, tset0, /* K */, struct imaginary)
CMC_COLLECTION_GENERATE(TREEMAP, tm0, tmap0, struct imaginary, struct imaginary)
CMC_COLLECTION_GENERATE(BIDIMAP, bd1, bidimap1, int, int)
CMC_COLLECTION_GENERATE(DEQUE, d1, deque1, /* K */, int)
CMC_COLLECTION_GENERATE(HASHMAP, hm1, hmap1, int, int)
CMC_COLLECTION_GENERATE(HASHSET, hs1, hset1, /* K */, int)
CMC_COLLECTION_GENERATE(HEAP, h1, heap1, /* K */, int)
CMC_COLLECTION_GENERATE(INTERVALHEAP, ih1, iheap1, int, int)
CMC_COLLECTION_GENERATE(LINKEDLIST, ll1, linked1, /* K */, int)
CMC_COLLECTION_GENERATE(LIST, l1, list1, /* K */, int)
CMC_COLLECTION_GENERATE(MULTIMAP, mm1, mmap1, int, int)
CMC_COLLECTION_GENERATE(MULTISET, ms1, mset1, /* K */, int)
CMC_COLLECTION_GENERATE(STACK, s1, stack1, /* K */, int)
CMC_COLLECTION_GENERATE(SORTEDLIST, sl1, sotredlist1, /* K */, int)
CMC_COLLECTION_GENERATE(QUEUE, q1, queue1, /* K */, int)
CMC_COLLECTION_GENERATE(TREESET, ts1, tset1, /* K */, int)
CMC_COLLECTION_GENERATE(TREEMAP, tm1, tmap1, int, int)
CMC_COLLECTION_GENERATE(BIDIMAP, bd2, bidimap2, double, double)
CMC_COLLECTION_GENERATE(DEQUE, d2, deque2, /* K */, double)
CMC_COLLECTION_GENERATE(HASHMAP, hm2, hmap2, double, double)
CMC_COLLECTION_GENERATE(HASHSET, hs2, hset2, /* K */, double)
CMC_COLLECTION_GENERATE(HEAP, h2, heap2, /* K */, double)
CMC_COLLECTION_GENERATE(INTERVALHEAP, ih2, iheap2, double, double)
CMC_COLLECTION_GENERATE(LINKEDLIST, ll2, linked2, /* K */, double)
CMC_COLLECTION_GENERATE(LIST, l2, list2, /* K */, double)
CMC_COLLECTION_GENERATE(MULTIMAP, mm2, mmap2, double, double)
CMC_COLLECTION_GENERATE(MULTISET, ms2, mset2, /* K */, double)
CMC_COLLECTION_GENERATE(STACK, s2, stack2, /* K */, double)
CMC_COLLECTION_GENERATE(SORTEDLIST, sl2, sotredlist2, /* K */, double)
CMC_COLLECTION_GENERATE(QUEUE, q2, queue2, /* K */, double)
CMC_COLLECTION_GENERATE(TREESET, ts2, tset2, /* K */, double)
CMC_COLLECTION_GENERATE(TREEMAP, tm2, tmap2, double, double)
CMC_COLLECTION_GENERATE(BIDIMAP, bd3, bidimap3, size_t, size_t)
CMC_COLLECTION_GENERATE(DEQUE, d3, deque3, /* K */, size_t)
CMC_COLLECTION_GENERATE(HASHMAP, hm3, hmap3, size_t, size_t)
CMC_COLLECTION_GENERATE(HASHSET, hs3, hset3, /* K */, size_t)
CMC_COLLECTION_GENERATE(HEAP, h3, heap3, /* K */, size_t)
CMC_COLLECTION_GENERATE(INTERVALHEAP, ih3, iheap3, size_t, size_t)
CMC_COLLECTION_GENERATE(LINKEDLIST, ll3, linked3, /* K */, size_t)
CMC_COLLECTION_GENERATE(LIST, l3, list3, /* K */, size_t)
CMC_COLLECTION_GENERATE(MULTIMAP, mm3, mmap3, size_t, size_t)
CMC_COLLECTION_GENERATE(MULTISET, ms3, mset3, /* K */, size_t)
CMC_COLLECTION_GENERATE(STACK, s3, stack3, /* K */, size_t)
CMC_COLLECTION_GENERATE(SORTEDLIST, sl3, sotredlist3, /* K */, size_t)
CMC_COLLECTION_GENERATE(QUEUE, q3, queue3, /* K */, size_t)
CMC_COLLECTION_GENERATE(TREESET, ts3, tset3, /* K */, size_t)
CMC_COLLECTION_GENERATE(TREEMAP, tm3, tmap3, size_t, size_t)
CMC_COLLECTION_GENERATE(BIDIMAP, bd4, bidimap4, enum app_state, enum app_state)
CMC_COLLECTION_GENERATE(DEQUE, d4, deque4, /* K */, enum app_state)
CMC_COLLECTION_GENERATE(HASHMAP, hm4, hmap4, enum app_state, enum app_state)
CMC_COLLECTION_GENERATE(HASHSET, hs4, hset4, /* K */, enum app_state)
CMC_COLLECTION_GENERATE(HEAP, h4, heap4, /* K */, enum app_state)
CMC_COLLECTION_GENERATE(INTERVALHEAP, ih4, iheap4, enum app_state, enum app_state)
CMC_COLLECTION_GENERATE(LINKEDLIST, ll4, linked4, /* K */, enum app_state)
CMC_COLLECTION_GENERATE(LIST, l4, list4, /* K */, enum app_state)
CMC_COLLECTION_GENERATE(MULTIMAP, mm4, mmap4, enum app_state, enum app_state)
CMC_COLLECTION_GENERATE(MULTISET, ms4, mset4, /* K */, enum app_state)
CMC_COLLECTION_GENERATE(STACK, s4, stack4, /* K */, enum app_state)
CMC_COLLECTION_GENERATE(SORTEDLIST, sl4, sotredlist4, /* K */, enum app_state)
CMC_COLLECTION_GENERATE(QUEUE, q4, queue4, /* K */, enum app_state)
CMC_COLLECTION_GENERATE(TREESET, ts4, tset4, /* K */, enum app_state)
CMC_COLLECTION_GENERATE(TREEMAP, tm4, tmap4, enum app_state, enum app_state)
CMC_COLLECTION_GENERATE(BIDIMAP, bd5, bidimap5, void *, void *)
CMC_COLLECTION_GENERATE(DEQUE, d5, deque5, /* K */, void *)
CMC_COLLECTION_GENERATE(HASHMAP, hm5, hmap5, void *, void *)
CMC_COLLECTION_GENERATE(HASHSET, hs5, hset5, /* K */, void *)
CMC_COLLECTION_GENERATE(HEAP, h5, heap5, /* K */, void *)
CMC_COLLECTION_GENERATE(INTERVALHEAP, ih5, iheap5, void *, void *)
CMC_COLLECTION_GENERATE(LINKEDLIST, ll5, linked5, /* K */, void *)
CMC_COLLECTION_GENERATE(LIST, l5, list5, /* K */, void *)
CMC_COLLECTION_GENERATE(MULTIMAP, mm5, mmap5, void *, void *)
CMC_COLLECTION_GENERATE(MULTISET, ms5, mset5, /* K */, void *)
CMC_COLLECTION_GENERATE(STACK, s5, stack5, /* K */, void *)
CMC_COLLECTION_GENERATE(SORTEDLIST, sl5, sotredlist5, /* K */, void *)
CMC_COLLECTION_GENERATE(QUEUE, q5, queue5, /* K */, void *)
CMC_COLLECTION_GENERATE(TREESET, ts5, tset5, /* K */, void *)
CMC_COLLECTION_GENERATE(TREEMAP, tm5, tmap5, void *, void *)
CMC_COLLECTION_GENERATE(BIDIMAP, bd6, bidimap6, int *, int *)
CMC_COLLECTION_GENERATE(DEQUE, d6, deque6, /* K */, int *)
CMC_COLLECTION_GENERATE(HASHMAP, hm6, hmap6, int *, int *)
CMC_COLLECTION_GENERATE(HASHSET, hs6, hset6, /* K */, int *)
CMC_COLLECTION_GENERATE(HEAP, h6, heap6, /* K */, int *)
CMC_COLLECTION_GENERATE(INTERVALHEAP, ih6, iheap6, int *, int *)
CMC_COLLECTION_GENERATE(LINKEDLIST, ll6, linked6, /* K */, int *)
CMC_COLLECTION_GENERATE(LIST, l6, list6, /* K */, int *)
CMC_COLLECTION_GENERATE(MULTIMAP, mm6, mmap6, int *, int *)
CMC_COLLECTION_GENERATE(MULTISET, ms6, mset6, /* K */, int *)
CMC_COLLECTION_GENERATE(STACK, s6, stack6, /* K */, int *)
CMC_COLLECTION_GENERATE(SORTEDLIST, sl6, sotredlist6, /* K */, int *)
CMC_COLLECTION_GENERATE(QUEUE, q6, queue6, /* K */, int *)
CMC_COLLECTION_GENERATE(TREESET, ts6, tset6, /* K */, int *)
CMC_COLLECTION_GENERATE(TREEMAP, tm6, tmap6, int *, int *)
CMC_COLLECTION_GENERATE(BIDIMAP, bd7, bidimap7, struct imaginary *, struct imaginary *)
CMC_COLLECTION_GENERATE(DEQUE, d7, deque7, /* K */, struct imaginary *)
CMC_COLLECTION_GENERATE(HASHMAP, hm7, hmap7, struct imaginary *, struct imaginary *)
CMC_COLLECTION_GENERATE(HASHSET, hs7, hset7, /* K */, struct imaginary *)
CMC_COLLECTION_GENERATE(HEAP, h7, heap7, /* K */, struct imaginary *)
CMC_COLLECTION_GENERATE(INTERVALHEAP, ih7, iheap7, struct imaginary *, struct imaginary *)
CMC_COLLECTION_GENERATE(LINKEDLIST, ll7, linked7, /* K */, struct imaginary *)
CMC_COLLECTION_GENERATE(LIST, l7, list7, /* K */, struct imaginary *)
CMC_COLLECTION_GENERATE(MULTIMAP, mm7, mmap7, struct imaginary *, struct imaginary *)
CMC_COLLECTION_GENERATE(MULTISET, ms7, mset7, /* K */, struct imaginary *)
CMC_COLLECTION_GENERATE(STACK, s7, stack7, /* K */, struct imaginary *)
CMC_COLLECTION_GENERATE(SORTEDLIST, sl7, sotredlist7, /* K */, struct imaginary *)
CMC_COLLECTION_GENERATE(QUEUE, q7, queue7, /* K */, struct imaginary *)
CMC_COLLECTION_GENERATE(TREESET, ts7, tset7, /* K */, struct imaginary *)
CMC_COLLECTION_GENERATE(TREEMAP, tm7, tmap7, struct imaginary *, struct imaginary *)
CMC_COLLECTION_GENERATE(BIDIMAP, bd8, bidimap8, double *, double *)
CMC_COLLECTION_GENERATE(DEQUE, d8, deque8, /* K */, double *)
CMC_COLLECTION_GENERATE(HASHMAP, hm8, hmap8, double *, double *)
CMC_COLLECTION_GENERATE(HASHSET, hs8, hset8, /* K */, double *)
CMC_COLLECTION_GENERATE(HEAP, h8, heap8, /* K */, double *)
CMC_COLLECTION_GENERATE(INTERVALHEAP, ih8, iheap8, double *, double *)
CMC_COLLECTION_GENERATE(LINKEDLIST, ll8, linked8, /* K */, double *)
CMC_COLLECTION_GENERATE(LIST, l8, list8, /* K */, double *)
CMC_COLLECTION_GENERATE(MULTIMAP, mm8, mmap8, double *, double *)
CMC_COLLECTION_GENERATE(MULTISET, ms8, mset8, /* K */, double *)
CMC_COLLECTION_GENERATE(STACK, s8, stack8, /* K */, double *)
CMC_COLLECTION_GENERATE(SORTEDLIST, sl8, sotredlist8, /* K */, double *)
CMC_COLLECTION_GENERATE(QUEUE, q8, queue8, /* K */, double *)
CMC_COLLECTION_GENERATE(TREESET, ts8, tset8, /* K */, double *)
CMC_COLLECTION_GENERATE(TREEMAP, tm8, tmap8, double *, double *)
CMC_COLLECTION_GENERATE(BIDIMAP, bd9, bidimap9, enum app_state *, enum app_state *)
CMC_COLLECTION_GENERATE(DEQUE, d9, deque9, /* K */, enum app_state *)
CMC_COLLECTION_GENERATE(HASHMAP, hm9, hmap9, enum app_state *, enum app_state *)
CMC_COLLECTION_GENERATE(HASHSET, hs9, hset9, /* K */, enum app_state *)
CMC_COLLECTION_GENERATE(HEAP, h9, heap9, /* K */, enum app_state *)
CMC_COLLECTION_GENERATE(INTERVALHEAP, ih9, iheap9, enum app_state *, enum app_state *)
CMC_COLLECTION_GENERATE(LINKEDLIST, ll9, linked9, /* K */, enum app_state *)
CMC_COLLECTION_GENERATE(LIST, l9, list9, /* K */, enum app_state *)
CMC_COLLECTION_GENERATE(MULTIMAP, mm9, mmap9, enum app_state *, enum app_state *)
CMC_COLLECTION_GENERATE(MULTISET, ms9, mset9, /* K */, enum app_state *)
CMC_COLLECTION_GENERATE(STACK, s9, stack9, /* K */, enum app_state *)
CMC_COLLECTION_GENERATE(SORTEDLIST, sl9, sotredlist9, /* K */, enum app_state *)
CMC_COLLECTION_GENERATE(QUEUE, q9, queue9, /* K */, enum app_state *)
CMC_COLLECTION_GENERATE(TREESET, ts9, tset9, /* K */, enum app_state *)
CMC_COLLECTION_GENERATE(TREEMAP, tm9, tmap9, enum app_state *, enum app_state *)
-433
View File
@@ -1,433 +0,0 @@
#include <macro_collections.h>
/**
* HashMap, MultiMap and BidiMap use hashtables with different strategies. This
* benchmark is aimed to explore the pros and cons of each implementation.
*
* HashMap - A plain hashtable with no indirection using linear probing and
* robin hood hashing.
* Expectations:
* - Constant memory usage which leads to high memory usage per element
* ratio when the hashtable has few elements but the ratio is
* somewhat good as it starts to fill up;
* - Faster lookup due to no indirection and good caching;
* - Faster insertion and removal due to no calls to free or malloc.
*
* MultiMap - A hashtable using separate chaining where each bucket is a doubly
* linked list.
* Expectations:
* - High memory usage per element ratio due to the double linked
* lists;
* - Pointer indirection might lead to slower lookup and poor caching
* due to using nodes to store the key and the value;
* - A bit slower insertion and removal as calls to free and malloc are
* needed.
*
* BidiMap - Two arrays, one representing the key set and one the value set.
* Each array is made of pointers to an entry. This way one entry can
* be referenced by both the key set and the value set using only one
* node. Uses robin hood hashing to adjust the pointers.
* Expectations:
* - Overrall low memory usage compared to other implementations;
* - Pointer indirection might lead to slower lookupand poor caching
* due to using nodes to store the key and the value;
* - Very slow insertion and removal as a node needs to be added or
* removed on both arrays.
*/
/* Generate Code */
CMC_COLLECTION_GENERATE(HASHMAP, hmap, hmap, int, int)
CMC_COLLECTION_GENERATE(MULTIMAP, mmap, mmap, int, int)
CMC_COLLECTION_GENERATE(BIDIMAP, bmap, bmap, int, int)
/* Forward declaration of benchmarks */
void benchmark_bidimap(const char *collection, int total_elements,
double load_factor);
void benchmark_hashmap(const char *collection, int total_elements,
double load_factor);
void benchmark_multimap(const char *collection, int total_elements,
double load_factor);
/* Comparator and Hash function */
int cmp(int a, int b)
{
return a - b;
}
size_t hash(int a)
{
size_t x = (size_t)a;
x = ((x >> 16) ^ x) * 0x45d9f3b;
x = ((x >> 16) ^ x) * 0x45d9f3b;
x = (x >> 16) ^ x;
return x;
}
/* Custom allocators to count memory usage */
size_t total_memory = 0;
/* Report Functions */
void print_overview(const char *collection, int total_elements,
double load_factor)
{
printf("Overview\n"
" Collection : %s\n"
" Total Elements : %d\n"
" Load Factor : %.4lf\n\n",
collection, total_elements, load_factor);
}
void print_time(const char *collection, double C, double R, double U, double D)
{
/* C - Create, R - Read, U - Update, D - Delete */
printf("Time [%s]: \n"
" Total : %8.0lf milliseconds \n"
" Create : %8.0lf milliseconds\n"
" Read : %8.0lf milliseconds\n"
" Update : %8.0lf milliseconds\n"
" Delete : %8.0lf milliseconds\n\n",
collection, C + R + U + D, C, R, U, D);
}
void print_memory(const char *s, size_t memory[11], int partition_size)
{
printf("Each Partition : %d elements\n\n", partition_size);
for (size_t i = 0; i < 11; i++)
{
printf(" %3" PRIuMAX "%% : %12" PRIuMAX " B | %10" PRIuMAX " kB | %8" PRIuMAX " MB (+ %2.0lf%%)\n",
i * 10, memory[i], memory[i] / 1000, memory[i] / 1000000, (1 - ((double)memory[0] / (double)memory[i])) * 100.0);
}
}
/* Custom allocation functions */
void *my_malloc(size_t size)
{
void *result = malloc(size);
if (result)
total_memory += size;
return result;
}
void *my_calloc(size_t count, size_t size)
{
void *result = calloc(count, size);
if (result)
total_memory += count * size;
return result;
}
void *my_realloc(void *buffer, size_t size)
{
/* This assumes that this benchmark never uses realloc */
return realloc(buffer, size);
}
void my_free(void *block)
{
free(block);
}
/* Default custom allocation node */
struct cmc_alloc_node alloc_default = { .malloc = my_malloc,
.calloc = my_calloc,
.realloc = my_realloc,
.free = my_free };
int main(int argc, char const *argv[])
{
if (argc != 4)
{
fprintf(
stderr,
"Usage:\n"
" %s collection_name total_elements load_factor\n"
"\nOPTIONS\n"
" - collection_name : (BIDIMAP|HASHMAP|MULTIMAP|ALL)\n"
" - total_elements : Total elements to be added to the hashtable (int > 0)\n"
" - load_factor : The hashtable's load factor (0 < l < 1.0)\n",
argv[0]);
return 1;
}
int total_elements = atoi(argv[2]);
double load_factor = atof(argv[3]);
bool error = false;
if (total_elements < 1)
{
error = true;
fprintf(stderr, "Invalid value for total_elements: %s\n", argv[2]);
}
if (load_factor <= 0.0 || load_factor >= 1.0)
{
error = true;
fprintf(stderr, "Invalid value for load_factor: %s\n", argv[3]);
}
if (error)
return 1;
const char *collection = argv[1];
if (strcmp(collection, "BIDIMAP") == 0)
{
benchmark_bidimap(collection, total_elements, load_factor);
}
else if (strcmp(collection, "HASHMAP") == 0)
{
benchmark_hashmap(collection, total_elements, load_factor);
}
else if (strcmp(collection, "MULTIMAP") == 0)
{
benchmark_multimap(collection, total_elements, load_factor);
}
else if (strcmp(collection, "ALL") == 0)
{
benchmark_bidimap("BIDIMAP", total_elements, load_factor);
benchmark_hashmap("HASHMAP", total_elements, load_factor);
benchmark_multimap("MULTIMAP", total_elements, load_factor);
}
else
{
fprintf(stderr, "Unknown parameter collection_name = %s\n", collection);
return 1;
}
return 0;
}
void benchmark_bidimap(const char *collection, int total_elements,
double load_factor)
{
printf("--------------------------------------------------------------------------------\n");
total_memory = 0;
/* Normalize total_elements to be a multiple of 10 and calculate partition size */
total_elements = total_elements % 10 == 0 ? total_elements : total_elements + (10 - total_elements % 10);
int partition = total_elements / 10;
print_overview(collection, total_elements, load_factor);
struct bmap *map = bmap_new_custom(total_elements, load_factor, cmp, hash,
cmp, hash, &alloc_default, NULL);
/* Create, Read, Update, Delete */
struct cmc_timer timers[4] = { 0 };
/* Memory Usage 0%, 10%, 20%, ... 100% */
size_t memory[11] = {0};
memory[0] = total_memory;
/* Create */
cmc_timer_start(timers[0]);
for (int i = 0; i < 10; i++)
{
for (int j = partition * i; j < partition * (i + 1); j++)
{
bmap_insert(map, j, j);
}
memory[i + 1] = total_memory;
}
cmc_timer_stop(timers[0]);
cmc_timer_calc(timers[0]);
/* Create End */
/* Read */
cmc_timer_start(timers[1]);
for (int i = 0; i < total_elements; i++)
bmap_contains_key(map, i);
cmc_timer_stop(timers[1]);
cmc_timer_calc(timers[1]);
/* Read End */
/* Update */
cmc_timer_start(timers[2]);
for (int i = 0; i < total_elements; i++)
bmap_update_val_by_key(map, i, total_elements - i - 1);
cmc_timer_stop(timers[2]);
cmc_timer_calc(timers[2]);
/* Update End */
/* Delete */
cmc_timer_start(timers[3]);
for (int i = 0; i < total_elements; i++)
bmap_remove_by_key(map, i, NULL, NULL);
cmc_timer_stop(timers[3]);
cmc_timer_calc(timers[3]);
/* Delete End */
print_time(collection, timers[0].result, timers[1].result, timers[2].result,
timers[3].result);
print_memory(collection, memory, partition);
bmap_free(map, NULL);
printf("--------------------------------------------------------------------------------\n");
}
void benchmark_hashmap(const char *collection, int total_elements,
double load_factor)
{
printf("--------------------------------------------------------------------------------\n");
total_memory = 0;
/* Normalize total_elements to be a multiple of 10 and calculate partition size */
total_elements = total_elements % 10 == 0 ? total_elements : total_elements + (10 - total_elements % 10);
int partition = total_elements / 10;
print_overview(collection, total_elements, load_factor);
struct hmap *map = hmap_new_custom(total_elements, load_factor, cmp, hash, &alloc_default, NULL);
/* Create, Read, Update, Delete */
struct cmc_timer timers[4] = { 0 };
/* Memory Usage 0%, 10%, 20%, ... 100% */
size_t memory[11] = {0};
memory[0] = total_memory;
/* Create */
cmc_timer_start(timers[0]);
for (int i = 0; i < 10; i++)
{
for (int j = partition * i; j < partition * (i + 1); j++)
{
hmap_insert(map, j, j);
}
memory[i + 1] = total_memory;
}
cmc_timer_stop(timers[0]);
cmc_timer_calc(timers[0]);
/* Create End */
/* Read */
cmc_timer_start(timers[1]);
for (int i = 0; i < total_elements; i++)
hmap_contains(map, i);
cmc_timer_stop(timers[1]);
cmc_timer_calc(timers[1]);
/* Read End */
/* Update */
cmc_timer_start(timers[2]);
for (int i = 0; i < total_elements; i++)
hmap_update(map, i, total_elements - i - 1, NULL);
cmc_timer_stop(timers[2]);
cmc_timer_calc(timers[2]);
/* Update End */
/* Delete */
cmc_timer_start(timers[3]);
for (int i = 0; i < total_elements; i++)
hmap_remove(map, i, NULL);
cmc_timer_stop(timers[3]);
cmc_timer_calc(timers[3]);
/* Delete End */
print_time(collection, timers[0].result, timers[1].result, timers[2].result,
timers[3].result);
print_memory(collection, memory, partition);
hmap_free(map, NULL);
printf("--------------------------------------------------------------------------------\n");
}
void benchmark_multimap(const char *collection, int total_elements,
double load_factor)
{
printf("--------------------------------------------------------------------------------\n");
total_memory = 0;
/* Normalize total_elements to be a multiple of 10 and calculate partition size */
total_elements = total_elements % 10 == 0 ? total_elements : total_elements + (10 - total_elements % 10);
int partition = total_elements / 10;
print_overview(collection, total_elements, load_factor);
struct mmap *map = mmap_new_custom(total_elements, load_factor, cmp, hash, &alloc_default, NULL);
/* Create, Read, Update, Delete */
struct cmc_timer timers[4] = { 0 };
/* Memory Usage 0%, 10%, 20%, ... 100% */
size_t memory[11] = {0};
memory[0] = total_memory;
/* Create */
cmc_timer_start(timers[0]);
for (int i = 0; i < 10; i++)
{
for (int j = partition * i; j < partition * (i + 1); j++)
{
mmap_insert(map, j, j);
}
memory[i + 1] = total_memory;
}
cmc_timer_stop(timers[0]);
cmc_timer_calc(timers[0]);
/* Create End */
/* Read */
cmc_timer_start(timers[1]);
for (int i = 0; i < total_elements; i++)
mmap_contains(map, i);
cmc_timer_stop(timers[1]);
cmc_timer_calc(timers[1]);
/* Read End */
/* Update */
cmc_timer_start(timers[2]);
for (int i = 0; i < total_elements; i++)
mmap_update(map, i, total_elements - i - 1, NULL);
cmc_timer_stop(timers[2]);
cmc_timer_calc(timers[2]);
/* Update End */
/* Delete */
cmc_timer_start(timers[3]);
for (int i = 0; i < total_elements; i++)
mmap_remove(map, i, NULL);
cmc_timer_stop(timers[3]);
cmc_timer_calc(timers[3]);
/* Delete End */
print_time(collection, timers[0].result, timers[1].result, timers[2].result,
timers[3].result);
print_memory(collection, memory, partition);
mmap_free(map, NULL);
printf("--------------------------------------------------------------------------------\n");
}
-8
View File
@@ -1,8 +0,0 @@
CFLAGS = -Wall -Wextra
INCLUDE = ../../src
main:
gcc queue.c -I $(INCLUDE) $(CFLAGS) -o a.exe -DCMC_QUEUE
a.exe
gcc queue.c -I $(INCLUDE) $(CFLAGS) -o a.exe -DSAC_QUEUE
a.exe
-76
View File
@@ -1,76 +0,0 @@
/**
* queue.c
*
* Creation Date: 24/06/2019
*
* Authors:
* Leonardo Vencovsky (https://github.com/LeoVen)
*
*/
/* Showing off how different queue implementations affect runtime cost */
#include "utl/timer.h"
#include <stdio.h>
#include <inttypes.h>
#define MAX 200000
#if defined(CMC_QUEUE)
#include "cmc/queue.h"
CMC_GENERATE_QUEUE(q, queue, int)
#define TARGET "QUEUE"
#elif defined(SAC_QUEUE)
#include "sac/queue.h"
SAC_QUEUE_GENERATE(q, queue, , int, MAX)
#define TARGET "SAC QUEUE"
#else
#error Please define either CMC_QUEUE, SAC_QUEUE or EXT_QUEUE
#endif
int main(void)
{
#if defined(CMC_QUEUE)
struct queue *q = q_new(MAX);
#elif defined(SAC_QUEUE)
queue _q = q_new();
queue_ptr q = &_q;
#endif
size_t sum = 0;
int i = 0;
struct cmc_timer timer;
cmc_timer_start(timer);
while (q_count(q) != MAX)
{
q_enqueue(q, i++);
if (i % 10 == 0)
{
for (size_t i = 0; i < 9; i++)
{
sum += q_peek(q);
q_dequeue(q);
}
}
}
cmc_timer_stop(timer);
cmc_timer_calc(timer);
printf("----------------------------------------\n");
printf("%s\n", TARGET);
printf("Execution time: %.0lf milliseconds\n", timer.result);
printf("SUM: %" PRIuMAX "\n", sum);
printf("----------------------------------------\n");
#if defined(CMC_QUEUE)
q_free(q, NULL);
#endif
return 0;
}
+92
View File
@@ -0,0 +1,92 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* bitset.h
*
* Creation Date: 30/04/2020
*
* Authors:
* Leonardo Vencovsky (https://github.com/LeoVen)
*
*/
/**
* BitSet
*
* A Bit Set is an array where each bit can be individually modified and queried
* by using bitwise operators such as |, &, ^, ~, >> and << (or, and, xor, not,
* right shift, left shift respectively).
*
* Implementation
*
* This BitSet implementation uses an array of type cmc_bitset_word which can be
* typedefed to any unsigned type such as uint8_t, uint16_t, uint32_t, uint64_t,
* size_t, etc. The BitSet does not make use of K or V. Because of that, it also
* doesn't have Functions Tables.
*
* The BitSet is initialized with a custom capacity but, if a bit index accessed
* is greater than the total capacity, the BitSet will resize. This means that
* the BitSet will try to guarantee that every bit index is accessible, as long
* as there is enough memory.
*/
#include "cor/bitset.h"
#include "cor/core.h"
#ifdef CMC_DEV
#include "utl/log.h"
#endif
/**
* Used values
* SNAME - struct name and prefix of other related structs
* PFX - functions prefix
*/
/* Structs definition */
#include "cmc/bitset/struct.h"
/* Function declaration */
#include "cmc/bitset/header.h"
/* Function implementation */
#include "cmc/bitset/code.h"
/**
* Extensions
*
* INIT - Initializes the struct on the stack
* ITER - bitset iterator
* STR - Print helper functions
*/
#define CMC_EXT_BITSET_PARTS INIT, ITER, STR
/**/
#include "cmc/bitset/ext/struct.h"
/**/
#include "cmc/bitset/ext/header.h"
/**/
#include "cmc/bitset/ext/code.h"
#include "cor/undef.h"
+512
View File
@@ -0,0 +1,512 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/* Implementation Detail Functions */
bool CMC_(PFX, _impl_resize)(struct SNAME *_bitset_, size_t n_bits, bool do_resize);
struct SNAME *CMC_(PFX, _new)(size_t n_bits)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return CMC_(PFX, _new_custom)(n_bits, NULL, NULL);
}
struct SNAME *CMC_(PFX, _new_custom)(size_t n_bits, CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
if (n_bits < 1)
return NULL;
if (!alloc)
alloc = &cmc_alloc_node_default;
size_t capacity = cmc_bidx_to_widx(n_bits - 1) + 1;
struct SNAME *_bitset_ = alloc->malloc(sizeof(struct SNAME));
if (!_bitset_)
return NULL;
_bitset_->buffer = alloc->calloc(capacity, sizeof(cmc_bitset_word));
if (!_bitset_->buffer)
{
alloc->free(_bitset_);
return NULL;
}
_bitset_->capacity = capacity;
_bitset_->flag = CMC_FLAG_OK;
_bitset_->alloc = alloc;
CMC_CALLBACKS_ASSIGN(_bitset_, callbacks);
return _bitset_;
}
struct SNAME CMC_(PFX, _init)(size_t n_bits)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return CMC_(PFX, _init_custom)(n_bits, NULL, NULL);
}
struct SNAME CMC_(PFX, _init_custom)(size_t n_bits, CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
struct SNAME _bitset_ = { 0 };
if (n_bits < 1)
return _bitset_;
if (!alloc)
alloc = &cmc_alloc_node_default;
size_t capacity = cmc_bidx_to_widx(n_bits - 1) + 1;
_bitset_.buffer = alloc->calloc(capacity, sizeof(cmc_bitset_word));
if (!_bitset_.buffer)
return _bitset_;
_bitset_.capacity = capacity;
_bitset_.flag = CMC_FLAG_OK;
_bitset_.alloc = alloc;
CMC_CALLBACKS_ASSIGN(&_bitset_, callbacks);
return _bitset_;
}
void CMC_(PFX, _free)(struct SNAME *_bitset_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
free(_bitset_->buffer);
free(_bitset_);
}
void CMC_(PFX, _release)(struct SNAME _bitset_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
free(_bitset_.buffer);
}
void CMC_(PFX, _customize)(struct SNAME *_bitset_, CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
if (!alloc)
_bitset_->alloc = &cmc_alloc_node_default;
else
_bitset_->alloc = alloc;
CMC_CALLBACKS_ASSIGN(_bitset_, callbacks);
_bitset_->flag = CMC_FLAG_OK;
}
bool CMC_(PFX, _set)(struct SNAME *_bitset_, size_t bit_index)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (!CMC_(PFX, _impl_resize)(_bitset_, bit_index + 1, false))
return false;
/* How many bits in a word */
const cmc_bitset_word bits = sizeof(cmc_bitset_word) * CHAR_BIT;
size_t i = cmc_bidx_to_widx(bit_index);
_bitset_->buffer[i] |= ((cmc_bitset_word)1) << (bit_index % bits);
_bitset_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_bitset_);
return true;
}
bool CMC_(PFX, _set_range)(struct SNAME *_bitset_, size_t from, size_t to)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (to < from)
{
_bitset_->flag = CMC_FLAG_INVALID;
return false;
}
if (!CMC_(PFX, _impl_resize)(_bitset_, to + 1, false))
return false;
size_t start_index = cmc_bidx_to_widx(from);
size_t end_index = cmc_bidx_to_widx(to);
/* How many bits in a word */
const cmc_bitset_word bits = sizeof(cmc_bitset_word) * CHAR_BIT;
/* 1111 ... 1111 */
const cmc_bitset_word ones = ~((cmc_bitset_word)0);
cmc_bitset_word shift_start = from % bits;
cmc_bitset_word shift_end = (cmc_bitset_word)(-(to + 1)) % bits;
cmc_bitset_word start_mask = ones << shift_start;
cmc_bitset_word end_mask = ones >> shift_end;
if (start_index == end_index)
{
_bitset_->buffer[end_index] |= (start_mask & end_mask);
}
else
{
_bitset_->buffer[start_index] |= start_mask;
for (size_t i = start_index + 1; i < end_index; i++)
_bitset_->buffer[i] |= ~((cmc_bitset_word)0);
_bitset_->buffer[end_index] |= end_mask;
}
_bitset_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_bitset_);
return true;
}
bool CMC_(PFX, _clear)(struct SNAME *_bitset_, size_t bit_index)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (!CMC_(PFX, _impl_resize)(_bitset_, bit_index + 1, false))
return false;
/* How many bits in a word */
const cmc_bitset_word bits = sizeof(cmc_bitset_word) * CHAR_BIT;
size_t i = cmc_bidx_to_widx(bit_index);
_bitset_->buffer[i] &= ~(((cmc_bitset_word)1) << (bit_index % bits));
_bitset_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_bitset_);
return true;
}
bool CMC_(PFX, _clear_range)(struct SNAME *_bitset_, size_t from, size_t to)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (to < from)
{
_bitset_->flag = CMC_FLAG_INVALID;
return false;
}
if (!CMC_(PFX, _impl_resize)(_bitset_, to + 1, false))
return false;
size_t start_index = cmc_bidx_to_widx(from);
size_t end_index = cmc_bidx_to_widx(to);
/* How many bits in a word */
const cmc_bitset_word bits = sizeof(cmc_bitset_word) * CHAR_BIT;
/* 1111 ... 1111 */
const cmc_bitset_word ones = ~((cmc_bitset_word)0);
cmc_bitset_word shift_start = from % bits;
cmc_bitset_word shift_end = (cmc_bitset_word)(-(to + 1)) % bits;
cmc_bitset_word start_mask = ones << shift_start;
cmc_bitset_word end_mask = ones >> shift_end;
if (start_index == end_index)
{
_bitset_->buffer[end_index] &= ~(start_mask & end_mask);
}
else
{
_bitset_->buffer[start_index] &= ~start_mask;
for (size_t i = start_index + 1; i < end_index; i++)
_bitset_->buffer[i] = 0;
_bitset_->buffer[end_index] &= ~end_mask;
}
_bitset_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_bitset_);
return true;
}
bool CMC_(PFX, _flip)(struct SNAME *_bitset_, size_t bit_index)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (!CMC_(PFX, _impl_resize)(_bitset_, bit_index + 1, false))
return false;
/* How many bits in a word */
const cmc_bitset_word bits = sizeof(cmc_bitset_word) * CHAR_BIT;
size_t i = cmc_bidx_to_widx(bit_index);
_bitset_->buffer[i] ^= ((cmc_bitset_word)1) << (bit_index % bits);
_bitset_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_bitset_);
return true;
}
bool CMC_(PFX, _flip_range)(struct SNAME *_bitset_, size_t from, size_t to)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (to < from)
{
_bitset_->flag = CMC_FLAG_INVALID;
return false;
}
if (!CMC_(PFX, _impl_resize)(_bitset_, to + 1, false))
return false;
size_t start_index = cmc_bidx_to_widx(from);
size_t end_index = cmc_bidx_to_widx(to);
/* How many bits in a word */
const cmc_bitset_word bits = sizeof(cmc_bitset_word) * CHAR_BIT;
/* 1111 ... 1111 */
const cmc_bitset_word ones = ~((cmc_bitset_word)0);
cmc_bitset_word shift_start = from % bits;
cmc_bitset_word shift_end = (cmc_bitset_word)(-(to + 1)) % bits;
cmc_bitset_word start_mask = ones << shift_start;
cmc_bitset_word end_mask = ones >> shift_end;
if (start_index == end_index)
{
_bitset_->buffer[end_index] ^= (start_mask & end_mask);
}
else
{
_bitset_->buffer[start_index] ^= start_mask;
for (size_t i = start_index + 1; i < end_index; i++)
_bitset_->buffer[i] ^= ones;
_bitset_->buffer[end_index] ^= end_mask;
}
_bitset_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_bitset_);
return true;
}
bool CMC_(PFX, _put)(struct SNAME *_bitset_, size_t bit_index, bool state)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (state)
return CMC_(PFX, _set)(_bitset_, bit_index);
else
return CMC_(PFX, _clear)(_bitset_, bit_index);
}
bool CMC_(PFX, _put_range)(struct SNAME *_bitset_, size_t from, size_t to, bool state)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (state)
return CMC_(PFX, _set_range)(_bitset_, from, to);
else
return CMC_(PFX, _clear_range)(_bitset_, from, to);
}
bool CMC_(PFX, _set_all)(struct SNAME *_bitset_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
for (size_t i = 0; i < _bitset_->capacity; i++)
_bitset_->buffer[i] = ~((cmc_bitset_word)0);
_bitset_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_bitset_);
return true;
}
bool CMC_(PFX, _clear_all)(struct SNAME *_bitset_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
for (size_t i = 0; i < _bitset_->capacity; i++)
_bitset_->buffer[i] = 0;
_bitset_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_bitset_);
return true;
}
bool CMC_(PFX, _flip_all)(struct SNAME *_bitset_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
for (size_t i = 0; i < _bitset_->capacity; i++)
_bitset_->buffer[i] ^= ~((cmc_bitset_word)0);
_bitset_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_bitset_);
return true;
}
bool CMC_(PFX, _get)(struct SNAME *_bitset_, size_t bit_index)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
/* How many bits in a word */
const cmc_bitset_word bits = sizeof(cmc_bitset_word) * CHAR_BIT;
cmc_bitset_word w = _bitset_->buffer[cmc_bidx_to_widx(bit_index)];
return w & ((cmc_bitset_word)1 << (bit_index % bits));
}
bool CMC_(PFX, _resize)(struct SNAME *_bitset_, size_t n_bits)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return CMC_(PFX, _impl_resize)(_bitset_, n_bits, true);
}
/* When do_resize is false, then we just want to assure that the bitset */
/* can accommodate n_bits */
bool CMC_(PFX, _impl_resize)(struct SNAME *_bitset_, size_t n_bits, bool do_resize)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (n_bits == 0)
{
_bitset_->flag = CMC_FLAG_INVALID;
return false;
}
/* -1 because n_bits is 1-based and we need to pass a 0-based index */
/* +1 to have a 1-based result */
size_t words = cmc_bidx_to_widx(n_bits - 1) + 1;
/* Be sure we are not always shrinking when we just want to make */
/* sure that we have enough size for n_bits */
if (!do_resize && words <= _bitset_->capacity)
return true;
cmc_bitset_word *new_buffer = realloc(_bitset_->buffer, words * sizeof(cmc_bitset_word));
if (!new_buffer)
{
_bitset_->flag = CMC_FLAG_ALLOC;
return false;
}
_bitset_->buffer = new_buffer;
/* Make new bits be all zeroes */
if (_bitset_->capacity < words)
memset(_bitset_->buffer + _bitset_->capacity, 0, (words - _bitset_->capacity) * sizeof(cmc_bitset_word));
_bitset_->capacity = words;
CMC_CALLBACKS_CALL(_bitset_);
_bitset_->flag = CMC_FLAG_OK;
return true;
}
+57
View File
@@ -0,0 +1,57 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* INIT
*
* The part 'INIT' gives a new way of initializing a collection. The collection
* struct is not heap allocated, only its internal structure (nodes, buffers).
*/
#ifdef CMC_EXT_INIT
#endif /* CMC_EXT_INIT */
/**
* ITER
*
* Bitset bi-directional iterator.
*/
#ifdef CMC_EXT_ITER
/* Iterator Functions */
/* Iterator Initialization */
/* Iterator State */
/* Iterator Movement */
/* Iterator Access */
#endif /* CMC_EXT_ITER */
/**
* STR
*
* Print helper functions.
*/
#ifdef CMC_EXT_STR
#endif /* CMC_EXT_STR */
+57
View File
@@ -0,0 +1,57 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* INIT
*
* The part 'INIT' gives a new way of initializing a collection. The collection
* struct is not heap allocated, only its internal structure (nodes, buffers).
*/
#ifdef CMC_EXT_INIT
#endif /* CMC_EXT_INIT */
/**
* ITER
*
* Bitset bi-directional iterator.
*/
#ifdef CMC_EXT_ITER
/* Iterator Functions */
/* Iterator Initialization */
/* Iterator State */
/* Iterator Movement */
/* Iterator Access */
#endif /* CMC_EXT_ITER */
/**
* STR
*
* Print helper functions.
*/
#ifdef CMC_EXT_STR
#endif /* CMC_EXT_STR */
+45
View File
@@ -0,0 +1,45 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* ITER
*
* Bitset bi-directional iterator.
*/
#ifdef CMC_EXT_ITER
/* BitSet Iterator */
struct CMC_DEF_ITER(SNAME)
{
/* Target bitset */
struct SNAME *target;
/* Cursor's position (index) */
size_t cursor;
/* If the iterator has reached the start of the iteration */
bool start;
/* If the iterator has reached the end of the iteration */
bool end;
};
#endif /* CMC_EXT_ITER */
+49
View File
@@ -0,0 +1,49 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/* Collection Allocation and Deallocation */
struct SNAME *CMC_(PFX, _new)(size_t n_bits);
struct SNAME *CMC_(PFX, _new_custom)(size_t n_bits, CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks);
struct SNAME CMC_(PFX, _init)(size_t n_bits);
struct SNAME CMC_(PFX, _init_custom)(size_t n_bits, CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks);
void CMC_(PFX, _free)(struct SNAME *_bitset_);
void CMC_(PFX, _release)(struct SNAME _bitset_);
void CMC_(PFX, _customize)(struct SNAME *_bitset_, CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks);
/* Collection Input and Output */
bool CMC_(PFX, _set)(struct SNAME *_bitset_, size_t bit_index);
bool CMC_(PFX, _set_range)(struct SNAME *_bitset_, size_t from, size_t to);
bool CMC_(PFX, _clear)(struct SNAME *_bitset_, size_t bit_index);
bool CMC_(PFX, _clear_range)(struct SNAME *_bitset_, size_t from, size_t to);
bool CMC_(PFX, _flip)(struct SNAME *_bitset_, size_t bit_index);
bool CMC_(PFX, _flip_range)(struct SNAME *_bitset_, size_t from, size_t to);
bool CMC_(PFX, _put)(struct SNAME *_bitset_, size_t bit_index, bool state);
bool CMC_(PFX, _put_range)(struct SNAME *_bitset_, size_t from, size_t to, bool state);
bool CMC_(PFX, _set_all)(struct SNAME *_bitset_);
bool CMC_(PFX, _clear_all)(struct SNAME *_bitset_);
bool CMC_(PFX, _flip_all)(struct SNAME *_bitset_);
/* Element Access */
bool CMC_(PFX, _get)(struct SNAME *_bitset_, size_t bit_index);
/* Collection State */
/* Collection Utility */
bool CMC_(PFX, _resize)(struct SNAME *_bitset_, size_t n_bits);
+42
View File
@@ -0,0 +1,42 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/* BitSet Structure */
struct SNAME
{
/* Dynamic Array of Bits */
cmc_bitset_word *buffer;
/* Current array capacity */
size_t capacity;
/* Currently used bits */
/* This should always be true: */
/* capacity - count < sizeof(cmc_bitset_word) * CHAR_BIT */
size_t count;
/* Flags indicating errors or success */
int flag;
/* Custom allocation functions */
CMC_ALLOC_TYPE alloc;
/* Custom callback functions */
CMC_CALLBACKS_DECL;
};
+10 -4
View File
@@ -1,7 +1,7 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Libray.
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -23,7 +23,7 @@
*/
/**
* cor_alloc.h
* alloc.h
*
* Creation Date: 24/05/2020
*
@@ -35,14 +35,15 @@
#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 "cor_core.h"
#include "core.h"
/**
* struct cmc_alloc_node
*
@@ -50,6 +51,9 @@
* 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);
@@ -58,4 +62,6 @@ static struct CMC_ALLOC_NODE_NAME
void (*free)(void *);
} CMC_UNUSED cmc_alloc_node_default = { malloc, calloc, realloc, free };
#endif /* CMC_NO_ALLOC */
#endif /* CMC_COR_ALLOC_H */
+7 -7
View File
@@ -1,7 +1,7 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Libray.
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -23,7 +23,7 @@
*/
/**
* cor_bitset.h
* bitset.h
*
* Creation Date: 20/05/2020
*
@@ -39,7 +39,7 @@
#ifndef CMC_COR_BITSET_H
#define CMC_COR_BITSET_H
#include <stdint.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 */
@@ -57,10 +57,10 @@ typedef CMC_BITSET_WORD_TYPE cmc_bitset_word;
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;
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;
}
+61
View File
@@ -0,0 +1,61 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* callbacks.h
*
* Creation Date: 24/05/2020
*
* Authors:
* Leonardo Vencovsky (https://github.com/LeoVen)
*
*/
#ifndef CMC_COR_CALLBACKS_H
#define CMC_COR_CALLBACKS_H
typedef void (*cmc_callback)(const char func_name[], void *self);
#define CMC_CALLBACK_TYPE cmc_callback
#ifdef CMC_CALLBACKS
#define CMC_CALLBACKS_DECL cmc_callback callbacks
#define CMC_CALLBACKS_MAYBE_UNUSED(param)
#define CMC_CALLBACKS_GET(ds) (ds)->callbacks
#define CMC_CALLBACKS_ASSIGN(ds, cb) CMC_CALLBACKS_GET(ds) = cb
#define CMC_CALLBACKS_CALL(ds) \
if (CMC_CALLBACKS_GET(ds)) \
CMC_CALLBACKS_GET(ds)(__func__, (void *)ds);
#else
#define CMC_CALLBACKS_DECL
#define CMC_CALLBACKS_MAYBE_UNUSED(param) CMC_UNUSED_PARAM(param) /* Prevent -Wunused-parameter */
#define CMC_CALLBACKS_GET(ds) NULL /* Helps with compatibility */
#define CMC_CALLBACKS_ASSIGN(ds, cb)
#define CMC_CALLBACKS_CALL(ds)
#endif
#endif /* CMC_COR_CALLBACKS_H */
+21 -46
View File
@@ -1,7 +1,7 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Libray.
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -23,7 +23,7 @@
*/
/**
* cor_core.h
* core.h
*
* Creation Date: 17/03/2020
*
@@ -40,29 +40,30 @@
* - CMC_TO_STRING
* - CMC_INTERNAL_PREFIX_[ITER|NODE|ENTRY|FKEY|FVAL]
* - CMC_DEF_[ITER|NODE|ENTRY|FKEY|FVAL]
* - CMC_PARAM_[PFX|SNAME|SIZE|K|V]
*/
#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
#include <inttypes.h>
#include <limits.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "cor_alloc.h"
#include "cor_callbacks.h"
#include "cor_flags.h"
#include "cor_ftable.h"
#define CMC_UNUSED_PARAM(param) ((void)param)
#define CMC__(A, B) A##B
#define CMC_(A, B) CMC__(A, B)
@@ -70,6 +71,12 @@
#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
@@ -90,36 +97,4 @@
#define CMC_DEF_FVAL(SNAME) CMC_(SNAME, CMC_INTERNAL_PREFIX_FVAL)
#define CMC_DEF_FKEY(SNAME) CMC_(SNAME, CMC_INTERNAL_PREFIX_FKEY)
/**
* Code to get specific arguments from tuples.
*/
#define CMC_TUP_0_(A, ...) A
#define CMC_TUP_0(TUP) CMC_TUP_0_ TUP
#define CMC_TUP_1_(A, B, ...) B
#define CMC_TUP_1(TUP) CMC_TUP_1_ TUP
#define CMC_TUP_2_(A, B, C, ...) C
#define CMC_TUP_2(TUP) CMC_TUP_2_ TUP
#define CMC_TUP_3_(A, B, C, D, ...) D
#define CMC_TUP_3(TUP) CMC_TUP_3_ TUP
#define CMC_TUP_4_(A, B, C, D, E, ...) E
#define CMC_TUP_4(TUP) CMC_TUP_4_ TUP
/**
* A PARAM is a unified way to pass arguments to all macros that generate code.
* It is a tuple that contains the following parameters in order:
*
* PFX - Functions prefix
* SNAME - `struct` name
* SIZE - Size for SAC library
* K - Key type
* V - Value type
*
* PARAMS := (PFX, SNAME, SIZE, K, V)
*/
#define CMC_PARAM_PFX CMC_TUP_0
#define CMC_PARAM_SNAME CMC_TUP_1
#define CMC_PARAM_SIZE CMC_TUP_2
#define CMC_PARAM_K CMC_TUP_3
#define CMC_PARAM_V CMC_TUP_4
#endif /* CMC_COR_CORE_H */
+10 -20
View File
@@ -1,7 +1,7 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Libray.
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -23,34 +23,24 @@
*/
/**
* ext_cmc_bitset.h
* dev.h
*
* Creation Date: 08/06/2020
* Creation Date: 01/02/2023
*
* Authors:
* Leonardo Vencovsky (https://github.com/LeoVen)
*
*/
#ifndef CMC_EXT_CMC_BITSET_H
#define CMC_EXT_CMC_BITSET_H
#include "cor_core.h"
#ifndef CMC_COR_DEV_H
#define CMC_COR_DEV_H
/**
* All the EXT parts of CMC BitSet.
* Macros for tracing and debugging data structures when CMC_DEV is enabled
*/
#define CMC_EXT_CMC_BITSET_PARTS PLACEHOLDER
#define CMC_EXT_CMC_BITSET_PLACEHOLDER(ACCESS, FILE, PARAMS) \
CMC_(CMC_(CMC_EXT_CMC_BITSET_PLACEHOLDER_, ACCESS), CMC_(_, FILE))(PARAMS)
#ifndef CMC_DEV_FCALL
#define CMC_DEV_FCALL cmc_log_trace("fcall")
#endif
#define CMC_EXT_CMC_BITSET_PLACEHOLDER_PUBLIC_HEADER(PARAMS)
#define CMC_EXT_CMC_BITSET_PLACEHOLDER_PUBLIC_SOURCE(PARAMS)
#define CMC_EXT_CMC_BITSET_PLACEHOLDER_PRIVATE_HEADER(PARAMS)
#define CMC_EXT_CMC_BITSET_PLACEHOLDER_PRIVATE_SOURCE(PARAMS)
#endif /* CMC_EXT_CMC_BITSET_H */
#endif /* CMC_COR_DEV_H */
+7 -5
View File
@@ -1,7 +1,7 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Libray.
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -23,7 +23,7 @@
*/
/**
* cor_flags.h
* flags.h
*
* Creation Date: 14/05/2020
*
@@ -35,7 +35,7 @@
#ifndef CMC_COR_FLAGS_H
#define CMC_COR_FLAGS_H
#include "cor_core.h"
#include "core.h"
/**
* enum cmc_flags
@@ -56,6 +56,7 @@ enum cmc_flags
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
@@ -64,7 +65,8 @@ enum cmc_flags
*
* Maps the error codes to their character representation.
*/
CMC_UNUSED static const char *cmc_flags_to_str[11] = { "OK", "ALLOC", "EMPTY", "NOT_FOUND", "INVALID",
"RANGE", "DUPLICATE", "ERROR", "THREAD", "MUTEX", "FULL" };
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 */
+2 -2
View File
@@ -1,7 +1,7 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Libray.
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -23,7 +23,7 @@
*/
/**
* cor_ftable.h
* ftable.h
*
* Creation Date: 27/05/2020
*
+3 -3
View File
@@ -1,7 +1,7 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Libray.
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -23,7 +23,7 @@
*/
/**
* cor_hashtable.h
* hashtable.h
*
* Creation Date: 17/03/2020
*
@@ -39,7 +39,7 @@
#ifndef CMC_COR_HASHTABLE_H
#define CMC_COR_HASHTABLE_H
#include "cor_core.h"
#include "core.h"
/**
* CMC_ENTRY_DELETED
+2 -2
View File
@@ -1,7 +1,7 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Libray.
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -23,7 +23,7 @@
*/
/**
* cor_heap.h
* heap.h
*
* Creation Date: 01/06/2020
*
+28 -17
View File
@@ -1,7 +1,7 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Libray.
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -23,34 +23,45 @@
*/
/**
* ext_sac_list.h
* undef.h
*
* Creation Date: 06/10/2020
* Creation Date: 12/01/2023
*
* Authors:
* Leonardo Vencovsky (https://github.com/LeoVen)
*
*/
#ifndef CMC_EXT_SAC_LIST_H
#define CMC_EXT_SAC_LIST_H
#include "cor_core.h"
/**
* All the EXT parts of SAC List.
* Common undefs
*/
#define CMC_EXT_SAC_LIST_PARTS PLACEHOLDER
#define CMC_EXT_SAC_LIST_PLACEHOLDER(ACCESS, FILE, PARAMS) \
CMC_(CMC_(CMC_EXT_SAC_LIST_PLACEHOLDER_, ACCESS), CMC_(_, FILE))(PARAMS)
/* You never want these to fallthrough since they should be unique for each collection */
#undef PFX
#undef SNAME
#define CMC_EXT_SAC_LIST_PLACEHOLDER_PUBLIC_HEADER(PARAMS)
#ifndef CMC_ARGS_FALLTHROUGH
#define CMC_EXT_SAC_LIST_PLACEHOLDER_PUBLIC_SOURCE(PARAMS)
#undef CMC_DEV
#undef CMC_SAC
#define CMC_EXT_SAC_LIST_PLACEHOLDER_PRIVATE_HEADER(PARAMS)
#ifndef CMC_ARGS_KEY_FALLTHROUGH
#undef K
#endif
#define CMC_EXT_SAC_LIST_PLACEHOLDER_PRIVATE_SOURCE(PARAMS)
#ifndef CMC_ARGS_VAL_FALLTHROUGH
#undef V
#endif
#endif /* CMC_EXT_SAC_LIST_H */
#undef SIZE
#ifndef CMC_EXT_FALLTHROUGH
#undef CMC_EXT_INIT
#undef CMC_EXT_ITER
#undef CMC_EXT_NODE
#undef CMC_EXT_SEQ
#undef CMC_EXT_SETF
#undef CMC_EXT_STR
#endif
#endif
+92
View File
@@ -0,0 +1,92 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* deque.h
*
* Creation Date: 20/03/2019
*
* Authors:
* Leonardo Vencovsky (https://github.com/LeoVen)
*
*/
/**
* Deque
*
* A Deque (double-ended queue) is a linear data structure that is able to add
* or remove elements from both ends. It can also be thought of a double-ended
* stack since you can push and pop elements from two ends. The Deque can also
* be used as a Queue.
*
* There is no random access for a Deque. The only elements accessible are the
* front element and the back.
*
* Implementation
*
* This implementation uses a circular buffer (ring buffer or cyclic buffer) in
* order to operate on O(1) for push and pop on either ends (only case where it
* takes longer than O(1) is when the buffer is reallocated). If it was
* implemented as a regular array, adding or removing elements from the front
* would take O(N) due to the need to shift all elements in the deque.
*/
#include "cor/core.h"
#ifdef CMC_DEV
#include "utl/log.h"
#endif
/**
* Used values
* V - deque data type
* SNAME - struct name and prefix of other related structs
* PFX - functions prefix
*/
/* Structs definition */
#include "cmc/deque/struct.h"
/* Function declaration */
#include "cmc/deque/header.h"
/* Function implementation */
#include "cmc/deque/code.h"
/**
* Extensions
*
* INIT - Initializes the struct on the stack
* ITER - Deque iterator
* STR - Print helper functions
*/
#define CMC_EXT_DEQUE_PARTS INIT, ITER, STR
/**/
#include "cmc/deque/ext/struct.h"
/**/
#include "cmc/deque/ext/header.h"
/**/
#include "cmc/deque/ext/code.h"
#include "cor/undef.h"
+461
View File
@@ -0,0 +1,461 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/* Implementation Detail Functions */
/* None */
struct SNAME *CMC_(PFX, _new)(size_t capacity, struct CMC_DEF_FVAL(SNAME) * f_val)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return CMC_(PFX, _new_custom)(capacity, f_val, NULL, NULL);
}
struct SNAME *CMC_(PFX, _new_custom)(size_t capacity, struct CMC_DEF_FVAL(SNAME) * f_val, CMC_ALLOC_TYPE alloc,
CMC_CALLBACK_TYPE callbacks)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
if (capacity < 1)
return NULL;
if (!f_val)
return NULL;
if (!alloc)
alloc = &cmc_alloc_node_default;
struct SNAME *_deque_ = alloc->malloc(sizeof(struct SNAME));
if (!_deque_)
return NULL;
_deque_->buffer = alloc->calloc(capacity, sizeof(V));
if (!_deque_->buffer)
{
alloc->free(_deque_);
return NULL;
}
_deque_->capacity = capacity;
_deque_->count = 0;
_deque_->front = 0;
_deque_->back = 0;
_deque_->flag = CMC_FLAG_OK;
_deque_->f_val = f_val;
_deque_->alloc = alloc;
CMC_CALLBACKS_ASSIGN(_deque_, callbacks);
return _deque_;
}
void CMC_(PFX, _clear)(struct SNAME *_deque_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (_deque_->f_val->free)
{
for (size_t i = _deque_->front, j = 0; j < _deque_->count; j++)
{
_deque_->f_val->free(_deque_->buffer[i]);
i = (i + 1) % _deque_->capacity;
}
}
memset(_deque_->buffer, 0, sizeof(V) * _deque_->capacity);
_deque_->count = 0;
_deque_->front = 0;
_deque_->back = 0;
_deque_->flag = CMC_FLAG_OK;
}
void CMC_(PFX, _free)(struct SNAME *_deque_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (_deque_->f_val->free)
{
for (size_t i = _deque_->front, j = 0; j < _deque_->count; j++)
{
_deque_->f_val->free(_deque_->buffer[i]);
i = (i + 1) % _deque_->capacity;
}
}
_deque_->alloc->free(_deque_->buffer);
_deque_->alloc->free(_deque_);
}
void CMC_(PFX, _customize)(struct SNAME *_deque_, CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
if (!alloc)
_deque_->alloc = &cmc_alloc_node_default;
else
_deque_->alloc = alloc;
CMC_CALLBACKS_ASSIGN(_deque_, callbacks);
_deque_->flag = CMC_FLAG_OK;
}
bool CMC_(PFX, _push_front)(struct SNAME *_deque_, V value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _full)(_deque_))
{
if (!CMC_(PFX, _resize)(_deque_, _deque_->capacity * 2))
return false;
}
_deque_->front = (_deque_->front == 0) ? _deque_->capacity - 1 : _deque_->front - 1;
_deque_->buffer[_deque_->front] = value;
_deque_->count++;
_deque_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_deque_);
return true;
}
bool CMC_(PFX, _push_back)(struct SNAME *_deque_, V value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _full)(_deque_))
{
if (!CMC_(PFX, _resize)(_deque_, _deque_->capacity * 2))
return false;
}
_deque_->buffer[_deque_->back] = value;
_deque_->back = (_deque_->back == _deque_->capacity - 1) ? 0 : _deque_->back + 1;
_deque_->count++;
_deque_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_deque_);
return true;
}
bool CMC_(PFX, _pop_front)(struct SNAME *_deque_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_deque_))
{
_deque_->flag = CMC_FLAG_EMPTY;
return false;
}
_deque_->buffer[_deque_->front] = (V){ 0 };
_deque_->front = (_deque_->front == _deque_->capacity - 1) ? 0 : _deque_->front + 1;
_deque_->count--;
_deque_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_deque_);
return true;
}
bool CMC_(PFX, _pop_back)(struct SNAME *_deque_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_deque_))
{
_deque_->flag = CMC_FLAG_EMPTY;
return false;
}
_deque_->back = (_deque_->back == 0) ? _deque_->capacity - 1 : _deque_->back - 1;
_deque_->buffer[_deque_->back] = (V){ 0 };
_deque_->count--;
_deque_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_deque_);
return true;
}
V CMC_(PFX, _front)(struct SNAME *_deque_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_deque_))
{
_deque_->flag = CMC_FLAG_EMPTY;
return (V){ 0 };
}
_deque_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_deque_);
return _deque_->buffer[_deque_->front];
}
V CMC_(PFX, _back)(struct SNAME *_deque_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_deque_))
{
_deque_->flag = CMC_FLAG_EMPTY;
return (V){ 0 };
}
_deque_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_deque_);
return _deque_->buffer[(_deque_->back == 0) ? _deque_->capacity - 1 : _deque_->back - 1];
}
bool CMC_(PFX, _contains)(struct SNAME *_deque_, V value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
_deque_->flag = CMC_FLAG_OK;
bool result = false;
for (size_t i = _deque_->front, j = 0; j < _deque_->count; j++)
{
if (_deque_->f_val->cmp(_deque_->buffer[i], value) == 0)
{
result = true;
break;
}
i = (i + 1) % _deque_->capacity;
}
CMC_CALLBACKS_CALL(_deque_);
return result;
}
bool CMC_(PFX, _empty)(struct SNAME *_deque_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _deque_->count == 0;
}
bool CMC_(PFX, _full)(struct SNAME *_deque_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _deque_->count >= _deque_->capacity;
}
size_t CMC_(PFX, _count)(struct SNAME *_deque_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _deque_->count;
}
size_t CMC_(PFX, _capacity)(struct SNAME *_deque_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _deque_->capacity;
}
int CMC_(PFX, _flag)(struct SNAME *_deque_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _deque_->flag;
}
bool CMC_(PFX, _resize)(struct SNAME *_deque_, size_t capacity)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
_deque_->flag = CMC_FLAG_OK;
if (_deque_->capacity == capacity)
goto success;
if (capacity < _deque_->count)
{
_deque_->flag = CMC_FLAG_INVALID;
return false;
}
V *new_buffer = _deque_->alloc->malloc(sizeof(V) * capacity);
if (!new_buffer)
{
_deque_->flag = CMC_FLAG_ALLOC;
return false;
}
for (size_t i = _deque_->front, j = 0; j < _deque_->count; j++)
{
new_buffer[j] = _deque_->buffer[i];
i = (i + 1) % _deque_->capacity;
}
_deque_->alloc->free(_deque_->buffer);
_deque_->buffer = new_buffer;
_deque_->capacity = capacity;
_deque_->front = 0;
_deque_->back = _deque_->count;
success:
CMC_CALLBACKS_CALL(_deque_);
return true;
}
struct SNAME *CMC_(PFX, _copy_of)(struct SNAME *_deque_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct SNAME *result = CMC_(PFX, _new_custom)(_deque_->capacity, _deque_->f_val, _deque_->alloc, NULL);
if (!result)
{
_deque_->flag = CMC_FLAG_ERROR;
return NULL;
}
CMC_CALLBACKS_ASSIGN(result, _deque_->callbacks);
if (_deque_->f_val->cpy)
{
for (size_t i = _deque_->front, j = 0; j < _deque_->count; j++)
{
result->buffer[j] = _deque_->f_val->cpy(_deque_->buffer[i]);
i = (i + 1) % _deque_->capacity;
}
}
else
{
for (size_t i = _deque_->front, j = 0; j < _deque_->count; j++)
{
result->buffer[j] = _deque_->buffer[i];
i = (i + 1) % _deque_->capacity;
}
}
result->count = _deque_->count;
result->front = 0;
result->back = _deque_->count;
_deque_->flag = CMC_FLAG_OK;
return result;
}
bool CMC_(PFX, _equals)(struct SNAME *_deque1_, struct SNAME *_deque2_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
_deque1_->flag = CMC_FLAG_OK;
_deque2_->flag = CMC_FLAG_OK;
if (_deque1_->count != _deque2_->count)
return false;
size_t i, j, k;
for (i = _deque1_->front, j = _deque2_->front, k = 0; k < _deque1_->count; k++)
{
if (_deque1_->f_val->cmp(_deque1_->buffer[i], _deque2_->buffer[j]) != 0)
return false;
i = (i + 1) % _deque1_->capacity;
j = (j + 1) % _deque2_->capacity;
}
return true;
}
+430
View File
@@ -0,0 +1,430 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* INIT
*
* The part 'INIT' gives a new way of initializing a collection. The collection
* struct is not heap allocated, only its internal structure (nodes, buffers).
*/
#ifdef CMC_EXT_INIT
struct SNAME CMC_(PFX, _init)(size_t capacity, struct CMC_DEF_FVAL(SNAME) * f_val)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return CMC_(PFX, _init_custom)(capacity, f_val, NULL, NULL);
}
struct SNAME CMC_(PFX, _init_custom)(size_t capacity, struct CMC_DEF_FVAL(SNAME) * f_val, CMC_ALLOC_TYPE alloc,
CMC_CALLBACK_TYPE callbacks)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
struct SNAME _deque_ = { 0 };
if (capacity < 1)
return _deque_;
if (!f_val)
return _deque_;
if (!alloc)
alloc = &cmc_alloc_node_default;
_deque_.buffer = alloc->calloc(capacity, sizeof(V));
if (!_deque_.buffer)
return _deque_;
_deque_.capacity = capacity;
_deque_.count = 0;
_deque_.front = 0;
_deque_.back = 0;
_deque_.flag = CMC_FLAG_OK;
_deque_.f_val = f_val;
_deque_.alloc = alloc;
CMC_CALLBACKS_ASSIGN(&_deque_, callbacks);
return _deque_;
}
void CMC_(PFX, _release)(struct SNAME _deque_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (_deque_.f_val->free)
{
for (size_t i = _deque_.front, j = 0; j < _deque_.count; j++)
{
_deque_.f_val->free(_deque_.buffer[i]);
i = (i + 1) % _deque_.capacity;
}
}
_deque_.alloc->free(_deque_.buffer);
}
#endif /* CMC_EXT_INIT */
/**
* ITER
*
* Deque bi-directional iterator.
*/
#ifdef CMC_EXT_ITER
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_start)(struct SNAME *target)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct CMC_DEF_ITER(SNAME) iter;
iter.target = target;
iter.cursor = target->front;
iter.index = 0;
iter.start = true;
iter.end = CMC_(PFX, _empty)(target);
return iter;
}
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_end)(struct SNAME *target)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct CMC_DEF_ITER(SNAME) iter;
iter.target = target;
if (!CMC_(PFX, _empty)(target))
{
if (iter.target->back == 0)
iter.cursor = iter.target->capacity - 1;
else
iter.cursor = iter.target->back - 1;
iter.index = iter.target->count - 1;
}
else
{
iter.cursor = 0;
iter.index = 0;
}
iter.start = CMC_(PFX, _empty)(target);
iter.end = true;
return iter;
}
bool CMC_(PFX, _iter_at_start)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return CMC_(PFX, _empty)(iter->target) || iter->start;
}
bool CMC_(PFX, _iter_at_end)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return CMC_(PFX, _empty)(iter->target) || iter->end;
}
bool CMC_(PFX, _iter_to_start)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (!CMC_(PFX, _empty)(iter->target))
{
iter->cursor = iter->target->front;
iter->index = 0;
iter->start = true;
iter->end = false;
return true;
}
return false;
}
bool CMC_(PFX, _iter_to_end)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (!CMC_(PFX, _empty)(iter->target))
{
if (iter->target->back == 0)
iter->cursor = iter->target->capacity - 1;
else
iter->cursor = iter->target->back - 1;
iter->index = iter->target->count - 1;
iter->start = false;
iter->end = true;
return true;
}
return false;
}
bool CMC_(PFX, _iter_next)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (iter->end)
return false;
if (iter->index + 1 == iter->target->count)
{
iter->end = true;
return false;
}
iter->start = CMC_(PFX, _empty)(iter->target);
iter->cursor = (iter->cursor + 1) % (iter->target->capacity);
iter->index++;
return true;
}
bool CMC_(PFX, _iter_prev)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (iter->start)
return false;
if (iter->index == 0)
{
iter->start = true;
return false;
}
iter->end = CMC_(PFX, _empty)(iter->target);
iter->cursor = (iter->cursor == 0) ? iter->target->capacity - 1 : iter->cursor - 1;
iter->index--;
return true;
}
/* Returns true only if the iterator moved */
bool CMC_(PFX, _iter_advance)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (iter->end)
return false;
if (iter->index + 1 == iter->target->count)
{
iter->end = true;
return false;
}
if (steps == 0 || iter->index + steps >= iter->target->count)
return false;
iter->start = CMC_(PFX, _empty)(iter->target);
iter->index += steps;
iter->cursor = (iter->cursor + steps) % iter->target->capacity;
return true;
}
/* Returns true only if the iterator moved */
bool CMC_(PFX, _iter_rewind)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (iter->start)
return false;
if (iter->index == 0)
{
iter->start = true;
return false;
}
if (steps == 0 || iter->index < steps)
return false;
iter->end = CMC_(PFX, _empty)(iter->target);
iter->index -= steps;
/* Prevent underflow */
if (iter->cursor < steps)
iter->cursor += iter->target->capacity;
iter->cursor -= steps;
return true;
}
/* Returns true only if the iterator was able to be positioned at the */
/* given index */
bool CMC_(PFX, _iter_go_to)(struct CMC_DEF_ITER(SNAME) * iter, size_t index)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (index >= iter->target->count)
return false;
if (iter->index > index)
return CMC_(PFX, _iter_rewind)(iter, iter->index - index);
else if (iter->index < index)
return CMC_(PFX, _iter_advance)(iter, index - iter->index);
return true;
}
V CMC_(PFX, _iter_value)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(iter->target))
return (V){ 0 };
return iter->target->buffer[iter->cursor];
}
V *CMC_(PFX, _iter_rvalue)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(iter->target))
return NULL;
return &(iter->target->buffer[iter->cursor]);
}
size_t CMC_(PFX, _iter_index)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return iter->index;
}
#endif /* CMC_EXT_ITER */
/**
* STR
*
* Print helper functions.
*/
#ifdef CMC_EXT_STR
bool CMC_(PFX, _to_string)(struct SNAME *_deque_, FILE *fptr)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct SNAME *d_ = _deque_;
return 0 <= fprintf(fptr,
"struct %s<%s> "
"at %p { "
"buffer:%p, "
"capacity:%" PRIuMAX ", "
"count:%" PRIuMAX ", "
"front:%" PRIuMAX ", "
"back:%" PRIuMAX ", "
"flag:%d, "
"f_val:%p, "
"alloc:%p, "
"callbacks:%p }",
CMC_TO_STRING(SNAME), CMC_TO_STRING(V), d_, d_->buffer, d_->capacity, d_->count, d_->front,
d_->back, d_->flag, d_->f_val, d_->alloc, CMC_CALLBACKS_GET(d_));
}
bool CMC_(PFX, _print)(struct SNAME *_deque_, FILE *fptr, const char *start, const char *separator, const char *end)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
fprintf(fptr, "%s", start);
for (size_t i = _deque_->front, j = 0; j < _deque_->count; j++)
{
if (!_deque_->f_val->str(fptr, _deque_->buffer[i]))
return false;
i = (i + 1) % _deque_->capacity;
if (j + 1 < _deque_->count)
fprintf(fptr, "%s", separator);
}
fprintf(fptr, "%s", end);
return true;
}
#endif /* CMC_EXT_STR */
+80
View File
@@ -0,0 +1,80 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* INIT
*
* The part 'INIT' gives a new way of initializing a collection. The collection
* struct is not heap allocated, only its internal structure (nodes, buffers).
*/
#ifdef CMC_EXT_INIT
struct SNAME CMC_(PFX, _init)(size_t capacity, struct CMC_DEF_FVAL(SNAME) * f_val);
struct SNAME CMC_(PFX, _init_custom)(size_t capacity, struct CMC_DEF_FVAL(SNAME) * f_val, CMC_ALLOC_TYPE alloc,
CMC_CALLBACK_TYPE callbacks);
void CMC_(PFX, _release)(struct SNAME _deque_);
#endif /* CMC_EXT_INIT */
/**
* ITER
*
* Deque bi-directional iterator.
*/
#ifdef CMC_EXT_ITER
/* Iterator Initialization */
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_start)(struct SNAME *target);
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_end)(struct SNAME *target);
/* Iterator State */
bool CMC_(PFX, _iter_at_start)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_at_end)(struct CMC_DEF_ITER(SNAME) * iter);
/* Iterator Movement */
bool CMC_(PFX, _iter_to_start)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_to_end)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_next)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_prev)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_advance)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps);
bool CMC_(PFX, _iter_rewind)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps);
bool CMC_(PFX, _iter_go_to)(struct CMC_DEF_ITER(SNAME) * iter, size_t index);
/* Iterator Access */
V CMC_(PFX, _iter_value)(struct CMC_DEF_ITER(SNAME) * iter);
V *CMC_(PFX, _iter_rvalue)(struct CMC_DEF_ITER(SNAME) * iter);
size_t CMC_(PFX, _iter_index)(struct CMC_DEF_ITER(SNAME) * iter);
#endif /* CMC_EXT_ITER */
/**
* STR
*
* Print helper functions.
*/
#ifdef CMC_EXT_STR
/* Debug prints the struct to fptr */
bool CMC_(PFX, _to_string)(struct SNAME *_deque_, FILE *fptr);
/* Prints each item in the deque as an array */
bool CMC_(PFX, _print)(struct SNAME *_deque_, FILE *fptr, const char *start, const char *separator, const char *end);
#endif /* CMC_EXT_STR */
+47
View File
@@ -0,0 +1,47 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* ITER
*
* Deque bi-directional iterator.
*/
#ifdef CMC_EXT_ITER
/* Deque Iterator */
struct CMC_DEF_ITER(SNAME)
{
/* Target deque */
struct SNAME *target;
/* Cursor's position (index) */
size_t cursor;
/* Keeps track of relative index to the iteration of elements */
size_t index;
/* If the iterator has reached the start of the iteration */
bool start;
/* If the iterator has reached the end of the iteration */
bool end;
};
#endif /* CMC_EXT_ITER */
+68
View File
@@ -0,0 +1,68 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/* Value function table */
struct CMC_DEF_FVAL(SNAME)
{
/* Comparator function */
CMC_DEF_FTAB_CMP(V);
/* Copy function */
CMC_DEF_FTAB_CPY(V);
/* To string function */
CMC_DEF_FTAB_STR(V);
/* Free from memory function */
CMC_DEF_FTAB_FREE(V);
/* Hash function */
CMC_DEF_FTAB_HASH(V);
/* Priority function */
CMC_DEF_FTAB_PRI(V);
};
/* Collection Allocation and Deallocation */
struct SNAME *CMC_(PFX, _new)(size_t capacity, struct CMC_DEF_FVAL(SNAME) * f_val);
struct SNAME *CMC_(PFX, _new_custom)(size_t capacity, struct CMC_DEF_FVAL(SNAME) * f_val, CMC_ALLOC_TYPE alloc,
CMC_CALLBACK_TYPE callbacks);
void CMC_(PFX, _clear)(struct SNAME *_deque_);
void CMC_(PFX, _free)(struct SNAME *_deque_);
/* Customization of Allocation and Callbacks */
void CMC_(PFX, _customize)(struct SNAME *_deque_, CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks);
/* Collection Input and Output */
bool CMC_(PFX, _push_front)(struct SNAME *_deque_, V value);
bool CMC_(PFX, _push_back)(struct SNAME *_deque_, V value);
bool CMC_(PFX, _pop_front)(struct SNAME *_deque_);
bool CMC_(PFX, _pop_back)(struct SNAME *_deque_);
/* Element Access */
V CMC_(PFX, _front)(struct SNAME *_deque_);
V CMC_(PFX, _back)(struct SNAME *_deque_);
/* Collection State */
bool CMC_(PFX, _contains)(struct SNAME *_deque_, V value);
bool CMC_(PFX, _empty)(struct SNAME *_deque_);
bool CMC_(PFX, _full)(struct SNAME *_deque_);
size_t CMC_(PFX, _count)(struct SNAME *_deque_);
size_t CMC_(PFX, _capacity)(struct SNAME *_deque_);
int CMC_(PFX, _flag)(struct SNAME *_deque_);
/* Collection Utility */
bool CMC_(PFX, _resize)(struct SNAME *_deque_, size_t capacity);
struct SNAME *CMC_(PFX, _copy_of)(struct SNAME *_deque_);
bool CMC_(PFX, _equals)(struct SNAME *_deque1_, struct SNAME *_deque2_);
+45
View File
@@ -0,0 +1,45 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
struct SNAME
{
/* Dynamic circular array of elements */
V *buffer;
/* Current circular array capacity */
size_t capacity;
/* Current amount of elements */
size_t count;
/* Index representing the front of the deque */
size_t front;
/* Index representing the back of the deque */
size_t back;
/* Flags indicating errors or success */
int flag;
/* Functions Table */
struct CMC_DEF_FVAL(SNAME) * f_val;
/* Custom allocation functions */
CMC_ALLOC_TYPE alloc;
/* Custom callback functions */
CMC_CALLBACKS_DECL;
};
+89
View File
@@ -0,0 +1,89 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* hashbidimap.h
*
* Creation Date: 26/09/2019
*
* Authors:
* Leonardo Vencovsky (https://github.com/LeoVen)
*
*/
/**
* HashBidiMap
*
* A bidirectional map is a map that allows you to create a bijection in both
* directions between two sets of elements (K <-> V). It is possible to retrieve
* the value using a key or retrieve a key using a value. The naming (key and
* value) is simply used to differentiate between one set of elements and the
* other set of elements.
*
* Implementation
*
* This implementation uses two arrays of pointers to an entry containing both
* the key and the value.
*/
#include "cor/core.h"
#include "cor/hashtable.h"
#ifdef CMC_DEV
#include "utl/log.h"
#endif
/**
* Used values
* K - hashbidimap key data type
* V - hashbidimap value data type
* SNAME - struct name and prefix of other related structs
* PFX - functions prefix
*/
/* Structs definition */
#include "cmc/hashbidimap/struct.h"
/* Function declaration */
#include "cmc/hashbidimap/header.h"
/* Function implementation */
#include "cmc/hashbidimap/code.h"
/**
* Extensions
*
* INIT - Initializes the struct on the stack
* ITER - Hashbidimap iterator
* STR - Print helper functions
*/
#define CMC_EXT_HASHBIDIMAP_PARTS INIT, ITER, STR
/**/
#include "cmc/hashbidimap/ext/struct.h"
/**/
#include "cmc/hashbidimap/ext/header.h"
/**/
#include "cmc/hashbidimap/ext/code.h"
#include "cor/undef.h"
+961
View File
@@ -0,0 +1,961 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/* Implementation Detail Functions */
static struct CMC_DEF_ENTRY(SNAME) * CMC_(PFX, _impl_new_entry)(struct SNAME *_map_, K key, V value);
static struct CMC_DEF_ENTRY(SNAME) * *CMC_(PFX, _impl_get_entry_by_key)(struct SNAME *_map_, K key);
static struct CMC_DEF_ENTRY(SNAME) * *CMC_(PFX, _impl_get_entry_by_val)(struct SNAME *_map_, V val);
static struct CMC_DEF_ENTRY(SNAME) *
*CMC_(PFX, _impl_add_entry_to_key)(struct SNAME *_map_, struct CMC_DEF_ENTRY(SNAME) * entry);
static struct CMC_DEF_ENTRY(SNAME) *
*CMC_(PFX, _impl_add_entry_to_val)(struct SNAME *_map_, struct CMC_DEF_ENTRY(SNAME) * entry);
static size_t CMC_(PFX, _impl_calculate_size)(size_t required);
struct SNAME *CMC_(PFX, _new)(size_t capacity, double load, struct CMC_DEF_FKEY(SNAME) * f_key,
struct CMC_DEF_FVAL(SNAME) * f_val)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return CMC_(PFX, _new_custom)(capacity, load, f_key, f_val, NULL, NULL);
}
struct SNAME *CMC_(PFX, _new_custom)(size_t capacity, double load, struct CMC_DEF_FKEY(SNAME) * f_key,
struct CMC_DEF_FVAL(SNAME) * f_val, CMC_ALLOC_TYPE alloc,
CMC_CALLBACK_TYPE callbacks)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
if (capacity == 0 || load <= 0 || load >= 1)
return NULL;
/* Prevent integer overflow */
if (capacity >= (double)UINTMAX_MAX * load)
return NULL;
if (!f_key || !f_val)
return NULL;
size_t real_capacity = CMC_(PFX, _impl_calculate_size)(capacity / load);
if (!alloc)
alloc = &cmc_alloc_node_default;
struct SNAME *_map_ = alloc->malloc(sizeof(struct SNAME));
if (!_map_)
return NULL;
_map_->buffer = alloc->calloc(real_capacity, sizeof(struct CMC_DEF_ENTRY(SNAME) *[2]));
if (!_map_->buffer)
{
alloc->free(_map_->buffer);
alloc->free(_map_);
return NULL;
}
_map_->count = 0;
_map_->capacity = real_capacity;
_map_->load = load;
_map_->flag = CMC_FLAG_OK;
_map_->f_key = f_key;
_map_->f_val = f_val;
_map_->flag = CMC_FLAG_OK;
_map_->alloc = alloc;
CMC_CALLBACKS_ASSIGN(_map_, callbacks);
return _map_;
}
void CMC_(PFX, _clear)(struct SNAME *_map_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
for (size_t i = 0; i < _map_->capacity; i++)
{
struct CMC_DEF_ENTRY(SNAME) *entry = _map_->buffer[i][0];
if (entry && entry != CMC_ENTRY_DELETED)
{
if (_map_->f_key->free)
_map_->f_key->free(entry->key);
if (_map_->f_val->free)
_map_->f_val->free(entry->value);
_map_->alloc->free(entry);
}
_map_->buffer[i][0] = NULL;
_map_->buffer[i][1] = NULL;
}
_map_->count = 0;
_map_->flag = CMC_FLAG_OK;
}
void CMC_(PFX, _free)(struct SNAME *_map_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
CMC_(PFX, _clear)(_map_);
_map_->alloc->free(_map_->buffer);
_map_->alloc->free(_map_);
}
void CMC_(PFX, _customize)(struct SNAME *_map_, CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
if (!alloc)
_map_->alloc = &cmc_alloc_node_default;
else
_map_->alloc = alloc;
CMC_CALLBACKS_ASSIGN(_map_, callbacks);
_map_->flag = CMC_FLAG_OK;
}
bool CMC_(PFX, _insert)(struct SNAME *_map_, K key, V value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _full)(_map_))
{
if (!CMC_(PFX, _resize)(_map_, _map_->capacity + 1))
return false;
}
if (CMC_(PFX, _impl_get_entry_by_key)(_map_, key) != NULL ||
CMC_(PFX, _impl_get_entry_by_val)(_map_, value) != NULL)
{
_map_->flag = CMC_FLAG_DUPLICATE;
return false;
}
struct CMC_DEF_ENTRY(SNAME) *entry = CMC_(PFX, _impl_new_entry)(_map_, key, value);
struct CMC_DEF_ENTRY(SNAME) **key_entry = CMC_(PFX, _impl_add_entry_to_key)(_map_, entry);
struct CMC_DEF_ENTRY(SNAME) **val_entry = CMC_(PFX, _impl_add_entry_to_val)(_map_, entry);
if (!key_entry || !val_entry)
{
if (key_entry)
*key_entry = CMC_ENTRY_DELETED;
if (val_entry)
*val_entry = CMC_ENTRY_DELETED;
_map_->alloc->free(entry);
_map_->flag = CMC_FLAG_ERROR;
return false;
}
_map_->count++;
_map_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_map_);
return true;
}
bool CMC_(PFX, _update_key)(struct SNAME *_map_, V val, K new_key)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_map_))
{
_map_->flag = CMC_FLAG_EMPTY;
return false;
}
struct CMC_DEF_ENTRY(SNAME) * *key_entry, **val_entry;
val_entry = CMC_(PFX, _impl_get_entry_by_val)(_map_, val);
if (!val_entry)
{
_map_->flag = CMC_FLAG_NOT_FOUND;
return false;
}
/* The mapping val -> new_key is already true */
if (_map_->f_key->cmp(new_key, (*val_entry)->key) == 0)
goto success;
if (CMC_(PFX, _impl_get_entry_by_key)(_map_, new_key) != NULL)
{
_map_->flag = CMC_FLAG_DUPLICATE;
return false;
}
key_entry = (*val_entry)->ref[0];
if (!key_entry || *key_entry != *val_entry)
{
/* Should never happen */
_map_->flag = CMC_FLAG_ERROR;
return false;
}
/* Remove entry from key buffer and add it again with new key */
struct CMC_DEF_ENTRY(SNAME) *to_add = *key_entry;
K tmp_key = to_add->key;
to_add->key = new_key;
*key_entry = CMC_ENTRY_DELETED;
if (!CMC_(PFX, _impl_add_entry_to_key)(_map_, to_add))
{
/* Revert changes */
to_add->key = tmp_key;
*key_entry = to_add;
_map_->flag = CMC_FLAG_ERROR;
return false;
}
success:
_map_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_map_);
return true;
}
bool CMC_(PFX, _update_val)(struct SNAME *_map_, K key, V new_val)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_map_))
{
_map_->flag = CMC_FLAG_EMPTY;
return false;
}
struct CMC_DEF_ENTRY(SNAME) * *key_entry, **val_entry;
key_entry = CMC_(PFX, _impl_get_entry_by_key)(_map_, key);
if (!key_entry)
{
_map_->flag = CMC_FLAG_NOT_FOUND;
return false;
}
/* The mapping key -> new_val is already true */
if (_map_->f_val->cmp(new_val, (*key_entry)->value) == 0)
goto success;
if (CMC_(PFX, _impl_get_entry_by_val)(_map_, new_val) != NULL)
{
_map_->flag = CMC_FLAG_DUPLICATE;
return false;
}
val_entry = (*key_entry)->ref[1];
if (!val_entry || *val_entry != *key_entry)
{
/* Should never happen */
_map_->flag = CMC_FLAG_ERROR;
return false;
}
/* Remove entry from value buffer and add it again with new value */
struct CMC_DEF_ENTRY(SNAME) *to_add = *val_entry;
V tmp_val = to_add->value;
to_add->value = new_val;
*val_entry = CMC_ENTRY_DELETED;
if (!CMC_(PFX, _impl_add_entry_to_val)(_map_, to_add))
{
/* Revert changes */
to_add->value = tmp_val;
*val_entry = to_add;
_map_->flag = CMC_FLAG_ERROR;
return false;
}
success:
_map_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_map_);
return true;
}
bool CMC_(PFX, _remove_by_key)(struct SNAME *_map_, K key, K *out_key, V *out_val)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_map_))
{
_map_->flag = CMC_FLAG_EMPTY;
return false;
}
struct CMC_DEF_ENTRY(SNAME) * *key_entry, **val_entry;
key_entry = CMC_(PFX, _impl_get_entry_by_key)(_map_, key);
if (!key_entry)
{
_map_->flag = CMC_FLAG_NOT_FOUND;
return false;
}
val_entry = (*key_entry)->ref[1];
if (!val_entry || *val_entry != *key_entry)
{
/* Should never happen */
_map_->flag = CMC_FLAG_ERROR;
return false;
}
if (out_key)
*out_key = (*key_entry)->key;
if (out_val)
*out_val = (*key_entry)->value;
_map_->alloc->free(*key_entry);
*key_entry = CMC_ENTRY_DELETED;
*val_entry = CMC_ENTRY_DELETED;
_map_->count--;
_map_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_map_);
return true;
}
bool CMC_(PFX, _remove_by_val)(struct SNAME *_map_, V val, K *out_key, V *out_val)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_map_))
{
_map_->flag = CMC_FLAG_EMPTY;
return false;
}
struct CMC_DEF_ENTRY(SNAME) * *key_entry, **val_entry;
val_entry = CMC_(PFX, _impl_get_entry_by_val)(_map_, val);
if (!val_entry)
{
_map_->flag = CMC_FLAG_NOT_FOUND;
return false;
}
key_entry = (*val_entry)->ref[0];
if (!key_entry || *key_entry != *val_entry)
{
/* Should never happen */
_map_->flag = CMC_FLAG_ERROR;
return false;
}
if (out_key)
*out_key = (*val_entry)->key;
if (out_val)
*out_val = (*val_entry)->value;
_map_->alloc->free(*val_entry);
*key_entry = CMC_ENTRY_DELETED;
*val_entry = CMC_ENTRY_DELETED;
_map_->count--;
_map_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_map_);
return true;
}
K CMC_(PFX, _get_key)(struct SNAME *_map_, V val)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct CMC_DEF_ENTRY(SNAME) **entry = CMC_(PFX, _impl_get_entry_by_val)(_map_, val);
if (!entry)
{
_map_->flag = CMC_FLAG_NOT_FOUND;
return (K){ 0 };
}
_map_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_map_);
return (*entry)->key;
}
V CMC_(PFX, _get_val)(struct SNAME *_map_, K key)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct CMC_DEF_ENTRY(SNAME) **entry = CMC_(PFX, _impl_get_entry_by_key)(_map_, key);
if (!entry)
{
_map_->flag = CMC_FLAG_NOT_FOUND;
return (V){ 0 };
}
_map_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_map_);
return (*entry)->value;
}
bool CMC_(PFX, _contains_key)(struct SNAME *_map_, K key)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
_map_->flag = CMC_FLAG_OK;
bool result = CMC_(PFX, _impl_get_entry_by_key)(_map_, key) != NULL;
CMC_CALLBACKS_CALL(_map_);
return result;
}
bool CMC_(PFX, _contains_val)(struct SNAME *_map_, V val)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
_map_->flag = CMC_FLAG_OK;
bool result = CMC_(PFX, _impl_get_entry_by_val)(_map_, val) != NULL;
CMC_CALLBACKS_CALL(_map_);
return result;
}
bool CMC_(PFX, _empty)(struct SNAME *_map_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _map_->count == 0;
}
bool CMC_(PFX, _full)(struct SNAME *_map_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return (double)_map_->capacity * _map_->load <= (double)_map_->count;
}
size_t CMC_(PFX, _count)(struct SNAME *_map_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _map_->count;
}
size_t CMC_(PFX, _capacity)(struct SNAME *_map_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _map_->capacity;
}
double CMC_(PFX, _load)(struct SNAME *_map_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _map_->load;
}
int CMC_(PFX, _flag)(struct SNAME *_map_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _map_->flag;
}
bool CMC_(PFX, _resize)(struct SNAME *_map_, size_t capacity)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
_map_->flag = CMC_FLAG_OK;
if (_map_->capacity == capacity)
goto success;
if (_map_->capacity > capacity / _map_->load)
goto success;
/* Prevent integer overflow */
if (capacity >= (double)UINTMAX_MAX * _map_->load)
{
_map_->flag = CMC_FLAG_ERROR;
return false;
}
/* Calculate required capacity based on the prime numbers */
size_t new_cap = CMC_(PFX, _impl_calculate_size)(capacity);
/* Not possible to shrink with current available prime numbers */
if (new_cap < _map_->count / _map_->load)
{
_map_->flag = CMC_FLAG_INVALID;
return false;
}
/* No callbacks since _new_map_ is just a temporary hashtable */
struct SNAME *_new_map_ =
CMC_(PFX, _new_custom)(capacity, _map_->load, _map_->f_key, _map_->f_val, _map_->alloc, NULL);
if (!_new_map_)
{
_map_->flag = CMC_FLAG_ALLOC;
return false;
}
for (size_t i = 0; i < _map_->capacity; i++)
{
struct CMC_DEF_ENTRY(SNAME) *scan = _map_->buffer[i][0];
if (scan && scan != CMC_ENTRY_DELETED)
{
struct CMC_DEF_ENTRY(SNAME) **e1 = CMC_(PFX, _impl_add_entry_to_key)(_new_map_, scan);
struct CMC_DEF_ENTRY(SNAME) **e2 = CMC_(PFX, _impl_add_entry_to_val)(_new_map_, scan);
if (!e1 || !e2)
{
/* Prevent the map from freeing the data */
_new_map_->f_key = &(struct CMC_DEF_FKEY(SNAME)){ 0 };
_new_map_->f_val = &(struct CMC_DEF_FVAL(SNAME)){ 0 };
_map_->alloc->free(_new_map_->buffer);
_map_->alloc->free(_new_map_);
_map_->flag = CMC_FLAG_ERROR;
return false;
}
_new_map_->count++;
}
}
if (_map_->count != _new_map_->count)
{
/* Prevent the map from freeing the data */
_new_map_->f_key = &(struct CMC_DEF_FKEY(SNAME)){ 0 };
_new_map_->f_val = &(struct CMC_DEF_FVAL(SNAME)){ 0 };
_map_->alloc->free(_new_map_->buffer);
_map_->alloc->free(_new_map_);
_map_->flag = CMC_FLAG_ERROR;
return false;
}
struct CMC_DEF_ENTRY(SNAME) * (*tmp_buff)[2] = _map_->buffer;
_map_->buffer = _new_map_->buffer;
_map_->capacity = _new_map_->capacity;
_map_->alloc->free(tmp_buff);
_map_->alloc->free(_new_map_);
success:
CMC_CALLBACKS_CALL(_map_);
return true;
}
struct SNAME *CMC_(PFX, _copy_of)(struct SNAME *_map_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
/* TODO this function can be optimized */
struct SNAME *result = CMC_(PFX, _new_custom)(_map_->capacity * _map_->load, _map_->load, _map_->f_key,
_map_->f_val, _map_->alloc, NULL);
if (!result)
{
_map_->flag = CMC_FLAG_ERROR;
return NULL;
}
CMC_CALLBACKS_ASSIGN(result, _map_->callbacks);
for (size_t i = 0; i < _map_->capacity; i++)
{
struct CMC_DEF_ENTRY(SNAME) *scan = _map_->buffer[i][0];
if (scan && scan != CMC_ENTRY_DELETED)
{
K tmp_key;
V tmp_val;
if (_map_->f_key->cpy)
tmp_key = _map_->f_key->cpy(scan->key);
else
tmp_key = scan->key;
if (_map_->f_val->cpy)
tmp_val = _map_->f_val->cpy(scan->value);
else
tmp_val = scan->value;
/* TODO treat the possible errors */
struct CMC_DEF_ENTRY(SNAME) *entry = CMC_(PFX, _impl_new_entry)(result, tmp_key, tmp_val);
CMC_(PFX, _impl_add_entry_to_key)(result, entry);
CMC_(PFX, _impl_add_entry_to_val)(result, entry);
result->count++;
}
}
_map_->flag = CMC_FLAG_OK;
return result;
}
bool CMC_(PFX, _equals)(struct SNAME *_map1_, struct SNAME *_map2_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
_map1_->flag = CMC_FLAG_OK;
_map2_->flag = CMC_FLAG_OK;
if (_map1_->count != _map2_->count)
return false;
struct SNAME *_mapA_;
struct SNAME *_mapB_;
if (_map1_->capacity < _map2_->capacity)
{
_mapA_ = _map1_;
_mapB_ = _map2_;
}
else
{
_mapA_ = _map2_;
_mapB_ = _map1_;
}
for (size_t i = 0; i < _mapA_->capacity; i++)
{
struct CMC_DEF_ENTRY(SNAME) *scan = _mapA_->buffer[i][0];
if (scan && scan != CMC_ENTRY_DELETED)
{
struct CMC_DEF_ENTRY(SNAME) **entry_B = CMC_(PFX, _impl_get_entry_by_key)(_mapB_, scan->key);
if (!entry_B)
return false;
if (_mapA_->f_val->cmp((*entry_B)->value, scan->value) != 0)
return false;
}
}
return true;
}
static struct CMC_DEF_ENTRY(SNAME) * CMC_(PFX, _impl_new_entry)(struct SNAME *_map_, K key, V value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct CMC_DEF_ENTRY(SNAME) *entry = _map_->alloc->malloc(sizeof(struct CMC_DEF_ENTRY(SNAME)));
if (!entry)
return NULL;
entry->key = key;
entry->value = value;
entry->dist[0] = 0;
entry->dist[1] = 0;
entry->ref[0] = NULL;
entry->ref[1] = NULL;
return entry;
}
static struct CMC_DEF_ENTRY(SNAME) * *CMC_(PFX, _impl_get_entry_by_key)(struct SNAME *_map_, K key)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
size_t hash = _map_->f_key->hash(key);
size_t pos = hash % _map_->capacity;
struct CMC_DEF_ENTRY(SNAME) *target = _map_->buffer[pos][0];
while (target != NULL)
{
if (target != CMC_ENTRY_DELETED && _map_->f_key->cmp(target->key, key) == 0)
return &(_map_->buffer[pos % _map_->capacity][0]);
pos++;
target = _map_->buffer[pos % _map_->capacity][0];
}
return NULL;
}
static struct CMC_DEF_ENTRY(SNAME) * *CMC_(PFX, _impl_get_entry_by_val)(struct SNAME *_map_, V val)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
size_t hash = _map_->f_val->hash(val);
size_t pos = hash % _map_->capacity;
struct CMC_DEF_ENTRY(SNAME) *target = _map_->buffer[pos][1];
while (target != NULL)
{
if (target != CMC_ENTRY_DELETED && _map_->f_val->cmp(target->value, val) == 0)
return &(_map_->buffer[pos % _map_->capacity][1]);
pos++;
target = _map_->buffer[pos % _map_->capacity][1];
}
return NULL;
}
static struct CMC_DEF_ENTRY(SNAME) *
*CMC_(PFX, _impl_add_entry_to_key)(struct SNAME *_map_, struct CMC_DEF_ENTRY(SNAME) * entry)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct CMC_DEF_ENTRY(SNAME) **to_return = NULL;
size_t hash = _map_->f_key->hash(entry->key);
size_t original_pos = hash % _map_->capacity;
size_t pos = original_pos;
struct CMC_DEF_ENTRY(SNAME) **scan = &(_map_->buffer[hash % _map_->capacity][0]);
if (*scan == NULL)
{
*scan = entry;
entry->ref[0] = scan;
return scan;
}
else
{
while (true)
{
pos++;
scan = &(_map_->buffer[pos % _map_->capacity][0]);
if (*scan == NULL || *scan == CMC_ENTRY_DELETED)
{
if (!to_return)
to_return = scan;
*scan = entry;
entry->ref[0] = scan;
entry->dist[0] = pos - original_pos;
return to_return;
}
else if ((*scan)->dist[0] < pos - original_pos)
{
if (!to_return)
to_return = scan;
size_t tmp_dist = (*scan)->dist[0];
entry->dist[0] = pos - original_pos;
original_pos = pos - tmp_dist;
entry->ref[0] = scan;
struct CMC_DEF_ENTRY(SNAME) *_tmp_ = *scan;
*scan = entry;
entry = _tmp_;
}
}
}
return NULL;
}
static struct CMC_DEF_ENTRY(SNAME) *
*CMC_(PFX, _impl_add_entry_to_val)(struct SNAME *_map_, struct CMC_DEF_ENTRY(SNAME) * entry)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct CMC_DEF_ENTRY(SNAME) **to_return = NULL;
size_t hash = _map_->f_val->hash(entry->value);
size_t original_pos = hash % _map_->capacity;
size_t pos = original_pos;
struct CMC_DEF_ENTRY(SNAME) **scan = &(_map_->buffer[hash % _map_->capacity][1]);
if (*scan == NULL)
{
*scan = entry;
entry->ref[1] = scan;
return scan;
}
else
{
while (true)
{
pos++;
scan = &(_map_->buffer[pos % _map_->capacity][1]);
if (*scan == NULL || *scan == CMC_ENTRY_DELETED)
{
if (!to_return)
to_return = scan;
*scan = entry;
entry->ref[1] = scan;
entry->dist[1] = pos - original_pos;
return to_return;
}
else if ((*scan)->dist[1] < pos - original_pos)
{
if (!to_return)
to_return = scan;
size_t tmp_dist = (*scan)->dist[1];
entry->dist[1] = pos - original_pos;
original_pos = pos - tmp_dist;
entry->ref[1] = scan;
struct CMC_DEF_ENTRY(SNAME) *_tmp_ = *scan;
*scan = entry;
entry = _tmp_;
}
}
}
return NULL;
}
static size_t CMC_(PFX, _impl_calculate_size)(size_t required)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
const size_t count = sizeof(cmc_hashtable_primes) / sizeof(cmc_hashtable_primes[0]);
if (cmc_hashtable_primes[count - 1] < required)
return required;
size_t i = 0;
while (cmc_hashtable_primes[i] < required)
i++;
return cmc_hashtable_primes[i];
}
+473
View File
@@ -0,0 +1,473 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* INIT
*
* The part 'INIT' gives a new way of initializing a collection. The collection
* struct is not heap allocated, only its internal structure (nodes, buffers).
*/
#ifdef CMC_EXT_INIT
struct SNAME CMC_(PFX, _init)(size_t capacity, double load, struct CMC_DEF_FKEY(SNAME) * f_key,
struct CMC_DEF_FVAL(SNAME) * f_val)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return CMC_(PFX, _init_custom)(capacity, load, f_key, f_val, NULL, NULL);
}
struct SNAME CMC_(PFX, _init_custom)(size_t capacity, double load, struct CMC_DEF_FKEY(SNAME) * f_key,
struct CMC_DEF_FVAL(SNAME) * f_val, CMC_ALLOC_TYPE alloc,
CMC_CALLBACK_TYPE callbacks)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
struct SNAME _map_ = { 0 };
if (capacity == 0 || load <= 0 || load >= 1)
return _map_;
/* Prevent integer overflow */
if (capacity >= (double)UINTMAX_MAX * load)
return _map_;
if (!f_key || !f_val)
return _map_;
size_t real_capacity = CMC_(PFX, _impl_calculate_size)(capacity / load);
if (!alloc)
alloc = &cmc_alloc_node_default;
_map_.buffer = alloc->calloc(real_capacity, sizeof(struct CMC_DEF_ENTRY(SNAME) *[2]));
if (!_map_.buffer)
return _map_;
_map_.count = 0;
_map_.capacity = real_capacity;
_map_.load = load;
_map_.flag = CMC_FLAG_OK;
_map_.f_key = f_key;
_map_.f_val = f_val;
_map_.flag = CMC_FLAG_OK;
_map_.alloc = alloc;
CMC_CALLBACKS_ASSIGN(&_map_, callbacks);
return _map_;
}
void CMC_(PFX, _release)(struct SNAME _map_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
CMC_(PFX, _clear)(&_map_);
_map_.alloc->free(_map_.buffer);
}
#endif /* CMC_EXT_INIT */
/**
* ITER
*
* Hashbidimap bi-directional iterator.
*/
#ifdef CMC_EXT_ITER
struct CMC_DEF_ITER(SNAME) * CMC_(PFX, _iter_new)(struct SNAME *target)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct CMC_DEF_ITER(SNAME) *iter = target->alloc->malloc(sizeof(struct CMC_DEF_ITER(SNAME)));
if (!iter)
return NULL;
CMC_(PFX, _iter_init)(iter, target);
return iter;
}
void CMC_(PFX, _iter_free)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
iter->target->alloc->free(iter);
}
void CMC_(PFX, _iter_init)(struct CMC_DEF_ITER(SNAME) * iter, struct SNAME *target)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
memset(iter, 0, sizeof(struct CMC_DEF_ITER(SNAME)));
iter->target = target;
iter->start = true;
iter->end = CMC_(PFX, _empty)(target);
if (!CMC_(PFX, _empty)(target))
{
for (size_t i = 0; i < target->capacity; i++)
{
struct CMC_DEF_ENTRY(SNAME) *entry = target->buffer[i][0];
if (entry && entry != CMC_ENTRY_DELETED)
{
iter->first = i;
break;
}
}
iter->cursor = iter->first;
for (size_t i = target->capacity; i > 0; i--)
{
struct CMC_DEF_ENTRY(SNAME) *entry = target->buffer[i - 1][0];
if (entry && entry != CMC_ENTRY_DELETED)
{
iter->last = i - 1;
break;
}
}
}
}
bool CMC_(PFX, _iter_start)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return CMC_(PFX, _empty)(iter->target) || iter->start;
}
bool CMC_(PFX, _iter_end)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return CMC_(PFX, _empty)(iter->target) || iter->end;
}
void CMC_(PFX, _iter_to_start)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (!CMC_(PFX, _empty)(iter->target))
{
iter->cursor = iter->first;
iter->index = 0;
iter->start = true;
iter->end = false;
}
}
void CMC_(PFX, _iter_to_end)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (!CMC_(PFX, _empty)(iter->target))
{
iter->cursor = iter->last;
iter->index = iter->target->count - 1;
iter->start = false;
iter->end = true;
}
}
bool CMC_(PFX, _iter_next)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (iter->end)
return false;
if (iter->index + 1 == iter->target->count)
{
iter->end = true;
return false;
}
iter->start = CMC_(PFX, _empty)(iter->target);
struct CMC_DEF_ENTRY(SNAME) *scan = iter->target->buffer[iter->cursor][0];
iter->index++;
while (1)
{
iter->cursor++;
scan = iter->target->buffer[iter->cursor][0];
if (scan != NULL && scan != CMC_ENTRY_DELETED)
break;
}
return true;
}
bool CMC_(PFX, _iter_prev)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (iter->start)
return false;
if (iter->index == 0)
{
iter->start = true;
return false;
}
iter->end = CMC_(PFX, _empty)(iter->target);
struct CMC_DEF_ENTRY(SNAME) *scan = iter->target->buffer[iter->cursor][0];
iter->index--;
while (1)
{
iter->cursor--;
scan = iter->target->buffer[iter->cursor][0];
if (scan != NULL && scan != CMC_ENTRY_DELETED)
break;
}
return true;
}
/* Returns true only if the iterator moved */
bool CMC_(PFX, _iter_advance)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (iter->end)
return false;
if (iter->index + 1 == iter->target->count)
{
iter->end = true;
return false;
}
if (steps == 0 || iter->index + steps >= iter->target->count)
return false;
for (size_t i = 0; i < steps; i++)
CMC_(PFX, _iter_next)(iter);
return true;
}
/* Returns true only if the iterator moved */
bool CMC_(PFX, _iter_rewind)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (iter->start)
return false;
if (iter->index == 0)
{
iter->start = true;
return false;
}
if (steps == 0 || iter->index < steps)
return false;
for (size_t i = 0; i < steps; i++)
CMC_(PFX, _iter_prev)(iter);
return true;
}
/* Returns true only if the iterator was able to be positioned at */
/* the given index */
bool CMC_(PFX, _iter_go_to)(struct CMC_DEF_ITER(SNAME) * iter, size_t index)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (index >= iter->target->count)
return false;
if (iter->index > index)
return CMC_(PFX, _iter_rewind)(iter, iter->index - index);
else if (iter->index < index)
return CMC_(PFX, _iter_advance)(iter, index - iter->index);
return true;
}
K CMC_(PFX, _iter_key)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(iter->target))
{
iter->target->flag = CMC_FLAG_EMPTY;
return (K){ 0 };
}
return iter->target->buffer[iter->cursor][0]->key;
}
V CMC_(PFX, _iter_value)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(iter->target))
{
iter->target->flag = CMC_FLAG_EMPTY;
return (V){ 0 };
}
return iter->target->buffer[iter->cursor][0]->value;
}
size_t CMC_(PFX, _iter_index)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return iter->index;
}
#endif /* CMC_EXT_ITER */
/**
* STR
*
* Print helper functions.
*/
#ifdef CMC_EXT_STR
bool CMC_(PFX, _to_string)(struct SNAME *_map_, FILE *fptr)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct SNAME *m_ = _map_;
return 0 <= fprintf(fptr,
"struct %s<%s, %s> "
"at %p { "
"buffer:%p, "
"capacity:%" PRIuMAX ", "
"count:%" PRIuMAX ", "
"load:%lf, "
"flag:%d, "
"f_key:%p, "
"f_val:%p, "
"alloc:%p, "
"callbacks:%p }",
CMC_TO_STRING(SNAME), CMC_TO_STRING(K), CMC_TO_STRING(V), m_, m_->buffer, m_->capacity,
m_->count, m_->load, m_->flag, m_->f_key, m_->f_val, m_->alloc, CMC_CALLBACKS_GET(m_));
}
bool CMC_(PFX, _print)(struct SNAME *_map_, FILE *fptr, const char *start, const char *separator, const char *end,
const char *key_val_sep)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
fprintf(fptr, "%s", start);
size_t last = 0;
for (size_t i = _map_->capacity; i > 0; i--)
{
struct CMC_DEF_ENTRY(SNAME) *entry = _map_->buffer[i - 1][0];
if (entry && entry != CMC_ENTRY_DELETED)
{
last = i - 1;
break;
}
}
for (size_t i = 0; i < _map_->capacity; i++)
{
struct CMC_DEF_ENTRY(SNAME) *entry = _map_->buffer[i][0];
if (entry && entry != CMC_ENTRY_DELETED)
{
if (!_map_->f_key->str(fptr, entry->key))
return false;
fprintf(fptr, "%s", key_val_sep);
if (!_map_->f_val->str(fptr, entry->value))
return false;
if (i + 1 < last)
fprintf(fptr, "%s", separator);
}
}
fprintf(fptr, "%s", end);
return true;
}
#endif /* CMC_EXT_STR */
+86
View File
@@ -0,0 +1,86 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* INIT
*
* The part 'INIT' gives a new way of initializing a collection. The collection
* struct is not heap allocated, only its internal structure (nodes, buffers).
*/
#ifdef CMC_EXT_INIT
struct SNAME CMC_(PFX, _init)(size_t capacity, double load, struct CMC_DEF_FKEY(SNAME) * f_key,
struct CMC_DEF_FVAL(SNAME) * f_val);
struct SNAME CMC_(PFX, _init_custom)(size_t capacity, double load, struct CMC_DEF_FKEY(SNAME) * f_key,
struct CMC_DEF_FVAL(SNAME) * f_val, CMC_ALLOC_TYPE alloc,
CMC_CALLBACK_TYPE callbacks);
void CMC_(PFX, _release)(struct SNAME _map_);
#endif /* CMC_EXT_INIT */
/**
* ITER
*
* Hashbidimap bi-directional iterator.
*/
#ifdef CMC_EXT_ITER
/* Iterator Functions */
/* Iterator Allocation and Deallocation */
struct CMC_DEF_ITER(SNAME) * CMC_(PFX, _iter_new)(struct SNAME *target);
void CMC_(PFX, _iter_free)(struct CMC_DEF_ITER(SNAME) * iter);
/* Iterator Initialization */
void CMC_(PFX, _iter_init)(struct CMC_DEF_ITER(SNAME) * iter, struct SNAME *target);
/* Iterator State */
bool CMC_(PFX, _iter_start)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_end)(struct CMC_DEF_ITER(SNAME) * iter);
/* Iterator Movement */
void CMC_(PFX, _iter_to_start)(struct CMC_DEF_ITER(SNAME) * iter);
void CMC_(PFX, _iter_to_end)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_next)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_prev)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_advance)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps);
bool CMC_(PFX, _iter_rewind)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps);
bool CMC_(PFX, _iter_go_to)(struct CMC_DEF_ITER(SNAME) * iter, size_t index);
/* Iterator Access */
K CMC_(PFX, _iter_key)(struct CMC_DEF_ITER(SNAME) * iter);
V CMC_(PFX, _iter_value)(struct CMC_DEF_ITER(SNAME) * iter);
size_t CMC_(PFX, _iter_index)(struct CMC_DEF_ITER(SNAME) * iter);
#endif /* CMC_EXT_ITER */
/**
* STR
*
* Print helper functions.
*/
#ifdef CMC_EXT_STR
/* Debug prints the struct to fptr */
bool CMC_(PFX, _to_string)(struct SNAME *_map_, FILE *fptr);
/* Prints each item in the hashbidimap as an array */
bool CMC_(PFX, _print)(struct SNAME *_map_, FILE *fptr, const char *start, const char *separator, const char *end,
const char *key_val_sep);
#endif /* CMC_EXT_STR */
+51
View File
@@ -0,0 +1,51 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* ITER
*
* Hashbidimap bi-directional iterator.
*/
#ifdef CMC_EXT_ITER
/* HashBidiMap Iterator */
struct CMC_DEF_ITER(SNAME)
{
/* Target hashbidimap */
struct SNAME *target;
/* Cursor's position (index) */
size_t cursor;
/* Keeps track of relative index to the iteration of elements */
size_t index;
/* The index of the first element */
size_t first;
/* The index of the last element */
size_t last;
/* If the iterator has reached the start of the iteration */
bool start;
/* If the iterator has reached the end of the iteration */
bool end;
};
#endif /* CMC_EXT_ITER */
+90
View File
@@ -0,0 +1,90 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/* Key struct function table */
struct CMC_DEF_FKEY(SNAME)
{
/* Comparator function */
CMC_DEF_FTAB_CMP(K);
/* Copy function */
CMC_DEF_FTAB_CPY(K);
/* To string function */
CMC_DEF_FTAB_STR(K);
/* Free from memory function */
CMC_DEF_FTAB_FREE(K);
/* Hash function */
CMC_DEF_FTAB_HASH(K);
/* Priority function */
CMC_DEF_FTAB_PRI(K);
};
/* Value struct function table */
struct CMC_DEF_FVAL(SNAME)
{
/* Comparator function */
CMC_DEF_FTAB_CMP(V);
/* Copy function */
CMC_DEF_FTAB_CPY(V);
/* To string function */
CMC_DEF_FTAB_STR(V);
/* Free from memory function */
CMC_DEF_FTAB_FREE(V);
/* Hash function */
CMC_DEF_FTAB_HASH(V);
/* Priority function */
CMC_DEF_FTAB_PRI(V);
};
/* Collection Allocation and Deallocation */
struct SNAME *CMC_(PFX, _new)(size_t capacity, double load, struct CMC_DEF_FKEY(SNAME) * f_key,
struct CMC_DEF_FVAL(SNAME) * f_val);
struct SNAME *CMC_(PFX, _new_custom)(size_t capacity, double load, struct CMC_DEF_FKEY(SNAME) * f_key,
struct CMC_DEF_FVAL(SNAME) * f_val, CMC_ALLOC_TYPE alloc,
CMC_CALLBACK_TYPE callbacks);
void CMC_(PFX, _clear)(struct SNAME *_map_);
void CMC_(PFX, _free)(struct SNAME *_map_);
/* Customization of Allocation and Callbacks */
void CMC_(PFX, _customize)(struct SNAME *_map_, CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks);
/* Collection Input and Output */
bool CMC_(PFX, _insert)(struct SNAME *_map_, K key, V value);
bool CMC_(PFX, _update_key)(struct SNAME *_map_, V val, K new_key);
bool CMC_(PFX, _update_val)(struct SNAME *_map_, K key, V new_val);
bool CMC_(PFX, _remove_by_key)(struct SNAME *_map_, K key, K *out_key, V *out_val);
bool CMC_(PFX, _remove_by_val)(struct SNAME *_map_, V val, K *out_key, V *out_val);
/* Element Access */
K CMC_(PFX, _get_key)(struct SNAME *_map_, V val);
V CMC_(PFX, _get_val)(struct SNAME *_map_, K key);
/* Collection State */
bool CMC_(PFX, _contains_key)(struct SNAME *_map_, K key);
bool CMC_(PFX, _contains_val)(struct SNAME *_map_, V val);
bool CMC_(PFX, _empty)(struct SNAME *_map_);
bool CMC_(PFX, _full)(struct SNAME *_map_);
size_t CMC_(PFX, _count)(struct SNAME *_map_);
size_t CMC_(PFX, _capacity)(struct SNAME *_map_);
double CMC_(PFX, _load)(struct SNAME *_map_);
int CMC_(PFX, _flag)(struct SNAME *_map_);
/* Collection Utility */
bool CMC_(PFX, _resize)(struct SNAME *_map_, size_t capacity);
struct SNAME *CMC_(PFX, _copy_of)(struct SNAME *_map_);
bool CMC_(PFX, _equals)(struct SNAME *_map1_, struct SNAME *_map2_);
+69
View File
@@ -0,0 +1,69 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
struct SNAME
{
/* Array 0 is K -> V and array 1 is V -> K */
struct CMC_DEF_ENTRY(SNAME) * (*buffer)[2];
/* Current arrays capacity */
size_t capacity;
/* Current amount of keys */
size_t count;
/* Load factor in range (0.0, 1.0) */
double load;
/* Flags indicating errors or success */
int flag;
/* Key function table */
struct CMC_DEF_FKEY(SNAME) * f_key;
/* Value function table */
struct CMC_DEF_FVAL(SNAME) * f_val;
/* Custom allocation functions */
CMC_ALLOC_TYPE alloc;
/* Custom callback functions */
CMC_CALLBACKS_DECL;
/* Methods */
/* Returns an iterator to the start of the hashbidimap */
struct CMC_DEF_ITER(SNAME) (*it_start)(struct SNAME *);
/* Returns an iterator to the end of the hashbidimap */
struct CMC_DEF_ITER(SNAME) (*it_end)(struct SNAME *);
};
/* HashBidiMap Entry */
struct CMC_DEF_ENTRY(SNAME)
{
/* Entry Key */
K key;
/* Entry Value */
V value;
/* The distance of this node to its original position */
/* dist[0] is relative to K -> V */
/* dist[1] is relative to V -> K */
size_t dist[2];
/* References to this node in the hashbidimap buffer. Used to */
/* prevent searching for this node twice for update() and */
/* remove(). Increases memory overhead but reduces execution time */
/* ref[0] is relative to K -> V */
/* ref[1] is relative to V -> K */
struct CMC_DEF_ENTRY(SNAME) * *ref[2];
};
+82
View File
@@ -0,0 +1,82 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* hashmap.h
*
* Creation Date: 03/04/2019
*
* Authors:
* Leonardo Vencovsky (https://github.com/LeoVen)
*
*/
/**
* HashMap
*
* A HashMap is an implementation of a Map with unique keys, where every key is
* mapped to a value. The keys are not sorted. It is implemented as a flat
* hashtable with linear probing and robin hood hashing.
*/
#include "cor/core.h"
#include "cor/hashtable.h"
#ifdef CMC_DEV
#include "utl/log.h"
#endif
/**
* Used values
* K - hashmap key data type
* V - hashmap value data type
* SNAME - struct name and prefix of other related structs
* PFX - functions prefix
*/
/* Structs definition */
#include "cmc/hashmap/struct.h"
/* Function declaration */
#include "cmc/hashmap/header.h"
/* Function implementation */
#include "cmc/hashmap/code.h"
/**
* Extensions
*
* INIT - Initializes the struct on the stack
* ITER - hashmap iterator
* STR - Print helper functions
*/
#define CMC_EXT_HASHMAP_PARTS INIT, ITER, STR
/**/
#include "cmc/hashmap/ext/struct.h"
/**/
#include "cmc/hashmap/ext/header.h"
/**/
#include "cmc/hashmap/ext/code.h"
#include "cor/undef.h"
+728
View File
@@ -0,0 +1,728 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/* Implementation Detail Functions */
static struct CMC_DEF_ENTRY(SNAME) * CMC_(PFX, _impl_get_entry)(struct SNAME *_map_, K key);
static size_t CMC_(PFX, _impl_calculate_size)(size_t required);
struct SNAME *CMC_(PFX, _new)(size_t capacity, double load, struct CMC_DEF_FKEY(SNAME) * f_key,
struct CMC_DEF_FVAL(SNAME) * f_val)
{
return CMC_(PFX, _new_custom)(capacity, load, f_key, f_val, NULL, NULL);
}
struct SNAME *CMC_(PFX, _new_custom)(size_t capacity, double load, struct CMC_DEF_FKEY(SNAME) * f_key,
struct CMC_DEF_FVAL(SNAME) * f_val, CMC_ALLOC_TYPE alloc,
CMC_CALLBACK_TYPE callbacks)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
if (capacity == 0 || load <= 0 || load >= 1)
return NULL;
/* Prevent integer overflow */
if (capacity >= (double)UINTMAX_MAX * load)
return NULL;
if (!f_key || !f_val)
return NULL;
size_t real_capacity = CMC_(PFX, _impl_calculate_size)(capacity / load);
if (!alloc)
alloc = &cmc_alloc_node_default;
struct SNAME *_map_ = alloc->malloc(sizeof(struct SNAME));
if (!_map_)
return NULL;
_map_->buffer = alloc->calloc(real_capacity, sizeof(struct CMC_DEF_ENTRY(SNAME)));
if (!_map_->buffer)
{
alloc->free(_map_);
return NULL;
}
_map_->count = 0;
_map_->capacity = real_capacity;
_map_->load = load;
_map_->flag = CMC_FLAG_OK;
_map_->f_key = f_key;
_map_->f_val = f_val;
_map_->alloc = alloc;
CMC_CALLBACKS_ASSIGN(_map_, callbacks);
return _map_;
}
void CMC_(PFX, _clear)(struct SNAME *_map_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (_map_->f_key->free || _map_->f_val->free)
{
for (size_t i = 0; i < _map_->capacity; i++)
{
struct CMC_DEF_ENTRY(SNAME) *entry = &(_map_->buffer[i]);
if (entry->state == CMC_ES_FILLED)
{
if (_map_->f_key->free)
_map_->f_key->free(entry->key);
if (_map_->f_val->free)
_map_->f_val->free(entry->value);
}
}
}
memset(_map_->buffer, 0, sizeof(struct CMC_DEF_ENTRY(SNAME)) * _map_->capacity);
_map_->count = 0;
_map_->flag = CMC_FLAG_OK;
}
void CMC_(PFX, _free)(struct SNAME *_map_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (_map_->f_key->free || _map_->f_val->free)
{
for (size_t i = 0; i < _map_->capacity; i++)
{
struct CMC_DEF_ENTRY(SNAME) *entry = &(_map_->buffer[i]);
if (entry->state == CMC_ES_FILLED)
{
if (_map_->f_key->free)
_map_->f_key->free(entry->key);
if (_map_->f_val->free)
_map_->f_val->free(entry->value);
}
}
}
_map_->alloc->free(_map_->buffer);
_map_->alloc->free(_map_);
}
void CMC_(PFX, _customize)(struct SNAME *_map_, CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
if (!alloc)
_map_->alloc = &cmc_alloc_node_default;
else
_map_->alloc = alloc;
CMC_CALLBACKS_ASSIGN(_map_, callbacks);
_map_->flag = CMC_FLAG_OK;
}
bool CMC_(PFX, _insert)(struct SNAME *_map_, K key, V value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _full)(_map_))
{
if (!CMC_(PFX, _resize)(_map_, _map_->capacity + 1))
return false;
}
if (CMC_(PFX, _impl_get_entry)(_map_, key) != NULL)
{
_map_->flag = CMC_FLAG_DUPLICATE;
return false;
}
size_t hash = _map_->f_key->hash(key);
size_t original_pos = hash % _map_->capacity;
size_t pos = original_pos;
struct CMC_DEF_ENTRY(SNAME) *target = &(_map_->buffer[pos]);
if (target->state == CMC_ES_EMPTY || target->state == CMC_ES_DELETED)
{
target->key = key;
target->value = value;
target->dist = 0;
target->state = CMC_ES_FILLED;
}
else
{
while (true)
{
pos++;
target = &(_map_->buffer[pos % _map_->capacity]);
if (target->state == CMC_ES_EMPTY || target->state == CMC_ES_DELETED)
{
target->key = key;
target->value = value;
target->dist = pos - original_pos;
target->state = CMC_ES_FILLED;
break;
}
else if (target->dist < pos - original_pos)
{
K tmp_k = target->key;
V tmp_v = target->value;
size_t tmp_dist = target->dist;
target->key = key;
target->value = value;
target->dist = pos - original_pos;
key = tmp_k;
value = tmp_v;
original_pos = pos - tmp_dist;
}
}
}
_map_->count++;
_map_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_map_);
return true;
}
bool CMC_(PFX, _update)(struct SNAME *_map_, K key, V new_value, V *old_value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_map_))
{
_map_->flag = CMC_FLAG_EMPTY;
return false;
}
struct CMC_DEF_ENTRY(SNAME) *entry = CMC_(PFX, _impl_get_entry)(_map_, key);
if (!entry)
{
_map_->flag = CMC_FLAG_NOT_FOUND;
return false;
}
if (old_value)
*old_value = entry->value;
entry->value = new_value;
_map_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_map_);
return true;
}
bool CMC_(PFX, _remove)(struct SNAME *_map_, K key, V *out_value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_map_))
{
_map_->flag = CMC_FLAG_EMPTY;
return false;
}
struct CMC_DEF_ENTRY(SNAME) *result = CMC_(PFX, _impl_get_entry)(_map_, key);
if (result == NULL)
{
_map_->flag = CMC_FLAG_NOT_FOUND;
return false;
}
if (out_value)
*out_value = result->value;
result->key = (K){ 0 };
result->value = (V){ 0 };
result->dist = 0;
result->state = CMC_ES_DELETED;
_map_->count--;
_map_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_map_);
return true;
}
bool CMC_(PFX, _max)(struct SNAME *_map_, K *key, V *value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_map_))
{
_map_->flag = CMC_FLAG_EMPTY;
return false;
}
bool first = true;
K max_key = (K){ 0 };
V max_val = (V){ 0 };
for (size_t i = 0; i < _map_->capacity; i++)
{
if (_map_->buffer[i].state == CMC_ES_FILLED)
{
if (first)
{
max_key = _map_->buffer[i].key;
max_val = _map_->buffer[i].value;
first = false;
}
else if (_map_->f_key->cmp(_map_->buffer[i].key, max_key) > 0)
{
max_key = _map_->buffer[i].key;
max_val = _map_->buffer[i].value;
}
}
}
if (key)
*key = max_key;
if (value)
*value = max_val;
_map_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_map_);
return true;
}
bool CMC_(PFX, _min)(struct SNAME *_map_, K *key, V *value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_map_))
{
_map_->flag = CMC_FLAG_EMPTY;
return false;
}
bool first = true;
K min_key = (K){ 0 };
V min_val = (V){ 0 };
for (size_t i = 0; i < _map_->capacity; i++)
{
if (_map_->buffer[i].state == CMC_ES_FILLED)
{
if (first)
{
min_key = _map_->buffer[i].key;
min_val = _map_->buffer[i].value;
first = false;
}
else if (_map_->f_key->cmp(_map_->buffer[i].key, min_key) < 0)
{
min_key = _map_->buffer[i].key;
min_val = _map_->buffer[i].value;
}
}
}
if (key)
*key = min_key;
if (value)
*value = min_val;
_map_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_map_);
return true;
}
V CMC_(PFX, _get)(struct SNAME *_map_, K key)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_map_))
{
_map_->flag = CMC_FLAG_EMPTY;
return (V){ 0 };
}
struct CMC_DEF_ENTRY(SNAME) *entry = CMC_(PFX, _impl_get_entry)(_map_, key);
if (!entry)
{
_map_->flag = CMC_FLAG_NOT_FOUND;
return (V){ 0 };
}
_map_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_map_);
return entry->value;
}
V *CMC_(PFX, _get_ref)(struct SNAME *_map_, K key)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_map_))
{
_map_->flag = CMC_FLAG_EMPTY;
return NULL;
}
struct CMC_DEF_ENTRY(SNAME) *entry = CMC_(PFX, _impl_get_entry)(_map_, key);
if (!entry)
{
_map_->flag = CMC_FLAG_NOT_FOUND;
return NULL;
}
_map_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_map_);
return &(entry->value);
}
bool CMC_(PFX, _contains)(struct SNAME *_map_, K key)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
_map_->flag = CMC_FLAG_OK;
bool result = CMC_(PFX, _impl_get_entry)(_map_, key) != NULL;
CMC_CALLBACKS_CALL(_map_);
return result;
}
bool CMC_(PFX, _empty)(struct SNAME *_map_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _map_->count == 0;
}
bool CMC_(PFX, _full)(struct SNAME *_map_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return (double)_map_->capacity * _map_->load <= (double)_map_->count;
}
size_t CMC_(PFX, _count)(struct SNAME *_map_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _map_->count;
}
size_t CMC_(PFX, _capacity)(struct SNAME *_map_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _map_->capacity;
}
double CMC_(PFX, _load)(struct SNAME *_map_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _map_->load;
}
int CMC_(PFX, _flag)(struct SNAME *_map_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _map_->flag;
}
bool CMC_(PFX, _resize)(struct SNAME *_map_, size_t capacity)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
_map_->flag = CMC_FLAG_OK;
if (_map_->capacity == capacity)
goto success;
if (_map_->capacity > capacity / _map_->load)
goto success;
/* Prevent integer overflow */
if (capacity >= (double)UINTMAX_MAX * _map_->load)
{
_map_->flag = CMC_FLAG_ERROR;
return false;
}
/* Calculate required capacity based on the prime numbers */
size_t theoretical_size = CMC_(PFX, _impl_calculate_size)(capacity);
/* Not possible to shrink with current available prime numbers */
if (theoretical_size < _map_->count / _map_->load)
{
_map_->flag = CMC_FLAG_INVALID;
return false;
}
/* No callbacks since _new_map_ is just a temporary hashtable */
struct SNAME *_new_map_ =
CMC_(PFX, _new_custom)(capacity, _map_->load, _map_->f_key, _map_->f_val, _map_->alloc, NULL);
if (!_new_map_)
{
_map_->flag = CMC_FLAG_ALLOC;
return false;
}
for (size_t i = 0; i < _map_->capacity; i++)
{
if (_map_->buffer[i].state == CMC_ES_FILLED)
{
K key = _map_->buffer[i].key;
V value = _map_->buffer[i].value;
/* TODO check this for possible errors */
CMC_(PFX, _insert)(_new_map_, key, value);
}
}
/* Unlikely */
if (_map_->count != _new_map_->count)
{
CMC_(PFX, _free)(_new_map_);
_map_->flag = CMC_FLAG_ERROR;
return false;
}
struct CMC_DEF_ENTRY(SNAME) *tmp_b = _map_->buffer;
_map_->buffer = _new_map_->buffer;
_new_map_->buffer = tmp_b;
size_t tmp_c = _map_->capacity;
_map_->capacity = _new_map_->capacity;
_new_map_->capacity = tmp_c;
/* Prevent the map from freeing the data */
_new_map_->f_key = &(struct CMC_DEF_FKEY(SNAME)){ 0 };
_new_map_->f_val = &(struct CMC_DEF_FVAL(SNAME)){ 0 };
CMC_(PFX, _free)(_new_map_);
success:
CMC_CALLBACKS_CALL(_map_);
return true;
}
struct SNAME *CMC_(PFX, _copy_of)(struct SNAME *_map_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct SNAME *result = CMC_(PFX, _new_custom)(_map_->capacity * _map_->load, _map_->load, _map_->f_key,
_map_->f_val, _map_->alloc, NULL);
if (!result)
{
_map_->flag = CMC_FLAG_ERROR;
return NULL;
}
CMC_CALLBACKS_ASSIGN(result, _map_->callbacks);
if (_map_->f_key->cpy || _map_->f_val->cpy)
{
for (size_t i = 0; i < _map_->capacity; i++)
{
struct CMC_DEF_ENTRY(SNAME) *scan = &(_map_->buffer[i]);
if (scan->state != CMC_ES_EMPTY)
{
struct CMC_DEF_ENTRY(SNAME) *target = &(result->buffer[i]);
if (scan->state == CMC_ES_DELETED)
target->state = CMC_ES_DELETED;
else
{
target->state = scan->state;
target->dist = scan->dist;
if (_map_->f_key->cpy)
target->key = _map_->f_key->cpy(scan->key);
else
target->key = scan->key;
if (_map_->f_val->cpy)
target->value = _map_->f_val->cpy(scan->value);
else
target->value = scan->value;
}
}
}
}
else
memcpy(result->buffer, _map_->buffer, sizeof(struct CMC_DEF_ENTRY(SNAME)) * _map_->capacity);
result->count = _map_->count;
_map_->flag = CMC_FLAG_OK;
return result;
}
bool CMC_(PFX, _equals)(struct SNAME *_map1_, struct SNAME *_map2_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
_map1_->flag = CMC_FLAG_OK;
_map2_->flag = CMC_FLAG_OK;
if (_map1_->count != _map2_->count)
return false;
/* Optimize loop using the smallest hashtable */
struct SNAME *_map_a_;
struct SNAME *_map_b_;
_map_a_ = _map1_->capacity < _map2_->capacity ? _map1_ : _map2_;
_map_b_ = _map_a_ == _map1_ ? _map2_ : _map1_;
for (size_t i = 0; i < _map_a_->capacity; i++)
{
if (_map_a_->buffer[i].state == CMC_ES_FILLED)
{
struct CMC_DEF_ENTRY(SNAME) *entry_a = &(_map_a_->buffer[i]);
struct CMC_DEF_ENTRY(SNAME) *entry_b = CMC_(PFX, _impl_get_entry)(_map_b_, entry_a->key);
if (!entry_b)
return false;
if (_map_a_->f_val->cmp(entry_a->value, entry_b->value) != 0)
return false;
}
}
return true;
}
static struct CMC_DEF_ENTRY(SNAME) * CMC_(PFX, _impl_get_entry)(struct SNAME *_map_, K key)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
size_t hash = _map_->f_key->hash(key);
size_t pos = hash % _map_->capacity;
struct CMC_DEF_ENTRY(SNAME) *target = &(_map_->buffer[pos]);
while (target->state == CMC_ES_FILLED || target->state == CMC_ES_DELETED)
{
if (target->state != CMC_ES_DELETED && _map_->f_key->cmp(target->key, key) == 0)
return target;
pos++;
target = &(_map_->buffer[pos % _map_->capacity]);
}
return NULL;
}
static size_t CMC_(PFX, _impl_calculate_size)(size_t required)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
const size_t count = sizeof(cmc_hashtable_primes) / sizeof(cmc_hashtable_primes[0]);
if (cmc_hashtable_primes[count - 1] < required)
return required;
size_t i = 0;
while (cmc_hashtable_primes[i] < required)
i++;
return cmc_hashtable_primes[i];
}
+514
View File
@@ -0,0 +1,514 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* INIT
*
* The part 'INIT' gives a new way of initializing a collection. The collection
* struct is not heap allocated, only its internal structure (nodes, buffers).
*/
#ifdef CMC_EXT_INIT
struct SNAME CMC_(PFX, _init)(size_t capacity, double load, struct CMC_DEF_FKEY(SNAME) * f_key,
struct CMC_DEF_FVAL(SNAME) * f_val)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return CMC_(PFX, _init_custom)(capacity, load, f_key, f_val, NULL, NULL);
}
struct SNAME CMC_(PFX, _init_custom)(size_t capacity, double load, struct CMC_DEF_FKEY(SNAME) * f_key,
struct CMC_DEF_FVAL(SNAME) * f_val, CMC_ALLOC_TYPE alloc,
CMC_CALLBACK_TYPE callbacks)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
struct SNAME _map_ = { 0 };
if (capacity == 0 || load <= 0 || load >= 1)
return _map_;
/* Prevent integer overflow */
if (capacity >= (double)UINTMAX_MAX * load)
return _map_;
if (!f_key || !f_val)
return _map_;
size_t real_capacity = CMC_(PFX, _impl_calculate_size)(capacity / load);
if (!alloc)
alloc = &cmc_alloc_node_default;
_map_.buffer = alloc->calloc(real_capacity, sizeof(struct CMC_DEF_ENTRY(SNAME)));
if (!_map_.buffer)
return _map_;
_map_.count = 0;
_map_.capacity = real_capacity;
_map_.load = load;
_map_.flag = CMC_FLAG_OK;
_map_.f_key = f_key;
_map_.f_val = f_val;
_map_.alloc = alloc;
CMC_CALLBACKS_ASSIGN(&_map_, callbacks);
return _map_;
}
void CMC_(PFX, _release)(struct SNAME _map_)
{
if (_map_.f_key->free || _map_.f_val->free)
{
for (size_t i = 0; i < _map_.capacity; i++)
{
struct CMC_DEF_ENTRY(SNAME) *entry = &(_map_.buffer[i]);
if (entry->state == CMC_ES_FILLED)
{
if (_map_.f_key->free)
_map_.f_key->free(entry->key);
if (_map_.f_val->free)
_map_.f_val->free(entry->value);
}
}
}
_map_.alloc->free(_map_.buffer);
}
#endif /* CMC_EXT_INIT */
/**
* ITER
*
* Hashmap bi-directional iterator.
*/
#ifdef CMC_EXT_ITER
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_start)(struct SNAME *target)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct CMC_DEF_ITER(SNAME) iter;
iter.target = target;
iter.cursor = 0;
iter.index = 0;
iter.first = 0;
iter.last = 0;
iter.start = true;
iter.end = CMC_(PFX, _empty)(target);
if (!CMC_(PFX, _empty)(target))
{
for (size_t i = 0; i < target->capacity; i++)
{
if (target->buffer[i].state == CMC_ES_FILLED)
{
iter.first = i;
break;
}
}
iter.cursor = iter.first;
for (size_t i = target->capacity; i > 0; i--)
{
if (target->buffer[i - 1].state == CMC_ES_FILLED)
{
iter.last = i - 1;
break;
}
}
}
return iter;
}
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_end)(struct SNAME *target)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct CMC_DEF_ITER(SNAME) iter;
iter.target = target;
iter.cursor = 0;
iter.index = 0;
iter.first = 0;
iter.last = 0;
iter.start = CMC_(PFX, _empty)(target);
iter.end = true;
if (!CMC_(PFX, _empty)(target))
{
for (size_t i = 0; i < target->capacity; i++)
{
if (target->buffer[i].state == CMC_ES_FILLED)
{
iter.first = i;
break;
}
}
for (size_t i = target->capacity; i > 0; i--)
{
if (target->buffer[i - 1].state == CMC_ES_FILLED)
{
iter.last = i - 1;
break;
}
}
iter.cursor = iter.last;
iter.index = target->count - 1;
}
return iter;
}
bool CMC_(PFX, _iter_at_start)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return CMC_(PFX, _empty)(iter->target) || iter->start;
}
bool CMC_(PFX, _iter_at_end)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return CMC_(PFX, _empty)(iter->target) || iter->end;
}
bool CMC_(PFX, _iter_to_start)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (!CMC_(PFX, _empty)(iter->target))
{
iter->cursor = iter->first;
iter->index = 0;
iter->start = true;
iter->end = CMC_(PFX, _empty)(iter->target);
return true;
}
return false;
}
bool CMC_(PFX, _iter_to_end)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (!CMC_(PFX, _empty)(iter->target))
{
iter->cursor = iter->last;
iter->index = iter->target->count - 1;
iter->start = CMC_(PFX, _empty)(iter->target);
iter->end = true;
return true;
}
return false;
}
bool CMC_(PFX, _iter_next)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (iter->end)
return false;
if (iter->index + 1 == iter->target->count)
{
iter->end = true;
return false;
}
iter->start = CMC_(PFX, _empty)(iter->target);
struct CMC_DEF_ENTRY(SNAME) *scan = &(iter->target->buffer[iter->cursor]);
iter->index++;
while (1)
{
iter->cursor++;
scan = &(iter->target->buffer[iter->cursor]);
if (scan->state == CMC_ES_FILLED)
break;
}
return true;
}
bool CMC_(PFX, _iter_prev)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (iter->start)
return false;
if (iter->index == 0)
{
iter->start = true;
return false;
}
iter->end = CMC_(PFX, _empty)(iter->target);
struct CMC_DEF_ENTRY(SNAME) *scan = &(iter->target->buffer[iter->cursor]);
iter->index--;
while (1)
{
iter->cursor--;
scan = &(iter->target->buffer[iter->cursor]);
if (scan->state == CMC_ES_FILLED)
break;
}
return true;
}
/* Returns true only if the iterator moved */
bool CMC_(PFX, _iter_advance)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (iter->end)
return false;
if (iter->index + 1 == iter->target->count)
{
iter->end = true;
return false;
}
if (steps == 0 || iter->index + steps >= iter->target->count)
return false;
for (size_t i = 0; i < steps; i++)
CMC_(PFX, _iter_next)(iter);
return true;
}
/* Returns true only if the iterator moved */
bool CMC_(PFX, _iter_rewind)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (iter->start)
return false;
if (iter->index == 0)
{
iter->start = true;
return false;
}
if (steps == 0 || iter->index < steps)
return false;
for (size_t i = 0; i < steps; i++)
CMC_(PFX, _iter_prev)(iter);
return true;
}
/* Returns true only if the iterator was able to be positioned at the */
/* given index */
bool CMC_(PFX, _iter_go_to)(struct CMC_DEF_ITER(SNAME) * iter, size_t index)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (index >= iter->target->count)
return false;
if (iter->index > index)
return CMC_(PFX, _iter_rewind)(iter, iter->index - index);
else if (iter->index < index)
return CMC_(PFX, _iter_advance)(iter, index - iter->index);
return true;
}
K CMC_(PFX, _iter_key)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(iter->target))
return (K){ 0 };
return iter->target->buffer[iter->cursor].key;
}
V CMC_(PFX, _iter_value)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(iter->target))
return (V){ 0 };
return iter->target->buffer[iter->cursor].value;
}
V *CMC_(PFX, _iter_rvalue)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(iter->target))
return NULL;
return &(iter->target->buffer[iter->cursor].value);
}
size_t CMC_(PFX, _iter_index)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return iter->index;
}
#endif /* CMC_EXT_ITER */
/**
* STR
*
* Print helper functions.
*/
#ifdef CMC_EXT_STR
bool CMC_(PFX, _to_string)(struct SNAME *_map_, FILE *fptr)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct SNAME *m_ = _map_;
return 0 <= fprintf(fptr,
"struct %s<%s, %s> "
"at %p { "
"buffer:%p, "
"capacity:%" PRIuMAX ", "
"count:%" PRIuMAX ", "
"load:%lf, "
"flag:%d, "
"f_key:%p, "
"f_val:%p, "
"alloc:%p, "
"callbacks:%p }",
CMC_TO_STRING(SNAME), CMC_TO_STRING(K), CMC_TO_STRING(V), m_, m_->buffer, m_->capacity,
m_->count, m_->load, m_->flag, m_->f_key, m_->f_val, m_->alloc, CMC_CALLBACKS_GET(m_));
}
bool CMC_(PFX, _print)(struct SNAME *_map_, FILE *fptr, const char *start, const char *separator, const char *end,
const char *key_val_sep)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
fprintf(fptr, "%s", start);
size_t last = 0;
for (size_t i = _map_->capacity; i > 0; i--)
{
if ((_map_->buffer[i - 1]).state == CMC_ES_FILLED)
{
last = i - 1;
break;
}
}
for (size_t i = 0; i < _map_->capacity; i++)
{
struct CMC_DEF_ENTRY(SNAME) *entry = &(_map_->buffer[i]);
if (entry->state == CMC_ES_FILLED)
{
if (!_map_->f_key->str(fptr, entry->key))
return false;
fprintf(fptr, "%s", key_val_sep);
if (!_map_->f_val->str(fptr, entry->value))
return false;
if (i + 1 < last)
fprintf(fptr, "%s", separator);
}
}
fprintf(fptr, "%s", end);
return true;
}
#endif /* CMC_EXT_STR */
+82
View File
@@ -0,0 +1,82 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* INIT
*
* The part 'INIT' gives a new way of initializing a collection. The collection
* struct is not heap allocated, only its internal structure (nodes, buffers).
*/
#ifdef CMC_EXT_INIT
struct SNAME CMC_(PFX, _init)(size_t capacity, double load, struct CMC_DEF_FKEY(SNAME) * f_key,
struct CMC_DEF_FVAL(SNAME) * f_val);
struct SNAME CMC_(PFX, _init_custom)(size_t capacity, double load, struct CMC_DEF_FKEY(SNAME) * f_key,
struct CMC_DEF_FVAL(SNAME) * f_val, CMC_ALLOC_TYPE alloc,
CMC_CALLBACK_TYPE callbacks);
void CMC_(PFX, _release)(struct SNAME _map_);
#endif /* CMC_EXT_INIT */
/**
* ITER
*
* Hashmap bi-directional iterator.
*/
#ifdef CMC_EXT_ITER
/* Iterator Initialization */
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_start)(struct SNAME *target);
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_end)(struct SNAME *target);
/* Iterator State */
bool CMC_(PFX, _iter_at_start)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_at_end)(struct CMC_DEF_ITER(SNAME) * iter);
/* Iterator Movement */
bool CMC_(PFX, _iter_to_start)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_to_end)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_next)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_prev)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_advance)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps);
bool CMC_(PFX, _iter_rewind)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps);
bool CMC_(PFX, _iter_go_to)(struct CMC_DEF_ITER(SNAME) * iter, size_t index);
/* Iterator Access */
K CMC_(PFX, _iter_key)(struct CMC_DEF_ITER(SNAME) * iter);
V CMC_(PFX, _iter_value)(struct CMC_DEF_ITER(SNAME) * iter);
V *CMC_(PFX, _iter_rvalue)(struct CMC_DEF_ITER(SNAME) * iter);
size_t CMC_(PFX, _iter_index)(struct CMC_DEF_ITER(SNAME) * iter);
#endif /* CMC_EXT_ITER */
/**
* STR
*
* Print helper functions.
*/
#ifdef CMC_EXT_STR
bool CMC_(PFX, _to_string)(struct SNAME *_map_, FILE *fptr);
bool CMC_(PFX, _print)(struct SNAME *_map_, FILE *fptr, const char *start, const char *separator, const char *end,
const char *key_val_sep);
#endif /* CMC_EXT_STR */
+51
View File
@@ -0,0 +1,51 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* ITER
*
* Hashmap bi-directional iterator.
*/
#ifdef CMC_EXT_ITER
/* HashMap Iterator */
struct CMC_DEF_ITER(SNAME)
{
/* Target hashmap */
struct SNAME *target;
/* Cursor's position (index) */
size_t cursor;
/* Keeps track of relative index to the iteration of elements */
size_t index;
/* The index of the first element */
size_t first;
/* The index of the last element */
size_t last;
/* If the iterator has reached the start of the iteration */
bool start;
/* If the iterator has reached the end of the iteration */
bool end;
};
#endif /* CMC_EXT_ITER */
+89
View File
@@ -0,0 +1,89 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/* Key struct function table */
struct CMC_DEF_FKEY(SNAME)
{
/* Comparator function */
CMC_DEF_FTAB_CMP(K);
/* Copy function */
CMC_DEF_FTAB_CPY(K);
/* To string function */
CMC_DEF_FTAB_STR(K);
/* Free from memory function */
CMC_DEF_FTAB_FREE(K);
/* Hash function */
CMC_DEF_FTAB_HASH(K);
/* Priority function */
CMC_DEF_FTAB_PRI(K);
};
/* Value struct function table */
struct CMC_DEF_FVAL(SNAME)
{
/* Comparator function */
CMC_DEF_FTAB_CMP(V);
/* Copy function */
CMC_DEF_FTAB_CPY(V);
/* To string function */
CMC_DEF_FTAB_STR(V);
/* Free from memory function */
CMC_DEF_FTAB_FREE(V);
/* Hash function */
CMC_DEF_FTAB_HASH(V);
/* Priority function */
CMC_DEF_FTAB_PRI(V);
};
/* Collection Allocation and Deallocation */
struct SNAME *CMC_(PFX, _new)(size_t capacity, double load, struct CMC_DEF_FKEY(SNAME) * f_key,
struct CMC_DEF_FVAL(SNAME) * f_val);
struct SNAME *CMC_(PFX, _new_custom)(size_t capacity, double load, struct CMC_DEF_FKEY(SNAME) * f_key,
struct CMC_DEF_FVAL(SNAME) * f_val, CMC_ALLOC_TYPE alloc,
CMC_CALLBACK_TYPE callbacks);
void CMC_(PFX, _clear)(struct SNAME *_map_);
void CMC_(PFX, _free)(struct SNAME *_map_);
/* Customization of Allocation and Callbacks */
void CMC_(PFX, _customize)(struct SNAME *_map_, CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks);
/* Collection Input and Output */
bool CMC_(PFX, _insert)(struct SNAME *_map_, K key, V value);
bool CMC_(PFX, _update)(struct SNAME *_map_, K key, V new_value, V *old_value);
bool CMC_(PFX, _remove)(struct SNAME *_map_, K key, V *out_value);
/* Element Access */
bool CMC_(PFX, _max)(struct SNAME *_map_, K *key, V *value);
bool CMC_(PFX, _min)(struct SNAME *_map_, K *key, V *value);
V CMC_(PFX, _get)(struct SNAME *_map_, K key);
V *CMC_(PFX, _get_ref)(struct SNAME *_map_, K key);
/* Collection State */
bool CMC_(PFX, _contains)(struct SNAME *_map_, K key);
bool CMC_(PFX, _empty)(struct SNAME *_map_);
bool CMC_(PFX, _full)(struct SNAME *_map_);
size_t CMC_(PFX, _count)(struct SNAME *_map_);
size_t CMC_(PFX, _capacity)(struct SNAME *_map_);
double CMC_(PFX, _load)(struct SNAME *_map_);
int CMC_(PFX, _flag)(struct SNAME *_map_);
/* Collection Utility */
bool CMC_(PFX, _resize)(struct SNAME *_map_, size_t capacity);
struct SNAME *CMC_(PFX, _copy_of)(struct SNAME *_map_);
bool CMC_(PFX, _equals)(struct SNAME *_map1_, struct SNAME *_map2_);
+60
View File
@@ -0,0 +1,60 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/* HashMap Structure */
struct SNAME
{
/* Array of Entries */
struct CMC_DEF_ENTRY(SNAME) * buffer;
/* Current array capacity */
size_t capacity;
/* Current amount of keys */
size_t count;
/* Load factor in range (0.0, 1.0) */
double load;
/* Flags indicating errors or success */
int flag;
/* Key function table */
struct CMC_DEF_FKEY(SNAME) * f_key;
/* Value function table */
struct CMC_DEF_FVAL(SNAME) * f_val;
/* Custom allocation functions */
CMC_ALLOC_TYPE alloc;
/* Custom callback functions */
CMC_CALLBACKS_DECL;
};
/* HashMap Entry */
struct CMC_DEF_ENTRY(SNAME)
{
/* Entry Key */
K key;
/* Entry Value */
V value;
/* The distance of this node to its original position, used by */
/* robin-hood hashing */
size_t dist;
/* The sate of this node (DELETED, EMPTY, FILLED) */
enum cmc_entry_state state;
};
+107
View File
@@ -0,0 +1,107 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* hashmultimap.h
*
* Creation Date: 26/04/2019
*
* Authors:
* Leonardo Vencovsky (https://github.com/LeoVen)
*
*/
/**
* HashMultiMap
*
* The HashMultiMap is a Map that allows for multiple keys. This is a data
* structure that has a very narrow usage. A Map (either TreeMap or HashMap) can
* also work like a HashMultiMap if a certain key is mapped to another
* collection.
*
* Map<K = int, V = List<int>> maps an integer to a list of integer.
* HashMultiMap<K = int, V = int> maps many integer keys to integer values.
*
* The difference is that in a HashMultiMap you can store keys that are the same
* but might be different instances of the same value. This is also relevant if
* your data type is more complex like a struct where its ID is the same but
* some other members of this data type are different.
*
* Implementation
*
* The map uses separate chaining and robin hood hashing. Its internal buffer
* is made of a pair of pointers to entries that represent a linked list. So
* accessing map->buffer[0] would give the first pair of pointers. Each entry
* has both a pointer to a previous entry and a next entry. This design choice
* was made so that every collection in this library has a two-way iterator
* with a very few exceptions.
*
* Each entry is composed of a Key and a Value. Entries with the same key should
* always hash to the same linked list. Also, keys that hash to the same bucket
* will also be in the same linked list.
*
* The order of inserting and removing the same keys will behave like a FIFO. So
* the first key added will be the first to be removed.
*/
#include "cor/core.h"
#include "cor/hashtable.h"
#ifdef CMC_DEV
#include "utl/log.h"
#endif
/**
* Used values
* K - hashmultimap key data type
* V - hashmultimap value data type
* SNAME - struct name and prefix of other related structs
* PFX - functions prefix
*/
/* Structs definition */
#include "cmc/hashmultimap/struct.h"
/* Function declaration */
#include "cmc/hashmultimap/header.h"
/* Function implementation */
#include "cmc/hashmultimap/code.h"
/**
* Extensions
*
* INIT - Initializes the struct on the stack
* ITER - hashmultimap iterator
* STR - Print helper functions
*/
#define CMC_EXT_HASHMULTIMAP_PARTS INIT, ITER, STR
/**/
#include "cmc/hashmultimap/ext/struct.h"
/**/
#include "cmc/hashmultimap/ext/header.h"
/**/
#include "cmc/hashmultimap/ext/code.h"
#include "cor/undef.h"
+986
View File
@@ -0,0 +1,986 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/* Implementation Detail Functions */
struct CMC_DEF_ENTRY(SNAME) * CMC_(PFX, _impl_new_entry)(struct SNAME *_map_, K key, V value);
struct CMC_DEF_ENTRY(SNAME) * CMC_(PFX, _impl_get_entry)(struct SNAME *_map_, K key);
size_t CMC_(PFX, _impl_key_count)(struct SNAME *_map_, K key);
size_t CMC_(PFX, _impl_calculate_size)(size_t required);
struct SNAME *CMC_(PFX, _new)(size_t capacity, double load, struct CMC_DEF_FKEY(SNAME) * f_key,
struct CMC_DEF_FVAL(SNAME) * f_val)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return CMC_(PFX, _new_custom)(capacity, load, f_key, f_val, NULL, NULL);
}
struct SNAME *CMC_(PFX, _new_custom)(size_t capacity, double load, struct CMC_DEF_FKEY(SNAME) * f_key,
struct CMC_DEF_FVAL(SNAME) * f_val, CMC_ALLOC_TYPE alloc,
CMC_CALLBACK_TYPE callbacks)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
if (capacity == 0 || load <= 0)
return NULL;
/* Prevent integer overflow */
if (capacity >= (double)UINTMAX_MAX * load)
return NULL;
if (!f_key || !f_val)
return NULL;
if (!alloc)
alloc = &cmc_alloc_node_default;
size_t real_capacity = CMC_(PFX, _impl_calculate_size)(capacity / load);
struct SNAME *_map_ = alloc->malloc(sizeof(struct SNAME));
if (!_map_)
return NULL;
_map_->buffer = alloc->calloc(real_capacity, sizeof(struct CMC_DEF_ENTRY(SNAME) *[2]));
if (!_map_->buffer)
{
alloc->free(_map_);
return NULL;
}
_map_->count = 0;
_map_->capacity = real_capacity;
_map_->load = load;
_map_->flag = CMC_FLAG_OK;
_map_->f_key = f_key;
_map_->f_val = f_val;
_map_->alloc = alloc;
CMC_CALLBACKS_ASSIGN(_map_, callbacks);
return _map_;
}
void CMC_(PFX, _clear)(struct SNAME *_map_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
for (size_t i = 0; i < _map_->capacity; i++)
{
struct CMC_DEF_ENTRY(SNAME) *scan = _map_->buffer[i][0];
while (scan)
{
struct CMC_DEF_ENTRY(SNAME) *next = scan->next;
if (_map_->f_key->free)
_map_->f_key->free(scan->key);
if (_map_->f_val->free)
_map_->f_val->free(scan->value);
_map_->alloc->free(scan);
scan = next;
}
}
memset(_map_->buffer, 0, sizeof(struct CMC_DEF_ENTRY(SNAME) *[2]) * _map_->capacity);
_map_->count = 0;
_map_->flag = CMC_FLAG_OK;
}
void CMC_(PFX, _free)(struct SNAME *_map_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
size_t index = 0;
while (index < _map_->capacity)
{
struct CMC_DEF_ENTRY(SNAME) *scan = _map_->buffer[index][0];
if (scan)
{
if (scan->next == NULL && scan->prev == NULL)
{
if (_map_->f_key->free)
_map_->f_key->free(scan->key);
if (_map_->f_val->free)
_map_->f_val->free(scan->value);
_map_->alloc->free(scan);
}
else
{
while (scan)
{
struct CMC_DEF_ENTRY(SNAME) *tmp = scan;
scan = scan->next;
if (_map_->f_key->free)
_map_->f_key->free(tmp->key);
if (_map_->f_val->free)
_map_->f_val->free(tmp->value);
_map_->alloc->free(tmp);
}
}
}
index++;
}
_map_->alloc->free(_map_->buffer);
_map_->alloc->free(_map_);
}
void CMC_(PFX, _customize)(struct SNAME *_map_, CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
if (!alloc)
_map_->alloc = &cmc_alloc_node_default;
else
_map_->alloc = alloc;
CMC_CALLBACKS_ASSIGN(_map_, callbacks);
_map_->flag = CMC_FLAG_OK;
}
bool CMC_(PFX, _insert)(struct SNAME *_map_, K key, V value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _full)(_map_))
{
if (!CMC_(PFX, _resize)(_map_, _map_->capacity + 1))
return false;
}
size_t hash = _map_->f_key->hash(key);
size_t pos = hash % _map_->capacity;
struct CMC_DEF_ENTRY(SNAME) *entry = CMC_(PFX, _impl_new_entry)(_map_, key, value);
if (_map_->buffer[pos][0] == NULL)
{
_map_->buffer[pos][0] = entry;
_map_->buffer[pos][1] = entry;
}
else
{
entry->prev = _map_->buffer[pos][1];
_map_->buffer[pos][1]->next = entry;
_map_->buffer[pos][1] = entry;
}
_map_->count++;
_map_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_map_);
return true;
}
bool CMC_(PFX, _update)(struct SNAME *_map_, K key, V new_value, V *old_value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_map_))
{
_map_->flag = CMC_FLAG_EMPTY;
return false;
}
struct CMC_DEF_ENTRY(SNAME) *entry = CMC_(PFX, _impl_get_entry)(_map_, key);
if (!entry)
{
_map_->flag = CMC_FLAG_NOT_FOUND;
return false;
}
if (old_value)
*old_value = entry->value;
entry->value = new_value;
_map_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_map_);
return true;
}
size_t CMC_(PFX, _update_all)(struct SNAME *_map_, K key, V new_value, V **old_values)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_map_))
{
_map_->flag = CMC_FLAG_EMPTY;
return 0;
}
size_t hash = _map_->f_key->hash(key);
struct CMC_DEF_ENTRY(SNAME) *entry = _map_->buffer[hash % _map_->capacity][0];
if (entry == NULL)
{
_map_->flag = CMC_FLAG_NOT_FOUND;
return 0;
}
if (old_values)
{
size_t total = CMC_(PFX, _impl_key_count)(_map_, key);
if (total == 0)
{
_map_->flag = CMC_FLAG_NOT_FOUND;
return 0;
}
*old_values = _map_->alloc->malloc(sizeof(V) * total);
if (!(*old_values))
{
_map_->flag = CMC_FLAG_ALLOC;
return 0;
}
}
size_t index = 0;
while (entry)
{
if (_map_->f_key->cmp(entry->key, key) == 0)
{
if (old_values)
(*old_values)[index] = entry->value;
index++;
entry->value = new_value;
}
entry = entry->next;
}
_map_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_map_);
return index;
}
bool CMC_(PFX, _remove)(struct SNAME *_map_, K key, V *out_value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_map_))
{
_map_->flag = CMC_FLAG_EMPTY;
return false;
}
size_t hash = _map_->f_key->hash(key);
struct CMC_DEF_ENTRY(SNAME) **head = &(_map_->buffer[hash % _map_->capacity][0]);
struct CMC_DEF_ENTRY(SNAME) **tail = &(_map_->buffer[hash % _map_->capacity][1]);
if (*head == NULL)
{
_map_->flag = CMC_FLAG_NOT_FOUND;
return false;
}
struct CMC_DEF_ENTRY(SNAME) *entry = *head;
if (entry->next == NULL && entry->prev == NULL)
{
if (_map_->f_key->cmp(entry->key, key) == 0)
{
*head = NULL;
*tail = NULL;
if (out_value)
*out_value = entry->value;
}
else
{
_map_->flag = CMC_FLAG_NOT_FOUND;
return false;
}
}
else
{
bool found = false;
while (entry)
{
if (_map_->f_key->cmp(entry->key, key) == 0)
{
if (*head == entry)
*head = entry->next;
if (*tail == entry)
*tail = entry->prev;
if (entry->prev)
entry->prev->next = entry->next;
if (entry->next)
entry->next->prev = entry->prev;
if (out_value)
*out_value = entry->value;
found = true;
break;
}
else
entry = entry->next;
}
if (!found)
{
_map_->flag = CMC_FLAG_NOT_FOUND;
return false;
}
}
_map_->alloc->free(entry);
_map_->count--;
_map_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_map_);
return true;
}
size_t CMC_(PFX, _remove_all)(struct SNAME *_map_, K key, V **out_values)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_map_))
{
_map_->flag = CMC_FLAG_EMPTY;
return false;
}
size_t hash = _map_->f_key->hash(key);
struct CMC_DEF_ENTRY(SNAME) **head = &(_map_->buffer[hash % _map_->capacity][0]);
struct CMC_DEF_ENTRY(SNAME) **tail = &(_map_->buffer[hash % _map_->capacity][1]);
if (*head == NULL)
{
_map_->flag = CMC_FLAG_NOT_FOUND;
return 0;
}
if (out_values)
{
size_t total = CMC_(PFX, _impl_key_count)(_map_, key);
if (total == 0)
{
_map_->flag = CMC_FLAG_NOT_FOUND;
return 0;
}
*out_values = _map_->alloc->malloc(sizeof(V) * total);
if (!(*out_values))
{
_map_->flag = CMC_FLAG_ALLOC;
return 0;
}
}
size_t index = 0;
struct CMC_DEF_ENTRY(SNAME) *entry = *head;
if (entry->next == NULL)
{
*head = NULL;
*tail = NULL;
if (out_values)
(*out_values)[index] = entry->value;
index++;
_map_->alloc->free(entry);
}
else
{
while (entry)
{
if (_map_->f_key->cmp(entry->key, key) == 0)
{
if (*head == entry)
*head = entry->next;
if (*tail == entry)
*tail = entry->prev;
struct CMC_DEF_ENTRY(SNAME) *next = entry->next;
if (entry->prev)
entry->prev->next = entry->next;
if (entry->next)
entry->next->prev = entry->prev;
if (out_values)
(*out_values)[index] = entry->value;
index++;
_map_->alloc->free(entry);
entry = next;
}
else
entry = entry->next;
}
}
_map_->count -= index;
_map_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_map_);
return index;
}
bool CMC_(PFX, _max)(struct SNAME *_map_, K *key, V *value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_map_))
{
_map_->flag = CMC_FLAG_EMPTY;
return false;
}
bool first = true;
K max_key = (K){ 0 };
V max_val = (V){ 0 };
for (size_t i = 0; i < _map_->capacity; i++)
{
struct CMC_DEF_ENTRY(SNAME) *scan = _map_->buffer[i][0];
while (scan)
{
if (first)
{
max_key = scan->key;
max_val = scan->value;
first = false;
}
else if (_map_->f_key->cmp(scan->key, max_key) > 0)
{
max_key = scan->key;
max_val = scan->value;
}
scan = scan->next;
}
}
if (key)
*key = max_key;
if (value)
*value = max_val;
_map_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_map_);
return true;
}
bool CMC_(PFX, _min)(struct SNAME *_map_, K *key, V *value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_map_))
{
_map_->flag = CMC_FLAG_EMPTY;
return false;
}
bool first = true;
K min_key = (K){ 0 };
V min_val = (V){ 0 };
for (size_t i = 0; i < _map_->capacity; i++)
{
struct CMC_DEF_ENTRY(SNAME) *scan = _map_->buffer[i][0];
while (scan)
{
if (first)
{
min_key = scan->key;
min_val = scan->value;
first = false;
}
else if (_map_->f_key->cmp(scan->key, min_key) < 0)
{
min_key = scan->key;
min_val = scan->value;
}
scan = scan->next;
}
}
if (key)
*key = min_key;
if (value)
*value = min_val;
_map_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_map_);
return true;
}
V CMC_(PFX, _get)(struct SNAME *_map_, K key)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_map_))
{
_map_->flag = CMC_FLAG_EMPTY;
return (V){ 0 };
}
struct CMC_DEF_ENTRY(SNAME) *entry = CMC_(PFX, _impl_get_entry)(_map_, key);
if (!entry)
{
_map_->flag = CMC_FLAG_NOT_FOUND;
return (V){ 0 };
}
_map_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_map_);
return entry->value;
}
V *CMC_(PFX, _get_ref)(struct SNAME *_map_, K key)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_map_))
{
_map_->flag = CMC_FLAG_EMPTY;
return NULL;
}
struct CMC_DEF_ENTRY(SNAME) *entry = CMC_(PFX, _impl_get_entry)(_map_, key);
if (!entry)
{
_map_->flag = CMC_FLAG_NOT_FOUND;
return NULL;
}
_map_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_map_);
return &(entry->value);
}
bool CMC_(PFX, _contains)(struct SNAME *_map_, K key)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
_map_->flag = CMC_FLAG_OK;
bool result = CMC_(PFX, _impl_get_entry)(_map_, key) != NULL;
CMC_CALLBACKS_CALL(_map_);
return result;
}
bool CMC_(PFX, _empty)(struct SNAME *_map_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _map_->count == 0;
}
bool CMC_(PFX, _full)(struct SNAME *_map_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return (double)_map_->capacity * _map_->load <= (double)_map_->count;
}
size_t CMC_(PFX, _count)(struct SNAME *_map_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _map_->count;
}
size_t CMC_(PFX, _key_count)(struct SNAME *_map_, K key)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return CMC_(PFX, _impl_key_count)(_map_, key);
}
size_t CMC_(PFX, _capacity)(struct SNAME *_map_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _map_->capacity;
}
double CMC_(PFX, _load)(struct SNAME *_map_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _map_->load;
}
int CMC_(PFX, _flag)(struct SNAME *_map_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _map_->flag;
}
bool CMC_(PFX, _resize)(struct SNAME *_map_, size_t capacity)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
_map_->flag = CMC_FLAG_OK;
if (_map_->capacity == capacity)
goto success;
if (_map_->capacity > capacity / _map_->load)
goto success;
/* Prevent integer overflow */
if (capacity >= (double)UINTMAX_MAX * _map_->load)
{
_map_->flag = CMC_FLAG_ERROR;
return false;
}
/* Calculate required capacity based on the prime numbers */
size_t theoretical_size = CMC_(PFX, _impl_calculate_size)(capacity);
/* Not possible to shrink with current available prime numbers */
if (theoretical_size < _map_->count / _map_->load)
{
_map_->flag = CMC_FLAG_INVALID;
return false;
}
/* No callbacks since _new_map_ is just a temporary hashtable */
struct SNAME *_new_map_ =
CMC_(PFX, _new_custom)(capacity, _map_->load, _map_->f_key, _map_->f_val, _map_->alloc, NULL);
if (!_new_map_)
{
_map_->flag = CMC_FLAG_ALLOC;
return false;
}
for (size_t i = 0; i < _map_->capacity; i++)
{
struct CMC_DEF_ENTRY(SNAME) *scan = _map_->buffer[i][0];
while (scan)
{
/* TODO check for errors */
CMC_(PFX, _insert)(_new_map_, scan->key, scan->value);
scan = scan->next;
}
}
if (_map_->count != _new_map_->count)
{
CMC_(PFX, _free)(_new_map_);
_map_->flag = CMC_FLAG_ERROR;
return false;
}
struct CMC_DEF_ENTRY(SNAME) * (*tmp_b)[2] = _map_->buffer;
_map_->buffer = _new_map_->buffer;
_new_map_->buffer = tmp_b;
size_t tmp_c = _map_->capacity;
_map_->capacity = _new_map_->capacity;
_new_map_->capacity = tmp_c;
/* Prevent the map from freeing the data */
_new_map_->f_key = &(struct CMC_DEF_FKEY(SNAME)){ 0 };
_new_map_->f_val = &(struct CMC_DEF_FVAL(SNAME)){ 0 };
CMC_(PFX, _free)(_new_map_);
success:
CMC_CALLBACKS_CALL(_map_);
return true;
}
struct SNAME *CMC_(PFX, _copy_of)(struct SNAME *_map_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
/* Callback will be added later */
struct SNAME *result = CMC_(PFX, _new_custom)(_map_->capacity * _map_->load, _map_->load, _map_->f_key,
_map_->f_val, _map_->alloc, NULL);
if (!result)
{
_map_->flag = CMC_FLAG_ERROR;
return NULL;
}
for (size_t i = 0; i < _map_->capacity; i++)
{
struct CMC_DEF_ENTRY(SNAME) *scan = _map_->buffer[i][0];
while (scan)
{
K key;
V value;
if (_map_->f_key->cpy)
key = _map_->f_key->cpy(scan->key);
else
key = scan->key;
if (_map_->f_val->cpy)
value = _map_->f_val->cpy(scan->value);
else
value = scan->value;
/* TODO check for errors */
CMC_(PFX, _insert)(result, key, value);
scan = scan->next;
}
}
CMC_CALLBACKS_ASSIGN(result, _map_->callbacks);
_map_->flag = CMC_FLAG_OK;
return result;
}
bool CMC_(PFX, _equals)(struct SNAME *_map1_, struct SNAME *_map2_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
_map1_->flag = CMC_FLAG_OK;
_map2_->flag = CMC_FLAG_OK;
if (_map1_->count != _map2_->count)
return false;
/* Optimize loop using the smallest hashtable */
struct SNAME *_map_a_;
struct SNAME *_map_b_;
_map_a_ = _map1_->capacity < _map2_->capacity ? _map1_ : _map2_;
_map_b_ = _map_a_ == _map1_ ? _map2_ : _map1_;
for (size_t i = 0; i < _map_a_->capacity; i++)
{
struct CMC_DEF_ENTRY(SNAME) *scan = _map_a_->buffer[i][0];
while (scan)
{
/* OPTIMIZE - This is calling key_count for repeating keys */
if (CMC_(PFX, _impl_key_count)(_map_a_, scan->key) != CMC_(PFX, _impl_key_count)(_map_b_, scan->key))
return false;
scan = scan->next;
}
}
return true;
}
struct CMC_DEF_ENTRY(SNAME) * CMC_(PFX, _impl_new_entry)(struct SNAME *_map_, K key, V value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct CMC_DEF_ENTRY(SNAME) *entry = _map_->alloc->malloc(sizeof(struct CMC_DEF_ENTRY(SNAME)));
if (!entry)
return NULL;
entry->key = key;
entry->value = value;
entry->next = NULL;
entry->prev = NULL;
return entry;
}
struct CMC_DEF_ENTRY(SNAME) * CMC_(PFX, _impl_get_entry)(struct SNAME *_map_, K key)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
size_t hash = _map_->f_key->hash(key);
struct CMC_DEF_ENTRY(SNAME) *entry = _map_->buffer[hash % _map_->capacity][0];
while (entry)
{
if (_map_->f_key->cmp(entry->key, key) == 0)
return entry;
entry = entry->next;
}
return NULL;
}
size_t CMC_(PFX, _impl_key_count)(struct SNAME *_map_, K key)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
size_t hash = _map_->f_key->hash(key);
struct CMC_DEF_ENTRY(SNAME) *entry = _map_->buffer[hash % _map_->capacity][0];
size_t total_count = 0;
if (!entry)
return total_count;
while (entry)
{
if (_map_->f_key->cmp(entry->key, key) == 0)
total_count++;
entry = entry->next;
}
return total_count;
}
size_t CMC_(PFX, _impl_calculate_size)(size_t required)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
const size_t count = sizeof(cmc_hashtable_primes) / sizeof(cmc_hashtable_primes[0]);
if (cmc_hashtable_primes[count - 1] < required)
return required;
size_t i = 0;
while (cmc_hashtable_primes[i] < required)
i++;
return cmc_hashtable_primes[i];
}
+465
View File
@@ -0,0 +1,465 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* INIT
*
* The part 'INIT' gives a new way of initializing a collection. The collection
* struct is not heap allocated, only its internal structure (nodes, buffers).
*/
#ifdef CMC_EXT_INIT
#endif /* CMC_EXT_INIT */
/**
* ITER
*
* List bi-directional iterator.
*/
#ifdef CMC_EXT_ITER
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_start)(struct SNAME *target)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct CMC_DEF_ITER(SNAME) iter;
iter.target = target;
iter.curr_entry = NULL;
iter.cursor = 0;
iter.index = 0;
iter.first = 0;
iter.last = 0;
iter.start = true;
iter.end = CMC_(PFX, _empty)(target);
if (!CMC_(PFX, _empty)(target))
{
for (size_t i = 0; i < target->capacity; i++)
{
struct CMC_DEF_ENTRY(SNAME) *entry = target->buffer[i][0];
if (entry && entry != CMC_ENTRY_DELETED)
{
iter.curr_entry = target->buffer[i][0];
iter.first = i;
break;
}
}
iter.cursor = iter.first;
for (size_t i = target->capacity; i > 0; i--)
{
struct CMC_DEF_ENTRY(SNAME) *entry = target->buffer[i - 1][1];
if (entry && entry != CMC_ENTRY_DELETED)
{
iter.last = i - 1;
break;
}
}
}
return iter;
}
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_end)(struct SNAME *target)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct CMC_DEF_ITER(SNAME) iter;
iter.target = target;
iter.curr_entry = NULL;
iter.cursor = 0;
iter.index = 0;
iter.first = 0;
iter.last = 0;
iter.start = CMC_(PFX, _empty)(target);
iter.end = true;
if (!CMC_(PFX, _empty)(target))
{
for (size_t i = 0; i < target->capacity; i++)
{
struct CMC_DEF_ENTRY(SNAME) *entry = target->buffer[i][0];
if (entry && entry != CMC_ENTRY_DELETED)
{
iter.first = i;
break;
}
}
for (size_t i = target->capacity; i > 0; i--)
{
struct CMC_DEF_ENTRY(SNAME) *entry = target->buffer[i - 1][1];
if (entry && entry != CMC_ENTRY_DELETED)
{
iter.curr_entry = target->buffer[i - 1][1];
iter.last = i - 1;
break;
}
}
iter.cursor = iter.last;
iter.index = target->count - 1;
}
return iter;
}
bool CMC_(PFX, _iter_at_start)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return CMC_(PFX, _empty)(iter->target) || iter->start;
}
bool CMC_(PFX, _iter_at_end)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return CMC_(PFX, _empty)(iter->target) || iter->end;
}
bool CMC_(PFX, _iter_to_start)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (!CMC_(PFX, _empty)(iter->target))
{
iter->cursor = iter->first;
iter->index = 0;
iter->start = true;
iter->end = CMC_(PFX, _empty)(iter->target);
iter->curr_entry = iter->target->buffer[iter->first][0];
return true;
}
return false;
}
bool CMC_(PFX, _iter_to_end)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (!CMC_(PFX, _empty)(iter->target))
{
iter->cursor = iter->last;
iter->index = iter->target->count - 1;
iter->start = CMC_(PFX, _empty)(iter->target);
iter->end = true;
iter->curr_entry = iter->target->buffer[iter->last][1];
return true;
}
return false;
}
bool CMC_(PFX, _iter_next)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (iter->end)
return false;
if (iter->curr_entry->next != NULL)
{
iter->curr_entry = iter->curr_entry->next;
iter->index++;
}
else
{
if (iter->cursor == iter->last)
{
iter->end = true;
return false;
}
iter->cursor++;
while (iter->target->buffer[iter->cursor][0] == NULL)
iter->cursor++;
iter->curr_entry = iter->target->buffer[iter->cursor][0];
iter->index++;
}
iter->start = CMC_(PFX, _empty)(iter->target);
return true;
}
bool CMC_(PFX, _iter_prev)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (iter->start)
return false;
if (iter->curr_entry->prev != NULL)
{
iter->curr_entry = iter->curr_entry->prev;
iter->index--;
}
else
{
if (iter->cursor == iter->first)
{
iter->start = true;
return false;
}
iter->cursor--;
while (iter->target->buffer[iter->cursor][1] == NULL)
iter->cursor--;
iter->curr_entry = iter->target->buffer[iter->cursor][1];
iter->index--;
}
iter->end = CMC_(PFX, _empty)(iter->target);
return true;
}
/* Returns true only if the iterator moved */
bool CMC_(PFX, _iter_advance)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (iter->end)
return false;
if (iter->index + 1 == iter->target->count)
{
iter->end = true;
return false;
}
if (steps == 0 || iter->index + steps >= iter->target->count)
return false;
for (size_t i = 0; i < steps; i++)
CMC_(PFX, _iter_next)(iter);
return true;
}
/* Returns true only if the iterator moved */
bool CMC_(PFX, _iter_rewind)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (iter->start)
return false;
if (iter->index == 0)
{
iter->start = true;
return false;
}
if (steps == 0 || iter->index < steps)
return false;
for (size_t i = 0; i < steps; i++)
CMC_(PFX, _iter_prev)(iter);
return true;
}
/* Returns true only if the iterator was able to be positioned at the */
/* given index */
bool CMC_(PFX, _iter_go_to)(struct CMC_DEF_ITER(SNAME) * iter, size_t index)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (index >= iter->target->count)
return false;
if (iter->index > index)
return CMC_(PFX, _iter_rewind)(iter, iter->index - index);
else if (iter->index < index)
return CMC_(PFX, _iter_advance)(iter, index - iter->index);
return true;
}
K CMC_(PFX, _iter_key)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(iter->target))
return (K){ 0 };
return iter->curr_entry->key;
}
V CMC_(PFX, _iter_value)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(iter->target))
return (V){ 0 };
return iter->curr_entry->value;
}
V *CMC_(PFX, _iter_rvalue)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(iter->target))
return NULL;
return &(iter->curr_entry->value);
}
size_t CMC_(PFX, _iter_index)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return iter->index;
}
#endif /* CMC_EXT_ITER */
/**
* STR
*
* Print helper functions.
*/
#ifdef CMC_EXT_STR
bool CMC_(PFX, _to_string)(struct SNAME *_map_, FILE *fptr)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct SNAME *m_ = _map_;
return 0 <= fprintf(fptr,
"struct %s<%s, %s> "
"at %p { "
"buffer:%p, "
"capacity:%" PRIuMAX ", "
"count:%" PRIuMAX ", "
"load:%lf, "
"flag:%d, "
"f_key:%p, "
"f_val:%p, "
"alloc:%p, "
"callbacks:%p }",
CMC_TO_STRING(SNAME), CMC_TO_STRING(K), CMC_TO_STRING(V), m_, m_->buffer, m_->capacity,
m_->count, m_->load, m_->flag, m_->f_key, m_->f_val, m_->alloc, CMC_CALLBACKS_GET(m_));
}
bool CMC_(PFX, _print)(struct SNAME *_map_, FILE *fptr, const char *start, const char *separator, const char *end,
const char *key_val_sep)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
fprintf(fptr, "%s", start);
size_t last = 0;
for (size_t i = _map_->capacity; i > 0; i--)
{
struct CMC_DEF_ENTRY(SNAME) *entry = _map_->buffer[i - 1][1];
if (entry && entry != CMC_ENTRY_DELETED)
{
last = i - 1;
break;
}
}
for (size_t i = 0; i < _map_->capacity; i++)
{
struct CMC_DEF_ENTRY(SNAME) *scan = _map_->buffer[i][0];
while (scan != NULL)
{
if (!_map_->f_key->str(fptr, scan->key))
return false;
fprintf(fptr, "%s", key_val_sep);
if (!_map_->f_val->str(fptr, scan->value))
return false;
scan = scan->next;
if (i + 1 < last)
fprintf(fptr, "%s", separator);
}
}
fprintf(fptr, "%s", end);
return true;
}
#endif /* CMC_EXT_STR */
+75
View File
@@ -0,0 +1,75 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* INIT
*
* The part 'INIT' gives a new way of initializing a collection. The collection
* struct is not heap allocated, only its internal structure (nodes, buffers).
*/
#ifdef CMC_EXT_INIT
#endif /* CMC_EXT_INIT */
/**
* ITER
*
* Hashmultimap bi-directional iterator.
*/
#ifdef CMC_EXT_ITER
/* Iterator Initialization */
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_start)(struct SNAME *target);
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_end)(struct SNAME *target);
/* Iterator State */
bool CMC_(PFX, _iter_at_start)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_at_end)(struct CMC_DEF_ITER(SNAME) * iter);
/* Iterator Movement */
bool CMC_(PFX, _iter_to_start)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_to_end)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_next)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_prev)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_advance)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps);
bool CMC_(PFX, _iter_rewind)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps);
bool CMC_(PFX, _iter_go_to)(struct CMC_DEF_ITER(SNAME) * iter, size_t index);
/* Iterator Access */
K CMC_(PFX, _iter_key)(struct CMC_DEF_ITER(SNAME) * iter);
V CMC_(PFX, _iter_value)(struct CMC_DEF_ITER(SNAME) * iter);
V *CMC_(PFX, _iter_rvalue)(struct CMC_DEF_ITER(SNAME) * iter);
size_t CMC_(PFX, _iter_index)(struct CMC_DEF_ITER(SNAME) * iter);
#endif /* CMC_EXT_ITER */
/**
* STR
*
* Print helper functions.
*/
#ifdef CMC_EXT_STR
bool CMC_(PFX, _to_string)(struct SNAME *_map_, FILE *fptr);
bool CMC_(PFX, _print)(struct SNAME *_map_, FILE *fptr, const char *start, const char *separator, const char *end,
const char *key_val_sep);
#endif /* CMC_EXT_STR */
+53
View File
@@ -0,0 +1,53 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* ITER
*
* Hashmultimap bi-directional iterator.
*/
#ifdef CMC_EXT_ITER
/* HashMultiMap Iterator */
struct CMC_DEF_ITER(SNAME)
{
/* Target hashmultimap */
struct SNAME *target;
/* Current entry */
struct CMC_DEF_ENTRY(SNAME) * curr_entry;
/* Cursor`s position (index) */
size_t cursor;
/* Keeps track of relative index to the iteration of elements */
size_t index;
/* The index of the first element */
size_t first;
/* The index of the last element */
size_t last;
/* If the iterator has reached the start of the iteration */
bool start;
/* If the iterator has reached the end of the iteration */
bool end;
};
#endif /* CMC_EXT_ITER */
+92
View File
@@ -0,0 +1,92 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/* Key struct function table */
struct CMC_DEF_FKEY(SNAME)
{
/* Comparator function */
CMC_DEF_FTAB_CMP(K);
/* Copy function */
CMC_DEF_FTAB_CPY(K);
/* To string function */
CMC_DEF_FTAB_STR(K);
/* Free from memory function */
CMC_DEF_FTAB_FREE(K);
/* Hash function */
CMC_DEF_FTAB_HASH(K);
/* Priority function */
CMC_DEF_FTAB_PRI(K);
};
/* Value struct function table */
struct CMC_DEF_FVAL(SNAME)
{
/* Comparator function */
CMC_DEF_FTAB_CMP(V);
/* Copy function */
CMC_DEF_FTAB_CPY(V);
/* To string function */
CMC_DEF_FTAB_STR(V);
/* Free from memory function */
CMC_DEF_FTAB_FREE(V);
/* Hash function */
CMC_DEF_FTAB_HASH(V);
/* Priority function */
CMC_DEF_FTAB_PRI(V);
};
/* Collection Allocation and Deallocation */
struct SNAME *CMC_(PFX, _new)(size_t capacity, double load, struct CMC_DEF_FKEY(SNAME) * f_key,
struct CMC_DEF_FVAL(SNAME) * f_val);
struct SNAME *CMC_(PFX, _new_custom)(size_t capacity, double load, struct CMC_DEF_FKEY(SNAME) * f_key,
struct CMC_DEF_FVAL(SNAME) * f_val, CMC_ALLOC_TYPE alloc,
CMC_CALLBACK_TYPE callbacks);
void CMC_(PFX, _clear)(struct SNAME *_map_);
void CMC_(PFX, _free)(struct SNAME *_map_);
/* Customization of Allocation and Callbacks */
void CMC_(PFX, _customize)(struct SNAME *_map_, CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks);
/* Collection Input and Output */
bool CMC_(PFX, _insert)(struct SNAME *_map_, K key, V value);
bool CMC_(PFX, _update)(struct SNAME *_map_, K key, V new_value, V *old_value);
size_t CMC_(PFX, _update_all)(struct SNAME *_map_, K key, V new_value, V **old_values);
bool CMC_(PFX, _remove)(struct SNAME *_map_, K key, V *out_value);
size_t CMC_(PFX, _remove_all)(struct SNAME *_map_, K key, V **out_values);
/* Element Access */
bool CMC_(PFX, _max)(struct SNAME *_map_, K *key, V *value);
bool CMC_(PFX, _min)(struct SNAME *_map_, K *key, V *value);
V CMC_(PFX, _get)(struct SNAME *_map_, K key);
V *CMC_(PFX, _get_ref)(struct SNAME *_map_, K key);
/* Collection State */
bool CMC_(PFX, _contains)(struct SNAME *_map_, K key);
bool CMC_(PFX, _empty)(struct SNAME *_map_);
bool CMC_(PFX, _full)(struct SNAME *_map_);
size_t CMC_(PFX, _count)(struct SNAME *_map_);
size_t CMC_(PFX, _key_count)(struct SNAME *_map_, K key);
size_t CMC_(PFX, _capacity)(struct SNAME *_map_);
double CMC_(PFX, _load)(struct SNAME *_map_);
int CMC_(PFX, _flag)(struct SNAME *_map_);
/* Collection Utility */
bool CMC_(PFX, _resize)(struct SNAME *_map_, size_t capacity);
struct SNAME *CMC_(PFX, _copy_of)(struct SNAME *_map_);
bool CMC_(PFX, _equals)(struct SNAME *_map1_, struct SNAME *_map2_);
+59
View File
@@ -0,0 +1,59 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/* HashMultimap Structure */
struct SNAME
{
/* Array of linked list to entries */
struct CMC_DEF_ENTRY(SNAME) * (*buffer)[2];
/* Current array capacity */
size_t capacity;
/* Current amount of keys */
size_t count;
/* Load factor in range (0.0, infinity) */
double load;
/* Flags indicating errors or success */
int flag;
/* Key function table */
struct CMC_DEF_FKEY(SNAME) * f_key;
/* Value function table */
struct CMC_DEF_FVAL(SNAME) * f_val;
/* Custom allocation functions */
CMC_ALLOC_TYPE alloc;
/* Custom callback functions */
CMC_CALLBACKS_DECL;
};
/* HashMultimap Entry */
struct CMC_DEF_ENTRY(SNAME)
{
/* Entry Key */
K key;
/* Entry Value */
V value;
/* Next entry on the linked list */
struct CMC_DEF_ENTRY(SNAME) * next;
/* Previous entry on the linked list */
struct CMC_DEF_ENTRY(SNAME) * prev;
};
+88
View File
@@ -0,0 +1,88 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* hashmultiset.h
*
* Creation Date: 10/04/2019
*
* Authors:
* Leonardo Vencovsky (https://github.com/LeoVen)
*
*/
/**
* HashMultiSet
*
* In mathematics, a multiset is a modification of the concept of a set that,
* unlike a set, allows for multiple instances for each of its elements. The
* positive integer number of instances, given for each element is called the
* multiplicity of this element in the multiset. A multiSet also has a
* cardinality which equals the sum of the multiplicities of its elements.
*
* Implementation
*
* In this implementation, the values are stored in a flat hashtable and are
* mapped to their multiplicity.
*/
#include "cor/core.h"
#include "cor/hashtable.h"
#ifdef CMC_DEV
#include "utl/log.h"
#endif
/**
* Used values
* V - hashmultiset value data type
* SNAME - struct name and prefix of other related structs
* PFX - functions prefix
*/
/* Structs definition */
#include "cmc/hashmultiset/struct.h"
/* Function declaration */
#include "cmc/hashmultiset/header.h"
/* Function implementation */
#include "cmc/hashmultiset/code.h"
/**
* Extensions
*
* INIT - Initializes the struct on the stack
* ITER - hashmultiset iterator
* STR - Print helper functions
*/
#define CMC_EXT_HASHMULTISET_PARTS INIT, ITER, SETF, STR
/**/
#include "cmc/hashmultiset/ext/struct.h"
/**/
#include "cmc/hashmultiset/ext/header.h"
/**/
#include "cmc/hashmultiset/ext/code.h"
#include "cor/undef.h"
+825
View File
@@ -0,0 +1,825 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/* Implementation Detail Functions */
static struct CMC_DEF_ENTRY(SNAME) * CMC_(PFX, _impl_insert_and_return)(struct SNAME *_set_, V value, bool *new_node);
static struct CMC_DEF_ENTRY(SNAME) * CMC_(PFX, _impl_get_entry)(struct SNAME *_set_, V value);
static size_t CMC_(PFX, _impl_calculate_size)(size_t required);
struct SNAME *CMC_(PFX, _new)(size_t capacity, double load, struct CMC_DEF_FVAL(SNAME) * f_val)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return CMC_(PFX, _new_custom)(capacity, load, f_val, NULL, NULL);
}
struct SNAME *CMC_(PFX, _new_custom)(size_t capacity, double load, struct CMC_DEF_FVAL(SNAME) * f_val,
CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
if (capacity == 0 || load <= 0 || load >= 1)
return NULL;
/* Prevent integer overflow */
if (capacity >= (double)UINTMAX_MAX * load)
return NULL;
if (!f_val)
return NULL;
size_t real_capacity = CMC_(PFX, _impl_calculate_size)(capacity / load);
if (!alloc)
alloc = &cmc_alloc_node_default;
struct SNAME *_set_ = alloc->malloc(sizeof(struct SNAME));
if (!_set_)
return NULL;
_set_->buffer = alloc->calloc(real_capacity, sizeof(struct CMC_DEF_ENTRY(SNAME)));
if (!_set_->buffer)
{
alloc->free(_set_);
return NULL;
}
_set_->count = 0;
_set_->cardinality = 0;
_set_->capacity = real_capacity;
_set_->load = load;
_set_->flag = CMC_FLAG_OK;
_set_->f_val = f_val;
_set_->alloc = alloc;
CMC_CALLBACKS_ASSIGN(_set_, callbacks);
return _set_;
}
void CMC_(PFX, _clear)(struct SNAME *_set_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (_set_->f_val->free)
{
for (size_t i = 0; i < _set_->capacity; i++)
{
struct CMC_DEF_ENTRY(SNAME) *entry = &(_set_->buffer[i]);
if (entry->state == CMC_ES_FILLED)
{
_set_->f_val->free(entry->value);
}
}
}
memset(_set_->buffer, 0, sizeof(struct CMC_DEF_ENTRY(SNAME)) * _set_->capacity);
_set_->count = 0;
_set_->flag = CMC_FLAG_OK;
}
void CMC_(PFX, _free)(struct SNAME *_set_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (_set_->f_val->free)
{
for (size_t i = 0; i < _set_->capacity; i++)
{
struct CMC_DEF_ENTRY(SNAME) *entry = &(_set_->buffer[i]);
if (entry->state == CMC_ES_FILLED)
{
_set_->f_val->free(entry->value);
}
}
}
_set_->alloc->free(_set_->buffer);
_set_->alloc->free(_set_);
}
void CMC_(PFX, _customize)(struct SNAME *_set_, CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
if (!alloc)
_set_->alloc = &cmc_alloc_node_default;
else
_set_->alloc = alloc;
CMC_CALLBACKS_ASSIGN(_set_, callbacks);
_set_->flag = CMC_FLAG_OK;
}
bool CMC_(PFX, _insert)(struct SNAME *_set_, V value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
bool new_node;
struct CMC_DEF_ENTRY(SNAME) *entry = CMC_(PFX, _impl_insert_and_return)(_set_, value, &new_node);
if (!entry)
{
_set_->flag = CMC_FLAG_ERROR;
return false;
}
if (!new_node)
entry->multiplicity++;
_set_->cardinality++;
_set_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_set_);
return true;
}
bool CMC_(PFX, _insert_many)(struct SNAME *_set_, V value, size_t count)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (count == 0)
goto success;
bool new_node;
struct CMC_DEF_ENTRY(SNAME) *entry = CMC_(PFX, _impl_insert_and_return)(_set_, value, &new_node);
if (!entry)
{
_set_->flag = CMC_FLAG_ERROR;
return false;
}
if (new_node)
entry->multiplicity = count;
else
entry->multiplicity += count;
_set_->cardinality += count;
success:
_set_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_set_);
return true;
}
bool CMC_(PFX, _update)(struct SNAME *_set_, V value, size_t multiplicity)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (multiplicity == 0)
{
/* Effectively delete the entry */
struct CMC_DEF_ENTRY(SNAME) *result = CMC_(PFX, _impl_get_entry)(_set_, value);
if (!result)
/* If no entry was found then its multiplicity is already 0 */
goto success;
_set_->count--;
_set_->cardinality -= result->multiplicity;
result->value = (V){ 0 };
result->multiplicity = 0;
result->dist = 0;
result->state = CMC_ES_DELETED;
goto success;
}
bool new_node;
struct CMC_DEF_ENTRY(SNAME) *entry = CMC_(PFX, _impl_insert_and_return)(_set_, value, &new_node);
if (!entry)
return false;
if (new_node)
_set_->cardinality++;
_set_->cardinality = (_set_->cardinality - entry->multiplicity) + multiplicity;
entry->multiplicity = multiplicity;
success:
_set_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_set_);
return true;
}
bool CMC_(PFX, _remove)(struct SNAME *_set_, V value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_set_))
{
_set_->flag = CMC_FLAG_EMPTY;
return false;
}
struct CMC_DEF_ENTRY(SNAME) *result = CMC_(PFX, _impl_get_entry)(_set_, value);
if (!result)
{
_set_->flag = CMC_FLAG_NOT_FOUND;
return false;
}
if (result->multiplicity > 1)
result->multiplicity--;
else
{
result->value = (V){ 0 };
result->multiplicity = 0;
result->dist = 0;
result->state = CMC_ES_DELETED;
_set_->count--;
}
_set_->cardinality--;
_set_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_set_);
return true;
}
size_t CMC_(PFX, _remove_all)(struct SNAME *_set_, V value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_set_))
{
_set_->flag = CMC_FLAG_EMPTY;
return false;
}
struct CMC_DEF_ENTRY(SNAME) *result = CMC_(PFX, _impl_get_entry)(_set_, value);
if (!result)
{
_set_->flag = CMC_FLAG_NOT_FOUND;
return 0;
}
size_t removed = result->multiplicity;
result->value = (V){ 0 };
result->multiplicity = 0;
result->dist = 0;
result->state = CMC_ES_DELETED;
_set_->count--;
_set_->cardinality -= removed;
_set_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_set_);
return removed;
}
bool CMC_(PFX, _max)(struct SNAME *_set_, V *value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_set_))
{
_set_->flag = CMC_FLAG_EMPTY;
return false;
}
bool first = true;
V max_val = (V){ 0 };
for (size_t i = 0; i < _set_->capacity; i++)
{
if (_set_->buffer[i].state == CMC_ES_FILLED)
{
if (first)
{
max_val = _set_->buffer[i].value;
first = false;
}
else if (_set_->f_val->cmp(_set_->buffer[i].value, max_val) > 0)
{
max_val = _set_->buffer[i].value;
}
}
}
if (value)
*value = max_val;
_set_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_set_);
return true;
}
bool CMC_(PFX, _min)(struct SNAME *_set_, V *value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_set_))
{
_set_->flag = CMC_FLAG_EMPTY;
return false;
}
bool first = true;
V min_val = (V){ 0 };
for (size_t i = 0; i < _set_->capacity; i++)
{
if (_set_->buffer[i].state == CMC_ES_FILLED)
{
if (first)
{
min_val = _set_->buffer[i].value;
first = false;
}
else if (_set_->f_val->cmp(_set_->buffer[i].value, min_val) < 0)
{
min_val = _set_->buffer[i].value;
}
}
}
if (value)
*value = min_val;
_set_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_set_);
return true;
}
size_t CMC_(PFX, _multiplicity_of)(struct SNAME *_set_, V value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct CMC_DEF_ENTRY(SNAME) *entry = CMC_(PFX, _impl_get_entry)(_set_, value);
_set_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_set_);
if (!entry)
return 0;
return entry->multiplicity;
}
bool CMC_(PFX, _contains)(struct SNAME *_set_, V value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
_set_->flag = CMC_FLAG_OK;
bool result = CMC_(PFX, _impl_get_entry)(_set_, value) != NULL;
CMC_CALLBACKS_CALL(_set_);
return result;
}
bool CMC_(PFX, _empty)(struct SNAME *_set_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _set_->count == 0;
}
bool CMC_(PFX, _full)(struct SNAME *_set_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return (double)_set_->capacity * _set_->load <= (double)_set_->count;
}
size_t CMC_(PFX, _count)(struct SNAME *_set_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _set_->count;
}
size_t CMC_(PFX, _cardinality)(struct SNAME *_set_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _set_->cardinality;
}
size_t CMC_(PFX, _capacity)(struct SNAME *_set_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _set_->capacity;
}
double CMC_(PFX, _load)(struct SNAME *_set_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _set_->load;
}
int CMC_(PFX, _flag)(struct SNAME *_set_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _set_->flag;
}
bool CMC_(PFX, _resize)(struct SNAME *_set_, size_t capacity)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
_set_->flag = CMC_FLAG_OK;
if (_set_->capacity == capacity)
goto success;
if (_set_->capacity > capacity / _set_->load)
goto success;
/* Prevent integer overflow */
if (capacity >= (double)UINTMAX_MAX * _set_->load)
{
_set_->flag = CMC_FLAG_ERROR;
return false;
}
/* Calculate required capacity based on the prime numbers */
size_t theoretical_size = CMC_(PFX, _impl_calculate_size)(capacity);
/* Not possible to shrink with current available prime numbers */
if (theoretical_size < _set_->count / _set_->load)
{
_set_->flag = CMC_FLAG_INVALID;
return false;
}
/* No callbacks since _new_set_ is just a temporary hashtable */
struct SNAME *_new_set_ = CMC_(PFX, _new_custom)(capacity, _set_->load, _set_->f_val, _set_->alloc, NULL);
if (!_new_set_)
{
_set_->flag = CMC_FLAG_ERROR;
return false;
}
for (size_t i = 0; i < _set_->capacity; i++)
{
if (_set_->buffer[i].state == CMC_ES_FILLED)
{
V value = _set_->buffer[i].value;
size_t multiplicity = _set_->buffer[i].multiplicity;
/* TODO check this for possible errors where entry == NULL */
struct CMC_DEF_ENTRY(SNAME) *entry = CMC_(PFX, _impl_insert_and_return)(_new_set_, value, NULL);
entry->multiplicity = multiplicity;
/* Setting cardinality not required, _new_set_ is temporary */
}
}
if (_set_->count != _new_set_->count)
{
CMC_(PFX, _free)(_new_set_);
_set_->flag = CMC_FLAG_ERROR;
return false;
}
struct CMC_DEF_ENTRY(SNAME) *tmp_b = _set_->buffer;
_set_->buffer = _new_set_->buffer;
_new_set_->buffer = tmp_b;
size_t tmp_c = _set_->capacity;
_set_->capacity = _new_set_->capacity;
_new_set_->capacity = tmp_c;
/* Prevent the set from freeing the data */
_new_set_->f_val = &(struct CMC_DEF_FVAL(SNAME)){ 0 };
CMC_(PFX, _free)(_new_set_);
success:
CMC_CALLBACKS_CALL(_set_);
return true;
}
struct SNAME *CMC_(PFX, _copy_of)(struct SNAME *_set_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct SNAME *result =
CMC_(PFX, _new_custom)(_set_->capacity * _set_->load, _set_->load, _set_->f_val, _set_->alloc, NULL);
if (!result)
{
_set_->flag = CMC_FLAG_ERROR;
return NULL;
}
CMC_CALLBACKS_ASSIGN(result, _set_->callbacks);
if (_set_->f_val->cpy)
{
for (size_t i = 0; i < _set_->capacity; i++)
{
struct CMC_DEF_ENTRY(SNAME) *scan = &(_set_->buffer[i]);
if (scan->state != CMC_ES_EMPTY)
{
struct CMC_DEF_ENTRY(SNAME) *target = &(result->buffer[i]);
if (scan->state == CMC_ES_DELETED)
target->state = CMC_ES_DELETED;
else
{
target->state = scan->state;
target->dist = scan->dist;
target->multiplicity = scan->multiplicity;
target->value = _set_->f_val->cpy(scan->value);
}
}
}
}
else
memcpy(result->buffer, _set_->buffer, sizeof(struct CMC_DEF_ENTRY(SNAME)) * _set_->capacity);
result->count = _set_->count;
result->cardinality = _set_->cardinality;
_set_->flag = CMC_FLAG_OK;
return result;
}
bool CMC_(PFX, _equals)(struct SNAME *_set1_, struct SNAME *_set2_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
_set1_->flag = CMC_FLAG_OK;
_set2_->flag = CMC_FLAG_OK;
if (_set1_->count != _set2_->count)
return false;
if (_set1_->cardinality != _set2_->cardinality)
return false;
if (_set1_->count == 0)
return true;
/* Optimize loop using the smallest hashtable */
struct SNAME *_set_a_;
struct SNAME *_set_b_;
_set_a_ = _set1_->capacity < _set2_->capacity ? _set1_ : _set2_;
_set_b_ = _set_a_ == _set1_ ? _set2_ : _set1_;
for (size_t i = 0; i < _set_a_->capacity; i++)
{
if (_set_a_->buffer[i].state == CMC_ES_FILLED)
{
struct CMC_DEF_ENTRY(SNAME) *entry_a = &(_set_a_->buffer[i]);
struct CMC_DEF_ENTRY(SNAME) *entry_b = CMC_(PFX, _impl_get_entry)(_set_b_, entry_a->value);
if (!entry_b)
return false;
if (entry_a->multiplicity != entry_b->multiplicity)
return false;
}
}
return true;
}
static struct CMC_DEF_ENTRY(SNAME) * CMC_(PFX, _impl_insert_and_return)(struct SNAME *_set_, V value, bool *new_node)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
/* If the entry already exists simply return it as we might do */
/* something with it. This function only guarantees that there is */
/* a valid entry for a given value */
if (new_node)
*new_node = false;
struct CMC_DEF_ENTRY(SNAME) *entry = CMC_(PFX, _impl_get_entry)(_set_, value);
if (entry != NULL)
return entry;
if (new_node)
*new_node = true;
if (CMC_(PFX, _full)(_set_))
{
if (!CMC_(PFX, _resize)(_set_, _set_->capacity + 1))
return NULL;
}
size_t hash = _set_->f_val->hash(value);
size_t original_pos = hash % _set_->capacity;
size_t pos = original_pos;
/* Current multiplicity. Might change due to robin hood hashing */
size_t curr_mul = 1;
struct CMC_DEF_ENTRY(SNAME) *target = &(_set_->buffer[pos]);
struct CMC_DEF_ENTRY(SNAME) *to_return = NULL;
if (target->state == CMC_ES_EMPTY || target->state == CMC_ES_DELETED)
{
target->value = value;
target->multiplicity = curr_mul;
target->dist = pos - original_pos;
target->state = CMC_ES_FILLED;
to_return = target;
}
else
{
while (true)
{
pos++;
target = &(_set_->buffer[pos % _set_->capacity]);
if (target->state == CMC_ES_EMPTY || target->state == CMC_ES_DELETED)
{
target->value = value;
target->multiplicity = curr_mul;
target->dist = pos - original_pos;
target->state = CMC_ES_FILLED;
if (!to_return)
to_return = target;
break;
}
else if (target->dist < pos - original_pos)
{
/* Swap everything */
V tmp = target->value;
size_t tmp_dist = target->dist;
size_t tmp_mul = target->multiplicity;
target->value = value;
target->dist = pos - original_pos;
target->multiplicity = curr_mul;
value = tmp;
original_pos = pos - tmp_dist;
curr_mul = tmp_mul;
if (!to_return)
to_return = target;
}
}
}
_set_->count++;
return to_return;
}
static struct CMC_DEF_ENTRY(SNAME) * CMC_(PFX, _impl_get_entry)(struct SNAME *_set_, V value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
size_t hash = _set_->f_val->hash(value);
size_t pos = hash % _set_->capacity;
struct CMC_DEF_ENTRY(SNAME) *target = &(_set_->buffer[pos]);
while (target->state == CMC_ES_FILLED || target->state == CMC_ES_DELETED)
{
if (target->state != CMC_ES_DELETED && _set_->f_val->cmp(target->value, value) == 0)
return target;
pos++;
target = &(_set_->buffer[pos % _set_->capacity]);
}
return NULL;
}
static size_t CMC_(PFX, _impl_calculate_size)(size_t required)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
const size_t count = sizeof(cmc_hashtable_primes) / sizeof(cmc_hashtable_primes[0]);
if (cmc_hashtable_primes[count - 1] < required)
return required;
size_t i = 0;
while (cmc_hashtable_primes[i] < required)
i++;
return cmc_hashtable_primes[i];
}
+742
View File
@@ -0,0 +1,742 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* INIT
*
* The part 'INIT' gives a new way of initializing a collection. The collection
* struct is not heap allocated, only its internal structure (nodes, buffers).
*/
#ifdef CMC_EXT_INIT
#endif /* CMC_EXT_INIT */
/**
* ITER
*
* List bi-directional iterator.
*/
#ifdef CMC_EXT_ITER
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_start)(struct SNAME *target)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct CMC_DEF_ITER(SNAME) iter;
iter.target = target;
iter.cursor = 0;
iter.index = 0;
iter.first = 0;
iter.last = 0;
iter.start = true;
iter.end = CMC_(PFX, _empty)(target);
if (!CMC_(PFX, _empty)(target))
{
for (size_t i = 0; i < target->capacity; i++)
{
if (target->buffer[i].state == CMC_ES_FILLED)
{
iter.first = i;
break;
}
}
iter.cursor = iter.first;
for (size_t i = target->capacity; i > 0; i--)
{
if (target->buffer[i - 1].state == CMC_ES_FILLED)
{
iter.last = i - 1;
break;
}
}
}
return iter;
}
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_end)(struct SNAME *target)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct CMC_DEF_ITER(SNAME) iter;
iter.target = target;
iter.cursor = 0;
iter.index = 0;
iter.first = 0;
iter.last = 0;
iter.start = CMC_(PFX, _empty)(target);
iter.end = true;
if (!CMC_(PFX, _empty)(target))
{
for (size_t i = 0; i < target->capacity; i++)
{
if (target->buffer[i].state == CMC_ES_FILLED)
{
iter.first = i;
break;
}
}
for (size_t i = target->capacity; i > 0; i--)
{
if (target->buffer[i - 1].state == CMC_ES_FILLED)
{
iter.last = i - 1;
break;
}
}
iter.cursor = iter.last;
iter.index = target->count - 1;
}
return iter;
}
bool CMC_(PFX, _iter_at_start)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return CMC_(PFX, _empty)(iter->target) || iter->start;
}
bool CMC_(PFX, _iter_at_end)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return CMC_(PFX, _empty)(iter->target) || iter->end;
}
bool CMC_(PFX, _iter_to_start)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (!CMC_(PFX, _empty)(iter->target))
{
iter->cursor = iter->first;
iter->index = 0;
iter->start = true;
iter->end = CMC_(PFX, _empty)(iter->target);
return true;
}
return false;
}
bool CMC_(PFX, _iter_to_end)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (!CMC_(PFX, _empty)(iter->target))
{
iter->cursor = iter->last;
iter->index = iter->target->count - 1;
iter->start = CMC_(PFX, _empty)(iter->target);
iter->end = true;
return true;
}
return false;
}
bool CMC_(PFX, _iter_next)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (iter->end)
return false;
if (iter->index + 1 == iter->target->count)
{
iter->end = true;
return false;
}
iter->start = CMC_(PFX, _empty)(iter->target);
struct CMC_DEF_ENTRY(SNAME) *scan = &(iter->target->buffer[iter->cursor]);
iter->index++;
while (1)
{
iter->cursor++;
scan = &(iter->target->buffer[iter->cursor]);
if (scan->state == CMC_ES_FILLED)
break;
}
return true;
}
bool CMC_(PFX, _iter_prev)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (iter->start)
return false;
if (iter->index == 0)
{
iter->start = true;
return false;
}
iter->end = CMC_(PFX, _empty)(iter->target);
struct CMC_DEF_ENTRY(SNAME) *scan = &(iter->target->buffer[iter->cursor]);
iter->index--;
while (1)
{
iter->cursor--;
scan = &(iter->target->buffer[iter->cursor]);
if (scan->state == CMC_ES_FILLED)
break;
}
return true;
}
/* Returns true only if the iterator moved */
bool CMC_(PFX, _iter_advance)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (iter->end)
return false;
if (iter->index + 1 == iter->target->count)
{
iter->end = true;
return false;
}
if (steps == 0 || iter->index + steps >= iter->target->count)
return false;
for (size_t i = 0; i < steps; i++)
CMC_(PFX, _iter_next)(iter);
return true;
}
/* Returns true only if the iterator moved */
bool CMC_(PFX, _iter_rewind)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (iter->start)
return false;
if (iter->index == 0)
{
iter->start = true;
return false;
}
if (steps == 0 || iter->index < steps)
return false;
for (size_t i = 0; i < steps; i++)
CMC_(PFX, _iter_prev)(iter);
return true;
}
/* Returns true only if the iterator was able to be positioned at the */
/* given index */
bool CMC_(PFX, _iter_go_to)(struct CMC_DEF_ITER(SNAME) * iter, size_t index)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (index >= iter->target->count)
return false;
if (iter->index > index)
return CMC_(PFX, _iter_rewind)(iter, iter->index - index);
else if (iter->index < index)
return CMC_(PFX, _iter_advance)(iter, index - iter->index);
return true;
}
V CMC_(PFX, _iter_value)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(iter->target))
return (V){ 0 };
return iter->target->buffer[iter->cursor].value;
}
size_t CMC_(PFX, _iter_multiplicity)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(iter->target))
return 0;
return iter->target->buffer[iter->cursor].multiplicity;
}
size_t CMC_(PFX, _iter_index)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return iter->index;
}
#endif /* CMC_EXT_ITER */
/**
* SETF
*
* Set functions
*/
#ifdef CMC_EXT_SETF
/* Implementation detail function */
static size_t CMC_(PFX, _impl_multiplicity_of)(struct SNAME *_set_, V value);
struct SNAME *CMC_(PFX, _union)(struct SNAME *_set1_, struct SNAME *_set2_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
/* Callbacks are added later */
struct SNAME *_set_r_ = CMC_(PFX, _new_custom)(_set1_->capacity, _set1_->load, _set1_->f_val, _set1_->alloc, NULL);
if (!_set_r_)
return NULL;
struct CMC_DEF_ITER(SNAME) iter1 = CMC_(PFX, _iter_start)(_set1_);
struct CMC_DEF_ITER(SNAME) iter2 = CMC_(PFX, _iter_start)(_set2_);
for (; !CMC_(PFX, _iter_at_end)(&iter1); CMC_(PFX, _iter_next)(&iter1))
{
V value = CMC_(PFX, _iter_value)(&iter1);
size_t m1 = CMC_(PFX, _iter_multiplicity)(&iter1);
size_t m2 = CMC_(PFX, _impl_multiplicity_of)(_set2_, value);
size_t max_ = m1 > m2 ? m1 : m2;
CMC_(PFX, _update)(_set_r_, value, max_);
}
for (; !CMC_(PFX, _iter_at_end)(&iter2); CMC_(PFX, _iter_next)(&iter2))
{
V value = CMC_(PFX, _iter_value)(&iter2);
size_t m1 = CMC_(PFX, _impl_multiplicity_of)(_set1_, value);
size_t m2 = CMC_(PFX, _iter_multiplicity)(&iter2);
size_t max_ = m1 > m2 ? m1 : m2;
CMC_(PFX, _update)(_set_r_, value, max_);
}
CMC_CALLBACKS_ASSIGN(_set_r_, _set1_->callbacks);
return _set_r_;
}
struct SNAME *CMC_(PFX, _intersection)(struct SNAME *_set1_, struct SNAME *_set2_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
/* Callbacks are added later */
struct SNAME *_set_r_ = CMC_(PFX, _new_custom)(_set1_->capacity, _set1_->load, _set1_->f_val, _set1_->alloc, NULL);
if (!_set_r_)
return NULL;
struct SNAME *_set_A_ = _set1_->count < _set2_->count ? _set1_ : _set2_;
struct SNAME *_set_B_ = _set_A_ == _set1_ ? _set2_ : _set1_;
struct CMC_DEF_ITER(SNAME) iter = CMC_(PFX, _iter_start)(_set_A_);
for (; !CMC_(PFX, _iter_at_end)(&iter); CMC_(PFX, _iter_next)(&iter))
{
V value = CMC_(PFX, _iter_value)(&iter);
size_t m1 = CMC_(PFX, _iter_multiplicity)(&iter);
size_t m2 = CMC_(PFX, _impl_multiplicity_of)(_set_B_, value);
size_t max_ = m1 < m2 ? m1 : m2;
CMC_(PFX, _update)(_set_r_, value, max_);
}
CMC_CALLBACKS_ASSIGN(_set_r_, _set1_->callbacks);
return _set_r_;
}
struct SNAME *CMC_(PFX, _difference)(struct SNAME *_set1_, struct SNAME *_set2_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
/* Callbacks are added later */
struct SNAME *_set_r_ = CMC_(PFX, _new_custom)(_set1_->capacity, _set1_->load, _set1_->f_val, _set1_->alloc, NULL);
if (!_set_r_)
return NULL;
struct CMC_DEF_ITER(SNAME) iter = CMC_(PFX, _iter_start)(_set1_);
for (; !CMC_(PFX, _iter_at_end)(&iter); CMC_(PFX, _iter_next)(&iter))
{
V value = CMC_(PFX, _iter_value)(&iter);
size_t m1 = CMC_(PFX, _iter_multiplicity)(&iter);
size_t m2 = CMC_(PFX, _impl_multiplicity_of)(_set2_, value);
if (m1 > m2)
CMC_(PFX, _update)(_set_r_, value, m1 - m2);
}
CMC_CALLBACKS_ASSIGN(_set_r_, _set1_->callbacks);
return _set_r_;
}
struct SNAME *CMC_(PFX, _summation)(struct SNAME *_set1_, struct SNAME *_set2_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
/* Callbacks are added later */
struct SNAME *_set_r_ = CMC_(PFX, _new_custom)(_set1_->capacity, _set1_->load, _set1_->f_val, _set1_->alloc, NULL);
if (!_set_r_)
return NULL;
struct CMC_DEF_ITER(SNAME) iter1 = CMC_(PFX, _iter_start)(_set1_);
struct CMC_DEF_ITER(SNAME) iter2 = CMC_(PFX, _iter_start)(_set2_);
for (; !CMC_(PFX, _iter_at_end)(&iter1); CMC_(PFX, _iter_next)(&iter1))
{
CMC_(PFX, _insert_many)
(_set_r_, CMC_(PFX, _iter_value)(&iter1), CMC_(PFX, _iter_multiplicity)(&iter1));
}
for (; !CMC_(PFX, _iter_at_end)(&iter2); CMC_(PFX, _iter_next)(&iter2))
{
CMC_(PFX, _insert_many)
(_set_r_, CMC_(PFX, _iter_value)(&iter2), CMC_(PFX, _iter_multiplicity)(&iter2));
}
CMC_CALLBACKS_ASSIGN(_set_r_, _set1_->callbacks);
return _set_r_;
}
struct SNAME *CMC_(PFX, _symmetric_difference)(struct SNAME *_set1_, struct SNAME *_set2_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
/* Callbacks are added later */
struct SNAME *_set_r_ = CMC_(PFX, _new_custom)(_set1_->capacity, _set1_->load, _set1_->f_val, _set1_->alloc, NULL);
if (!_set_r_)
return NULL;
struct CMC_DEF_ITER(SNAME) iter1 = CMC_(PFX, _iter_start)(_set1_);
struct CMC_DEF_ITER(SNAME) iter2 = CMC_(PFX, _iter_start)(_set2_);
for (; !CMC_(PFX, _iter_at_end)(&iter1); CMC_(PFX, _iter_next)(&iter1))
{
V value = CMC_(PFX, _iter_value)(&iter1);
size_t m1 = CMC_(PFX, _iter_multiplicity)(&iter1);
size_t m2 = CMC_(PFX, _impl_multiplicity_of)(_set2_, value);
if (m1 != m2)
{
if (m1 > m2)
CMC_(PFX, _update)(_set_r_, value, m1 - m2);
else
CMC_(PFX, _update)(_set_r_, value, m2 - m1);
}
}
for (; !CMC_(PFX, _iter_at_end)(&iter2); CMC_(PFX, _iter_next)(&iter2))
{
V value = CMC_(PFX, _iter_value)(&iter2);
size_t m1 = CMC_(PFX, _impl_multiplicity_of)(_set1_, value);
size_t m2 = CMC_(PFX, _iter_multiplicity)(&iter2);
if (m1 != m2)
{
if (m1 > m2)
CMC_(PFX, _update)(_set_r_, value, m1 - m2);
else
CMC_(PFX, _update)(_set_r_, value, m2 - m1);
}
}
CMC_CALLBACKS_ASSIGN(_set_r_, _set1_->callbacks);
return _set_r_;
}
bool CMC_(PFX, _is_subset)(struct SNAME *_set1_, struct SNAME *_set2_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (_set1_->count > _set2_->count)
return false;
if (CMC_(PFX, _empty)(_set1_))
return true;
struct CMC_DEF_ITER(SNAME) iter = CMC_(PFX, _iter_start)(_set1_);
for (; !CMC_(PFX, _iter_at_end)(&iter); CMC_(PFX, _iter_next)(&iter))
{
V value = CMC_(PFX, _iter_value)(&iter);
size_t m1 = CMC_(PFX, _iter_multiplicity)(&iter);
size_t m2 = CMC_(PFX, _impl_multiplicity_of)(_set2_, value);
if (m1 > m2)
return false;
}
return true;
}
bool CMC_(PFX, _is_superset)(struct SNAME *_set1_, struct SNAME *_set2_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return CMC_(PFX, _is_subset)(_set2_, _set1_);
}
bool CMC_(PFX, _is_proper_subset)(struct SNAME *_set1_, struct SNAME *_set2_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (_set1_->count >= _set2_->count)
return false;
if (CMC_(PFX, _empty)(_set1_))
{
if (!CMC_(PFX, _empty)(_set2_))
return true;
else
return false;
}
struct CMC_DEF_ITER(SNAME) iter = CMC_(PFX, _iter_start)(_set1_);
for (; !CMC_(PFX, _iter_at_end)(&iter); CMC_(PFX, _iter_next)(&iter))
{
V value = CMC_(PFX, _iter_value)(&iter);
size_t m1 = CMC_(PFX, _iter_multiplicity)(&iter);
size_t m2 = CMC_(PFX, _impl_multiplicity_of)(_set2_, value);
if (m1 >= m2)
return false;
}
return true;
}
bool CMC_(PFX, _is_proper_superset)(struct SNAME *_set1_, struct SNAME *_set2_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return CMC_(PFX, _is_proper_subset)(_set2_, _set1_);
}
bool CMC_(PFX, _is_disjointset)(struct SNAME *_set1_, struct SNAME *_set2_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_set1_))
return true;
struct CMC_DEF_ITER(SNAME) iter = CMC_(PFX, _iter_start)(_set1_);
for (; !CMC_(PFX, _iter_at_end)(&iter); CMC_(PFX, _iter_next)(&iter))
{
V value = CMC_(PFX, _iter_value)(&iter);
if (CMC_(PFX, _impl_get_entry)(_set2_, value) != NULL)
return false;
}
return true;
}
static size_t CMC_(PFX, _impl_multiplicity_of)(struct SNAME *_set_, V value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct CMC_DEF_ENTRY(SNAME) *entry = CMC_(PFX, _impl_get_entry)(_set_, value);
if (!entry)
return 0;
return entry->multiplicity;
}
#endif /* CMC_EXT_SETF */
/**
* STR
*
* Print helper functions.
*/
#ifdef CMC_EXT_STR
bool CMC_(PFX, _to_string)(struct SNAME *_set_, FILE *fptr)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct SNAME *s_ = _set_;
return 0 <= fprintf(fptr,
"struct %s<%s> "
"at %p { "
"buffer:%p, "
"capacity:%" PRIuMAX ", "
"count:%" PRIuMAX ", "
"cardinality:%" PRIuMAX ", "
"load:%lf, "
"flag:%d, "
"f_val:%p, "
"alloc:%p, "
"callbacks:%p }",
CMC_TO_STRING(SNAME), CMC_TO_STRING(V), s_, s_->buffer, s_->capacity, s_->count,
s_->cardinality, s_->load, s_->flag, s_->f_val, s_->alloc, CMC_CALLBACKS_GET(s_));
}
bool CMC_(PFX, _print)(struct SNAME *_set_, FILE *fptr, const char *start, const char *separator, const char *end,
const char *val_mul_sep)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
fprintf(fptr, "%s", start);
size_t last = 0;
for (size_t i = _set_->capacity; i > 0; i--)
{
if ((_set_->buffer[i - 1]).state == CMC_ES_FILLED)
{
last = i - 1;
break;
}
}
for (size_t i = 0; i < _set_->capacity; i++)
{
struct CMC_DEF_ENTRY(SNAME) *entry = &(_set_->buffer[i]);
if (entry->state == CMC_ES_FILLED)
{
if (!_set_->f_val->str(fptr, entry->value))
return false;
fprintf(fptr, "%s", val_mul_sep);
if (fprintf(fptr, "%" PRIuMAX "", entry->multiplicity) < 0)
return false;
if (i + 1 < last)
fprintf(fptr, "%s", separator);
}
}
fprintf(fptr, "%s", end);
return true;
}
#endif /* CMC_EXT_STR */
+95
View File
@@ -0,0 +1,95 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* INIT
*
* The part 'INIT' gives a new way of initializing a collection. The collection
* struct is not heap allocated, only its internal structure (nodes, buffers).
*/
#ifdef CMC_EXT_INIT
#endif /* CMC_EXT_INIT */
/**
* ITER
*
* List bi-directional iterator.
*/
#ifdef CMC_EXT_ITER
/* Iterator Initialization */
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_start)(struct SNAME *target);
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_end)(struct SNAME *target);
/* Iterator State */
bool CMC_(PFX, _iter_at_start)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_at_end)(struct CMC_DEF_ITER(SNAME) * iter);
/* Iterator Movement */
bool CMC_(PFX, _iter_to_start)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_to_end)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_next)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_prev)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_advance)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps);
bool CMC_(PFX, _iter_rewind)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps);
bool CMC_(PFX, _iter_go_to)(struct CMC_DEF_ITER(SNAME) * iter, size_t index);
/* Iterator Access */
V CMC_(PFX, _iter_value)(struct CMC_DEF_ITER(SNAME) * iter);
size_t CMC_(PFX, _iter_multiplicity)(struct CMC_DEF_ITER(SNAME) * iter);
size_t CMC_(PFX, _iter_index)(struct CMC_DEF_ITER(SNAME) * iter);
#endif /* CMC_EXT_ITER */
/**
* SETF
*
* Set functions
*/
#ifdef CMC_EXT_SETF
/* Set Operations */
struct SNAME *CMC_(PFX, _union)(struct SNAME *_set1_, struct SNAME *_set2_);
struct SNAME *CMC_(PFX, _intersection)(struct SNAME *_set1_, struct SNAME *_set2_);
struct SNAME *CMC_(PFX, _difference)(struct SNAME *_set1_, struct SNAME *_set2_);
struct SNAME *CMC_(PFX, _summation)(struct SNAME *_set1_, struct SNAME *_set2_);
struct SNAME *CMC_(PFX, _symmetric_difference)(struct SNAME *_set1_, struct SNAME *_set2_);
bool CMC_(PFX, _is_subset)(struct SNAME *_set1_, struct SNAME *_set2_);
bool CMC_(PFX, _is_superset)(struct SNAME *_set1_, struct SNAME *_set2_);
bool CMC_(PFX, _is_proper_subset)(struct SNAME *_set1_, struct SNAME *_set2_);
bool CMC_(PFX, _is_proper_superset)(struct SNAME *_set1_, struct SNAME *_set2_);
bool CMC_(PFX, _is_disjointset)(struct SNAME *_set1_, struct SNAME *_set2_);
#endif /* CMC_EXT_SETF */
/**
* STR
*
* Print helper functions.
*/
#ifdef CMC_EXT_STR
bool CMC_(PFX, _to_string)(struct SNAME *_set_, FILE *fptr);
bool CMC_(PFX, _print)(struct SNAME *_set_, FILE *fptr, const char *start, const char *separator, const char *end,
const char *key_val_sep);
#endif /* CMC_EXT_STR */
+57
View File
@@ -0,0 +1,57 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* ITER
*
* Hashmultiset bi-directional iterator.
*/
#ifdef CMC_EXT_ITER
/* HashMultiSet Iterator */
struct CMC_DEF_ITER(SNAME)
{
/* Target HashMultiset */
struct SNAME *target;
/* Cursor's position (index) */
size_t cursor;
/* Keeps track of relative index to the iteration of elements */
size_t index;
/* The index of the first element */
size_t first;
/* The index of the last element */
size_t last;
/* If the iterator has reached the start of the iteration */
bool start;
/* If the iterator has reached the end of the iteration */
bool end;
};
#endif /* CMC_EXT_ITER */
+72
View File
@@ -0,0 +1,72 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/* Value struct function table */
struct CMC_DEF_FVAL(SNAME)
{
/* Comparator function */
CMC_DEF_FTAB_CMP(V);
/* Copy function */
CMC_DEF_FTAB_CPY(V);
/* To string function */
CMC_DEF_FTAB_STR(V);
/* Free from memory function */
CMC_DEF_FTAB_FREE(V);
/* Hash function */
CMC_DEF_FTAB_HASH(V);
/* Priority function */
CMC_DEF_FTAB_PRI(V);
};
/* Collection Allocation and Deallocation */
struct SNAME *CMC_(PFX, _new)(size_t capacity, double load, struct CMC_DEF_FVAL(SNAME) * f_val);
struct SNAME *CMC_(PFX, _new_custom)(size_t capacity, double load, struct CMC_DEF_FVAL(SNAME) * f_val,
CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks);
void CMC_(PFX, _clear)(struct SNAME *_set_);
void CMC_(PFX, _free)(struct SNAME *_set_);
/* Customization of Allocation and Callbacks */
void CMC_(PFX, _customize)(struct SNAME *_set_, CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks);
/* Collection Input and Output */
bool CMC_(PFX, _insert)(struct SNAME *_set_, V value);
bool CMC_(PFX, _insert_many)(struct SNAME *_set_, V value, size_t count);
bool CMC_(PFX, _update)(struct SNAME *_set_, V value, size_t multiplicity);
bool CMC_(PFX, _remove)(struct SNAME *_set_, V value);
size_t CMC_(PFX, _remove_all)(struct SNAME *_set_, V value);
/* Element Access */
bool CMC_(PFX, _max)(struct SNAME *_set_, V *value);
bool CMC_(PFX, _min)(struct SNAME *_set_, V *value);
size_t CMC_(PFX, _multiplicity_of)(struct SNAME *_set_, V value);
/* Collection State */
bool CMC_(PFX, _contains)(struct SNAME *_set_, V value);
bool CMC_(PFX, _empty)(struct SNAME *_set_);
bool CMC_(PFX, _full)(struct SNAME *_set_);
size_t CMC_(PFX, _count)(struct SNAME *_set_);
size_t CMC_(PFX, _cardinality)(struct SNAME *_set_);
size_t CMC_(PFX, _capacity)(struct SNAME *_set_);
double CMC_(PFX, _load)(struct SNAME *_set_);
int CMC_(PFX, _flag)(struct SNAME *_set_);
/* Collection Utility */
bool CMC_(PFX, _resize)(struct SNAME *_set_, size_t capacity);
struct SNAME *CMC_(PFX, _copy_of)(struct SNAME *_set_);
bool CMC_(PFX, _equals)(struct SNAME *_set1_, struct SNAME *_set2_);
+58
View File
@@ -0,0 +1,58 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
struct SNAME
{
/* Array of Entries */
struct CMC_DEF_ENTRY(SNAME) * buffer;
/* Current Array Capcity */
size_t capacity;
/* Current amount of unique elements */
size_t count;
/* Total amount of elements taking into account their multiplicity */
size_t cardinality;
/* Load factor in range (0.0, 1.0) */
double load;
/* Flags indicating errors or success */
int flag;
/* Key function table */
struct CMC_DEF_FVAL(SNAME) * f_val;
/* Custom allocation functions */
CMC_ALLOC_TYPE alloc;
/* Custom callback functions */
CMC_CALLBACKS_DECL;
};
struct CMC_DEF_ENTRY(SNAME)
{
/* Entry element */
V value;
/* The element's multiplicity */
size_t multiplicity;
/* The distance of this node to its original position, used by */
/* robin-hood hashing */
size_t dist;
/* The sate of this node (DELETED, EMPTY, FILLED) */
enum cmc_entry_state state;
};
+81
View File
@@ -0,0 +1,81 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* hashset.h
*
* Creation Date: 01/04/2019
*
* Authors:
* Leonardo Vencovsky (https://github.com/LeoVen)
*
*/
/**
* HashSet
*
* A HashSet is an implementation of a Set with unique keys. The keys are not
* sorted. It is implemented as a flat hashtable with linear probing and robin
* hood hashing.
*/
#include "cor/core.h"
#include "cor/hashtable.h"
#ifdef CMC_DEV
#include "utl/log.h"
#endif
/**
* Used values
* V - hashset value data type
* SNAME - struct name and prefix of other related structs
* PFX - functions prefix
*/
/* Structs definition */
#include "cmc/hashset/struct.h"
/* Function declaration */
#include "cmc/hashset/header.h"
/* Function implementation */
#include "cmc/hashset/code.h"
/**
* Extensions
*
* INIT - Initializes the struct on the stack
* ITER - hashset iterator
* STR - Print helper functions
*/
#define CMC_EXT_HASHSET_PARTS ITER, SETF, STR
/**/
#include "cmc/hashset/ext/struct.h"
/**/
#include "cmc/hashset/ext/header.h"
/**/
#include "cmc/hashset/ext/code.h"
#include "cor/undef.h"
+602
View File
@@ -0,0 +1,602 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/* Implementation Detail Functions */
static struct CMC_DEF_ENTRY(SNAME) * CMC_(PFX, _impl_get_entry)(struct SNAME *_set_, V value);
static size_t CMC_(PFX, _impl_calculate_size)(size_t required);
struct SNAME *CMC_(PFX, _new)(size_t capacity, double load, struct CMC_DEF_FVAL(SNAME) * f_val)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return CMC_(PFX, _new_custom)(capacity, load, f_val, NULL, NULL);
}
struct SNAME *CMC_(PFX, _new_custom)(size_t capacity, double load, struct CMC_DEF_FVAL(SNAME) * f_val,
CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
if (capacity == 0 || load <= 0 || load >= 1)
return NULL;
/* Prevent integer overflow */
if (capacity >= (double)UINTMAX_MAX * load)
return NULL;
if (!f_val)
return NULL;
size_t real_capacity = CMC_(PFX, _impl_calculate_size)(capacity / load);
if (!alloc)
alloc = &cmc_alloc_node_default;
struct SNAME *_set_ = alloc->malloc(sizeof(struct SNAME));
if (!_set_)
return NULL;
_set_->buffer = alloc->calloc(real_capacity, sizeof(struct CMC_DEF_ENTRY(SNAME)));
if (!_set_->buffer)
{
alloc->free(_set_);
return NULL;
}
_set_->count = 0;
_set_->capacity = real_capacity;
_set_->load = load;
_set_->flag = CMC_FLAG_OK;
_set_->f_val = f_val;
_set_->alloc = alloc;
CMC_CALLBACKS_ASSIGN(_set_, callbacks);
return _set_;
}
void CMC_(PFX, _clear)(struct SNAME *_set_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (_set_->f_val->free)
{
for (size_t i = 0; i < _set_->capacity; i++)
{
struct CMC_DEF_ENTRY(SNAME) *entry = &(_set_->buffer[i]);
if (entry->state == CMC_ES_FILLED)
{
_set_->f_val->free(entry->value);
}
}
}
memset(_set_->buffer, 0, sizeof(struct CMC_DEF_ENTRY(SNAME)) * _set_->capacity);
_set_->count = 0;
_set_->flag = CMC_FLAG_OK;
}
void CMC_(PFX, _free)(struct SNAME *_set_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (_set_->f_val->free)
{
for (size_t i = 0; i < _set_->capacity; i++)
{
struct CMC_DEF_ENTRY(SNAME) *entry = &(_set_->buffer[i]);
if (entry->state == CMC_ES_FILLED)
{
_set_->f_val->free(entry->value);
}
}
}
_set_->alloc->free(_set_->buffer);
_set_->alloc->free(_set_);
}
void CMC_(PFX, _customize)(struct SNAME *_set_, CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
if (!alloc)
_set_->alloc = &cmc_alloc_node_default;
else
_set_->alloc = alloc;
CMC_CALLBACKS_ASSIGN(_set_, callbacks);
_set_->flag = CMC_FLAG_OK;
}
bool CMC_(PFX, _insert)(struct SNAME *_set_, V value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _full)(_set_))
{
if (!CMC_(PFX, _resize)(_set_, _set_->capacity + 1))
return false;
}
if (CMC_(PFX, _impl_get_entry)(_set_, value) != NULL)
{
_set_->flag = CMC_FLAG_DUPLICATE;
return false;
}
size_t hash = _set_->f_val->hash(value);
size_t original_pos = hash % _set_->capacity;
size_t pos = original_pos;
struct CMC_DEF_ENTRY(SNAME) *target = &(_set_->buffer[pos]);
if (target->state == CMC_ES_EMPTY || target->state == CMC_ES_DELETED)
{
target->value = value;
target->dist = 0;
target->state = CMC_ES_FILLED;
}
else
{
while (true)
{
pos++;
target = &(_set_->buffer[pos % _set_->capacity]);
if (target->state == CMC_ES_EMPTY || target->state == CMC_ES_DELETED)
{
target->value = value;
target->dist = pos - original_pos;
target->state = CMC_ES_FILLED;
break;
}
else if (target->dist < pos - original_pos)
{
V tmp = target->value;
size_t tmp_dist = target->dist;
target->value = value;
target->dist = pos - original_pos;
value = tmp;
original_pos = pos - tmp_dist;
}
}
}
_set_->count++;
_set_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_set_);
return true;
}
bool CMC_(PFX, _remove)(struct SNAME *_set_, V value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_set_))
{
_set_->flag = CMC_FLAG_EMPTY;
return false;
}
struct CMC_DEF_ENTRY(SNAME) *result = CMC_(PFX, _impl_get_entry)(_set_, value);
if (result == NULL)
{
_set_->flag = CMC_FLAG_NOT_FOUND;
return false;
}
result->value = (V){ 0 };
result->dist = 0;
result->state = CMC_ES_DELETED;
_set_->count--;
_set_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_set_);
return true;
}
bool CMC_(PFX, _max)(struct SNAME *_set_, V *value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_set_))
{
_set_->flag = CMC_FLAG_EMPTY;
return false;
}
bool first = true;
V max_val = (V){ 0 };
for (size_t i = 0; i < _set_->capacity; i++)
{
if (_set_->buffer[i].state == CMC_ES_FILLED)
{
if (first)
{
max_val = _set_->buffer[i].value;
first = false;
}
else if (_set_->f_val->cmp(_set_->buffer[i].value, max_val) > 0)
{
max_val = _set_->buffer[i].value;
}
}
}
if (value)
*value = max_val;
_set_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_set_);
return true;
}
bool CMC_(PFX, _min)(struct SNAME *_set_, V *value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_set_))
{
_set_->flag = CMC_FLAG_EMPTY;
return false;
}
bool first = true;
V min_val = (V){ 0 };
for (size_t i = 0; i < _set_->capacity; i++)
{
if (_set_->buffer[i].state == CMC_ES_FILLED)
{
if (first)
{
min_val = _set_->buffer[i].value;
first = false;
}
else if (_set_->f_val->cmp(_set_->buffer[i].value, min_val) < 0)
{
min_val = _set_->buffer[i].value;
}
}
}
if (value)
*value = min_val;
_set_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_set_);
return true;
}
bool CMC_(PFX, _contains)(struct SNAME *_set_, V value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
_set_->flag = CMC_FLAG_OK;
bool result = CMC_(PFX, _impl_get_entry)(_set_, value) != NULL;
CMC_CALLBACKS_CALL(_set_);
return result;
}
bool CMC_(PFX, _empty)(struct SNAME *_set_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _set_->count == 0;
}
bool CMC_(PFX, _full)(struct SNAME *_set_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return (double)_set_->capacity * _set_->load <= (double)_set_->count;
}
size_t CMC_(PFX, _count)(struct SNAME *_set_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _set_->count;
}
size_t CMC_(PFX, _capacity)(struct SNAME *_set_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _set_->capacity;
}
double CMC_(PFX, _load)(struct SNAME *_set_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _set_->load;
}
int CMC_(PFX, _flag)(struct SNAME *_set_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _set_->flag;
}
bool CMC_(PFX, _resize)(struct SNAME *_set_, size_t capacity)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
_set_->flag = CMC_FLAG_OK;
if (_set_->capacity == capacity)
goto success;
if (_set_->capacity > capacity / _set_->load)
goto success;
/* Prevent integer overflow */
if (capacity >= (double)UINTMAX_MAX * _set_->load)
{
_set_->flag = CMC_FLAG_ERROR;
return false;
}
/* Calculate required capacity based on the prime numbers */
size_t theoretical_size = CMC_(PFX, _impl_calculate_size)(capacity);
/* Not possible to shrink with current available prime numbers */
if (theoretical_size < _set_->count / _set_->load)
{
_set_->flag = CMC_FLAG_INVALID;
return false;
}
/* No callbacks since _new_set_ is just a temporary hashtable */
struct SNAME *_new_set_ = CMC_(PFX, _new_custom)(capacity, _set_->load, _set_->f_val, _set_->alloc, NULL);
if (!_new_set_)
{
_set_->flag = CMC_FLAG_ALLOC;
return false;
}
for (size_t i = 0; i < _set_->capacity; i++)
{
if (_set_->buffer[i].state == CMC_ES_FILLED)
{
V value = _set_->buffer[i].value;
/* TODO check this for possible errors */
CMC_(PFX, _insert)(_new_set_, value);
}
}
/* Unlikely */
if (_set_->count != _new_set_->count)
{
CMC_(PFX, _free)(_new_set_);
_set_->flag = CMC_FLAG_ERROR;
return false;
}
struct CMC_DEF_ENTRY(SNAME) *tmp_b = _set_->buffer;
_set_->buffer = _new_set_->buffer;
_new_set_->buffer = tmp_b;
size_t tmp_c = _set_->capacity;
_set_->capacity = _new_set_->capacity;
_new_set_->capacity = tmp_c;
/* Prevent the set from freeing the data */
_new_set_->f_val = &(struct CMC_DEF_FVAL(SNAME)){ 0 };
CMC_(PFX, _free)(_new_set_);
success:
CMC_CALLBACKS_CALL(_set_);
return true;
}
struct SNAME *CMC_(PFX, _copy_of)(struct SNAME *_set_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct SNAME *result =
CMC_(PFX, _new_custom)(_set_->capacity * _set_->load, _set_->load, _set_->f_val, _set_->alloc, NULL);
if (!result)
{
_set_->flag = CMC_FLAG_ERROR;
return NULL;
}
CMC_CALLBACKS_ASSIGN(result, _set_->callbacks);
if (_set_->f_val->cpy)
{
for (size_t i = 0; i < _set_->capacity; i++)
{
struct CMC_DEF_ENTRY(SNAME) *scan = &(_set_->buffer[i]);
if (scan->state != CMC_ES_EMPTY)
{
struct CMC_DEF_ENTRY(SNAME) *target = &(result->buffer[i]);
if (scan->state == CMC_ES_DELETED)
target->state = CMC_ES_DELETED;
else
{
target->state = scan->state;
target->dist = scan->dist;
target->value = _set_->f_val->cpy(scan->value);
}
}
}
}
else
memcpy(result->buffer, _set_->buffer, sizeof(struct CMC_DEF_ENTRY(SNAME)) * _set_->capacity);
result->count = _set_->count;
_set_->flag = CMC_FLAG_OK;
return result;
}
bool CMC_(PFX, _equals)(struct SNAME *_set1_, struct SNAME *_set2_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
_set1_->flag = CMC_FLAG_OK;
_set2_->flag = CMC_FLAG_OK;
if (_set1_->count != _set2_->count)
return false;
/* Optimize loop using the smallest hashtable */
struct SNAME *_set_a_;
struct SNAME *_set_b_;
_set_a_ = _set1_->capacity < _set2_->capacity ? _set1_ : _set2_;
_set_b_ = _set_a_ == _set1_ ? _set2_ : _set1_;
for (size_t i = 0; i < _set_a_->capacity; i++)
{
if (_set_a_->buffer[i].state == CMC_ES_FILLED)
{
if (!CMC_(PFX, _impl_get_entry)(_set_b_, _set_a_->buffer[i].value))
return false;
}
}
return true;
}
static struct CMC_DEF_ENTRY(SNAME) * CMC_(PFX, _impl_get_entry)(struct SNAME *_set_, V value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
size_t hash = _set_->f_val->hash(value);
size_t pos = hash % _set_->capacity;
struct CMC_DEF_ENTRY(SNAME) *target = &(_set_->buffer[pos]);
while (target->state == CMC_ES_FILLED || target->state == CMC_ES_DELETED)
{
if (target->state != CMC_ES_DELETED && _set_->f_val->cmp(target->value, value) == 0)
return target;
pos++;
target = &(_set_->buffer[pos % _set_->capacity]);
}
return NULL;
}
static size_t CMC_(PFX, _impl_calculate_size)(size_t required)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
const size_t count = sizeof(cmc_hashtable_primes) / sizeof(cmc_hashtable_primes[0]);
if (cmc_hashtable_primes[count - 1] < required)
return required;
size_t i = 0;
while (cmc_hashtable_primes[i] < required)
i++;
return cmc_hashtable_primes[i];
}
+687
View File
@@ -0,0 +1,687 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* INIT
*
* The part 'INIT' gives a new way of initializing a collection. The collection
* struct is not heap allocated, only its internal structure (nodes, buffers).
*/
#ifdef CMC_EXT_INIT
#endif /* CMC_EXT_INIT */
/**
* ITER
*
* Hashset bi-directional iterator.
*/
#ifdef CMC_EXT_ITER
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_start)(struct SNAME *target)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct CMC_DEF_ITER(SNAME) iter;
iter.target = target;
iter.cursor = 0;
iter.index = 0;
iter.first = 0;
iter.last = 0;
iter.start = true;
iter.end = CMC_(PFX, _empty)(target);
if (!CMC_(PFX, _empty)(target))
{
for (size_t i = 0; i < target->capacity; i++)
{
if (target->buffer[i].state == CMC_ES_FILLED)
{
iter.first = i;
break;
}
}
iter.cursor = iter.first;
for (size_t i = target->capacity; i > 0; i--)
{
if (target->buffer[i - 1].state == CMC_ES_FILLED)
{
iter.last = i - 1;
break;
}
}
}
return iter;
}
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_end)(struct SNAME *target)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct CMC_DEF_ITER(SNAME) iter;
iter.target = target;
iter.cursor = 0;
iter.index = 0;
iter.first = 0;
iter.last = 0;
iter.start = CMC_(PFX, _empty)(target);
iter.end = true;
if (!CMC_(PFX, _empty)(target))
{
for (size_t i = 0; i < target->capacity; i++)
{
if (target->buffer[i].state == CMC_ES_FILLED)
{
iter.first = i;
break;
}
}
for (size_t i = target->capacity; i > 0; i--)
{
if (target->buffer[i - 1].state == CMC_ES_FILLED)
{
iter.last = i - 1;
break;
}
}
iter.cursor = iter.last;
iter.index = target->count - 1;
}
return iter;
}
bool CMC_(PFX, _iter_at_start)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return CMC_(PFX, _empty)(iter->target) || iter->start;
}
bool CMC_(PFX, _iter_at_end)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return CMC_(PFX, _empty)(iter->target) || iter->end;
}
bool CMC_(PFX, _iter_to_start)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (!CMC_(PFX, _empty)(iter->target))
{
iter->cursor = iter->first;
iter->index = 0;
iter->start = true;
iter->end = CMC_(PFX, _empty)(iter->target);
return true;
}
return false;
}
bool CMC_(PFX, _iter_to_end)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (!CMC_(PFX, _empty)(iter->target))
{
iter->cursor = iter->last;
iter->index = iter->target->count - 1;
iter->start = CMC_(PFX, _empty)(iter->target);
iter->end = true;
return true;
}
return false;
}
bool CMC_(PFX, _iter_next)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (iter->end)
return false;
if (iter->index + 1 == iter->target->count)
{
iter->end = true;
return false;
}
iter->start = CMC_(PFX, _empty)(iter->target);
struct CMC_DEF_ENTRY(SNAME) *scan = &(iter->target->buffer[iter->cursor]);
iter->index++;
while (1)
{
iter->cursor++;
scan = &(iter->target->buffer[iter->cursor]);
if (scan->state == CMC_ES_FILLED)
break;
}
return true;
}
bool CMC_(PFX, _iter_prev)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (iter->start)
return false;
if (iter->index == 0)
{
iter->start = true;
return false;
}
iter->end = CMC_(PFX, _empty)(iter->target);
struct CMC_DEF_ENTRY(SNAME) *scan = &(iter->target->buffer[iter->cursor]);
iter->index--;
while (1)
{
iter->cursor--;
scan = &(iter->target->buffer[iter->cursor]);
if (scan->state == CMC_ES_FILLED)
break;
}
return true;
}
/* Returns true only if the iterator moved */
bool CMC_(PFX, _iter_advance)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (iter->end)
return false;
if (iter->index + 1 == iter->target->count)
{
iter->end = true;
return false;
}
if (steps == 0 || iter->index + steps >= iter->target->count)
return false;
for (size_t i = 0; i < steps; i++)
CMC_(PFX, _iter_next)(iter);
return true;
}
/* Returns true only if the iterator moved */
bool CMC_(PFX, _iter_rewind)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (iter->start)
return false;
if (iter->index == 0)
{
iter->start = true;
return false;
}
if (steps == 0 || iter->index < steps)
return false;
for (size_t i = 0; i < steps; i++)
CMC_(PFX, _iter_prev)(iter);
return true;
}
/* Returns true only if the iterator was able to be positioned at the */
/* given index */
bool CMC_(PFX, _iter_go_to)(struct CMC_DEF_ITER(SNAME) * iter, size_t index)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (index >= iter->target->count)
return false;
if (iter->index > index)
return CMC_(PFX, _iter_rewind)(iter, iter->index - index);
else if (iter->index < index)
return CMC_(PFX, _iter_advance)(iter, index - iter->index);
return true;
}
V CMC_(PFX, _iter_value)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(iter->target))
return (V){ 0 };
return iter->target->buffer[iter->cursor].value;
}
size_t CMC_(PFX, _iter_index)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return iter->index;
}
#endif /* CMC_EXT_ITER */
/**
* SETF
*
* Set functions
*/
#ifdef CMC_EXT_SETF
struct SNAME *CMC_(PFX, _union)(struct SNAME *_set1_, struct SNAME *_set2_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
/* Callbacks are added later */
struct SNAME *_set_r_ = CMC_(PFX, _new_custom)(_set1_->capacity, _set1_->load, _set1_->f_val, _set1_->alloc, NULL);
if (!_set_r_)
{
_set1_->flag = CMC_FLAG_ALLOC;
_set2_->flag = CMC_FLAG_ALLOC;
return NULL;
}
struct CMC_DEF_ITER(SNAME) iter1 = CMC_(PFX, _iter_start)(_set1_);
struct CMC_DEF_ITER(SNAME) iter2 = CMC_(PFX, _iter_start)(_set2_);
/* TODO turn this into a normal loop and check for errors */
for (; !CMC_(PFX, _iter_at_end)(&iter1); CMC_(PFX, _iter_next)(&iter1))
{
CMC_(PFX, _insert)(_set_r_, CMC_(PFX, _iter_value)(&iter1));
}
for (; !CMC_(PFX, _iter_at_end)(&iter2); CMC_(PFX, _iter_next)(&iter2))
{
CMC_(PFX, _insert)(_set_r_, CMC_(PFX, _iter_value)(&iter2));
}
CMC_CALLBACKS_ASSIGN(_set_r_, _set1_->callbacks);
return _set_r_;
}
struct SNAME *CMC_(PFX, _intersection)(struct SNAME *_set1_, struct SNAME *_set2_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
/* Callbacks are added later */
struct SNAME *_set_r_ = CMC_(PFX, _new_custom)(_set1_->capacity, _set1_->load, _set1_->f_val, _set1_->alloc, NULL);
if (!_set_r_)
{
_set1_->flag = CMC_FLAG_ALLOC;
_set2_->flag = CMC_FLAG_ALLOC;
return NULL;
}
struct SNAME *_set_A_ = _set1_->count < _set2_->count ? _set1_ : _set2_;
struct SNAME *_set_B_ = _set_A_ == _set1_ ? _set2_ : _set1_;
struct CMC_DEF_ITER(SNAME) iter = CMC_(PFX, _iter_start)(_set_A_);
for (; !CMC_(PFX, _iter_at_end)(&iter); CMC_(PFX, _iter_next)(&iter))
{
V value = CMC_(PFX, _iter_value)(&iter);
if (CMC_(PFX, _impl_get_entry)(_set_B_, value) != NULL)
CMC_(PFX, _insert)(_set_r_, value);
}
CMC_CALLBACKS_ASSIGN(_set_r_, _set1_->callbacks);
return _set_r_;
}
struct SNAME *CMC_(PFX, _difference)(struct SNAME *_set1_, struct SNAME *_set2_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
/* Callbacks are added later */
struct SNAME *_set_r_ = CMC_(PFX, _new_custom)(_set1_->capacity, _set1_->load, _set1_->f_val, _set1_->alloc, NULL);
if (!_set_r_)
{
_set1_->flag = CMC_FLAG_ALLOC;
_set2_->flag = CMC_FLAG_ALLOC;
return NULL;
}
struct CMC_DEF_ITER(SNAME) iter = CMC_(PFX, _iter_start)(_set1_);
for (; !CMC_(PFX, _iter_at_end)(&iter); CMC_(PFX, _iter_next)(&iter))
{
V value = CMC_(PFX, _iter_value)(&iter);
if (CMC_(PFX, _impl_get_entry)(_set2_, value) == NULL)
CMC_(PFX, _insert)(_set_r_, value);
}
CMC_CALLBACKS_ASSIGN(_set_r_, _set1_->callbacks);
return _set_r_;
}
struct SNAME *CMC_(PFX, _symmetric_difference)(struct SNAME *_set1_, struct SNAME *_set2_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
/* Callbacks are added later */
struct SNAME *_set_r_ = CMC_(PFX, _new_custom)(_set1_->capacity, _set1_->load, _set1_->f_val, _set1_->alloc, NULL);
if (!_set_r_)
{
_set1_->flag = CMC_FLAG_ALLOC;
_set2_->flag = CMC_FLAG_ALLOC;
return NULL;
}
struct CMC_DEF_ITER(SNAME) iter1 = CMC_(PFX, _iter_start)(_set1_);
struct CMC_DEF_ITER(SNAME) iter2 = CMC_(PFX, _iter_start)(_set2_);
for (; !CMC_(PFX, _iter_at_end)(&iter1); CMC_(PFX, _iter_next)(&iter1))
{
V value = CMC_(PFX, _iter_value)(&iter1);
if (CMC_(PFX, _impl_get_entry)(_set2_, value) == NULL)
CMC_(PFX, _insert)(_set_r_, value);
}
for (; !CMC_(PFX, _iter_at_end)(&iter2); CMC_(PFX, _iter_next)(&iter2))
{
V value = CMC_(PFX, _iter_value)(&iter2);
if (CMC_(PFX, _impl_get_entry)(_set1_, value) == NULL)
CMC_(PFX, _insert)(_set_r_, value);
}
CMC_CALLBACKS_ASSIGN(_set_r_, _set1_->callbacks);
return _set_r_;
}
/* Is _set1_ a subset of _set2_ ? */
/* A set X is a subset of a set Y when: X <= Y */
/* If X is a subset of Y, then Y is a superset of X */
bool CMC_(PFX, _is_subset)(struct SNAME *_set1_, struct SNAME *_set2_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
_set1_->flag = CMC_FLAG_OK;
_set2_->flag = CMC_FLAG_OK;
/* If the cardinality of _set1_ is greater than that of _set2_, */
/* then it is safe to say that _set1_ can't be a subset of _set2_ */
if (_set1_->count > _set2_->count)
return false;
/* The empty set is a subset of all sets */
if (CMC_(PFX, _empty)(_set1_))
return true;
struct CMC_DEF_ITER(SNAME) iter = CMC_(PFX, _iter_start)(_set1_);
for (; !CMC_(PFX, _iter_at_end)(&iter); CMC_(PFX, _iter_next)(&iter))
{
V value = CMC_(PFX, _iter_value)(&iter);
if (CMC_(PFX, _impl_get_entry)(_set2_, value) == NULL)
return false;
}
return true;
}
/* Is _set1_ a superset of _set2_ ? */
/* A set X is a superset of a set Y when: X >= Y */
/* If X is a superset of Y, then Y is a subset of X */
bool CMC_(PFX, _is_superset)(struct SNAME *_set1_, struct SNAME *_set2_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return CMC_(PFX, _is_subset)(_set2_, _set1_);
}
/* Is _set1_ a proper subset of _set2_ ? */
/* A set X is a proper subset of a set Y when: X < Y */
/* If X is a proper subset of Y, then Y is a proper superset of X */
bool CMC_(PFX, _is_proper_subset)(struct SNAME *_set1_, struct SNAME *_set2_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
_set1_->flag = CMC_FLAG_OK;
_set2_->flag = CMC_FLAG_OK;
/* If the cardinality of _set1_ is greater than or equal to that of */
/* _set2_, then it is safe to say that _set1_ can't be a proper */
/* subset of _set2_ */
if (_set1_->count >= _set2_->count)
return false;
if (CMC_(PFX, _empty)(_set1_))
{
/* The empty set is a proper subset of all non-empty sets */
if (!CMC_(PFX, _empty)(_set2_))
return true;
/* The empty set is not a proper subset of itself (this is true */
/* for any set) */
else
return false;
}
struct CMC_DEF_ITER(SNAME) iter = CMC_(PFX, _iter_start)(_set1_);
for (; !CMC_(PFX, _iter_at_end)(&iter); CMC_(PFX, _iter_next)(&iter))
{
V value = CMC_(PFX, _iter_value)(&iter);
if (CMC_(PFX, _impl_get_entry)(_set2_, value) == NULL)
return false;
}
return true;
}
/* Is _set1_ a proper superset of _set2_ ? */
/* A set X is a proper superset of a set Y when: X > Y */
/* If X is a proper superset of Y, then Y is a proper subset of X */
bool CMC_(PFX, _is_proper_superset)(struct SNAME *_set1_, struct SNAME *_set2_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return CMC_(PFX, _is_proper_subset)(_set2_, _set1_);
}
/* Is _set1_ a disjointset of _set2_ ? */
/* A set X is a disjointset of a set Y if their intersection is empty, */
/* that is, if there are no elements in common between the two */
bool CMC_(PFX, _is_disjointset)(struct SNAME *_set1_, struct SNAME *_set2_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
_set1_->flag = CMC_FLAG_OK;
_set2_->flag = CMC_FLAG_OK;
/* The intersection of an empty set with any other set will result */
/* in an empty set */
if (CMC_(PFX, _empty)(_set1_))
return true;
struct CMC_DEF_ITER(SNAME) iter = CMC_(PFX, _iter_start)(_set1_);
for (; !CMC_(PFX, _iter_at_end)(&iter); CMC_(PFX, _iter_next)(&iter))
{
V value = CMC_(PFX, _iter_value)(&iter);
if (CMC_(PFX, _impl_get_entry)(_set2_, value) != NULL)
return false;
}
return true;
}
#endif /* CMC_EXT_SETF */
/**
* STR
*
* Print helper functions.
*/
#ifdef CMC_EXT_STR
bool CMC_(PFX, _to_string)(struct SNAME *_set_, FILE *fptr)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct SNAME *s_ = _set_;
return 0 <= fprintf(fptr,
"struct %s<%s> "
"at %p { "
"buffer:%p, "
"capacity:%" PRIuMAX ", "
"count:%" PRIuMAX ", "
"load:%lf, "
"flag:%d, "
"f_val:%p, "
"alloc:%p, "
"callbacks: %p }",
CMC_TO_STRING(SNAME), CMC_TO_STRING(V), s_, s_->buffer, s_->capacity, s_->count, s_->load,
s_->flag, s_->f_val, s_->alloc, CMC_CALLBACKS_GET(s_));
}
bool CMC_(PFX, _print)(struct SNAME *_set_, FILE *fptr, const char *start, const char *separator, const char *end)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
fprintf(fptr, "%s", start);
size_t last = 0;
for (size_t i = _set_->capacity; i > 0; i--)
{
if ((_set_->buffer[i - 1]).state == CMC_ES_FILLED)
{
last = i - 1;
break;
}
}
for (size_t i = 0; i < _set_->capacity; i++)
{
struct CMC_DEF_ENTRY(SNAME) *entry = &(_set_->buffer[i]);
if (entry->state == CMC_ES_FILLED)
{
if (!_set_->f_val->str(fptr, entry->value))
return false;
if (i + 1 < last)
fprintf(fptr, "%s", separator);
}
}
fprintf(fptr, "%s", end);
return true;
}
#endif /* CMC_EXT_STR */
+92
View File
@@ -0,0 +1,92 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* INIT
*
* The part 'INIT' gives a new way of initializing a collection. The collection
* struct is not heap allocated, only its internal structure (nodes, buffers).
*/
#ifdef CMC_EXT_INIT
#endif /* CMC_EXT_INIT */
/**
* ITER
*
* List bi-directional iterator.
*/
#ifdef CMC_EXT_ITER
/* Iterator Initialization */
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_start)(struct SNAME *target);
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_end)(struct SNAME *target);
/* Iterator State */
bool CMC_(PFX, _iter_at_start)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_at_end)(struct CMC_DEF_ITER(SNAME) * iter);
/* Iterator Movement */
bool CMC_(PFX, _iter_to_start)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_to_end)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_next)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_prev)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_advance)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps);
bool CMC_(PFX, _iter_rewind)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps);
bool CMC_(PFX, _iter_go_to)(struct CMC_DEF_ITER(SNAME) * iter, size_t index);
/* Iterator Access */
V CMC_(PFX, _iter_value)(struct CMC_DEF_ITER(SNAME) * iter);
size_t CMC_(PFX, _iter_index)(struct CMC_DEF_ITER(SNAME) * iter);
#endif /* CMC_EXT_ITER */
/**
* SETF
*
* Set functions
*/
#ifdef CMC_EXT_SETF
/* Set Operations */
struct SNAME *CMC_(PFX, _union)(struct SNAME *_set1_, struct SNAME *_set2_);
struct SNAME *CMC_(PFX, _intersection)(struct SNAME *_set1_, struct SNAME *_set2_);
struct SNAME *CMC_(PFX, _difference)(struct SNAME *_set1_, struct SNAME *_set2_);
struct SNAME *CMC_(PFX, _symmetric_difference)(struct SNAME *_set1_, struct SNAME *_set2_);
bool CMC_(PFX, _is_subset)(struct SNAME *_set1_, struct SNAME *_set2_);
bool CMC_(PFX, _is_superset)(struct SNAME *_set1_, struct SNAME *_set2_);
bool CMC_(PFX, _is_proper_subset)(struct SNAME *_set1_, struct SNAME *_set2_);
bool CMC_(PFX, _is_proper_superset)(struct SNAME *_set1_, struct SNAME *_set2_);
bool CMC_(PFX, _is_disjointset)(struct SNAME *_set1_, struct SNAME *_set2_);
#endif /* CMC_EXT_SETF */
/**
* STR
*
* Print helper functions.
*/
#ifdef CMC_EXT_STR
bool CMC_(PFX, _to_string)(struct SNAME *_set_, FILE *fptr);
bool CMC_(PFX, _print)(struct SNAME *_set_, FILE *fptr, const char *start, const char *separator, const char *end);
#endif /* CMC_EXT_STR */
+51
View File
@@ -0,0 +1,51 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* ITER
*
* Hashset bi-directional iterator.
*/
#ifdef CMC_EXT_ITER
/* HashSet Iterator */
struct CMC_DEF_ITER(SNAME)
{
/* Target HashSet */
struct SNAME *target;
/* Cursor's position (index) */
size_t cursor;
/* Keeps track of relative index to the iteration of elements */
size_t index;
/* The index of the first element */
size_t first;
/* The index of the last element */
size_t last;
/* If the iterator has reached the start of the iteration */
bool start;
/* If the iterator has reached the end of the iteration */
bool end;
};
#endif /* CMC_EXT_ITER */
+67
View File
@@ -0,0 +1,67 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/* Value struct function table */
struct CMC_DEF_FVAL(SNAME)
{
/* Comparator function */
CMC_DEF_FTAB_CMP(V);
/* Copy function */
CMC_DEF_FTAB_CPY(V);
/* To string function */
CMC_DEF_FTAB_STR(V);
/* Free from memory function */
CMC_DEF_FTAB_FREE(V);
/* Hash function */
CMC_DEF_FTAB_HASH(V);
/* Priority function */
CMC_DEF_FTAB_PRI(V);
};
/* Collection Allocation and Deallocation */
struct SNAME *CMC_(PFX, _new)(size_t capacity, double load, struct CMC_DEF_FVAL(SNAME) * f_val);
struct SNAME *CMC_(PFX, _new_custom)(size_t capacity, double load, struct CMC_DEF_FVAL(SNAME) * f_val,
CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks);
void CMC_(PFX, _clear)(struct SNAME *_set_);
void CMC_(PFX, _free)(struct SNAME *_set_);
/* Customization of Allocation and Callbacks */
void CMC_(PFX, _customize)(struct SNAME *_set_, CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks);
/* Collection Input and Output */
bool CMC_(PFX, _insert)(struct SNAME *_set_, V value);
bool CMC_(PFX, _remove)(struct SNAME *_set_, V value);
/* Element Access */
bool CMC_(PFX, _max)(struct SNAME *_set_, V *value);
bool CMC_(PFX, _min)(struct SNAME *_set_, V *value);
/* Collection State */
bool CMC_(PFX, _contains)(struct SNAME *_set_, V value);
bool CMC_(PFX, _empty)(struct SNAME *_set_);
bool CMC_(PFX, _full)(struct SNAME *_set_);
size_t CMC_(PFX, _count)(struct SNAME *_set_);
size_t CMC_(PFX, _capacity)(struct SNAME *_set_);
double CMC_(PFX, _load)(struct SNAME *_set_);
int CMC_(PFX, _flag)(struct SNAME *_set_);
/* Collection Utility */
bool CMC_(PFX, _resize)(struct SNAME *_set_, size_t capacity);
struct SNAME *CMC_(PFX, _copy_of)(struct SNAME *_set_);
bool CMC_(PFX, _equals)(struct SNAME *_set1_, struct SNAME *_set2_);
+55
View File
@@ -0,0 +1,55 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/* Hashset Structure */
struct SNAME
{
/* Array of Entries */
struct CMC_DEF_ENTRY(SNAME) * buffer;
/* Current Array Capcity */
size_t capacity;
/* Current amount of elements */
size_t count;
/* Load factor in range (0.0, 1.0) */
double load;
/* Flags indicating errors or success */
int flag;
/* Value function table */
struct CMC_DEF_FVAL(SNAME) * f_val;
/* Custom allocation functions */
CMC_ALLOC_TYPE alloc;
/* Custom callback functions */
CMC_CALLBACKS_DECL;
};
struct CMC_DEF_ENTRY(SNAME)
{
/* Entry value */
V value;
/* The distance of this node to its original position, used by */
/* robin-hood hashing */
size_t dist;
/* The sate of this node (DELETED, EMPTY, FILLED) */
enum cmc_entry_state state;
};
+92
View File
@@ -0,0 +1,92 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* heap.h
*
* Creation Date: 25/03/2019
*
* Authors:
* Leonardo Vencovsky (https://github.com/LeoVen)
*
*/
/**
* Heap
*
* The Heap is a specialized tree-based data structure which is essentially a
* complete tree that satisfies the heap property:
* - MaxHeap:
* - The root node is the greatest element of the unique set of keys.
* - A node key is always greater than or equal to its children keys.
* - Minheap:
* - The root node is the smallest element of the unique set of keys.
* - A node Key is always greater than or equal to its children keys.
*
* The heap is mostly used to implement priority queues. Sometimes it can also
* be used to sort elements. There are three main functions:
* - insert : Adds an element to the heap
* - remove_(min/max): Removes the min/max element from the heap
* - min/max : Accesses the min/max element from the heap
*/
#include "cor/core.h"
#include "cor/heap.h"
#ifdef CMC_DEV
#include "utl/log.h"
#endif
/**
* Used values
* V - heap value data type
* SNAME - struct name and prefix of other related structs
* PFX - functions prefix
*/
/* Structs definition */
#include "cmc/heap/struct.h"
/* Function declaration */
#include "cmc/heap/header.h"
/* Function implementation */
#include "cmc/heap/code.h"
/**
* Extensions
*
* INIT - Initializes the struct on the stack
* ITER - heap iterator
* STR - Print helper functions
*/
#define CMC_EXT_HEAP_PARTS ITER, SETF, STR
/**/
#include "cmc/heap/ext/struct.h"
/**/
#include "cmc/heap/ext/header.h"
/**/
#include "cmc/heap/ext/code.h"
#include "cor/undef.h"
+437
View File
@@ -0,0 +1,437 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/* Implementation Detail Functions */
static void CMC_(PFX, _impl_float_up)(struct SNAME *_heap_, size_t index);
static void CMC_(PFX, _impl_float_down)(struct SNAME *_heap_, size_t index);
struct SNAME *CMC_(PFX, _new)(size_t capacity, enum cmc_heap_order HO, struct CMC_DEF_FVAL(SNAME) * f_val)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return CMC_(PFX, _new_custom)(capacity, HO, f_val, NULL, NULL);
}
struct SNAME *CMC_(PFX, _new_custom)(size_t capacity, enum cmc_heap_order HO, struct CMC_DEF_FVAL(SNAME) * f_val,
CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
if (capacity < 1)
return NULL;
if (HO != CMC_MIN_HEAP && HO != CMC_MAX_HEAP)
return NULL;
if (!f_val)
return NULL;
if (!alloc)
alloc = &cmc_alloc_node_default;
struct SNAME *_heap_ = alloc->malloc(sizeof(struct SNAME));
if (!_heap_)
return NULL;
_heap_->buffer = alloc->calloc(capacity, sizeof(V));
if (!_heap_->buffer)
{
alloc->free(_heap_);
return NULL;
}
_heap_->capacity = capacity;
_heap_->count = 0;
_heap_->HO = HO;
_heap_->flag = CMC_FLAG_OK;
_heap_->f_val = f_val;
_heap_->alloc = alloc;
CMC_CALLBACKS_ASSIGN(_heap_, callbacks);
return _heap_;
}
void CMC_(PFX, _clear)(struct SNAME *_heap_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (_heap_->f_val->free)
{
for (size_t i = 0; i < _heap_->count; i++)
{
_heap_->f_val->free(_heap_->buffer[i]);
}
}
memset(_heap_->buffer, 0, sizeof(V) * _heap_->capacity);
_heap_->count = 0;
_heap_->flag = CMC_FLAG_OK;
}
void CMC_(PFX, _free)(struct SNAME *_heap_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (_heap_->f_val->free)
{
for (size_t i = 0; i < _heap_->count; i++)
{
_heap_->f_val->free(_heap_->buffer[i]);
}
}
_heap_->alloc->free(_heap_->buffer);
_heap_->alloc->free(_heap_);
}
void CMC_(PFX, _customize)(struct SNAME *_heap_, CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
if (!alloc)
_heap_->alloc = &cmc_alloc_node_default;
else
_heap_->alloc = alloc;
CMC_CALLBACKS_ASSIGN(_heap_, callbacks);
_heap_->flag = CMC_FLAG_OK;
}
bool CMC_(PFX, _insert)(struct SNAME *_heap_, V value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _full)(_heap_))
{
if (!CMC_(PFX, _resize)(_heap_, _heap_->count * 2))
return false;
}
_heap_->buffer[_heap_->count++] = value;
if (_heap_->count > 1)
{
CMC_(PFX, _impl_float_up)(_heap_, _heap_->count - 1);
}
_heap_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_heap_);
return true;
}
bool CMC_(PFX, _remove)(struct SNAME *_heap_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_heap_))
{
_heap_->flag = CMC_FLAG_EMPTY;
return false;
}
_heap_->buffer[0] = _heap_->buffer[_heap_->count - 1];
_heap_->buffer[_heap_->count - 1] = (V){ 0 };
_heap_->count--;
CMC_(PFX, _impl_float_down)(_heap_, 0);
_heap_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_heap_);
return true;
}
V CMC_(PFX, _peek)(struct SNAME *_heap_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_heap_))
{
_heap_->flag = CMC_FLAG_EMPTY;
return (V){ 0 };
}
_heap_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_heap_);
return _heap_->buffer[0];
}
bool CMC_(PFX, _contains)(struct SNAME *_heap_, V value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
_heap_->flag = CMC_FLAG_OK;
bool result = false;
for (size_t i = 0; i < _heap_->count; i++)
{
if (_heap_->f_val->cmp(_heap_->buffer[i], value) == 0)
{
result = true;
break;
}
}
CMC_CALLBACKS_CALL(_heap_);
return result;
}
bool CMC_(PFX, _empty)(struct SNAME *_heap_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _heap_->count == 0;
}
bool CMC_(PFX, _full)(struct SNAME *_heap_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _heap_->count >= _heap_->capacity;
}
size_t CMC_(PFX, _count)(struct SNAME *_heap_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _heap_->count;
}
size_t CMC_(PFX, _capacity)(struct SNAME *_heap_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _heap_->capacity;
}
int CMC_(PFX, _flag)(struct SNAME *_heap_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _heap_->flag;
}
bool CMC_(PFX, _resize)(struct SNAME *_heap_, size_t capacity)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
_heap_->flag = CMC_FLAG_OK;
if (_heap_->capacity == capacity)
goto success;
if (capacity < _heap_->count)
{
_heap_->flag = CMC_FLAG_INVALID;
return false;
}
V *new_buffer = _heap_->alloc->realloc(_heap_->buffer, sizeof(V) * capacity);
if (!new_buffer)
{
_heap_->flag = CMC_FLAG_ALLOC;
return false;
}
/* TODO zero out new slots */
_heap_->buffer = new_buffer;
_heap_->capacity = capacity;
success:
CMC_CALLBACKS_CALL(_heap_);
return true;
}
struct SNAME *CMC_(PFX, _copy_of)(struct SNAME *_heap_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct SNAME *result = CMC_(PFX, _new_custom)(_heap_->capacity, _heap_->HO, _heap_->f_val, _heap_->alloc, NULL);
if (!result)
{
_heap_->flag = CMC_FLAG_ERROR;
return NULL;
}
CMC_CALLBACKS_ASSIGN(result, _heap_->callbacks);
if (_heap_->f_val->cpy)
{
for (size_t i = 0; i < _heap_->count; i++)
result->buffer[i] = _heap_->f_val->cpy(_heap_->buffer[i]);
}
else
memcpy(result->buffer, _heap_->buffer, sizeof(V) * _heap_->count);
result->count = _heap_->count;
_heap_->flag = CMC_FLAG_OK;
return result;
}
bool CMC_(PFX, _equals)(struct SNAME *_heap1_, struct SNAME *_heap2_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
_heap1_->flag = CMC_FLAG_OK;
_heap2_->flag = CMC_FLAG_OK;
if (_heap1_->count != _heap2_->count)
return false;
for (size_t i = 0; i < _heap1_->count; i++)
{
if (_heap1_->f_val->cmp(_heap1_->buffer[i], _heap2_->buffer[i]) != 0)
return false;
}
return true;
}
static void CMC_(PFX, _impl_float_up)(struct SNAME *_heap_, size_t index)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
/* Current index */
size_t C = index;
V child = _heap_->buffer[C];
V parent = _heap_->buffer[(index - 1) / 2];
int mod = _heap_->HO;
while (C > 0 && _heap_->f_val->cmp(child, parent) * mod > 0)
{
/* Swap between C (current element) and its parent */
V tmp = _heap_->buffer[C];
_heap_->buffer[C] = _heap_->buffer[(C - 1) / 2];
_heap_->buffer[(C - 1) / 2] = tmp;
/* Go to parent */
C = (C - 1) / 2;
/* Prevent the two lines below from accessing a negative index */
if (C == 0)
break;
child = _heap_->buffer[C];
parent = _heap_->buffer[(C - 1) / 2];
}
}
static void CMC_(PFX, _impl_float_down)(struct SNAME *_heap_, size_t index)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
int mod = _heap_->HO;
while (index < _heap_->count)
{
size_t L = 2 * index + 1;
size_t R = 2 * index + 2;
size_t C = index;
/* Determine if we swap with the left or right element */
if (L < _heap_->count && _heap_->f_val->cmp(_heap_->buffer[L], _heap_->buffer[C]) * mod > 0)
{
C = L;
}
if (R < _heap_->count && _heap_->f_val->cmp(_heap_->buffer[R], _heap_->buffer[C]) * mod > 0)
{
C = R;
}
/* Swap only if either left or right was picked, otherwise done */
if (C != index)
{
V tmp = _heap_->buffer[index];
_heap_->buffer[index] = _heap_->buffer[C];
_heap_->buffer[C] = tmp;
index = C;
}
else
break;
}
}
+325
View File
@@ -0,0 +1,325 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* INIT
*
* The part 'INIT' gives a new way of initializing a collection. The collection
* struct is not heap allocated, only its internal structure (nodes, buffers).
*/
#ifdef CMC_EXT_INIT
#endif /* CMC_EXT_INIT */
/**
* ITER
*
* Heap bi-directional iterator.
*/
#ifdef CMC_EXT_ITER
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_start)(struct SNAME *target)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct CMC_DEF_ITER(SNAME) iter;
iter.target = target;
iter.cursor = 0;
iter.start = true;
iter.end = CMC_(PFX, _empty)(target);
return iter;
}
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_end)(struct SNAME *target)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct CMC_DEF_ITER(SNAME) iter;
iter.target = target;
iter.cursor = 0;
iter.start = CMC_(PFX, _empty)(target);
iter.end = true;
if (!CMC_(PFX, _empty)(target))
iter.cursor = target->count - 1;
return iter;
}
bool CMC_(PFX, _iter_at_start)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return CMC_(PFX, _empty)(iter->target) || iter->start;
}
bool CMC_(PFX, _iter_at_end)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return CMC_(PFX, _empty)(iter->target) || iter->end;
}
bool CMC_(PFX, _iter_to_start)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (!CMC_(PFX, _empty)(iter->target))
{
iter->cursor = 0;
iter->start = true;
iter->end = CMC_(PFX, _empty)(iter->target);
return true;
}
return false;
}
bool CMC_(PFX, _iter_to_end)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (!CMC_(PFX, _empty)(iter->target))
{
iter->cursor = iter->target->count - 1;
iter->start = CMC_(PFX, _empty)(iter->target);
iter->end = true;
return true;
}
return false;
}
bool CMC_(PFX, _iter_next)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (iter->end)
return false;
if (iter->cursor + 1 == iter->target->count)
{
iter->end = true;
return false;
}
iter->start = CMC_(PFX, _empty)(iter->target);
iter->cursor++;
return true;
}
bool CMC_(PFX, _iter_prev)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (iter->start)
return false;
if (iter->cursor == 0)
{
iter->start = true;
return false;
}
iter->end = CMC_(PFX, _empty)(iter->target);
iter->cursor--;
return true;
}
/* Returns true only if the iterator moved */
bool CMC_(PFX, _iter_advance)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (iter->end)
return false;
if (iter->cursor + 1 == iter->target->count)
{
iter->end = true;
return false;
}
if (steps == 0 || iter->cursor + steps >= iter->target->count)
return false;
if (iter->end)
return false;
iter->start = CMC_(PFX, _empty)(iter->target);
iter->cursor += steps;
return true;
}
/* Returns true only if the iterator moved */
bool CMC_(PFX, _iter_rewind)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (iter->start)
return false;
if (iter->cursor == 0)
{
iter->start = true;
return false;
}
if (steps == 0 || iter->cursor < steps)
return false;
iter->end = CMC_(PFX, _empty)(iter->target);
iter->cursor -= steps;
return true;
}
/* Returns true only if the iterator was able to be positioned at the */
/* given index */
bool CMC_(PFX, _iter_go_to)(struct CMC_DEF_ITER(SNAME) * iter, size_t index)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (index >= iter->target->count)
return false;
if (iter->cursor > index)
return CMC_(PFX, _iter_rewind)(iter, iter->cursor - index);
else if (iter->cursor < index)
return CMC_(PFX, _iter_advance)(iter, index - iter->cursor);
return true;
}
V CMC_(PFX, _iter_value)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(iter->target))
return (V){ 0 };
return iter->target->buffer[iter->cursor];
}
size_t CMC_(PFX, _iter_index)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return iter->cursor;
}
#endif /* CMC_EXT_ITER */
/**
* STR
*
* Print helper functions.
*/
#ifdef CMC_EXT_STR
bool CMC_(PFX, _to_string)(struct SNAME *_heap_, FILE *fptr)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct SNAME *h_ = _heap_;
const char *t = h_->HO == 1 ? "MaxHeap" : "MinHeap";
return 0 <= fprintf(fptr,
"struct %s<%s> "
"at %p { "
"buffer:%p, "
"capacity:%" PRIuMAX ", "
"count:%" PRIuMAX ", "
"type:%s, "
"flag:%d, "
"f_val:%p, "
"alloc:%p, "
"callbacks: %p}",
CMC_TO_STRING(SNAME), CMC_TO_STRING(V), h_, h_->buffer, h_->capacity, h_->count, t, h_->flag,
h_->f_val, h_->alloc, CMC_CALLBACKS_GET(h_));
}
bool CMC_(PFX, _print)(struct SNAME *_heap_, FILE *fptr, const char *start, const char *separator, const char *end)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
fprintf(fptr, "%s", start);
for (size_t i = 0; i < _heap_->count; i++)
{
if (!_heap_->f_val->str(fptr, _heap_->buffer[i]))
return false;
if (i + 1 < _heap_->count)
fprintf(fptr, "%s", separator);
}
fprintf(fptr, "%s", end);
return true;
}
#endif /* CMC_EXT_STR */
+72
View File
@@ -0,0 +1,72 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* INIT
*
* The part 'INIT' gives a new way of initializing a collection. The collection
* struct is not heap allocated, only its internal structure (nodes, buffers).
*/
#ifdef CMC_EXT_INIT
#endif /* CMC_EXT_INIT */
/**
* ITER
*
* Heap bi-directional iterator.
*/
#ifdef CMC_EXT_ITER
/* Iterator Initialization */
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_start)(struct SNAME *target);
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_end)(struct SNAME *target);
/* Iterator State */
bool CMC_(PFX, _iter_at_start)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_at_end)(struct CMC_DEF_ITER(SNAME) * iter);
/* Iterator Movement */
bool CMC_(PFX, _iter_to_start)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_to_end)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_next)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_prev)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_advance)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps);
bool CMC_(PFX, _iter_rewind)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps);
bool CMC_(PFX, _iter_go_to)(struct CMC_DEF_ITER(SNAME) * iter, size_t index);
/* Iterator Access */
V CMC_(PFX, _iter_value)(struct CMC_DEF_ITER(SNAME) * iter);
size_t CMC_(PFX, _iter_index)(struct CMC_DEF_ITER(SNAME) * iter);
#endif /* CMC_EXT_ITER */
/**
* STR
*
* Print helper functions.
*/
#ifdef CMC_EXT_STR
bool CMC_(PFX, _to_string)(struct SNAME *_heap_, FILE *fptr);
bool CMC_(PFX, _print)(struct SNAME *_heap_, FILE *fptr, const char *start, const char *separator, const char *end);
#endif /* CMC_EXT_STR */
+45
View File
@@ -0,0 +1,45 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* ITER
*
* Heap bi-directional iterator.
*/
#ifdef CMC_EXT_ITER
/* Heap Iterator */
struct CMC_DEF_ITER(SNAME)
{
/* Target heap */
struct SNAME *target;
/* Cursor's position (index) */
size_t cursor;
/* If the iterator has reached the start of the iteration */
bool start;
/* If the iterator has reached the end of the iteration */
bool end;
};
#endif /* CMC_EXT_ITER */
+65
View File
@@ -0,0 +1,65 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/* Value struct function table */
struct CMC_DEF_FVAL(SNAME)
{
/* Comparator function */
CMC_DEF_FTAB_CMP(V);
/* Copy function */
CMC_DEF_FTAB_CPY(V);
/* To string function */
CMC_DEF_FTAB_STR(V);
/* Free from memory function */
CMC_DEF_FTAB_FREE(V);
/* Hash function */
CMC_DEF_FTAB_HASH(V);
/* Priority function */
CMC_DEF_FTAB_PRI(V);
};
/* Collection Allocation and Deallocation */
struct SNAME *CMC_(PFX, _new)(size_t capacity, enum cmc_heap_order HO, struct CMC_DEF_FVAL(SNAME) * f_val);
struct SNAME *CMC_(PFX, _new_custom)(size_t capacity, enum cmc_heap_order HO, struct CMC_DEF_FVAL(SNAME) * f_val,
CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks);
void CMC_(PFX, _clear)(struct SNAME *_heap_);
void CMC_(PFX, _free)(struct SNAME *_heap_);
/* Customization of Allocation and Callbacks */
void CMC_(PFX, _customize)(struct SNAME *_heap_, CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks);
/* Collection Input and Output */
bool CMC_(PFX, _insert)(struct SNAME *_heap_, V value);
bool CMC_(PFX, _remove)(struct SNAME *_heap_);
/* Element Access */
V CMC_(PFX, _peek)(struct SNAME *_heap_);
/* Collection State */
bool CMC_(PFX, _contains)(struct SNAME *_heap_, V value);
bool CMC_(PFX, _empty)(struct SNAME *_heap_);
bool CMC_(PFX, _full)(struct SNAME *_heap_);
size_t CMC_(PFX, _count)(struct SNAME *_heap_);
size_t CMC_(PFX, _capacity)(struct SNAME *_heap_);
int CMC_(PFX, _flag)(struct SNAME *_heap_);
/* Collection Utility */
bool CMC_(PFX, _resize)(struct SNAME *_heap_, size_t capacity);
struct SNAME *CMC_(PFX, _copy_of)(struct SNAME *_heap_);
bool CMC_(PFX, _equals)(struct SNAME *_heap1_, struct SNAME *_heap2_);
+43
View File
@@ -0,0 +1,43 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
struct SNAME
{
/* Dynamic array of elements */
V *buffer;
/* Current array capacity */
size_t capacity;
/* Current amount of elements in the heap */
size_t count;
/* Heap order (MaxHeap or MinHeap) */
enum cmc_heap_order HO;
/* Flags indicating errors or success */
int flag;
/* Value function table */
struct CMC_DEF_FVAL(SNAME) * f_val;
/* Custom allocation functions */
CMC_ALLOC_TYPE alloc;
/* Custom callback functions */
CMC_CALLBACKS_DECL;
};
+84
View File
@@ -0,0 +1,84 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* intervalheap.h
*
* Creation Date: 06/07/2019
*
* Authors:
* Leonardo Vencovsky (https://github.com/LeoVen)
*
*/
/**
* Interval Heap
*
* An interval heap is a specialized heap with:
*
* - O(1) - Find Min
* - O(1) - Find Max
* - O(log n) - Insert
* - O(log n) - Remove Min
* - O(log n) - Remove Max
*/
#include "cor/core.h"
#ifdef CMC_DEV
#include "utl/log.h"
#endif
/**
* Used values
* V - intervalheap value data type
* SNAME - struct name and prefix of other related structs
* PFX - functions prefix
*/
/* Structs definition */
#include "cmc/intervalheap/struct.h"
/* Function declaration */
#include "cmc/intervalheap/header.h"
/* Function implementation */
#include "cmc/intervalheap/code.h"
/**
* Extensions
*
* INIT - Initializes the struct on the stack
* ITER - intervalheap iterator
* STR - Print helper functions
*/
#define CMC_EXT_HEAP_PARTS ITER, SETF, STR
/**/
#include "cmc/intervalheap/ext/struct.h"
/**/
#include "cmc/intervalheap/ext/header.h"
/**/
#include "cmc/intervalheap/ext/code.h"
#include "cor/undef.h"
+860
View File
@@ -0,0 +1,860 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/* Implementation Detail Functions */
static void CMC_(PFX, _impl_float_up_max)(struct SNAME *_heap_);
static void CMC_(PFX, _impl_float_up_min)(struct SNAME *_heap_);
static void CMC_(PFX, _impl_float_down_max)(struct SNAME *_heap_);
static void CMC_(PFX, _impl_float_down_min)(struct SNAME *_heap_);
struct SNAME *CMC_(PFX, _new)(size_t capacity, struct CMC_DEF_FVAL(SNAME) * f_val)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return CMC_(PFX, _new_custom)(capacity, f_val, NULL, NULL);
}
struct SNAME *CMC_(PFX, _new_custom)(size_t capacity, struct CMC_DEF_FVAL(SNAME) * f_val, CMC_ALLOC_TYPE alloc,
CMC_CALLBACK_TYPE callbacks)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
if (capacity == 0 || capacity == UINTMAX_MAX)
return NULL;
if (!f_val)
return NULL;
if (!alloc)
alloc = &cmc_alloc_node_default;
struct SNAME *_heap_ = alloc->malloc(sizeof(struct SNAME));
if (!_heap_)
return NULL;
capacity = (capacity + capacity % 2) / 2;
_heap_->buffer = alloc->calloc(capacity, sizeof(V[2]));
if (!_heap_->buffer)
{
alloc->free(_heap_);
return NULL;
}
_heap_->capacity = capacity;
_heap_->size = 0;
_heap_->count = 0;
_heap_->flag = CMC_FLAG_OK;
_heap_->f_val = f_val;
_heap_->alloc = alloc;
CMC_CALLBACKS_ASSIGN(_heap_, callbacks);
return _heap_;
}
void CMC_(PFX, _clear)(struct SNAME *_heap_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (_heap_->f_val->free)
{
for (size_t i = 0; i < _heap_->count; i++)
{
_heap_->f_val->free(_heap_->buffer[i / 2][i % 2]);
}
}
memset(_heap_->buffer, 0, sizeof(V[2]) * _heap_->capacity);
_heap_->size = 0;
_heap_->count = 0;
_heap_->flag = CMC_FLAG_OK;
}
void CMC_(PFX, _free)(struct SNAME *_heap_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (_heap_->f_val->free)
{
for (size_t i = 0; i < _heap_->count; i++)
{
_heap_->f_val->free(_heap_->buffer[i / 2][i % 2]);
}
}
_heap_->alloc->free(_heap_->buffer);
_heap_->alloc->free(_heap_);
}
void CMC_(PFX, _customize)(struct SNAME *_heap_, CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
if (!alloc)
_heap_->alloc = &cmc_alloc_node_default;
else
_heap_->alloc = alloc;
CMC_CALLBACKS_ASSIGN(_heap_, callbacks);
_heap_->flag = CMC_FLAG_OK;
}
bool CMC_(PFX, _insert)(struct SNAME *_heap_, V value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _full)(_heap_))
{
if (!CMC_(PFX, _resize)(_heap_, _heap_->capacity * 4))
return false;
}
if (_heap_->count % 2 == 0)
{
/* Occupying a new node */
_heap_->buffer[_heap_->size][0] = value;
_heap_->buffer[_heap_->size][1] = (V){ 0 };
_heap_->size++;
}
else
{
V(*node)[2] = &(_heap_->buffer[_heap_->size - 1]);
/* Decide if the new element goes into the MinHeap or MaxHeap */
if (_heap_->f_val->cmp((*node)[0], value) > 0)
{
/* Swap current value and add new element to the MinHeap */
(*node)[1] = (*node)[0];
(*node)[0] = value;
}
else
{
/* No need to swap and add the new element to the MaxHeap */
(*node)[1] = value;
}
}
_heap_->count++;
_heap_->flag = CMC_FLAG_OK;
if (_heap_->count > 2)
{
/* Determine wheather to do a MaxHeap insert or a MinHeap */
/* insert. For any integer this index calculation results in */
/* an even number representing the parent of the last value */
V(*parent)[2] = &(_heap_->buffer[(_heap_->size - 2) / 2]);
if (_heap_->f_val->cmp((*parent)[0], value) > 0)
CMC_(PFX, _impl_float_up_min)(_heap_);
else if (_heap_->f_val->cmp((*parent)[1], value) < 0)
CMC_(PFX, _impl_float_up_max)(_heap_);
/* else no float up required */
}
CMC_CALLBACKS_CALL(_heap_);
return true;
}
bool CMC_(PFX, _remove_max)(struct SNAME *_heap_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_heap_))
{
_heap_->flag = CMC_FLAG_EMPTY;
return false;
}
if (_heap_->count == 1)
{
_heap_->buffer[0][0] = (V){ 0 };
_heap_->count--;
_heap_->size--;
goto success;
}
/* Swap the result with the last element in the MaxHeap and float */
/* it down */
V(*last_node)[2] = &(_heap_->buffer[_heap_->size - 1]);
if (_heap_->count % 2 == 1)
{
/* Grab from MinHeap and discard last node */
_heap_->buffer[0][1] = (*last_node)[0];
(*last_node)[0] = (V){ 0 };
_heap_->size--;
}
else
{
_heap_->buffer[0][1] = (*last_node)[1];
(*last_node)[1] = (V){ 0 };
}
_heap_->count--;
/* FLoat Down on the MaxHeap */
CMC_(PFX, _impl_float_down_max)(_heap_);
success:
_heap_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_heap_);
return true;
}
bool CMC_(PFX, _remove_min)(struct SNAME *_heap_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_heap_))
{
_heap_->flag = CMC_FLAG_EMPTY;
return false;
}
if (_heap_->count == 1)
{
_heap_->buffer[0][0] = (V){ 0 };
_heap_->count--;
_heap_->size--;
goto success;
}
/* Swap the result with the last element in the MinHeap and float */
/* it down */
V(*last_node)[2] = &(_heap_->buffer[_heap_->size - 1]);
_heap_->buffer[0][0] = (*last_node)[0];
if (_heap_->count % 2 == 1)
{
/* Discard last node */
(*last_node)[0] = (V){ 0 };
_heap_->size--;
}
else
{
/* Place the MaxHeap value in the MinHeap value spot */
(*last_node)[0] = (*last_node)[1];
(*last_node)[1] = (V){ 0 };
}
_heap_->count--;
/* FLoat Down on the MinHeap */
CMC_(PFX, _impl_float_down_min)(_heap_);
success:
_heap_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_heap_);
return true;
}
bool CMC_(PFX, _update_max)(struct SNAME *_heap_, V value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_heap_))
{
_heap_->flag = CMC_FLAG_EMPTY;
return false;
}
if (_heap_->count == 1)
{
_heap_->buffer[0][0] = value;
}
else if (_heap_->f_val->cmp(value, _heap_->buffer[0][0]) < 0)
{
/* Corner case: we are updating the Max value but it is less */
/* than the Min value */
_heap_->buffer[0][1] = _heap_->buffer[0][0];
_heap_->buffer[0][0] = value;
CMC_(PFX, _impl_float_down_max)(_heap_);
}
else
{
/* Update Max element and float it down */
_heap_->buffer[0][1] = value;
CMC_(PFX, _impl_float_down_max)(_heap_);
}
_heap_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_heap_);
return true;
}
bool CMC_(PFX, _update_min)(struct SNAME *_heap_, V value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_heap_))
{
_heap_->flag = CMC_FLAG_EMPTY;
return false;
}
if (_heap_->count == 1)
{
_heap_->buffer[0][0] = value;
}
else if (_heap_->f_val->cmp(value, _heap_->buffer[0][1]) > 0)
{
/* Corner case: we are updating the Min value but it is greater */
/* than the Max value. */
_heap_->buffer[0][0] = _heap_->buffer[0][1];
_heap_->buffer[0][1] = value;
CMC_(PFX, _impl_float_down_min)(_heap_);
}
else
{
/* Update Min element and float it down */
_heap_->buffer[0][0] = value;
CMC_(PFX, _impl_float_down_min)(_heap_);
}
_heap_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_heap_);
return true;
}
V CMC_(PFX, _max)(struct SNAME *_heap_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_heap_))
{
_heap_->flag = CMC_FLAG_EMPTY;
return (V){ 0 };
}
_heap_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_heap_);
/* If there is only one element, then the maximum element is the */
/* same as the one in the MinHeap */
if (_heap_->count == 1)
return _heap_->buffer[0][0];
return _heap_->buffer[0][1];
}
V CMC_(PFX, _min)(struct SNAME *_heap_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(_heap_))
{
_heap_->flag = CMC_FLAG_EMPTY;
return (V){ 0 };
}
_heap_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_heap_);
return _heap_->buffer[0][0];
}
bool CMC_(PFX, _contains)(struct SNAME *_heap_, V value)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
_heap_->flag = CMC_FLAG_OK;
bool result = false;
for (size_t i = 0; i < _heap_->count; i++)
{
if (_heap_->f_val->cmp(_heap_->buffer[i / 2][i % 2], value) == 0)
{
result = true;
break;
}
}
CMC_CALLBACKS_CALL(_heap_);
return result;
}
bool CMC_(PFX, _empty)(struct SNAME *_heap_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _heap_->count == 0;
}
bool CMC_(PFX, _full)(struct SNAME *_heap_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
/* The heap is full if all nodes are completely filled */
return _heap_->size >= _heap_->capacity && _heap_->count % 2 == 0;
}
size_t CMC_(PFX, _count)(struct SNAME *_heap_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _heap_->count;
}
size_t CMC_(PFX, _capacity)(struct SNAME *_heap_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _heap_->capacity;
}
int CMC_(PFX, _flag)(struct SNAME *_heap_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return _heap_->flag;
}
bool CMC_(PFX, _resize)(struct SNAME *_heap_, size_t capacity)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (_heap_->capacity == capacity)
goto success;
if (capacity < _heap_->count)
{
_heap_->flag = CMC_FLAG_INVALID;
return false;
}
/* Prevent overflow */
if (capacity == UINTMAX_MAX)
{
_heap_->flag = CMC_FLAG_ERROR;
return false;
}
capacity += capacity % 2;
V(*new_buffer)[2] = _heap_->alloc->realloc(_heap_->buffer, sizeof(V[2]) * capacity);
if (!new_buffer)
{
_heap_->flag = CMC_FLAG_ALLOC;
return false;
}
if (capacity > _heap_->capacity)
{
memset(new_buffer + _heap_->capacity, 0, sizeof(V[2]) * (capacity - _heap_->capacity));
}
_heap_->buffer = new_buffer;
_heap_->capacity = capacity;
success:
_heap_->flag = CMC_FLAG_OK;
CMC_CALLBACKS_CALL(_heap_);
return true;
}
struct SNAME *CMC_(PFX, _copy_of)(struct SNAME *_heap_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct SNAME *result = _heap_->alloc->malloc(sizeof(struct SNAME));
if (!result)
{
_heap_->flag = CMC_FLAG_ALLOC;
return NULL;
}
memcpy(result, _heap_, sizeof(struct SNAME));
result->buffer = _heap_->alloc->malloc(sizeof(V[2]) * _heap_->capacity);
if (!result->buffer)
{
_heap_->alloc->free(result);
_heap_->flag = CMC_FLAG_ALLOC;
return NULL;
}
if (_heap_->f_val->cpy)
{
for (size_t i = 0; i < _heap_->count; i++)
result->buffer[i / 2][i % 2] = _heap_->f_val->cpy(_heap_->buffer[i / 2][i % 2]);
}
else
memcpy(result->buffer, _heap_->buffer, sizeof(V[2]) * _heap_->capacity);
result->capacity = _heap_->capacity;
result->size = _heap_->size;
result->count = _heap_->count;
result->flag = CMC_FLAG_OK;
result->f_val = _heap_->f_val;
result->alloc = _heap_->alloc;
CMC_CALLBACKS_ASSIGN(result, _heap_->callbacks);
_heap_->flag = CMC_FLAG_OK;
return result;
}
bool CMC_(PFX, _equals)(struct SNAME *_heap1_, struct SNAME *_heap2_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
_heap1_->flag = CMC_FLAG_OK;
_heap2_->flag = CMC_FLAG_OK;
if (_heap1_->count != _heap2_->count)
return false;
for (size_t i = 0; i < _heap1_->count; i++)
{
V value1 = _heap1_->buffer[i / 2][i % 2];
V value2 = _heap2_->buffer[i / 2][i % 2];
if (_heap1_->f_val->cmp(value1, value2) != 0)
return false;
}
return true;
}
static void CMC_(PFX, _impl_float_up_max)(struct SNAME *_heap_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
size_t index = _heap_->size - 1;
V(*curr_node)[2] = &(_heap_->buffer[index]);
/* FLoat Up on the MaxHeap */
while (index > 0)
{
/* Parent index */
size_t P_index = (index - 1) / 2;
V(*parent)[2] = &(_heap_->buffer[P_index]);
if (index == _heap_->size - 1 && _heap_->count % 2 != 0)
{
/* In this case, the current node has no MaxHeap value so */
/* we instead compare with the MinHeap value */
if (_heap_->f_val->cmp((*curr_node)[0], (*parent)[1]) < 0)
break;
/* Since the comparison above passed now we need to swap */
/* the current node with the parent but it will have to be */
/* done with the node's MinHeap value since the MaxHeap */
/* value doesn't exist */
V tmp = (*curr_node)[0];
(*curr_node)[0] = (*parent)[1];
(*parent)[1] = tmp;
}
else
{
/* Usual case, just compare both MaxHeap values */
if (_heap_->f_val->cmp((*curr_node)[1], (*parent)[1]) < 0)
break;
/* Swap with parent and repeat */
V tmp = (*curr_node)[1];
(*curr_node)[1] = (*parent)[1];
(*parent)[1] = tmp;
}
/* Update indexe and node */
index = P_index;
curr_node = parent;
}
}
static void CMC_(PFX, _impl_float_up_min)(struct SNAME *_heap_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
size_t index = _heap_->size - 1;
V(*curr_node)[2] = &(_heap_->buffer[index]);
/* FLoat Up on the MinHeap */
while (index > 0)
{
/* Parent index */
size_t P_index = (index - 1) / 2;
V(*parent)[2] = &(_heap_->buffer[P_index]);
if (_heap_->f_val->cmp((*curr_node)[0], (*parent)[0]) >= 0)
break;
/* Swap with parent and repeat */
V tmp = (*curr_node)[0];
(*curr_node)[0] = (*parent)[0];
(*parent)[0] = tmp;
/* Update indexe and node */
index = P_index;
curr_node = parent;
}
}
static void CMC_(PFX, _impl_float_down_max)(struct SNAME *_heap_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
/* Floats Down from the MaxHeap */
size_t index = 0;
V(*curr_node)[2] = &(_heap_->buffer[index]);
while (true)
{
/* If there are no children it is done */
if (2 * index + 1 >= _heap_->size)
break;
/* Child index to be compared with current value */
size_t child;
size_t L_index = index * 2 + 1;
size_t R_index = index * 2 + 2;
/* If there are two children, pick the smallest one */
if (R_index < _heap_->size)
{
V(*L)[2] = &(_heap_->buffer[L_index]);
V(*R)[2] = &(_heap_->buffer[R_index]);
/* If the right child is the last node and there is no */
/* MaxHeap value */
/* then do the comparison with the MinHeap value */
if (R_index == _heap_->size - 1 && _heap_->count % 2 != 0)
child = _heap_->f_val->cmp((*L)[1], (*R)[0]) > 0 ? L_index : R_index;
else
child = _heap_->f_val->cmp((*L)[1], (*R)[1]) > 0 ? L_index : R_index;
}
/* Pick the only one available */
else
child = L_index;
V(*child_node)[2] = &(_heap_->buffer[child]);
/* Again, check if the child node is the last one and has no */
/* MaxHeap value */
if (child == _heap_->size - 1 && _heap_->count % 2 != 0)
{
/* Odd case, compare with MinHeap value */
/* If current value is not less than the child node's */
/* value it is done */
if (_heap_->f_val->cmp((*curr_node)[1], (*child_node)[0]) >= 0)
break;
/* Otherwise swap and continue */
V tmp = (*child_node)[0];
(*child_node)[0] = (*curr_node)[1];
(*curr_node)[1] = tmp;
}
else
{
/* If current value is not less than the child node's */
/* value it is done */
if (_heap_->f_val->cmp((*curr_node)[1], (*child_node)[1]) >= 0)
break;
/* Otherwise swap and continue */
V tmp = (*child_node)[1];
(*child_node)[1] = (*curr_node)[1];
(*curr_node)[1] = tmp;
/* Check if the MinHeap and MaxHeap values need to be */
/* swapped */
if (_heap_->f_val->cmp((*child_node)[0], (*child_node)[1]) > 0)
{
/* Swap because the MinHeap value is greater than the */
/* MaxHeap value */
tmp = (*child_node)[0];
(*child_node)[0] = (*child_node)[1];
(*child_node)[1] = tmp;
}
}
/* Update index and node */
index = child;
curr_node = child_node;
}
}
static void CMC_(PFX, _impl_float_down_min)(struct SNAME *_heap_)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
/* Floats Down from the MinHeap */
size_t index = 0;
V(*curr_node)[2] = &(_heap_->buffer[index]);
while (true)
{
/* If there are no children it is done */
if (2 * index + 1 >= _heap_->size)
break;
/* Child index to be compared with current value */
size_t child;
size_t L_index = index * 2 + 1;
size_t R_index = index * 2 + 2;
/* If there are two children, pick the smallest one */
if (R_index < _heap_->size)
{
V(*L)[2] = &(_heap_->buffer[L_index]);
V(*R)[2] = &(_heap_->buffer[R_index]);
child = _heap_->f_val->cmp((*L)[0], (*R)[0]) < 0 ? L_index : R_index;
}
/* Pick the only one available */
else
child = L_index;
V(*child_node)[2] = &(_heap_->buffer[child]);
/* If current value is smaller than the child node's value, it */
/* is done */
if (_heap_->f_val->cmp((*curr_node)[0], (*child_node)[0]) < 0)
break;
/* Otherwise swap and continue */
V tmp = (*child_node)[0];
(*child_node)[0] = (*curr_node)[0];
(*curr_node)[0] = tmp;
/* If the child node is the last node check if the MinHeap and */
/* MaxHeap values need to be swapped */
if (child != _heap_->size - 1 || _heap_->count % 2 == 0)
{
if (_heap_->f_val->cmp((*child_node)[0], (*child_node)[1]) > 0)
{
/* Swap because the MinHeap value is greater than the */
/* MaxHeap value */
tmp = (*child_node)[0];
(*child_node)[0] = (*child_node)[1];
(*child_node)[1] = tmp;
}
}
/* Update index and node */
index = child;
curr_node = child_node;
}
}
+326
View File
@@ -0,0 +1,326 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* INIT
*
* The part 'INIT' gives a new way of initializing a collection. The collection
* struct is not heap allocated, only its internal structure (nodes, buffers).
*/
#ifdef CMC_EXT_INIT
#endif /* CMC_EXT_INIT */
/**
* ITER
*
* Intervalheap bi-directional iterator.
*
* TODO allow creation of iterators exclusively for min or max heap
*/
#ifdef CMC_EXT_ITER
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_start)(struct SNAME *target)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct CMC_DEF_ITER(SNAME) iter;
iter.target = target;
iter.cursor = 0;
iter.start = true;
iter.end = CMC_(PFX, _empty)(target);
return iter;
}
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_end)(struct SNAME *target)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct CMC_DEF_ITER(SNAME) iter;
iter.target = target;
iter.cursor = 0;
iter.start = CMC_(PFX, _empty)(target);
iter.end = true;
if (!CMC_(PFX, _empty)(target))
iter.cursor = target->count - 1;
return iter;
}
bool CMC_(PFX, _iter_at_start)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return CMC_(PFX, _empty)(iter->target) || iter->start;
}
bool CMC_(PFX, _iter_at_end)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return CMC_(PFX, _empty)(iter->target) || iter->end;
}
bool CMC_(PFX, _iter_to_start)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (!CMC_(PFX, _empty)(iter->target))
{
iter->cursor = 0;
iter->start = true;
iter->end = CMC_(PFX, _empty)(iter->target);
return true;
}
return false;
}
bool CMC_(PFX, _iter_to_end)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (!CMC_(PFX, _empty)(iter->target))
{
iter->cursor = iter->target->count - 1;
iter->start = CMC_(PFX, _empty)(iter->target);
iter->end = true;
return true;
}
return false;
}
bool CMC_(PFX, _iter_next)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (iter->end)
return false;
if (iter->cursor + 1 == iter->target->count)
{
iter->end = true;
return false;
}
iter->start = CMC_(PFX, _empty)(iter->target);
iter->cursor++;
return true;
}
bool CMC_(PFX, _iter_prev)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (iter->start)
return false;
if (iter->cursor == 0)
{
iter->start = true;
return false;
}
iter->end = CMC_(PFX, _empty)(iter->target);
iter->cursor--;
return true;
}
/* Returns true only if the iterator moved */
bool CMC_(PFX, _iter_advance)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (iter->end)
return false;
if (iter->cursor + 1 == iter->target->count)
{
iter->end = true;
return false;
}
if (steps == 0 || iter->cursor + steps >= iter->target->count)
return false;
if (iter->end)
return false;
iter->start = CMC_(PFX, _empty)(iter->target);
iter->cursor += steps;
return true;
}
/* Returns true only if the iterator moved */
bool CMC_(PFX, _iter_rewind)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (iter->start)
return false;
if (iter->cursor == 0)
{
iter->start = true;
return false;
}
if (steps == 0 || iter->cursor < steps)
return false;
iter->end = CMC_(PFX, _empty)(iter->target);
iter->cursor -= steps;
return true;
}
/* Returns true only if the iterator was able to be positioned at the */
/* given index */
bool CMC_(PFX, _iter_go_to)(struct CMC_DEF_ITER(SNAME) * iter, size_t index)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (index >= iter->target->count)
return false;
if (iter->cursor > index)
return CMC_(PFX, _iter_rewind)(iter, iter->cursor - index);
else if (iter->cursor < index)
return CMC_(PFX, _iter_advance)(iter, index - iter->cursor);
return true;
}
V CMC_(PFX, _iter_value)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
if (CMC_(PFX, _empty)(iter->target))
return (V){ 0 };
return iter->target->buffer[iter->cursor / 2][iter->cursor % 2];
}
size_t CMC_(PFX, _iter_index)(struct CMC_DEF_ITER(SNAME) * iter)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
return iter->cursor;
}
#endif /* CMC_EXT_ITER */
/**
* STR
*
* Print helper functions.
*/
#ifdef CMC_EXT_STR
bool CMC_(PFX, _to_string)(struct SNAME *_heap_, FILE *fptr)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
struct SNAME *h_ = _heap_;
return 0 <= fprintf(fptr,
"struct %s<%s> "
"at %p { "
"buffer:%p, "
"capacity:%" PRIuMAX ", "
"size:%" PRIuMAX ", "
"count:%" PRIuMAX ", "
"flag:%d, "
"f_val:%p, "
"alloc:%p, "
"callbacks:%p }",
CMC_TO_STRING(SNAME), CMC_TO_STRING(V), h_, h_->buffer, h_->capacity, h_->size, h_->count,
h_->flag, h_->f_val, h_->alloc, CMC_CALLBACKS_GET(h_));
}
bool CMC_(PFX, _print)(struct SNAME *_heap_, FILE *fptr, const char *start, const char *separator, const char *end)
{
#ifdef CMC_DEV
CMC_DEV_FCALL;
#endif
fprintf(fptr, "%s", start);
for (size_t i = 0; i < _heap_->count; i++)
{
if (!_heap_->f_val->str(fptr, _heap_->buffer[i / 2][i % 2]))
return false;
if (i + 1 < _heap_->count)
fprintf(fptr, "%s", separator);
}
fprintf(fptr, "%s", end);
return true;
}
#endif /* CMC_EXT_STR */
+88
View File
@@ -0,0 +1,88 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* INIT
*
* The part 'INIT' gives a new way of initializing a collection. The collection
* struct is not heap allocated, only its internal structure (nodes, buffers).
*/
#ifdef CMC_EXT_INIT
#endif /* CMC_EXT_INIT */
/**
* ITER
*
* List bi-directional iterator.
*/
#ifdef CMC_EXT_ITER
/* IntervalHeap Iterator */
struct CMC_DEF_ITER(SNAME)
{
/* Target IntervalHeap */
struct SNAME *target;
/* Cursor's position (index) */
size_t cursor;
/* If the iterator has reached the start of the iteration */
bool start;
/* If the iterator has reached the end of the iteration */
bool end;
};
/* Iterator Initialization */
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_start)(struct SNAME *target);
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_end)(struct SNAME *target);
/* Iterator State */
bool CMC_(PFX, _iter_at_start)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_at_end)(struct CMC_DEF_ITER(SNAME) * iter);
/* Iterator Movement */
bool CMC_(PFX, _iter_to_start)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_to_end)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_next)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_prev)(struct CMC_DEF_ITER(SNAME) * iter);
bool CMC_(PFX, _iter_advance)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps);
bool CMC_(PFX, _iter_rewind)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps);
bool CMC_(PFX, _iter_go_to)(struct CMC_DEF_ITER(SNAME) * iter, size_t index);
/* Iterator Access */
V CMC_(PFX, _iter_value)(struct CMC_DEF_ITER(SNAME) * iter);
size_t CMC_(PFX, _iter_index)(struct CMC_DEF_ITER(SNAME) * iter);
#endif /* CMC_EXT_ITER */
/**
* STR
*
* Print helper functions.
*/
#ifdef CMC_EXT_STR
bool CMC_(PFX, _to_string)(struct SNAME *_heap_, FILE *fptr);
bool CMC_(PFX, _print)(struct SNAME *_heap_, FILE *fptr, const char *start, const char *separator, const char *end);
#endif /* CMC_EXT_STR */
+23
View File
@@ -0,0 +1,23 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
+71
View File
@@ -0,0 +1,71 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/* Value struct function table */
struct CMC_DEF_FVAL(SNAME)
{
/* Comparator function */
CMC_DEF_FTAB_CMP(V);
/* Copy function */
CMC_DEF_FTAB_CPY(V);
/* To string function */
CMC_DEF_FTAB_STR(V);
/* Free from memory function */
CMC_DEF_FTAB_FREE(V);
/* Hash function */
CMC_DEF_FTAB_HASH(V);
/* Priority function */
CMC_DEF_FTAB_PRI(V);
};
/* Collection Functions */
/* Collection Allocation and Deallocation */
struct SNAME *CMC_(PFX, _new)(size_t capacity, struct CMC_DEF_FVAL(SNAME) * f_val);
struct SNAME *CMC_(PFX, _new_custom)(size_t capacity, struct CMC_DEF_FVAL(SNAME) * f_val, CMC_ALLOC_TYPE alloc,
CMC_CALLBACK_TYPE callbacks);
void CMC_(PFX, _clear)(struct SNAME *_heap_);
void CMC_(PFX, _free)(struct SNAME *_heap_);
/* Customization of Allocation and Callbacks */
void CMC_(PFX, _customize)(struct SNAME *_heap_, CMC_ALLOC_TYPE alloc, CMC_CALLBACK_TYPE callbacks);
/* Collection Input and Output */
bool CMC_(PFX, _insert)(struct SNAME *_heap_, V value);
bool CMC_(PFX, _remove_max)(struct SNAME *_heap_);
bool CMC_(PFX, _remove_min)(struct SNAME *_heap_);
/* Collection Update */
bool CMC_(PFX, _update_max)(struct SNAME *_heap_, V value);
bool CMC_(PFX, _update_min)(struct SNAME *_heap_, V value);
/* Element Access */
V CMC_(PFX, _max)(struct SNAME *_heap_);
V CMC_(PFX, _min)(struct SNAME *_heap_);
/* Collection State */
bool CMC_(PFX, _contains)(struct SNAME *_heap_, V value);
bool CMC_(PFX, _empty)(struct SNAME *_heap_);
bool CMC_(PFX, _full)(struct SNAME *_heap_);
size_t CMC_(PFX, _count)(struct SNAME *_heap_);
size_t CMC_(PFX, _capacity)(struct SNAME *_heap_);
int CMC_(PFX, _flag)(struct SNAME *_heap_);
/* Collection Utility */
bool CMC_(PFX, _resize)(struct SNAME *_heap_, size_t capacity);
struct SNAME *CMC_(PFX, _copy_of)(struct SNAME *_heap_);
bool CMC_(PFX, _equals)(struct SNAME *_heap1_, struct SNAME *_heap2_);
+44
View File
@@ -0,0 +1,44 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
struct SNAME
{
/* Dynamic array of elements */
/* buffer[n][0] is MinHeap and buffer[n][1] is MaxHeap */
V (*buffer)[2];
/* Current array capacity */
size_t capacity;
/* Current amount of pairs of values in the array */
size_t size;
/* Current amount of elements in the heap */
size_t count;
/* Flags indicating errors or success */
int flag;
/* Value function table */
struct CMC_DEF_FVAL(SNAME) * f_val;
/* Custom allocation functions */
CMC_ALLOC_TYPE alloc;
/* Custom callback functions */
CMC_CALLBACKS_DECL;
};
+90
View File
@@ -0,0 +1,90 @@
/**
* Copyright (c) 2019 Leonardo Vencovsky
*
* This file is part of the C Macro Collections Library.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* linkedlist.h
*
* Creation Date: 22/03/2019
*
* Authors:
* Leonardo Vencovsky (https://github.com/LeoVen)
*
*/
/**
* LinkedList
*
* A LinkedList is a linear collection of elements, whose order is not given by
* their physical placement in memory. Instead, each element points to the next
* (singly-linked list) and to a previous one (doubly-linked list). It consists
* of nodes connected by these next or previous pointers. Unlike an array, the
* LinkedList can indefinitely grow.
*
* Implementation
*
* The LinkedList is implemented as a doubly-linked list and allows insertions
* and removals at both ends in O(1) and in a given index in O(N). The list has
* a head and tail pointer. The head points to the first element in the sequence
* and tail points to the last.
*/
#include "cor/core.h"
#ifdef CMC_DEV
#include "utl/log.h"
#endif
/**
* Used values
* V - linkedlist data type
* SNAME - struct name and prefix of other related structs
* PFX - functions prefix
*/
/* Structs definition */
#include "cmc/linkedlist/struct.h"
/* Function declaration */
#include "cmc/linkedlist/header.h"
/* Function implementation */
#include "cmc/linkedlist/code.h"
/**
* Extensions
*
* INIT - Initializes the struct on the stack
* ITER - List iterator
* NODE - Operations relative to a linkedlist node
* STR - Print helper functions
*/
#define CMC_EXT_LINKEDLIST_PARTS INIT, ITER, NODE, STR
/**/
#include "cmc/linkedlist/ext/struct.h"
/**/
#include "cmc/linkedlist/ext/header.h"
/**/
#include "cmc/linkedlist/ext/code.h"
#include "cor/undef.h"
Loaded 100 of 450 files, more files were not shown because too many files have changed in this diff. Show more