Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5b39676d79 | ||
|
|
5e2b841e9e | ||
|
|
3ec32bd57b | ||
|
|
9531f7b5da | ||
|
|
5f39eb011c | ||
|
|
22e84db11a | ||
|
|
8410111eab | ||
|
|
490936bddd | ||
|
|
f956094178 | ||
|
|
812d0240e3 | ||
|
|
918b73ad51 | ||
|
|
ae5241a6fb | ||
|
|
d3e7d64d2a | ||
|
|
226e4ec817 | ||
|
|
221c55cf2a | ||
|
|
444f597a98 | ||
|
|
8843a8fb7a | ||
|
|
bc350611fc | ||
|
|
c61ac2e347 | ||
|
|
6002650f06 | ||
|
|
21ab3eeb07 | ||
|
|
2f767f7623 | ||
|
|
d89972c621 | ||
|
|
f0b763afba | ||
|
|
661455abe4 | ||
|
|
71fb0a52c5 | ||
|
|
d715ea70a8 | ||
|
|
a37207e9d7 | ||
|
|
be9c5af7cb | ||
|
|
73171f5068 | ||
|
|
f07efbd828 | ||
|
|
8cc5ef1f90 | ||
|
|
fbf020c784 | ||
|
|
b6d0424bb4 | ||
|
|
e2916aedb4 | ||
|
|
8966cd5e7d | ||
|
|
58bb89086e | ||
|
|
763ea5dbd5 | ||
|
|
0413da5c12 | ||
|
|
fe57443433 | ||
|
|
e4d5687907 | ||
|
|
ae5c745ef8 | ||
|
|
e8cfd9131b | ||
|
|
8625a6a411 | ||
|
|
bd8d745d7d | ||
|
|
469cddb515 | ||
|
|
00fe35810b | ||
|
|
9b632895b1 | ||
|
|
032d34a6bd | ||
|
|
bddb9252f3 | ||
|
|
213fa25a3a | ||
|
|
a208b4d41b | ||
|
|
1741e77c33 | ||
|
|
ad93db4203 | ||
|
|
bc46ace086 | ||
|
|
964ececf0b | ||
|
|
c449025e52 | ||
|
|
44a29874eb | ||
|
|
2b18531478 | ||
|
|
2d533c2db5 | ||
|
|
0b07829041 |
No files matched your search
@@ -4,7 +4,7 @@
|
||||
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
### To Reproduce
|
||||
### How to Reproduce
|
||||
|
||||
Steps to reproduce the behavior:
|
||||
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# Feature Request Template
|
||||
|
||||
### What is the nature of this request?
|
||||
|
||||
* New functionalities
|
||||
* Change in standards
|
||||
* Change in source code details (names of variables, functions, parameters, etc)
|
||||
|
||||
### Is your feature request related to a problem? Please describe.
|
||||
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
+8
-4
@@ -11,8 +11,12 @@ addons:
|
||||
script:
|
||||
- sudo ln -s /usr/bin/gcc-6 /usr/local/bin/gcc
|
||||
- export CC=gcc-7
|
||||
- cd ./C-Macro-Containers/tests
|
||||
- gcc foreach.c -Wall -Wextra -o foreach
|
||||
- cd ./tests
|
||||
- gcc foreach.c -Wall -Wextra -o foreach -std=c11
|
||||
- ./foreach
|
||||
after_success:
|
||||
- bash <(curl -s https://codecov.io/bash)
|
||||
- gcc iterators.c -Wall -Wextra -o iterators -std=c11
|
||||
- ./iterators
|
||||
- gcc contains.c -Wall -Wextra -o contains -std=c11
|
||||
- ./contains
|
||||
- gcc pointertype.c -Wall -Wextra -o pointertype -std=c11
|
||||
- ./pointertype
|
||||
@@ -0,0 +1,85 @@
|
||||
# MAJOR.MINOR.ADJUSTMENTS
|
||||
|
||||
1.0.0
|
||||
First stable version
|
||||
Includes the following collections:
|
||||
- deque
|
||||
- hashmap
|
||||
- hashset
|
||||
- heap
|
||||
- linkedlist
|
||||
- list
|
||||
- queue
|
||||
- stack
|
||||
- treemap
|
||||
- treeset
|
||||
Two-way iterators
|
||||
Benchmarks
|
||||
Tests:
|
||||
- foreach
|
||||
- iterator
|
||||
|
||||
1.0.1
|
||||
Fixed hashset logic in robin-hood hashing
|
||||
|
||||
1.1.0
|
||||
Added new list functions:
|
||||
- new_from
|
||||
- prepend
|
||||
- insert
|
||||
- append
|
||||
- remove
|
||||
- fits
|
||||
|
||||
1.1.1
|
||||
Reordering functions (implementation details are now at the end of each file)
|
||||
|
||||
1.1.2
|
||||
Fixing iterators for when they are initialized with an empty target
|
||||
Better iterator tests
|
||||
More examples
|
||||
|
||||
1.1.3
|
||||
Renamed deque's 'rear' struct member to 'back' to be more consistent with other collections
|
||||
Better benchmark and foreach tests are alphabetically ordered
|
||||
|
||||
1.2.0
|
||||
'contains' functions added to all collections
|
||||
'contains' tests and benchmark
|
||||
Unified Benchmark
|
||||
Updated examples
|
||||
|
||||
1.2.1
|
||||
Optimized list - now using 'string.h' functions to shift elements around instead of for-loops:
|
||||
- memset
|
||||
- memcpy
|
||||
- memmove
|
||||
|
||||
1.2.2
|
||||
Removed unnecessary modulo operation in hashtable functions
|
||||
|
||||
1.2.3
|
||||
Added get_ref functions to all collections that support it (only included in hashmap, linkedlist, list and treemap)
|
||||
|
||||
1.2.4
|
||||
Fixing some declarations in hashset and hashmap where a pointer type would cause problems
|
||||
Added a test to make sure all collections support pointer type
|
||||
Tests:
|
||||
- pointertype
|
||||
|
||||
1.3.0
|
||||
Changed how the linkedlist functions relative to nodes work
|
||||
Removed reference to owner list on each node
|
||||
Renamed some functions for consistency
|
||||
|
||||
1.4.0
|
||||
New way on how iterators work to all collections
|
||||
Added iter_init to work with stack allocated iterators
|
||||
Added iter_new and iter_free to work with heap allocated iterators
|
||||
Added two pointers to functions (it_start and it_end) that allow you to access iterators to both start and end of the target collection easily
|
||||
iter_next and iter_prev now only move the iterator
|
||||
To access the key, value and index, use a separate function
|
||||
Removed FOR_EACH_MAP as it is no longer necessary since FOR_EACH also works to associative containers now
|
||||
Updated benchmark, examples and tests to work on these new iterators
|
||||
Changed pointertype test to be a pointer to struct instead of pointer to char
|
||||
Added CHANGELOG and TODO
|
||||
+6
-2
@@ -2,11 +2,15 @@
|
||||
|
||||
Two simple steps:
|
||||
|
||||
* Fork this repository
|
||||
* Fork this repository to your github account
|
||||
* Clone it to your machine
|
||||
|
||||
Now you can start working on the project.
|
||||
|
||||
## Open Issues
|
||||
|
||||
Check out `bug_report.md` and `feature_request.md` templates in the `.github` folder to know how to make a bug report or feature request.
|
||||
|
||||
## Here are things you could work on:
|
||||
|
||||
1. New features, new functions, new stuff!
|
||||
@@ -34,7 +38,7 @@ Now you can start working on the project.
|
||||
4. All source files (`.c`, `.h`, etc) must contain a header with the following template:
|
||||
* Complete file name.
|
||||
* First commit date in `dd/mm/yyyy`.
|
||||
* Authors name with (optional) github link to his page.
|
||||
* Authors name with (optional) link to github page.
|
||||
|
||||
```
|
||||
/**
|
||||
|
||||
+1560
-276
File diff suppressed because it is too large.
Load diff
@@ -3,7 +3,7 @@
|
||||
Generate Simple Data Structures of any type in C for you to use in your projects.
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
## Available Collections
|
||||
@@ -19,11 +19,32 @@ Generate Simple Data Structures of any type in C for you to use in your projects
|
||||
* HashSet
|
||||
* HashMap
|
||||
|
||||
Check out **Documentation.md** for more information about each data structure.
|
||||
## Available Collections in future updates
|
||||
|
||||
* Multimap
|
||||
* Multiset
|
||||
* Treehashmap
|
||||
* Heap will be a MinMaxHeap
|
||||
|
||||
Check out **Documentation.md** for more information about each collection.
|
||||
|
||||
## What to use
|
||||
|
||||
The following table shows how each collection is implemented and how well they do when using as common [abstract data types](https://en.wikipedia.org/wiki/Abstract_data_type).
|
||||
|
||||
* **Ideal** - The collection implements correctly the abstract data type;
|
||||
* **Not Ideal** - The implementation is fulfilled but some functionalities are either not part of the ADT or not present;
|
||||
* **Bad** - It can be done, but its a bad idea.
|
||||
|
||||

|
||||
|
||||

|
||||

|
||||

|
||||
|
||||
## How to use
|
||||
|
||||
To generate the data structures, all you need to do is to include the necessary header files. You can include the containers you want to use individually or you can include the master header, `macro_collections.h`, that comes with all collections and other functionalities like the `FOR_EACH` macro.
|
||||
To generate the collection, all you need to do is to include the necessary header files. You can include the containers you want to use individually or you can include the master header, `macro_collections.h`, that comes with all collections and other functionalities like the `FOR_EACH` macro.
|
||||
|
||||
There are three C standard headers that all collections use:
|
||||
|
||||
@@ -35,46 +56,37 @@ With the last one being used only by array based containers. These headers are a
|
||||
|
||||
### Macros
|
||||
|
||||
> Note here that `SNAME` represents the uppercase name of the data structure.
|
||||
> Note here that `SNAME` represents the uppercase name of the collection.
|
||||
|
||||
Every collection is separated by three parts:
|
||||
Every collection is separated by two parts:
|
||||
|
||||
* `STRUCT` - Contains all structure definitions.
|
||||
* `HEADER` - Contains all functions definitions.
|
||||
* `SOURCE` - Contains all functions implementations.
|
||||
* `HEADER` - Contains all struct definitions and function definitions.
|
||||
* `SOURCE` - Contains all function implementations.
|
||||
|
||||
All collections have five main macros:
|
||||
All collections have three main macros:
|
||||
|
||||
* PUBLIC
|
||||
* `SNAME_GENERATE_HEADER_PUBLIC` - Generates both `STRUCT` and `HEADER`
|
||||
* `SNAME_GENERATE_SOURCE_PUBLIC` - Generates `SOURCE`
|
||||
* PRIVATE
|
||||
* `SNAME_GENERATE_HEADER_PRIVATE` - Generates `HEADER`
|
||||
* `SNAME_GENERATE_SOURCE_PRIVATE` - Generates both `STRUCT` and `SOURCE`
|
||||
* Standalone
|
||||
* `SNAME_GENERATE` - Generates `STRUCT`, `HEADER` and `SOURCE`.
|
||||
* `SNAME_GENERATE` - Generates `SNAME_GENERATE_HEADER` and `SNAME_GENERATE_SOURCE`.
|
||||
|
||||
Or you can generate each part individually:
|
||||
|
||||
* `SNAME_GENERATE_STRUCT` - Generates all structure definitions.
|
||||
* `SNAME_GENERATE_HEADER` - Generates all functions definitions.
|
||||
* `SNAME_GENERATE_SOURCE` - Generates all functions implementations.
|
||||
* `SNAME_GENERATE_HEADER` - Generates all struct definitions and function definitions.
|
||||
* `SNAME_GENERATE_SOURCE` - Generates all function implementations.
|
||||
|
||||
### For Each
|
||||
|
||||
There are 4 for-each macros:
|
||||
There are 2 for-each macros:
|
||||
|
||||
* `FOR_EACH` - Starts at the start of the data structure towards the end.
|
||||
* `FOR_EACH_REV` - Starts at the end of the data structure towards the start.
|
||||
* `FOR_EACH_MAP` - Like `FOR_EACH` but for associative data structures like *TREEMAP* and *HASHMAP*.
|
||||
* `FOR_EACH_MAP_REV` - Like `FOR_EACH_REV` but for associative data structures like *TREEMAP* and *HASHMAP*.
|
||||
* `FOR_EACH` - Starts at the start of the collection towards the end.
|
||||
* `FOR_EACH_REV` - Starts at the end of the collection towards the start.
|
||||
|
||||
Check out the **Documentation.md** to know exactly what represents the *end* and the *start* of each data structure.
|
||||
Check out the **Documentation.md** to know exactly what represents the *end* and the *start* of each collection.
|
||||
|
||||
### Parameters
|
||||
|
||||
When including `macro_collections.h` in your source code you gain access to a macro called `COLLECTION_GENERATE` with the following parameters:
|
||||
|
||||
> Note: in future updates, PRIVATE and PUBLIC will no longer exist
|
||||
|
||||
* \*__C__ - Container name in uppercase (*LIST*, *LINKEDLIST*, *STACK*, *QUEUE*, *DEQUE*, *HEAP*, *TREESET*, *TREEMAP*, *HASHSET*, *HASHMAP*).
|
||||
* \*__P__ - Permission (PRIVATE, PUBLIC). Only matters when header and source are declared in separate files.
|
||||
* *PRIVATE* - Members of a struct are hidden in source file and only accessible through functions.
|
||||
@@ -83,7 +95,7 @@ When including `macro_collections.h` in your source code you gain access to a ma
|
||||
* \*__SNAME__ - Structure name (`typedef struct SNAME##_s SNAME`).
|
||||
* __FMOD__ - Function modifier (`static` or empty).
|
||||
* \*\*__K__ - Key type. Only used in *HASHMAP* and *TREEMAP*; ignored by others.
|
||||
* \*__V__ - Value type. Primary type for most data structures, or value to be mapped by *HASHMAP* and *TREEMAP*.
|
||||
* \*__V__ - Value type. Primary type for most collections, or value to be mapped by *HASHMAP* and *TREEMAP*.
|
||||
|
||||
\* Required parameters
|
||||
|
||||
@@ -95,81 +107,7 @@ When including `foreach.h` in your source code you gain access to all for-each m
|
||||
|
||||
* __PFX__ - Functions prefix or namespace.
|
||||
* __SNAME__ - Structure name.
|
||||
* __V__ - Value type.
|
||||
* \*__K__ - Key type.
|
||||
* __TARGET__ - The variable name of the data structure you wish to iterate over.
|
||||
* __TARGET__ - The variable name of the collection you wish to iterate over.
|
||||
* __BODY__ - Block of code.
|
||||
|
||||
\* Only available for `FOR_EACH_MAP` and `FOR_EACH_MAP_REV`.
|
||||
|
||||
Inside body you will have access to three new variables:
|
||||
|
||||
* `iter` - Represents the iterator.
|
||||
* \*`key` - Represents the resulting key on each iteration.
|
||||
* `value` - Represents the resulting value on each iteration.
|
||||
|
||||
\* Only available in `FOR_EACH_MAP` and `FOR_EACH_MAP_REV`.
|
||||
|
||||
### Separate Header and Source
|
||||
|
||||
Below is an example of how to hide the struct members when using a separate source file.
|
||||
|
||||
**header.h**
|
||||
|
||||
```c
|
||||
#include "macro_collection.h"
|
||||
|
||||
COLLECTION_GENERATE_HEADER(LIST, PRIVATE, l, list, , , int)
|
||||
```
|
||||
|
||||
**source.c**
|
||||
|
||||
```c
|
||||
#include "header.h"
|
||||
|
||||
COLLECTION_GENERATE_SOURCE(LIST, PRIVATE, l, list, , , int)
|
||||
```
|
||||
|
||||
**main.c**
|
||||
|
||||
|
||||
```c
|
||||
#include "header.h"
|
||||
|
||||
int main(void)
|
||||
{
|
||||
list *my_list = l_new(100);
|
||||
|
||||
// Valid code
|
||||
size_t len1 = l_count(my_list);
|
||||
|
||||
// Invalid code
|
||||
size_t len2 = my_list->count;
|
||||
|
||||
l_free(my_list);
|
||||
}
|
||||
```
|
||||
|
||||
**Compilation process**
|
||||
|
||||
```
|
||||
gcc -c source.c -I ./path/to/source
|
||||
gcc -c main.c -I ./path/to/source
|
||||
gcc source.o main.o
|
||||
```
|
||||
|
||||
The container members won't be visible to the file `main.c`. For this to work, all parameters must be identical, with the only difference being the macro name.
|
||||
|
||||
## What to use
|
||||
|
||||
The following table shows how each data structure is implemented and how well they do when using as common [abstract data types](https://en.wikipedia.org/wiki/Abstract_data_type).
|
||||
|
||||
* **Ideal** - The data structure 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.
|
||||
|
||||

|
||||
|
||||

|
||||

|
||||

|
||||
Inside body you will have access to the iterator variable. With it you can use functions to access the key, value or index from the iterator.
|
||||
@@ -0,0 +1,56 @@
|
||||
TODO
|
||||
|
||||
[ ] Finish Documentation
|
||||
[ ] Simplify PUBLIC and PRIVATE
|
||||
[ ] Add multiset
|
||||
[ ] Add multimap
|
||||
[ ] Upgrade heap to a min-max heap
|
||||
[ ] Add dispose function
|
||||
[ ] Serialization
|
||||
[ ] Iterator based functions (like C++ collections)
|
||||
|
||||
|
||||
MAYBE
|
||||
|
||||
[ ] Add conditional code generation based on variadic macros
|
||||
|
||||
|
||||
PLANNED
|
||||
|
||||
Before 2.0
|
||||
Get Documentation fixed and completed
|
||||
|
||||
1.5
|
||||
Simplify PUBLIC and PRIVATE (simply remove them)
|
||||
Conditional code generation
|
||||
Add extra content macro (Insert/Remove/Append/Prepend) and let user decide if he wants to include them or not
|
||||
Separate Implementation Detail into a different MACRO (LIST_GENERATE_DETAIL)
|
||||
|
||||
1.6
|
||||
Iterator move and move_to
|
||||
LinkedList - Insert/Remove/Append/Prepend/Extract
|
||||
to_array - Creates an array with all the elements inside the collection
|
||||
|
||||
1.7
|
||||
Add shrink function that shrinks the internal buffer to current count of elements
|
||||
|
||||
2.0
|
||||
Add multiset, multimap and new heap implementation
|
||||
|
||||
2.1
|
||||
Adapt multiset, multimap, treehashmap and new heap implementation to the current standards
|
||||
Add dispose method to each collection in order to automatically free its data
|
||||
|
||||
2.2
|
||||
Add serialization functions
|
||||
Header:
|
||||
%d - Type specifier (LIST = 0, DEQUE = 1, STACK = 2, etc) for quick check
|
||||
%llu - How many elements there are
|
||||
%d - If data varies in size
|
||||
%llu - Data size
|
||||
|
||||
2.3
|
||||
Iterator functions (functions that operate relative to iterators position) like add or remove ranges
|
||||
|
||||
Sometime
|
||||
Add treehashmap
|
||||
@@ -0,0 +1,232 @@
|
||||
/**
|
||||
* benchmark.c
|
||||
*
|
||||
* Creation Date: 13/04/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
* Benchmarks:
|
||||
* - Input
|
||||
* - Search
|
||||
* - Iteration
|
||||
* - Output
|
||||
*/
|
||||
#include "macro_collections.h"
|
||||
#include "util/timer.h"
|
||||
#include "util/twister.c"
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#define NTOTAL UINT64_C(10000000)
|
||||
#define NMIN UINT64_C(100)
|
||||
|
||||
// Percentage % macro
|
||||
#define PC(x) x * 100.0
|
||||
|
||||
static int intcmp(int a, int b)
|
||||
{
|
||||
return a - b;
|
||||
}
|
||||
|
||||
static size_t inthash(int t)
|
||||
{
|
||||
size_t a = t;
|
||||
a += ~(a << 15);
|
||||
a ^= (a >> 10);
|
||||
a += (a << 3);
|
||||
a ^= (a >> 6);
|
||||
a += ~(a << 11);
|
||||
a ^= (a >> 16);
|
||||
return a;
|
||||
}
|
||||
|
||||
size_t randsize(size_t min, size_t max, mt_state_ptr st)
|
||||
{
|
||||
return (size_t)floor(twist_real(st) * ((double)max - (double)min + 1.0) + (double)min);
|
||||
}
|
||||
|
||||
void shuffle(int *array, mt_state_ptr st)
|
||||
{
|
||||
for (size_t i = 0; i < NTOTAL; i++)
|
||||
{
|
||||
size_t j = randsize(0, NTOTAL - 1, st);
|
||||
int tmp = array[j];
|
||||
array[j] = array[i];
|
||||
array[i] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
COLLECTION_GENERATE(LIST, PUBLIC, l, list, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE(STACK, PUBLIC, s, stack, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE(QUEUE, PUBLIC, q, queue, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE(DEQUE, PUBLIC, d, deque, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE(LINKEDLIST, PUBLIC, ll, linked, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE(HEAP, PUBLIC, h, heap, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE(TREESET, PUBLIC, ts, tset, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE(TREEMAP, PUBLIC, tm, tmap, /* FMOD */, int, int)
|
||||
COLLECTION_GENERATE(HASHSET, PUBLIC, hs, hset, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE(HASHMAP, PUBLIC, hm, hmap, /* FMOD */, int, int)
|
||||
|
||||
#define BENCHMARK(NAME, PFX, sname, initfunc, insertbody, removebody, searchbody) \
|
||||
void NAME##_io_benchmark(int *array, int *sarray, size_t s) \
|
||||
{ \
|
||||
printf("+------------------------------------------------------------ %10s\n", #NAME); \
|
||||
printf("+------------------------------------------------------------ \n"); \
|
||||
timer_t timer, total; \
|
||||
int r, k, v; \
|
||||
size_t j; \
|
||||
\
|
||||
sname *coll = initfunc; \
|
||||
\
|
||||
TIMER_START(total) \
|
||||
TIMER_START(timer) \
|
||||
\
|
||||
for (size_t i = 0; i < NTOTAL; i++) \
|
||||
{ \
|
||||
insertbody; \
|
||||
} \
|
||||
\
|
||||
TIMER_STOP(timer) \
|
||||
\
|
||||
TIMER_CALC(timer) \
|
||||
\
|
||||
size_t s1 = PFX##_count(coll); \
|
||||
\
|
||||
printf(" INPUT %10s TOOK %8.0lf milliseconds for %8" PRIuMAX " elements\n", #NAME, timer.result, s1); \
|
||||
\
|
||||
double input_time = timer.result; \
|
||||
\
|
||||
TIMER_START(timer) \
|
||||
\
|
||||
for (size_t i = 0; i < s; i++) \
|
||||
{ \
|
||||
searchbody; \
|
||||
} \
|
||||
\
|
||||
TIMER_STOP(timer) \
|
||||
\
|
||||
TIMER_CALC(timer) \
|
||||
\
|
||||
printf(" SEARCH %10s TOOK %8.0lf milliseconds for %8" PRIuMAX " elements\n", #NAME, timer.result, s); \
|
||||
\
|
||||
double search_time = timer.result; \
|
||||
\
|
||||
sname##_iter iter; \
|
||||
\
|
||||
TIMER_START(timer) \
|
||||
\
|
||||
for (PFX##_iter_init(&iter, coll); !PFX##_iter_end(&iter); PFX##_iter_next(&iter)) \
|
||||
{ \
|
||||
} \
|
||||
\
|
||||
TIMER_STOP(timer) \
|
||||
\
|
||||
TIMER_CALC(timer) \
|
||||
\
|
||||
printf("ITERATION %10s TOOK %8.0lf milliseconds for %8" PRIuMAX " elements\n", #NAME, timer.result, s1); \
|
||||
\
|
||||
double iter_time = timer.result; \
|
||||
\
|
||||
TIMER_START(timer); \
|
||||
\
|
||||
for (size_t i = 0; i < NTOTAL; i++) \
|
||||
{ \
|
||||
removebody; \
|
||||
} \
|
||||
\
|
||||
TIMER_STOP(timer) \
|
||||
\
|
||||
TIMER_CALC(timer) \
|
||||
\
|
||||
size_t s2 = PFX##_count(coll); \
|
||||
\
|
||||
printf(" OUTPUT %10s TOOK %8.0lf milliseconds for %8" PRIuMAX " elements\n", #NAME, timer.result, s1); \
|
||||
\
|
||||
double output_time = timer.result; \
|
||||
\
|
||||
TIMER_STOP(total) \
|
||||
TIMER_CALC(total) \
|
||||
\
|
||||
PFX##_free(coll); \
|
||||
\
|
||||
double adj_search_time = (total.result - search_time) + (search_time * (double)NTOTAL) / (double)s; \
|
||||
double no_search = input_time + iter_time + output_time; \
|
||||
\
|
||||
printf("+------------------------------------------------------------ \n"); \
|
||||
printf("TOTAL TIME : %.0lf milliseconds\n", total.result); \
|
||||
printf("ADJUSTED TIME : %.0lf milliseconds\n", adj_search_time); \
|
||||
\
|
||||
printf("+------------------------------------------------------------ \n"); \
|
||||
printf(" INPUT : %5.2lf%% (%5.2f%%)\n", PC(input_time / total.result), PC(input_time / no_search)); \
|
||||
printf(" SEARCH : %5.2lf%%\n", PC(search_time / total.result)); \
|
||||
printf("ITERATION : %5.2lf%% (%5.2f%%)\n", PC(iter_time / total.result), PC(iter_time / no_search)); \
|
||||
printf(" OUTPUT : %5.2lf%% (%5.2f%%)\n", PC(output_time / total.result), PC(output_time / no_search)); \
|
||||
printf("+------------------------------------------------------------ \n"); \
|
||||
\
|
||||
assert(s1 == NTOTAL && s2 == 0); \
|
||||
\
|
||||
printf("+------------------------------------------------------------ %10s\n\n", #NAME); \
|
||||
}
|
||||
|
||||
BENCHMARK(DEQUE, d, deque, d_new(NTOTAL), d_push_back(coll, array[i]), d_pop_back(coll), d_contains(coll, sarray[i], intcmp))
|
||||
BENCHMARK(HASHMAP, hm, hmap, hm_new(NTOTAL, 0.8, intcmp, inthash), hm_insert(coll, array[i], array[i]), hm_remove(coll, array[i], &r), hm_contains(coll, sarray[i]))
|
||||
BENCHMARK(HASHSET, hs, hset, hs_new(NTOTAL, 0.8, intcmp, inthash), hs_insert(coll, array[i]), hs_remove(coll, array[i]), hs_contains(coll, sarray[i]))
|
||||
BENCHMARK(HEAP, h, heap, h_new(NTOTAL, MinHeap, intcmp), h_insert(coll, array[i]), h_remove(coll, &r), h_contains(coll, sarray[i]))
|
||||
BENCHMARK(LINKEDLIST, ll, linked, ll_new(), ll_push_back(coll, array[i]), ll_pop_back(coll), ll_contains(coll, sarray[i], intcmp))
|
||||
BENCHMARK(LIST, l, list, l_new(NTOTAL), l_push_back(coll, array[i]), l_pop_back(coll), l_contains(coll, sarray[i], intcmp))
|
||||
BENCHMARK(QUEUE, q, queue, q_new(NTOTAL), q_enqueue(coll, array[i]), q_dequeue(coll), q_contains(coll, sarray[i], intcmp))
|
||||
BENCHMARK(STACK, s, stack, s_new(NTOTAL), s_push(coll, array[i]), s_pop(coll), s_contains(coll, sarray[i], intcmp))
|
||||
BENCHMARK(TREEMAP, tm, tmap, tm_new(intcmp), tm_insert(coll, array[i], array[i]), tm_remove(coll, array[i], &r), tm_contains(coll, sarray[i]))
|
||||
BENCHMARK(TREESET, ts, tset, ts_new(intcmp), ts_insert(coll, array[i]), ts_remove(coll, array[i]), ts_contains(coll, sarray[i]))
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// Using the Mersenne Twister to generate random numbers. This seed
|
||||
// guarantees that everytime this program runs it will generate the same
|
||||
// random numbers. The random numbers influence on the shuffling of the
|
||||
// array.
|
||||
mt_state st;
|
||||
twist_init(&st, UINT64_C(12604951237));
|
||||
|
||||
int *array = malloc(NTOTAL * sizeof(int));
|
||||
int *sarray = malloc(NTOTAL * sizeof(int));
|
||||
|
||||
if (!array)
|
||||
{
|
||||
printf("Allocation failed\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (int i = -5000000; i < 5000000; i++)
|
||||
array[i + 5000000] = i;
|
||||
|
||||
shuffle(array, &st);
|
||||
|
||||
memcpy(sarray, array, NTOTAL * sizeof(int));
|
||||
|
||||
shuffle(sarray, &st);
|
||||
|
||||
printf("\nNote: Adjusted Time refers to if the container had done a search over all %" PRIuMAX " elements.\n\n", NTOTAL);
|
||||
|
||||
// Linear containers have to search for NMIN elements and non-linear (hash
|
||||
// and tree) have to search for all elements.
|
||||
DEQUE_io_benchmark(array, sarray, NMIN);
|
||||
HASHMAP_io_benchmark(array, sarray, NTOTAL);
|
||||
HASHSET_io_benchmark(array, sarray, NTOTAL);
|
||||
HEAP_io_benchmark(array, sarray, NMIN);
|
||||
LINKEDLIST_io_benchmark(array, sarray, NMIN);
|
||||
LIST_io_benchmark(array, sarray, NMIN);
|
||||
QUEUE_io_benchmark(array, sarray, NMIN);
|
||||
STACK_io_benchmark(array, sarray, NMIN);
|
||||
TREEMAP_io_benchmark(array, sarray, NTOTAL);
|
||||
TREESET_io_benchmark(array, sarray, NTOTAL);
|
||||
|
||||
free(array);
|
||||
free(sarray);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include "../src/macro_collections.h"
|
||||
|
||||
int intcmp(int a, int b)
|
||||
{
|
||||
return a - b;
|
||||
}
|
||||
|
||||
size_t inthash(int t)
|
||||
{
|
||||
size_t a = t;
|
||||
a += ~(a << 15);
|
||||
a ^= (a >> 10);
|
||||
a += (a << 3);
|
||||
a ^= (a >> 6);
|
||||
a += ~(a << 11);
|
||||
a ^= (a >> 16);
|
||||
return a;
|
||||
}
|
||||
|
||||
COLLECTION_GENERATE(HASHSET, PUBLIC, set, hash_set, static, , int)
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
{
|
||||
hash_set *set = set_new(50000, 0.9, intcmp, inthash);
|
||||
//hash_set *set = set_new(intcmp);
|
||||
|
||||
for (int i = -1000000; i <= 1000000; i++)
|
||||
set_insert(set, i);
|
||||
|
||||
hash_set_iter iter;
|
||||
|
||||
size_t index;
|
||||
int result, total_sum = 0;
|
||||
for (set_iter_new(&iter, set); !set_iter_end(&iter);)
|
||||
{
|
||||
set_iter_next(&iter, &result, &index);
|
||||
total_sum += result;
|
||||
}
|
||||
|
||||
set_free(set);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include "../src/macro_collections.h"
|
||||
|
||||
int intcmp(int a, int b)
|
||||
{
|
||||
return a - b;
|
||||
}
|
||||
|
||||
size_t inthash(int t)
|
||||
{
|
||||
size_t a = t;
|
||||
a += ~(a << 15);
|
||||
a ^= (a >> 10);
|
||||
a += (a << 3);
|
||||
a ^= (a >> 6);
|
||||
a += ~(a << 11);
|
||||
a ^= (a >> 16);
|
||||
return a;
|
||||
}
|
||||
|
||||
COLLECTION_GENERATE(TREESET, PUBLIC, set, hash_set, static, , int)
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
{
|
||||
//hash_set *set = set_new(50000, 0.9, intcmp, inthash);
|
||||
hash_set *set = set_new(intcmp);
|
||||
|
||||
for (int i = -1000000; i <= 1000000; i++)
|
||||
set_insert(set, i);
|
||||
|
||||
hash_set_iter iter;
|
||||
|
||||
size_t index;
|
||||
int result, total_sum = 0;
|
||||
for (set_iter_new(&iter, set); !set_iter_end(&iter);)
|
||||
{
|
||||
set_iter_next(&iter, &result, &index);
|
||||
total_sum += result;
|
||||
}
|
||||
|
||||
set_free(set);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* timer.h
|
||||
*
|
||||
* Creation Date: 12/04/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
* Simple timer macros.
|
||||
*/
|
||||
#include <time.h>
|
||||
|
||||
typedef struct timer_s
|
||||
{
|
||||
clock_t start;
|
||||
clock_t stop;
|
||||
double result;
|
||||
} timer_t;
|
||||
|
||||
#define TIMER_START(timer) \
|
||||
timer.start = clock();
|
||||
|
||||
#define TIMER_STOP(timer) \
|
||||
timer.stop = clock();
|
||||
|
||||
#define TIMER_CALC(timer) \
|
||||
timer.result = (double)(((timer.stop - timer.start) * 1000.0) / CLOCKS_PER_SEC);
|
||||
@@ -0,0 +1,102 @@
|
||||
/**
|
||||
* twister.c
|
||||
*
|
||||
* Creation Date: 09/05/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
* Mersenne Twister PRNG utility
|
||||
*
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define NN 312
|
||||
#define MM 156
|
||||
#define MATRIX_A UINT64_C(0xB5026F5AA96619E9)
|
||||
#define UM UINT64_C(0xFFFFFFFF80000000) // Most significant 33 bits
|
||||
#define LM UINT64_C(0x7FFFFFFF) // Least significant 31 bits
|
||||
|
||||
// State vector
|
||||
typedef struct mt_state_s
|
||||
{
|
||||
uint64_t mt[NN];
|
||||
int mti;
|
||||
} mt_state, *mt_state_ptr;
|
||||
|
||||
// Initializes mt[NN] with a seed
|
||||
void twist_init(mt_state_ptr st, uint64_t seed);
|
||||
|
||||
// Generates a random uint64_t in [0, 2^64-1] interval
|
||||
uint64_t twist_uint64(mt_state_ptr st);
|
||||
|
||||
// Generates a double in [0, 1) interval
|
||||
double twist_real(mt_state_ptr st);
|
||||
|
||||
//
|
||||
// Implementation
|
||||
//
|
||||
|
||||
// Initialize a state mt[NN] with a seed
|
||||
void twist_init(mt_state_ptr st, uint64_t seed)
|
||||
{
|
||||
st->mti = NN + 1;
|
||||
|
||||
st->mt[0] = seed;
|
||||
|
||||
for (st->mti = 1; st->mti < NN; st->mti++)
|
||||
{
|
||||
st->mt[st->mti] = (UINT64_C(6364136223846793005) * (st->mt[st->mti - 1] ^ (st->mt[st->mti - 1] >> 62)) + st->mti);
|
||||
}
|
||||
}
|
||||
|
||||
// Generates a random uint64_t in [0, 2^64-1] interval
|
||||
uint64_t twist_uint64(mt_state_ptr st)
|
||||
{
|
||||
int i;
|
||||
uint64_t x;
|
||||
static uint64_t mag01[2] = {UINT64_C(0), MATRIX_A};
|
||||
|
||||
if (st->mti >= NN)
|
||||
{
|
||||
// Generate NN words at one time if twist_init() has not been called
|
||||
// A default initial seed is used
|
||||
if (st->mti == NN + 1)
|
||||
twist_init(st, UINT64_C(5489));
|
||||
|
||||
for (i = 0; i < NN - MM; i++)
|
||||
{
|
||||
x = (st->mt[i] & UM) | (st->mt[i + 1] & LM);
|
||||
st->mt[i] = st->mt[i + MM] ^ (x >> 1) ^ mag01[(int)(x & UINT64_C(1))];
|
||||
}
|
||||
|
||||
for (; i < NN - 1; i++)
|
||||
{
|
||||
x = (st->mt[i] & UM) | (st->mt[i + 1] & LM);
|
||||
st->mt[i] = st->mt[i + (MM - NN)] ^ (x >> 1) ^ mag01[(int)(x & UINT64_C(1))];
|
||||
}
|
||||
|
||||
x = (st->mt[NN - 1] & UM) | (st->mt[0] & LM);
|
||||
|
||||
st->mt[NN - 1] = st->mt[MM - 1] ^ (x >> 1) ^ mag01[(int)(x & UINT64_C(1))];
|
||||
|
||||
st->mti = 0;
|
||||
}
|
||||
|
||||
x = st->mt[st->mti++];
|
||||
|
||||
x ^= (x >> 29) & UINT64_C(0x5555555555555555);
|
||||
x ^= (x << 17) & UINT64_C(0x71D67FFFEDA60000);
|
||||
x ^= (x << 37) & UINT64_C(0xFFF7EEE000000000);
|
||||
x ^= (x >> 43);
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
// Generates a double in [0, 1) interval
|
||||
double twist_real(mt_state_ptr st)
|
||||
{
|
||||
return (twist_uint64(st) >> 11) * (1.0 / 9007199254740992.0);
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
# Deque examples
|
||||
|
||||
* even_odd.c - separates odd numbers to one end of the deque and even number to the other. Sum only half of it to give the total sum of even numbers.
|
||||
* iterator.c - A complete example of the deque iterator
|
||||
@@ -29,13 +29,14 @@ int main(int argc, char const *argv[])
|
||||
}
|
||||
|
||||
deque_iter iter;
|
||||
d_iter_new(&iter, numbers);
|
||||
d_iter_init(&iter, numbers);
|
||||
|
||||
size_t result, index, sum = 0;
|
||||
|
||||
for (d_iter_toend(&iter); !d_iter_start(&iter);)
|
||||
for (d_iter_to_end(&iter); !d_iter_start(&iter); d_iter_prev(&iter))
|
||||
{
|
||||
d_iter_prev(&iter, &result, &index);
|
||||
result = d_iter_value(&iter);
|
||||
index = d_iter_index(&iter);
|
||||
|
||||
if ((double)index < (double)d_count(numbers) / 2.0)
|
||||
break;
|
||||
|
||||
@@ -0,0 +1,199 @@
|
||||
/**
|
||||
* iterator.c
|
||||
*
|
||||
* Creation Date: 13/05/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
* Iterator Example
|
||||
*/
|
||||
#include "deque.h"
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
// Creates a deque of integers
|
||||
DEQUE_GENERATE(d, deque, /* FMOD */, int)
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
{
|
||||
// Create a new deque with an initial capacity of 100
|
||||
deque *my_deque = d_new(100);
|
||||
|
||||
// Add elements to the deque
|
||||
for (int i = 0; i < 20; i++)
|
||||
{
|
||||
// Add odd numbers to the front
|
||||
d_push_front_if(my_deque, i, !(i % 2 == 0));
|
||||
|
||||
// And even numbers to the back
|
||||
d_push_back_if(my_deque, i, i % 2 == 0);
|
||||
}
|
||||
|
||||
// Iterate from the start (front index) to the end (rear index) of the deque
|
||||
for (deque_iter it = my_deque->it_start(my_deque); // Initialize iterator 'it' to the start of the deque
|
||||
!d_iter_end(&it); // Conditional stop (until it is not at the end)
|
||||
d_iter_next(&it)) // Iterator goes one position forward
|
||||
{
|
||||
// Access the current element
|
||||
int e = d_iter_value(&it);
|
||||
|
||||
// Access the current index (index is relative to all the elements in the iteration)
|
||||
size_t i = d_iter_index(&it);
|
||||
|
||||
// Print deque
|
||||
|
||||
// Index is useful in situations like this
|
||||
// If it is the first element
|
||||
if (i == 0)
|
||||
printf("[ %d, ", e);
|
||||
// If it is the last element
|
||||
else if (i == d_count(my_deque) - 1)
|
||||
printf("%d ]\n", e);
|
||||
// For elements at the middle
|
||||
else
|
||||
printf("%d, ", e);
|
||||
}
|
||||
|
||||
// Index can also be used to iterate over a certain portion of a collection
|
||||
size_t limit = d_count(my_deque) / 2;
|
||||
for (deque_iter it = my_deque->it_start(my_deque); !d_iter_end(&it); d_iter_next(&it))
|
||||
{
|
||||
// Access the current element
|
||||
int e = d_iter_value(&it);
|
||||
|
||||
// Access the current index (index is relative to all the elements in the iteration)
|
||||
size_t i = d_iter_index(&it);
|
||||
|
||||
// Print deque up until limit
|
||||
|
||||
// If it is the first element
|
||||
if (i == 0)
|
||||
printf("[ %d, ", e);
|
||||
// If it is the last element
|
||||
else if (i == limit - 1) // -1 because index is 0 based and we want half of the deque
|
||||
{
|
||||
printf("%d ]\n", e);
|
||||
break;
|
||||
}
|
||||
// For elements at the middle
|
||||
else
|
||||
printf("%d, ", e);
|
||||
}
|
||||
|
||||
// Going backwards
|
||||
for (deque_iter it = my_deque->it_end(my_deque); // Initialize iterator 'it' to the end of the deque
|
||||
!d_iter_start(&it); // Conditional stop (until it is not at the start)
|
||||
d_iter_prev(&it)) // Iterator goes one position backwards
|
||||
{
|
||||
// Access the current element
|
||||
int e = d_iter_value(&it);
|
||||
|
||||
// Access the current index (index is relative to all the elements in the iteration)
|
||||
size_t i = d_iter_index(&it);
|
||||
|
||||
// Print deque
|
||||
// Note how the conditions for the first and last elements are simply swapped
|
||||
// Because iterating backwards make the first element be the index count - 1
|
||||
// and the last one be the index 0
|
||||
|
||||
// If it is the first element
|
||||
if (i == d_count(my_deque) - 1)
|
||||
printf("[ %d, ", e);
|
||||
// If it is the last element
|
||||
else if (i == 0)
|
||||
printf("%d ]\n", e);
|
||||
// For elements at the middle
|
||||
else
|
||||
printf("%d, ", e);
|
||||
}
|
||||
|
||||
// You can also use iterators in a while loop
|
||||
// But to do so you must declare the iterator struct outside the loop first
|
||||
deque_iter it;
|
||||
|
||||
// You have three options:
|
||||
// - Initialize it using the functions provided by the deque [ my_deque->it_start() and my_deque->it_end() ]
|
||||
// - Initialize it using the init() function (when the iterator is already allocated)
|
||||
// - Initialize it using the new() function (allocates on the heap, pointers only)
|
||||
|
||||
it = my_deque->it_start(my_deque);
|
||||
it = my_deque->it_end(my_deque);
|
||||
|
||||
// This is equivalent to it_start()
|
||||
d_iter_init(&it, my_deque);
|
||||
|
||||
// For pointers
|
||||
// Also equivalent to it_start()
|
||||
deque_iter *iter = d_iter_new(my_deque);
|
||||
|
||||
// The actual while loop
|
||||
while (!d_iter_end(iter))
|
||||
{
|
||||
// Accessing elements
|
||||
int e = d_iter_value(iter);
|
||||
size_t i = d_iter_index(iter);
|
||||
|
||||
// Print index and element
|
||||
printf("deque[%2" PRIuMAX "] = %2d\n", i, e);
|
||||
|
||||
// Move iterator forwards
|
||||
d_iter_next(iter);
|
||||
}
|
||||
|
||||
// Send the iterator to the start of the deque
|
||||
d_iter_to_start(iter);
|
||||
|
||||
// Send the iterator to the end of the deque
|
||||
d_iter_to_end(iter);
|
||||
|
||||
// Backwards loop
|
||||
while (!d_iter_start(iter))
|
||||
{
|
||||
// Accessing elements
|
||||
int e = d_iter_value(iter);
|
||||
size_t i = d_iter_index(iter);
|
||||
|
||||
// Print index and element
|
||||
printf("deque[%2" PRIuMAX "] = %2d\n", i, e);
|
||||
|
||||
// Move iterator backwards
|
||||
d_iter_prev(iter);
|
||||
}
|
||||
|
||||
// Certain iterators also allow you to modify the contents it is iterating over
|
||||
// Exceptions are collections that depend of the current state of the element
|
||||
// like tree-based collections and heap (collections that have some kind of ordering).
|
||||
// You also can't change the keys of an associative collection
|
||||
|
||||
// Change every element that is divisible by 3 to the number 7
|
||||
for (d_iter_to_start(&it); !d_iter_end(&it); d_iter_next(&it))
|
||||
{
|
||||
// Get a reference to the current value
|
||||
int *r = d_iter_rvalue(&it);
|
||||
|
||||
if (r != NULL && *r % 3 == 0)
|
||||
*r = 7;
|
||||
}
|
||||
|
||||
// Now print it to see the difference
|
||||
for (deque_iter it = my_deque->it_start(my_deque); !d_iter_end(&it); d_iter_next(&it))
|
||||
{
|
||||
int e = d_iter_value(&it);
|
||||
size_t i = d_iter_index(&it);
|
||||
|
||||
if (i == 0)
|
||||
printf("[ %d, ", e);
|
||||
else if (i == d_count(my_deque) - 1)
|
||||
printf("%d ]\n", e);
|
||||
else
|
||||
printf("%d, ", e);
|
||||
}
|
||||
|
||||
// Dispose the iterator called by d_iter_new()
|
||||
d_iter_free(iter);
|
||||
// Dispose the deque created
|
||||
d_free(my_deque);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
# Hashmap examples
|
||||
|
||||
Currently none
|
||||
* countries - Uses a hashmap to map the country name to its population
|
||||
* iterator.c - A complete example of the hashmap iterator
|
||||
@@ -0,0 +1,216 @@
|
||||
Afghanistan,34656032
|
||||
Albania,2876101
|
||||
Algeria,40606052
|
||||
American Samoa,55599
|
||||
Andorra,77281
|
||||
Angola,28813463
|
||||
Antigua and Barbuda,100963
|
||||
Argentina,43847430
|
||||
Armenia,2924816
|
||||
Aruba,104822
|
||||
Australia,24127159
|
||||
Austria,8747358
|
||||
Azerbaijan,9762274
|
||||
Bahamas; The,391232
|
||||
Bahrain,1425171
|
||||
Bangladesh,162951560
|
||||
Barbados,284996
|
||||
Belarus,9507120
|
||||
Belgium,11348159
|
||||
Belize,366954
|
||||
Benin,10872298
|
||||
Bermuda,65331
|
||||
Bhutan,797765
|
||||
Bolivia,10887882
|
||||
Bosnia and Herzegovina,3516816
|
||||
Botswana,2250260
|
||||
Brazil,207652865
|
||||
British Virgin Islands,30661
|
||||
Brunei Darussalam,423196
|
||||
Bulgaria,7127822
|
||||
Burkina Faso,18646433
|
||||
Burundi,10524117
|
||||
Cabo Verde,539560
|
||||
Cambodia,15762370
|
||||
Cameroon,23439189
|
||||
Canada,36286425
|
||||
Cayman Islands,60765
|
||||
Central African Republic,4594621
|
||||
Chad,14452543
|
||||
Channel Islands,164541
|
||||
Chile,17909754
|
||||
China,1378665000
|
||||
Colombia,48653419
|
||||
Comoros,795601
|
||||
Congo; Dem. Rep.,78736153
|
||||
Congo; Rep.,5125821
|
||||
Costa Rica,4857274
|
||||
Cote d'Ivoire,23695919
|
||||
Croatia,4170600
|
||||
Cuba,11475982
|
||||
Curacao,159999
|
||||
Cyprus,1170125
|
||||
Czech Republic,10561633
|
||||
Denmark,5731118
|
||||
Djibouti,942333
|
||||
Dominica,73543
|
||||
Dominican Republic,10648791
|
||||
Ecuador,16385068
|
||||
Egypt; Arab Rep.,95688681
|
||||
El Salvador,6344722
|
||||
Equatorial Guinea,1221490
|
||||
Estonia,1316481
|
||||
Ethiopia,102403196
|
||||
Faroe Islands,49117
|
||||
Fiji,898760
|
||||
Finland,5495096
|
||||
France,66896109
|
||||
French Polynesia,280208
|
||||
Gabon,1979786
|
||||
Gambia; The,2038501
|
||||
Georgia,3719300
|
||||
Germany,82667685
|
||||
Ghana,28206728
|
||||
Gibraltar,34408
|
||||
Greece,10746740
|
||||
Greenland,56186
|
||||
Grenada,107317
|
||||
Guam,162896
|
||||
Guatemala,16582469
|
||||
Guinea,12395924
|
||||
Guinea-Bissau,1815698
|
||||
Guyana,773303
|
||||
Haiti,10847334
|
||||
Honduras,9112867
|
||||
Hong Kong SAR; China,7346700
|
||||
Hungary,9817958
|
||||
Iceland,334252
|
||||
India,1324171354
|
||||
Indonesia,261115456
|
||||
Iran; Islamic Rep.,80277428
|
||||
Iraq,37202572
|
||||
Ireland,4773095
|
||||
Isle of Man,83737
|
||||
Israel,8547100
|
||||
Italy,60600590
|
||||
Jamaica,2881355
|
||||
Japan,126994511
|
||||
Jordan,9455802
|
||||
Kazakhstan,17797032
|
||||
Kenya,48461567
|
||||
Kiribati,114395
|
||||
Korea; Dem. People’s Rep.,25368620
|
||||
Korea; Rep.,51245707
|
||||
Kosovo,1816200
|
||||
Kuwait,4052584
|
||||
Kyrgyz Republic,6082700
|
||||
Lao PDR,6758353
|
||||
Latvia,1960424
|
||||
Lebanon,6006668
|
||||
Lesotho,2203821
|
||||
Liberia,4613823
|
||||
Libya,6293253
|
||||
Liechtenstein,37666
|
||||
Lithuania,2872298
|
||||
Luxembourg,582972
|
||||
Macao SAR; China,612167
|
||||
Macedonia; FYR,2081206
|
||||
Madagascar,24894551
|
||||
Malawi,18091575
|
||||
Malaysia,31187265
|
||||
Maldives,417492
|
||||
Mali,17994837
|
||||
Malta,436947
|
||||
Marshall Islands,53066
|
||||
Mauritania,4301018
|
||||
Mauritius,1263473
|
||||
Mexico,127540423
|
||||
Micronesia; Fed. Sts.,104937
|
||||
Moldova,3552000
|
||||
Monaco,38499
|
||||
Mongolia,3027398
|
||||
Montenegro,622781
|
||||
Morocco,35276786
|
||||
Mozambique,28829476
|
||||
Myanmar,52885223
|
||||
Namibia,2479713
|
||||
Nauru,13049
|
||||
Nepal,28982771
|
||||
Netherlands,17018408
|
||||
New Caledonia,278000
|
||||
New Zealand,4692700
|
||||
Nicaragua,6149928
|
||||
Niger,20672987
|
||||
Nigeria,185989640
|
||||
Northern Mariana Islands,55023
|
||||
Norway,5232929
|
||||
Oman,4424762
|
||||
Pakistan,193203476
|
||||
Palau,21503
|
||||
Panama,4034119
|
||||
Papua New Guinea,8084991
|
||||
Paraguay,6725308
|
||||
Peru,31773839
|
||||
Philippines,103320222
|
||||
Poland,37948016
|
||||
Portugal,10324611
|
||||
Puerto Rico,3411307
|
||||
Qatar,2569804
|
||||
Romania,19705301
|
||||
Russian Federation,144342396
|
||||
Rwanda,11917508
|
||||
Samoa,195125
|
||||
San Marino,33203
|
||||
Sao Tome and Principe,199910
|
||||
Saudi Arabia,32275687
|
||||
Senegal,15411614
|
||||
Serbia,7057412
|
||||
Seychelles,94677
|
||||
Sierra Leone,7396190
|
||||
Singapore,5607283
|
||||
Sint Maarten (Dutch part),40005
|
||||
Slovak Republic,5428704
|
||||
Slovenia,2064845
|
||||
Solomon Islands,599419
|
||||
Somalia,14317996
|
||||
South Africa,55908865
|
||||
South Sudan,12230730
|
||||
Spain,46443959
|
||||
Sri Lanka,21203000
|
||||
St. Kitts and Nevis,54821
|
||||
St. Lucia,178015
|
||||
St. Martin (French part),31949
|
||||
St. Vincent and the Grenadines,109643
|
||||
Sudan,39578828
|
||||
Suriname,558368
|
||||
Swaziland,1343098
|
||||
Sweden,9903122
|
||||
Switzerland,8372098
|
||||
Syrian Arab Republic,18430453
|
||||
Tajikistan,8734951
|
||||
Tanzania,55572201
|
||||
Thailand,68863514
|
||||
Timor-Leste,1268671
|
||||
Togo,7606374
|
||||
Tonga,107122
|
||||
Trinidad and Tobago,1364962
|
||||
Tunisia,11403248
|
||||
Turkey,79512426
|
||||
Turkmenistan,5662544
|
||||
Turks and Caicos Islands,34900
|
||||
Tuvalu,11097
|
||||
Uganda,41487965
|
||||
Ukraine,45004645
|
||||
United Arab Emirates,9269612
|
||||
United Kingdom,65637239
|
||||
United States,323127513
|
||||
Uruguay,3444006
|
||||
Uzbekistan,31848200
|
||||
Vanuatu,270402
|
||||
Venezuela; RB,31568179
|
||||
Vietnam,92701100
|
||||
Virgin Islands (U.S.),102951
|
||||
West Bank and Gaza,4551566
|
||||
Yemen; Rep.,27584213
|
||||
Zambia,16591390
|
||||
Zimbabwe,16150362
|
||||
|
@@ -0,0 +1,90 @@
|
||||
#include "hashmap.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <inttypes.h>
|
||||
#include "util.c"
|
||||
|
||||
HASHMAP_GENERATE(hm, hmap, , char *, size_t)
|
||||
|
||||
hmap *load(const char *fname);
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
{
|
||||
hmap *map = load("data.csv");
|
||||
|
||||
if (!map)
|
||||
return 1;
|
||||
|
||||
printf("+--------------------------------------------------+\n");
|
||||
printf("| Search Country Population by Country Name |\n");
|
||||
printf("| |\n");
|
||||
printf("| - Type 'exit' to exit |\n");
|
||||
printf("| - Type country name to search its population |\n");
|
||||
printf("+--------------------------------------------------+\n\n");
|
||||
|
||||
// If you wish to list all items
|
||||
// char *key;
|
||||
// size_t value, index;
|
||||
|
||||
// hmap_iter iter;
|
||||
// for (hm_iter_new(&iter, map); !hm_iter_end(&iter);)
|
||||
// {
|
||||
// hm_iter_next(&iter, &key, &value, &index);
|
||||
// printf("%30s : %" PRIuMAX "\n", key, value);
|
||||
|
||||
// free(key);
|
||||
// }
|
||||
|
||||
char sbuffer[1000];
|
||||
|
||||
while (1)
|
||||
{
|
||||
printf("Query > ");
|
||||
fflush(stdin);
|
||||
scanf("%[^\n]s", sbuffer);
|
||||
|
||||
if (strcmp(sbuffer, "exit") == 0)
|
||||
break;
|
||||
|
||||
size_t *result = hm_get_ref(map, sbuffer);
|
||||
|
||||
if (result == NULL)
|
||||
printf("Result > %s Not Found\n", sbuffer);
|
||||
else
|
||||
printf("Result > %" PRIuMAX "\n", *result);
|
||||
}
|
||||
|
||||
hm_free(map);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
hmap *load(const char *fname)
|
||||
{
|
||||
FILE *fptr = fopen(fname, "r");
|
||||
|
||||
if (!fptr)
|
||||
return NULL;
|
||||
|
||||
hmap *map = hm_new(10000, 0.7, chrcmp, chrhash);
|
||||
|
||||
char buff[400];
|
||||
size_t value;
|
||||
|
||||
while (fscanf(fptr, "%[^,],%" PRIuMAX "\n", buff, &value) != EOF)
|
||||
{
|
||||
char *name = strdup(buff);
|
||||
|
||||
if (!hm_insert(map, name, value))
|
||||
{
|
||||
printf("\n\n\nERROR\n");
|
||||
printf("%s : %" PRIuMAX "", name, value);
|
||||
|
||||
exit(2);
|
||||
}
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
int chrcmp(char *a, char *b)
|
||||
{
|
||||
return strcmp(a, b);
|
||||
}
|
||||
|
||||
size_t chrhash(char *str)
|
||||
{
|
||||
size_t hash = 5381;
|
||||
int c;
|
||||
|
||||
while ((c = *str++))
|
||||
hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
|
||||
|
||||
return hash;
|
||||
}
|
||||
@@ -0,0 +1,230 @@
|
||||
/**
|
||||
* iterator.c
|
||||
*
|
||||
* Creation Date: 14/05/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
* Iterator Example
|
||||
*/
|
||||
#include "hashmap.h"
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
// Int hash function
|
||||
size_t inthash(int t)
|
||||
{
|
||||
size_t a = t;
|
||||
a += ~(a << 15);
|
||||
a ^= (a >> 10);
|
||||
a += (a << 3);
|
||||
a ^= (a >> 6);
|
||||
a += ~(a << 11);
|
||||
a ^= (a >> 16);
|
||||
return a;
|
||||
}
|
||||
|
||||
// Int compare function
|
||||
int intcmp(int a, int b)
|
||||
{
|
||||
return a - b;
|
||||
}
|
||||
|
||||
// Creates a hashmap of integers
|
||||
HASHMAP_GENERATE(hm, hashmap, /* FMOD */, int, double)
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
{
|
||||
// Create a new hashmap with an initial capacity of 100 and load factor of 0.6
|
||||
hashmap *my_map = hm_new(100, 0.6, intcmp, inthash);
|
||||
|
||||
// Add pairs to the hashmap
|
||||
for (int i = 0; i < 20; i++)
|
||||
{
|
||||
// Map integers to doubles
|
||||
hm_insert(my_map, i, (double)i / 10.0);
|
||||
}
|
||||
|
||||
// Iterate from the start (index 0) to the end (index count - 1) of the hashmap
|
||||
for (hashmap_iter it = my_map->it_start(my_map); // Initialize iterator 'it' to the start of the hashmap
|
||||
!hm_iter_end(&it); // Conditional stop (until it is not at the end)
|
||||
hm_iter_next(&it)) // Iterator goes one position forward
|
||||
{
|
||||
// Access the current key
|
||||
int k = hm_iter_key(&it);
|
||||
|
||||
// Access the current value
|
||||
double v = hm_iter_value(&it);
|
||||
|
||||
// Access the current index (index is relative to all the pairs in the iteration)
|
||||
size_t i = hm_iter_index(&it);
|
||||
|
||||
// Print hashmap
|
||||
|
||||
// Index is useful in situations like this
|
||||
// If it is the first pair
|
||||
if (i == 0)
|
||||
printf("[ {%d:%.2lf}, ", k, v);
|
||||
// If it is the last pair
|
||||
else if (i == hm_count(my_map) - 1)
|
||||
printf("{%d:%.2lf} ]\n", k, v);
|
||||
// For pairs at the middle
|
||||
else
|
||||
printf("{%d:%.2lf}, ", k, v);
|
||||
}
|
||||
|
||||
// Index can also be used to iterate over a certain portion of a collection
|
||||
size_t limit = hm_count(my_map) / 2;
|
||||
for (hashmap_iter it = my_map->it_start(my_map); !hm_iter_end(&it); hm_iter_next(&it))
|
||||
{
|
||||
// Access the current key
|
||||
int k = hm_iter_key(&it);
|
||||
|
||||
// Access the current value
|
||||
double v = hm_iter_value(&it);
|
||||
|
||||
// Access the current index (index is relative to all the pairs in the iteration)
|
||||
size_t i = hm_iter_index(&it);
|
||||
|
||||
// Print hashmap up until limit
|
||||
|
||||
// If it is the first pair
|
||||
if (i == 0)
|
||||
printf("[ {%d:%.2lf}, ", k, v);
|
||||
// If it is the last pair
|
||||
else if (i == limit - 1) // -1 because index is 0 based and we want half of the hashmap
|
||||
{
|
||||
printf("{%d:%.2lf} ]\n", k, v);
|
||||
break;
|
||||
}
|
||||
// For pairs at the middle
|
||||
else
|
||||
printf("{%d:%.2lf}, ", k, v);
|
||||
}
|
||||
|
||||
// Going backwards
|
||||
for (hashmap_iter it = my_map->it_end(my_map); // Initialize iterator 'it' to the end of the hashmap
|
||||
!hm_iter_start(&it); // Conditional stop (until it is not at the start)
|
||||
hm_iter_prev(&it)) // Iterator goes one position backwards
|
||||
{
|
||||
// Access the current key
|
||||
int k = hm_iter_key(&it);
|
||||
|
||||
// Access the current value
|
||||
double v = hm_iter_value(&it);
|
||||
|
||||
// Access the current index (index is relative to all the pairs in the iteration)
|
||||
size_t i = hm_iter_index(&it);
|
||||
|
||||
// Print hashmap
|
||||
// Note how the conditions for the first and last pairs are simply swapped
|
||||
// Because iterating backwards make the first pair be the index count - 1
|
||||
// and the last one be the index 0
|
||||
|
||||
// If it is the first pair
|
||||
if (i == hm_count(my_map) - 1)
|
||||
printf("[ {%d:%.2lf}, ", k, v);
|
||||
// If it is the last pair
|
||||
else if (i == 0)
|
||||
printf("{%d:%.2lf} ]\n", k, v);
|
||||
// For pairs at the middle
|
||||
else
|
||||
printf("{%d:%.2lf}, ", k, v);
|
||||
}
|
||||
|
||||
// You can also use iterators in a while loop
|
||||
// But to do so you must declare the iterator struct outside the loop first
|
||||
hashmap_iter it;
|
||||
|
||||
// You have three options:
|
||||
// - Initialize it using the functions provided by the hashmap [ my_map->it_start() and my_map->it_end() ]
|
||||
// - Initialize it using the init() function (when the iterator is already allocated)
|
||||
// - Initialize it using the new() function (allocates on the heap, pointers only)
|
||||
|
||||
it = my_map->it_start(my_map);
|
||||
it = my_map->it_end(my_map);
|
||||
|
||||
// This is equivalent to it_start()
|
||||
hm_iter_init(&it, my_map);
|
||||
|
||||
// For pointers
|
||||
// Also equivalent to it_start()
|
||||
hashmap_iter *iter = hm_iter_new(my_map);
|
||||
|
||||
// The actual while loop
|
||||
while (!hm_iter_end(iter))
|
||||
{
|
||||
// Accessing pairs
|
||||
int k = hm_iter_key(iter);
|
||||
double v = hm_iter_value(iter);
|
||||
size_t i = hm_iter_index(iter);
|
||||
|
||||
// Print index and key value pair
|
||||
printf("hashmap[%2" PRIuMAX "] = { %2d : %.2lf }\n", i, k, v);
|
||||
|
||||
// Move iterator forwards
|
||||
hm_iter_next(iter);
|
||||
}
|
||||
|
||||
// Send the iterator to the start of the hashmap
|
||||
hm_iter_to_start(iter);
|
||||
|
||||
// Send the iterator to the end of the hashmap
|
||||
hm_iter_to_end(iter);
|
||||
|
||||
// Backwards loop
|
||||
while (!hm_iter_start(iter))
|
||||
{
|
||||
// Accessing pairs
|
||||
int k = hm_iter_key(iter);
|
||||
double v = hm_iter_value(iter);
|
||||
size_t i = hm_iter_index(iter);
|
||||
|
||||
// Print index and the key value pair
|
||||
printf("hashmap[%2" PRIuMAX "] = { %2d : %.2lf }\n", i, k, v);
|
||||
|
||||
// Move iterator backwards
|
||||
hm_iter_prev(iter);
|
||||
}
|
||||
|
||||
// Certain iterators also allow you to modify the contents it is iterating over
|
||||
// Exceptions are collections that depend of the current state of the pair
|
||||
// like tree-based collections and heap (collections that have some kind of ordering).
|
||||
// You also can't change the keys of an associative collection
|
||||
|
||||
// Change every value where its key is divisible by 3 to the number 7
|
||||
for (hm_iter_to_start(&it); !hm_iter_end(&it); hm_iter_next(&it))
|
||||
{
|
||||
// Get current key
|
||||
int k = hm_iter_key(&it);
|
||||
|
||||
// Get a reference to the current value
|
||||
double *v = hm_iter_rvalue(&it);
|
||||
|
||||
if (k % 3 == 0)
|
||||
*v = 7;
|
||||
}
|
||||
|
||||
// Now print it to see the difference
|
||||
for (hashmap_iter it = my_map->it_start(my_map); !hm_iter_end(&it); hm_iter_next(&it))
|
||||
{
|
||||
int k = hm_iter_key(&it);
|
||||
double v = hm_iter_value(&it);
|
||||
size_t i = hm_iter_index(&it);
|
||||
|
||||
if (i == 0)
|
||||
printf("[ {%d:%.2lf}, ", k, v);
|
||||
else if (i == hm_count(my_map) - 1)
|
||||
printf("{%d:%.2lf} ]\n", k, v);
|
||||
else
|
||||
printf("{%d:%.2lf}, ", k, v);
|
||||
}
|
||||
|
||||
// Dispose the iterator called by hm_iter_new()
|
||||
hm_iter_free(iter);
|
||||
// Dispose the hashmap created
|
||||
hm_free(my_map);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
# Hashset examples
|
||||
|
||||
* iterator.c - A complete example of the hashset iterator
|
||||
* set_ops.c - Demonstrates common set operations like *union*, *intersection*, *difference* and *symmetric difference*.
|
||||
@@ -0,0 +1,194 @@
|
||||
/**
|
||||
* iterator.c
|
||||
*
|
||||
* Creation Date: 15/05/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
* Iterator Example
|
||||
*/
|
||||
#include "hashset.h"
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
// Int hash function
|
||||
size_t inthash(int t)
|
||||
{
|
||||
size_t a = t;
|
||||
a += ~(a << 15);
|
||||
a ^= (a >> 10);
|
||||
a += (a << 3);
|
||||
a ^= (a >> 6);
|
||||
a += ~(a << 11);
|
||||
a ^= (a >> 16);
|
||||
return a;
|
||||
}
|
||||
|
||||
// Int compare function
|
||||
int intcmp(int a, int b)
|
||||
{
|
||||
return a - b;
|
||||
}
|
||||
|
||||
// Creates a hashset of integers
|
||||
HASHSET_GENERATE(hs, hashset, /* FMOD */, int)
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
{
|
||||
// Create a new hashset with an initial capacity of 100 and load factor of 0.6
|
||||
hashset *my_hashset = hs_new(100, 0.6, intcmp, inthash);
|
||||
|
||||
// Add elements to the hashset
|
||||
for (int i = 0; i < 20; i++)
|
||||
{
|
||||
hs_insert(my_hashset, i);
|
||||
}
|
||||
|
||||
// Iterate from the start (index 0) to the end (index count - 1) of the hashset
|
||||
for (hashset_iter it = my_hashset->it_start(my_hashset); // Initialize iterator 'it' to the start of the hashset
|
||||
!hs_iter_end(&it); // Conditional stop (until it is not at the end)
|
||||
hs_iter_next(&it)) // Iterator goes one position forward
|
||||
{
|
||||
// Access the current element
|
||||
int e = hs_iter_value(&it);
|
||||
|
||||
// Access the current index (index is relative to all the elements in the iteration)
|
||||
size_t i = hs_iter_index(&it);
|
||||
|
||||
// Print hashset
|
||||
|
||||
// Index is useful in situations like this
|
||||
// If it is the first element
|
||||
if (i == 0)
|
||||
printf("[ %d, ", e);
|
||||
// If it is the last element
|
||||
else if (i == hs_count(my_hashset) - 1)
|
||||
printf("%d ]\n", e);
|
||||
// For elements at the middle
|
||||
else
|
||||
printf("%d, ", e);
|
||||
}
|
||||
|
||||
// Index can also be used to iterate over a certain portion of a collection
|
||||
size_t limit = hs_count(my_hashset) / 2;
|
||||
for (hashset_iter it = my_hashset->it_start(my_hashset); !hs_iter_end(&it); hs_iter_next(&it))
|
||||
{
|
||||
// Access the current element
|
||||
int e = hs_iter_value(&it);
|
||||
|
||||
// Access the current index (index is relative to all the elements in the iteration)
|
||||
size_t i = hs_iter_index(&it);
|
||||
|
||||
// Print hashset up until limit
|
||||
|
||||
// If it is the first element
|
||||
if (i == 0)
|
||||
printf("[ %d, ", e);
|
||||
// If it is the last element
|
||||
else if (i == limit - 1) // -1 because index is 0 based and we want half of the hashset
|
||||
{
|
||||
printf("%d ]\n", e);
|
||||
break;
|
||||
}
|
||||
// For elements at the middle
|
||||
else
|
||||
printf("%d, ", e);
|
||||
}
|
||||
|
||||
// Going backwards
|
||||
for (hashset_iter it = my_hashset->it_end(my_hashset); // Initialize iterator 'it' to the end of the hashset
|
||||
!hs_iter_start(&it); // Conditional stop (until it is not at the start)
|
||||
hs_iter_prev(&it)) // Iterator goes one position backwards
|
||||
{
|
||||
// Access the current element
|
||||
int e = hs_iter_value(&it);
|
||||
|
||||
// Access the current index (index is relative to all the elements in the iteration)
|
||||
size_t i = hs_iter_index(&it);
|
||||
|
||||
// Print hashset
|
||||
// Note how the conditions for the first and last elements are simply swapped
|
||||
// Because iterating backwards make the first element be the index count - 1
|
||||
// and the last one be the index 0
|
||||
|
||||
// If it is the first element
|
||||
if (i == hs_count(my_hashset) - 1)
|
||||
printf("[ %d, ", e);
|
||||
// If it is the last element
|
||||
else if (i == 0)
|
||||
printf("%d ]\n", e);
|
||||
// For elements at the middle
|
||||
else
|
||||
printf("%d, ", e);
|
||||
}
|
||||
|
||||
// You can also use iterators in a while loop
|
||||
// But to do so you must declare the iterator struct outside the loop first
|
||||
hashset_iter it;
|
||||
|
||||
// You have three options:
|
||||
// - Initialize it using the functions provided by the hashset [ my_hashset->it_start() and my_hashset->it_end() ]
|
||||
// - Initialize it using the init() function (when the iterator is already allocated)
|
||||
// - Initialize it using the new() function (allocates on the heap, pointers only)
|
||||
|
||||
it = my_hashset->it_start(my_hashset);
|
||||
it = my_hashset->it_end(my_hashset);
|
||||
|
||||
// This is equivalent to it_start()
|
||||
hs_iter_init(&it, my_hashset);
|
||||
|
||||
// For pointers
|
||||
// Also equivalent to it_start()
|
||||
hashset_iter *iter = hs_iter_new(my_hashset);
|
||||
|
||||
// The actual while loop
|
||||
while (!hs_iter_end(iter))
|
||||
{
|
||||
// Accessing elements
|
||||
int e = hs_iter_value(iter);
|
||||
size_t i = hs_iter_index(iter);
|
||||
|
||||
// Print index and element
|
||||
printf("hashset[%2" PRIuMAX "] = %2d\n", i, e);
|
||||
|
||||
// Move iterator forwards
|
||||
hs_iter_next(iter);
|
||||
}
|
||||
|
||||
// Send the iterator to the start of the hashset
|
||||
hs_iter_to_start(iter);
|
||||
|
||||
// Send the iterator to the end of the hashset
|
||||
hs_iter_to_end(iter);
|
||||
|
||||
// Backwards loop
|
||||
while (!hs_iter_start(iter))
|
||||
{
|
||||
// Accessing elements
|
||||
int e = hs_iter_value(iter);
|
||||
size_t i = hs_iter_index(iter);
|
||||
|
||||
// Print index and element
|
||||
printf("hashset[%2" PRIuMAX "] = %2d\n", i, e);
|
||||
|
||||
// Move iterator backwards
|
||||
hs_iter_prev(iter);
|
||||
}
|
||||
|
||||
// Certain iterators also allow you to modify the contents it is iterating over
|
||||
// Exceptions are collections that depend of the current state of the element
|
||||
// like tree-based collections and heap (collections that have some kind of ordering).
|
||||
// You also can't change the keys of an associative collection
|
||||
|
||||
// In the case of a hashset or any set, this is not possible because the
|
||||
// values of a set are its keys. Changing the elements could cause the set
|
||||
// to be in an invalid state.
|
||||
|
||||
// Dispose the iterator called by hs_iter_new()
|
||||
hs_iter_free(iter);
|
||||
// Dispose the hashset created
|
||||
hs_free(my_hashset);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -18,18 +18,17 @@
|
||||
#include <stdlib.h>
|
||||
#include "hashset.h"
|
||||
|
||||
// change to hashset to have the same effects
|
||||
HASHSET_GENERATE(set, set, /* static */, int)
|
||||
|
||||
void print_set(set *s)
|
||||
{
|
||||
size_t index;
|
||||
int result;
|
||||
set_iter iter;
|
||||
set_iter_new(&iter, s);
|
||||
for (set_iter_tostart(&iter); !set_iter_end(&iter);)
|
||||
set_iter_init(&iter, s);
|
||||
for (set_iter_to_start(&iter); !set_iter_end(&iter); set_iter_next(&iter))
|
||||
{
|
||||
set_iter_next(&iter, &result, &index);
|
||||
int result = set_iter_value(&iter);
|
||||
size_t index = set_iter_index(&iter);
|
||||
|
||||
if (index == 0)
|
||||
printf("[ %2d, ", result);
|
||||
else if (index == s->count - 1)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
# Heap examples
|
||||
|
||||
* heapsort.c - Uses the heap to sort the elements in a given array.
|
||||
* iterator.c - A complete example of the heap iterator
|
||||
@@ -0,0 +1,181 @@
|
||||
/**
|
||||
* iterator.c
|
||||
*
|
||||
* Creation Date: 15/05/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
* Iterator Example
|
||||
*/
|
||||
#include "heap.h"
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
// Int compare function
|
||||
int intcmp(int a, int b)
|
||||
{
|
||||
return a - b;
|
||||
}
|
||||
|
||||
// Creates a heap of integers
|
||||
HEAP_GENERATE(h, heap, /* FMOD */, int)
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
{
|
||||
// Create a new max heap with an initial capacity of 100
|
||||
heap *my_heap = h_new(100, MaxHeap, intcmp);
|
||||
|
||||
// Add elements to the heap
|
||||
for (int i = 0; i < 20; i++)
|
||||
{
|
||||
h_insert(my_heap, i);
|
||||
}
|
||||
|
||||
// Iterate from the start (index 0) to the end (index count - 1) of the heap
|
||||
for (heap_iter it = my_heap->it_start(my_heap); // Initialize iterator 'it' to the start of the heap
|
||||
!h_iter_end(&it); // Conditional stop (until it is not at the end)
|
||||
h_iter_next(&it)) // Iterator goes one position forward
|
||||
{
|
||||
// Access the current element
|
||||
int e = h_iter_value(&it);
|
||||
|
||||
// Access the current index (index is relative to all the elements in the iteration)
|
||||
size_t i = h_iter_index(&it);
|
||||
|
||||
// Print heap
|
||||
|
||||
// Index is useful in situations like this
|
||||
// If it is the first element
|
||||
if (i == 0)
|
||||
printf("[ %d, ", e);
|
||||
// If it is the last element
|
||||
else if (i == h_count(my_heap) - 1)
|
||||
printf("%d ]\n", e);
|
||||
// For elements at the middle
|
||||
else
|
||||
printf("%d, ", e);
|
||||
}
|
||||
|
||||
// Index can also be used to iterate over a certain portion of a collection
|
||||
size_t limit = h_count(my_heap) / 2;
|
||||
for (heap_iter it = my_heap->it_start(my_heap); !h_iter_end(&it); h_iter_next(&it))
|
||||
{
|
||||
// Access the current element
|
||||
int e = h_iter_value(&it);
|
||||
|
||||
// Access the current index (index is relative to all the elements in the iteration)
|
||||
size_t i = h_iter_index(&it);
|
||||
|
||||
// Print heap up until limit
|
||||
|
||||
// If it is the first element
|
||||
if (i == 0)
|
||||
printf("[ %d, ", e);
|
||||
// If it is the last element
|
||||
else if (i == limit - 1) // -1 because index is 0 based and we want half of the heap
|
||||
{
|
||||
printf("%d ]\n", e);
|
||||
break;
|
||||
}
|
||||
// For elements at the middle
|
||||
else
|
||||
printf("%d, ", e);
|
||||
}
|
||||
|
||||
// Going backwards
|
||||
for (heap_iter it = my_heap->it_end(my_heap); // Initialize iterator 'it' to the end of the heap
|
||||
!h_iter_start(&it); // Conditional stop (until it is not at the start)
|
||||
h_iter_prev(&it)) // Iterator goes one position backwards
|
||||
{
|
||||
// Access the current element
|
||||
int e = h_iter_value(&it);
|
||||
|
||||
// Access the current index (index is relative to all the elements in the iteration)
|
||||
size_t i = h_iter_index(&it);
|
||||
|
||||
// Print heap
|
||||
// Note how the conditions for the first and last elements are simply swapped
|
||||
// Because iterating backwards make the first element be the index count - 1
|
||||
// and the last one be the index 0
|
||||
|
||||
// If it is the first element
|
||||
if (i == h_count(my_heap) - 1)
|
||||
printf("[ %d, ", e);
|
||||
// If it is the last element
|
||||
else if (i == 0)
|
||||
printf("%d ]\n", e);
|
||||
// For elements at the middle
|
||||
else
|
||||
printf("%d, ", e);
|
||||
}
|
||||
|
||||
// You can also use iterators in a while loop
|
||||
// But to do so you must declare the iterator struct outside the loop first
|
||||
heap_iter it;
|
||||
|
||||
// You have three options:
|
||||
// - Initialize it using the functions provided by the heap [ my_heap->it_start() and my_heap->it_end() ]
|
||||
// - Initialize it using the init() function (when the iterator is already allocated)
|
||||
// - Initialize it using the new() function (allocates on the heap, pointers only)
|
||||
|
||||
it = my_heap->it_start(my_heap);
|
||||
it = my_heap->it_end(my_heap);
|
||||
|
||||
// This is equivalent to it_start()
|
||||
h_iter_init(&it, my_heap);
|
||||
|
||||
// For pointers
|
||||
// Also equivalent to it_start()
|
||||
heap_iter *iter = h_iter_new(my_heap);
|
||||
|
||||
// The actual while loop
|
||||
while (!h_iter_end(iter))
|
||||
{
|
||||
// Accessing elements
|
||||
int e = h_iter_value(iter);
|
||||
size_t i = h_iter_index(iter);
|
||||
|
||||
// Print index and element
|
||||
printf("heap[%2" PRIuMAX "] = %2d\n", i, e);
|
||||
|
||||
// Move iterator forwards
|
||||
h_iter_next(iter);
|
||||
}
|
||||
|
||||
// Send the iterator to the start of the heap
|
||||
h_iter_to_start(iter);
|
||||
|
||||
// Send the iterator to the end of the heap
|
||||
h_iter_to_end(iter);
|
||||
|
||||
// Backwards loop
|
||||
while (!h_iter_start(iter))
|
||||
{
|
||||
// Accessing elements
|
||||
int e = h_iter_value(iter);
|
||||
size_t i = h_iter_index(iter);
|
||||
|
||||
// Print index and element
|
||||
printf("heap[%2" PRIuMAX "] = %2d\n", i, e);
|
||||
|
||||
// Move iterator backwards
|
||||
h_iter_prev(iter);
|
||||
}
|
||||
|
||||
// Certain iterators also allow you to modify the contents it is iterating over
|
||||
// Exceptions are collections that depend of the current state of the element
|
||||
// like tree-based collections and heap (collections that have some kind of ordering).
|
||||
// You also can't change the keys of an associative collection
|
||||
|
||||
// In the case of a heap this is not possible because the heap have its
|
||||
// elements ordered. Changing them could cause the heap to be in an invalid
|
||||
// state.
|
||||
|
||||
// Dispose the iterator called by h_iter_new()
|
||||
h_iter_free(iter);
|
||||
// Dispose the heap created
|
||||
h_free(my_heap);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
* deque.c
|
||||
*
|
||||
* Creation Date: 11/04/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
*/
|
||||
#include "deque.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
DEQUE_GENERATE(d, deque, static, int)
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
{
|
||||
// Initialize deque and add some elements
|
||||
deque *d = d_new(10);
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
i % 2 == 0 ? d_push_back(d, i) : d_push_front(d, i);
|
||||
}
|
||||
|
||||
// Initialize iterator
|
||||
deque_iter iter;
|
||||
d_iter_init(&iter, d);
|
||||
|
||||
// Make the iterator go back and forward
|
||||
for (int j = 0; j < 4; j++)
|
||||
{
|
||||
while (!d_iter_end(&iter))
|
||||
{
|
||||
printf("C[%2d] = %2d\n", d_iter_index(&iter), d_iter_value(&iter));
|
||||
d_iter_next(&iter);
|
||||
}
|
||||
printf("\n");
|
||||
while (!d_iter_start(&iter))
|
||||
{
|
||||
printf("C[%2d] = %2d\n", d_iter_index(&iter), d_iter_value(&iter));
|
||||
d_iter_prev(&iter);
|
||||
}
|
||||
printf("\n\n");
|
||||
}
|
||||
|
||||
for (d_iter_to_start(&iter); !d_iter_end(&iter); d_iter_next(&iter))
|
||||
{
|
||||
printf("D[%2d] = %2d\n", d_iter_index(&iter), d_iter_value(&iter));
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
|
||||
for (d_iter_to_end(&iter); !d_iter_start(&iter); d_iter_prev(&iter))
|
||||
{
|
||||
printf("D[%2d] = %2d\n", d_iter_index(&iter), d_iter_value(&iter));
|
||||
}
|
||||
|
||||
d_free(d);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/**
|
||||
* hashmap.c
|
||||
*
|
||||
* Creation Date: 11/04/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
*/
|
||||
#include "hashmap.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
HASHMAP_GENERATE(hm, hmap, static, int, double)
|
||||
|
||||
size_t inthash(int t)
|
||||
{
|
||||
size_t a = t;
|
||||
a += ~(a << 15);
|
||||
a ^= (a >> 10);
|
||||
a += (a << 3);
|
||||
a ^= (a >> 6);
|
||||
a += ~(a << 11);
|
||||
a ^= (a >> 16);
|
||||
return a;
|
||||
}
|
||||
|
||||
int intcmp(int a, int b)
|
||||
{
|
||||
return a - b;
|
||||
}
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
{
|
||||
double varr[10] = {0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9};
|
||||
|
||||
// Initialize hashmap and add some element
|
||||
hmap *hm = hm_new(50, 0.9, intcmp, inthash);
|
||||
for (int i = 0; i < 10; i++)
|
||||
hm_insert(hm, i, varr[i]);
|
||||
|
||||
// Initialize iterator
|
||||
hmap_iter iter;
|
||||
hm_iter_init(&iter, hm);
|
||||
|
||||
for (int j = 0; j < 4; j++)
|
||||
{
|
||||
while (!hm_iter_end(&iter))
|
||||
{
|
||||
printf("C[%2d] = { %2d : %2.2lf }\n", hm_iter_index(&iter), hm_iter_key(&iter), hm_iter_value(&iter));
|
||||
hm_iter_next(&iter);
|
||||
}
|
||||
printf("\n");
|
||||
while (!hm_iter_start(&iter))
|
||||
{
|
||||
printf("C[%2d] = { %2d : %2.2lf }\n", hm_iter_index(&iter), hm_iter_key(&iter), hm_iter_value(&iter));
|
||||
hm_iter_prev(&iter);
|
||||
}
|
||||
printf("\n\n");
|
||||
}
|
||||
|
||||
for (hm_iter_to_start(&iter); !hm_iter_end(&iter); hm_iter_next(&iter))
|
||||
{
|
||||
printf("M[%2d] = { %2d : %2.2lf }\n", hm_iter_index(&iter), hm_iter_key(&iter), hm_iter_value(&iter));
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
|
||||
for (hm_iter_to_end(&iter); !hm_iter_start(&iter); hm_iter_prev(&iter))
|
||||
{
|
||||
printf("M[%2d] = { %2d : %2.2lf }\n", hm_iter_index(&iter), hm_iter_key(&iter), hm_iter_value(&iter));
|
||||
}
|
||||
|
||||
hm_free(hm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/**
|
||||
* hashset.c
|
||||
*
|
||||
* Creation Date: 11/04/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
*/
|
||||
#include "hashset.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
HASHSET_GENERATE(hs, hset, static, int)
|
||||
|
||||
size_t inthash(int t)
|
||||
{
|
||||
size_t a = t;
|
||||
a += ~(a << 15);
|
||||
a ^= (a >> 10);
|
||||
a += (a << 3);
|
||||
a ^= (a >> 6);
|
||||
a += ~(a << 11);
|
||||
a ^= (a >> 16);
|
||||
return a;
|
||||
}
|
||||
|
||||
int intcmp(int a, int b)
|
||||
{
|
||||
return a - b;
|
||||
}
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
{
|
||||
// Initialize hash set and add some elements
|
||||
hset *hs = hs_new(10, 0.9, intcmp, inthash);
|
||||
for (int i = 0; i < 10; i++)
|
||||
hs_insert(hs, i);
|
||||
|
||||
// Initialize iterator
|
||||
hset_iter iter;
|
||||
hs_iter_init(&iter, hs);
|
||||
|
||||
// Make the iterator go back and forward
|
||||
for (int j = 0; j < 4; j++)
|
||||
{
|
||||
while (!hs_iter_end(&iter))
|
||||
{
|
||||
printf("C[%2d] = %2d\n", hs_iter_index(&iter), hs_iter_value(&iter));
|
||||
hs_iter_next(&iter);
|
||||
}
|
||||
printf("\n");
|
||||
while (!hs_iter_start(&iter))
|
||||
{
|
||||
printf("C[%2d] = %2d\n", hs_iter_index(&iter), hs_iter_value(&iter));
|
||||
hs_iter_prev(&iter);
|
||||
}
|
||||
printf("\n\n");
|
||||
}
|
||||
|
||||
for (hs_iter_to_start(&iter); !hs_iter_end(&iter); hs_iter_next(&iter))
|
||||
{
|
||||
printf("S[%2d] = %2d\n", hs_iter_index(&iter), hs_iter_value(&iter));
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
|
||||
for (hs_iter_to_end(&iter); !hs_iter_start(&iter); hs_iter_prev(&iter))
|
||||
{
|
||||
printf("S[%2d] = %2d\n", hs_iter_index(&iter), hs_iter_value(&iter));
|
||||
}
|
||||
|
||||
hs_free(hs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/**
|
||||
* heap.c
|
||||
*
|
||||
* Creation Date: 11/04/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
*/
|
||||
#include "heap.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int intcmp(int a, int b)
|
||||
{
|
||||
return a - b;
|
||||
}
|
||||
|
||||
HEAP_GENERATE(h, heap, static, int)
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
{
|
||||
// Initialize heap and add some elements
|
||||
heap *h = h_new(10, MaxHeap, intcmp);
|
||||
for (int i = 0; i < 10; i++)
|
||||
h_insert(h, i);
|
||||
|
||||
// Initialize iterator
|
||||
heap_iter iter;
|
||||
h_iter_init(&iter, h);
|
||||
|
||||
// Make the iterator go back and forward
|
||||
for (int j = 0; j < 4; j++)
|
||||
{
|
||||
while (!h_iter_end(&iter))
|
||||
{
|
||||
printf("C[%2d] = %2d\n", h_iter_index(&iter), h_iter_value(&iter));
|
||||
h_iter_next(&iter);
|
||||
}
|
||||
printf("\n");
|
||||
while (!h_iter_start(&iter))
|
||||
{
|
||||
printf("C[%2d] = %2d\n", h_iter_index(&iter), h_iter_value(&iter));
|
||||
h_iter_prev(&iter);
|
||||
}
|
||||
printf("\n\n");
|
||||
}
|
||||
|
||||
for (h_iter_to_start(&iter); !h_iter_end(&iter); h_iter_next(&iter))
|
||||
{
|
||||
printf("H[%2d] = %2d\n", h_iter_index(&iter), h_iter_value(&iter));
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
|
||||
for (h_iter_to_end(&iter); !h_iter_start(&iter); h_iter_prev(&iter))
|
||||
{
|
||||
printf("H[%2d] = %2d\n", h_iter_index(&iter), h_iter_value(&iter));
|
||||
}
|
||||
|
||||
h_free(h);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* linkedlist.c
|
||||
*
|
||||
* Creation Date: 11/04/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
*/
|
||||
#include "linkedlist.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
LINKEDLIST_GENERATE(ll, linkedlist, static, int)
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
{
|
||||
// Initialize list and add some elements
|
||||
linkedlist *l = ll_new();
|
||||
for (int i = 0; i < 10; i++)
|
||||
ll_push_back(l, i);
|
||||
|
||||
// Initialize iterator
|
||||
linkedlist_iter iter;
|
||||
ll_iter_init(&iter, l);
|
||||
|
||||
// Make the iterator go back and forward
|
||||
for (int j = 0; j < 4; j++)
|
||||
{
|
||||
while (!ll_iter_end(&iter))
|
||||
{
|
||||
printf("C[%2d] = %2d\n", ll_iter_index(&iter), ll_iter_value(&iter));
|
||||
ll_iter_next(&iter);
|
||||
}
|
||||
printf("\n");
|
||||
while (!ll_iter_start(&iter))
|
||||
{
|
||||
printf("C[%2d] = %2d\n", ll_iter_index(&iter), ll_iter_value(&iter));
|
||||
ll_iter_prev(&iter);
|
||||
}
|
||||
printf("\n\n");
|
||||
}
|
||||
|
||||
for (ll_iter_to_start(&iter); !ll_iter_end(&iter); ll_iter_next(&iter))
|
||||
{
|
||||
printf("LL[%2d] = %2d\n", ll_iter_index(&iter), ll_iter_value(&iter));
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
|
||||
for (ll_iter_to_end(&iter); !ll_iter_start(&iter); ll_iter_prev(&iter))
|
||||
{
|
||||
printf("LL[%2d] = %2d\n", ll_iter_index(&iter), ll_iter_value(&iter));
|
||||
}
|
||||
|
||||
ll_free(l);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* list.c
|
||||
*
|
||||
* Creation Date: 11/04/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
*/
|
||||
#include "list.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
LIST_GENERATE(l, list, static, int)
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
{
|
||||
// Initialize list and add some elements
|
||||
list *l = l_new(10);
|
||||
for (int i = 0; i < 10; i++)
|
||||
l_push_back(l, i);
|
||||
|
||||
// Initialize iterator
|
||||
list_iter iter;
|
||||
l_iter_init(&iter, l);
|
||||
|
||||
// Make the iterator go back and forward
|
||||
for (int j = 0; j < 4; j++)
|
||||
{
|
||||
while (!l_iter_end(&iter))
|
||||
{
|
||||
printf("C[%2d] = %2d\n", l_iter_index(&iter), l_iter_value(&iter));
|
||||
l_iter_next(&iter);
|
||||
}
|
||||
printf("\n");
|
||||
while (!l_iter_start(&iter))
|
||||
{
|
||||
printf("C[%2d] = %2d\n", l_iter_index(&iter), l_iter_value(&iter));
|
||||
l_iter_prev(&iter);
|
||||
}
|
||||
printf("\n\n");
|
||||
}
|
||||
|
||||
for (l_iter_to_start(&iter); !l_iter_end(&iter); l_iter_next(&iter))
|
||||
{
|
||||
printf("L[%2d] = %2d\n", l_iter_index(&iter), l_iter_value(&iter));
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
|
||||
for (l_iter_to_end(&iter); !l_iter_start(&iter); l_iter_prev(&iter))
|
||||
{
|
||||
printf("L[%2d] = %2d\n", l_iter_index(&iter), l_iter_value(&iter));
|
||||
}
|
||||
|
||||
l_free(l);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,10 +1,15 @@
|
||||
// Checks if the queue iterator can go back and forward in the queue without
|
||||
// hitting invalid states or a null pointer. Check is done visually.
|
||||
/**
|
||||
* queue.c
|
||||
*
|
||||
* Creation Date: 11/04/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "../../src/queue.h"
|
||||
#include "queue.h"
|
||||
|
||||
QUEUE_GENERATE(q, queue, static, int)
|
||||
|
||||
@@ -20,7 +25,7 @@ int main(int argc, char const *argv[])
|
||||
|
||||
// Initialize iterator
|
||||
queue_iter iter;
|
||||
q_iter_new(&iter, q);
|
||||
q_iter_init(&iter, q);
|
||||
|
||||
// Make the iterator go back and forward
|
||||
for (int j = 0; j < 4; j++)
|
||||
@@ -1,10 +1,15 @@
|
||||
// Checks if the stack iterator can go back and forward in the stack without
|
||||
// hitting invalid states or a null pointer. Check is done visually.
|
||||
/**
|
||||
* stack.c
|
||||
*
|
||||
* Creation Date: 11/04/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "../../src/stack.h"
|
||||
#include "stack.h"
|
||||
|
||||
STACK_GENERATE(s, stack, static, int)
|
||||
|
||||
@@ -20,7 +25,7 @@ int main(int argc, char const *argv[])
|
||||
|
||||
// Initialize iterator
|
||||
stack_iter iter;
|
||||
s_iter_new(&iter, s);
|
||||
s_iter_init(&iter, s);
|
||||
|
||||
// Make the iterator go back and forward
|
||||
for (int j = 0; j < 4; j++)
|
||||
@@ -1,10 +1,15 @@
|
||||
// Checks if the treemap iterator can go back and forward in the treemap without
|
||||
// hitting invalid states or a null pointer. Check is done visually.
|
||||
/**
|
||||
* treemap.c
|
||||
*
|
||||
* Creation Date: 11/04/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "../../src/treemap.h"
|
||||
#include "treemap.h"
|
||||
|
||||
int intcmp(int a, int b)
|
||||
{
|
||||
@@ -26,7 +31,7 @@ int main(int argc, char const *argv[])
|
||||
|
||||
// Initialize iterator
|
||||
tmap_iter iter;
|
||||
tm_iter_new(&iter, tm);
|
||||
tm_iter_init(&iter, tm);
|
||||
|
||||
// Make the iterator go back and forward
|
||||
for (int j = 0; j < 4; j++)
|
||||
@@ -1,10 +1,15 @@
|
||||
// Checks if the treeset iterator can go back and forward in the treeset without
|
||||
// hitting invalid states or a null pointer. Check is done visually.
|
||||
/**
|
||||
* treeset.c
|
||||
*
|
||||
* Creation Date: 11/04/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "../../src/treeset.h"
|
||||
#include "treeset.h"
|
||||
|
||||
int intcmp(int a, int b)
|
||||
{
|
||||
@@ -25,7 +30,7 @@ int main(int argc, char const *argv[])
|
||||
|
||||
// Initialize iterator
|
||||
tset_iter iter;
|
||||
ts_iter_new(&iter, ts);
|
||||
ts_iter_init(&iter, ts);
|
||||
|
||||
// Make the iterator go back and forward
|
||||
for (int j = 0; j < 4; j++)
|
||||
@@ -1,4 +1,4 @@
|
||||
# Linkedlist examples
|
||||
|
||||
* iterator.c - Example of using a linked list iterator.
|
||||
* iterator.c - A complete example of the linked list iterator
|
||||
* linked_list_node.c - Example of using functions that add or remove elements relative to a node.
|
||||
+172
-23
@@ -1,46 +1,195 @@
|
||||
/**
|
||||
* iterator.c
|
||||
*
|
||||
* Creation Date: 22/03/2019
|
||||
* Creation Date: 10/05/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
* Iterator Example
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include "linkedlist.h"
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
LINKEDLIST_GENERATE(ll, linked, static, int)
|
||||
// Creates a linkedlist of integers
|
||||
LINKEDLIST_GENERATE(ll, linkedlist, /* FMOD */, int)
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
{
|
||||
size_t i;
|
||||
int r;
|
||||
// Create a new linkedlist
|
||||
linkedlist *my_linkedlist = ll_new();
|
||||
|
||||
// Initliazie linked list and add some elements
|
||||
linked *ll = ll_new();
|
||||
// Add elements to the linkedlist
|
||||
for (int i = 0; i < 20; i++)
|
||||
ll_push_back(ll, i);
|
||||
{
|
||||
ll_push_back(my_linkedlist, i);
|
||||
}
|
||||
|
||||
// Initialize iterator
|
||||
linked_iter iter;
|
||||
ll_iter_new(&iter, ll);
|
||||
// Iterate from the start (index 0) to the end (index count - 1) of the linkedlist
|
||||
for (linkedlist_iter it = my_linkedlist->it_start(my_linkedlist); // Initialize iterator 'it' to the start of the linkedlist
|
||||
!ll_iter_end(&it); // Conditional stop (until it is not at the end)
|
||||
ll_iter_next(&it)) // Iterator goes one position forward
|
||||
{
|
||||
// Access the current element
|
||||
int e = ll_iter_value(&it);
|
||||
|
||||
// Move cursor to the end of the list
|
||||
ll_iter_toend(&iter);
|
||||
// While there is a previous element on the list
|
||||
while (ll_iter_prev(&iter, &r, &i))
|
||||
printf("list[%2d] = %2d\n", i, r);
|
||||
// Access the current index (index is relative to all the elements in the iteration)
|
||||
size_t i = ll_iter_index(&it);
|
||||
|
||||
printf("\n");
|
||||
// Print linkedlist
|
||||
|
||||
// Move cursor to the start of the list
|
||||
ll_iter_tostart(&iter);
|
||||
// While there is a next element on the list
|
||||
while (ll_iter_next(&iter, &r, &i))
|
||||
printf("list[%2d] = %2d\n", i, r);
|
||||
// Index is useful in situations like this
|
||||
// If it is the first element
|
||||
if (i == 0)
|
||||
printf("[ %d, ", e);
|
||||
// If it is the last element
|
||||
else if (i == ll_count(my_linkedlist) - 1)
|
||||
printf("%d ]\n", e);
|
||||
// For elements at the middle
|
||||
else
|
||||
printf("%d, ", e);
|
||||
}
|
||||
|
||||
ll_free(ll);
|
||||
// Index can also be used to iterate over a certain portion of a collection
|
||||
size_t limit = ll_count(my_linkedlist) / 2;
|
||||
for (linkedlist_iter it = my_linkedlist->it_start(my_linkedlist); !ll_iter_end(&it); ll_iter_next(&it))
|
||||
{
|
||||
// Access the current element
|
||||
int e = ll_iter_value(&it);
|
||||
|
||||
// Access the current index (index is relative to all the elements in the iteration)
|
||||
size_t i = ll_iter_index(&it);
|
||||
|
||||
// Print linkedlist up until limit
|
||||
|
||||
// If it is the first element
|
||||
if (i == 0)
|
||||
printf("[ %d, ", e);
|
||||
// If it is the last element
|
||||
else if (i == limit - 1) // -1 because index is 0 based and we want half of the linkedlist
|
||||
{
|
||||
printf("%d ]\n", e);
|
||||
break;
|
||||
}
|
||||
// For elements at the middle
|
||||
else
|
||||
printf("%d, ", e);
|
||||
}
|
||||
|
||||
// Going backwards
|
||||
for (linkedlist_iter it = my_linkedlist->it_end(my_linkedlist); // Initialize iterator 'it' to the end of the linkedlist
|
||||
!ll_iter_start(&it); // Conditional stop (until it is not at the start)
|
||||
ll_iter_prev(&it)) // Iterator goes one position backwards
|
||||
{
|
||||
// Access the current element
|
||||
int e = ll_iter_value(&it);
|
||||
|
||||
// Access the current index (index is relative to all the elements in the iteration)
|
||||
size_t i = ll_iter_index(&it);
|
||||
|
||||
// Print linkedlist
|
||||
// Note how the conditions for the first and last elements are simply swapped
|
||||
// Because iterating backwards make the first element be the index count - 1
|
||||
// and the last one be the index 0
|
||||
|
||||
// If it is the first element
|
||||
if (i == ll_count(my_linkedlist) - 1)
|
||||
printf("[ %d, ", e);
|
||||
// If it is the last element
|
||||
else if (i == 0)
|
||||
printf("%d ]\n", e);
|
||||
// For elements at the middle
|
||||
else
|
||||
printf("%d, ", e);
|
||||
}
|
||||
|
||||
// You can also use iterators in a while loop
|
||||
// But to do so you must declare the iterator struct outside the loop first
|
||||
linkedlist_iter it;
|
||||
|
||||
// You have three options:
|
||||
// - Initialize it using the functions provided by the linkedlist [ my_linkedlist->it_start() and my_linkedlist->it_end() ]
|
||||
// - Initialize it using the init() function (when the iterator is already allocated)
|
||||
// - Initialize it using the new() function (allocates on the heap, pointers only)
|
||||
|
||||
it = my_linkedlist->it_start(my_linkedlist);
|
||||
it = my_linkedlist->it_end(my_linkedlist);
|
||||
|
||||
// This is equivalent to it_start()
|
||||
ll_iter_init(&it, my_linkedlist);
|
||||
|
||||
// For pointers
|
||||
// Also equivalent to it_start()
|
||||
linkedlist_iter *iter = ll_iter_new(my_linkedlist);
|
||||
|
||||
// The actual while loop
|
||||
while (!ll_iter_end(iter))
|
||||
{
|
||||
// Accessing elements
|
||||
int e = ll_iter_value(iter);
|
||||
size_t i = ll_iter_index(iter);
|
||||
|
||||
// Print index and element
|
||||
printf("linkedlist[%2" PRIuMAX "] = %2d\n", i, e);
|
||||
|
||||
// Move iterator forwards
|
||||
ll_iter_next(iter);
|
||||
}
|
||||
|
||||
// Send the iterator to the start of the linkedlist
|
||||
ll_iter_to_start(iter);
|
||||
|
||||
// Send the iterator to the end of the linkedlist
|
||||
ll_iter_to_end(iter);
|
||||
|
||||
// Backwards loop
|
||||
while (!ll_iter_start(iter))
|
||||
{
|
||||
// Accessing elements
|
||||
int e = ll_iter_value(iter);
|
||||
size_t i = ll_iter_index(iter);
|
||||
|
||||
// Print index and element
|
||||
printf("linkedlist[%2" PRIuMAX "] = %2d\n", i, e);
|
||||
|
||||
// Move iterator backwards
|
||||
ll_iter_prev(iter);
|
||||
}
|
||||
|
||||
// Certain iterators also allow you to modify the contents it is iterating over
|
||||
// Exceptions are collections that depend of the current state of the element
|
||||
// like tree-based collections and heap (collections that have some kind of ordering).
|
||||
// You also can't change the keys of an associative collection
|
||||
|
||||
// Change every element that is divisible by 2 to the number 7
|
||||
for (ll_iter_to_start(&it); !ll_iter_end(&it); ll_iter_next(&it))
|
||||
{
|
||||
// Get a reference to the current value
|
||||
int *r = ll_iter_rvalue(&it);
|
||||
|
||||
if (r != NULL && *r % 2 == 0)
|
||||
*r = 7;
|
||||
}
|
||||
|
||||
// Now print it to see the difference
|
||||
for (linkedlist_iter it = my_linkedlist->it_start(my_linkedlist); !ll_iter_end(&it); ll_iter_next(&it))
|
||||
{
|
||||
int e = ll_iter_value(&it);
|
||||
size_t i = ll_iter_index(&it);
|
||||
|
||||
if (i == 0)
|
||||
printf("[ %d, ", e);
|
||||
else if (i == ll_count(my_linkedlist) - 1)
|
||||
printf("%d ]\n", e);
|
||||
else
|
||||
printf("%d, ", e);
|
||||
}
|
||||
|
||||
// Dispose the iterator called by ll_iter_new()
|
||||
ll_iter_free(iter);
|
||||
// Dispose the linkedlist created
|
||||
ll_free(my_linkedlist);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -7,13 +7,14 @@
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
*/
|
||||
#include "linkedlist.h"
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include "linkedlist.h"
|
||||
#include <inttypes.h>
|
||||
|
||||
LINKEDLIST_GENERATE(l, list, /* static */, int)
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
int main(void)
|
||||
{
|
||||
list *l = l_new();
|
||||
|
||||
@@ -25,14 +26,14 @@ int main(int argc, char const *argv[])
|
||||
{
|
||||
if (node->data % 3 == 0)
|
||||
{
|
||||
l_insert_prv(node, 33);
|
||||
l_insert_nxt(node, 99);
|
||||
l_insert_before(l, node, 33);
|
||||
l_insert_after(l, node, 99);
|
||||
node = node->next; // skip 99
|
||||
}
|
||||
}
|
||||
|
||||
size_t s = 0;
|
||||
for (list_node *node = l_front_node(l); node != NULL; node = l_next_node(node), s++)
|
||||
for (list_node *node = l_head(l); node != NULL; node = l_next_node(node), s++)
|
||||
{
|
||||
if (node->prev == NULL)
|
||||
printf("[ %d, ", node->data);
|
||||
@@ -42,7 +43,22 @@ int main(int argc, char const *argv[])
|
||||
printf("%d, ", node->data);
|
||||
}
|
||||
|
||||
printf("List Head: %d\nList Tail: %d\nList Count: %d\n", l->head->data, l->tail->data, l->count);
|
||||
printf("\n\n");
|
||||
|
||||
s = 0;
|
||||
for (list_node *node = l_tail(l); node != NULL; node = l_prev_node(node), s++)
|
||||
{
|
||||
if (node->next == NULL)
|
||||
printf("[ %d, ", node->data);
|
||||
else if (node->prev == NULL)
|
||||
printf("%d ]\n", node->data);
|
||||
else
|
||||
printf("%d, ", node->data);
|
||||
}
|
||||
|
||||
printf("\n\n");
|
||||
|
||||
printf("List Head: %d\nList Tail: %d\nList Count: %" PRIuMAX "\n", l->head->data, l->tail->data, l->count);
|
||||
|
||||
assert(s == l->count);
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
# List examples
|
||||
|
||||
Currently none
|
||||
* iterator.c - A complete example of the list iterator
|
||||
* list.c - Example of using a list and its iterator.
|
||||
* string.c - How to treat a list as a mutable string.
|
||||
@@ -0,0 +1,195 @@
|
||||
/**
|
||||
* iterator.c
|
||||
*
|
||||
* Creation Date: 10/05/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
* Iterator Example
|
||||
*/
|
||||
#include "list.h"
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
// Creates a list of integers
|
||||
LIST_GENERATE(l, list, /* FMOD */, int)
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
{
|
||||
// Create a new list with an initial capacity of 100
|
||||
list *my_list = l_new(100);
|
||||
|
||||
// Add elements to the list
|
||||
for (int i = 0; i < 20; i++)
|
||||
{
|
||||
l_push_back(my_list, i);
|
||||
}
|
||||
|
||||
// Iterate from the start (index 0) to the end (index count - 1) of the list
|
||||
for (list_iter it = my_list->it_start(my_list); // Initialize iterator 'it' to the start of the list
|
||||
!l_iter_end(&it); // Conditional stop (until it is not at the end)
|
||||
l_iter_next(&it)) // Iterator goes one position forward
|
||||
{
|
||||
// Access the current element
|
||||
int e = l_iter_value(&it);
|
||||
|
||||
// Access the current index (index is relative to all the elements in the iteration)
|
||||
size_t i = l_iter_index(&it);
|
||||
|
||||
// Print list
|
||||
|
||||
// Index is useful in situations like this
|
||||
// If it is the first element
|
||||
if (i == 0)
|
||||
printf("[ %d, ", e);
|
||||
// If it is the last element
|
||||
else if (i == l_count(my_list) - 1)
|
||||
printf("%d ]\n", e);
|
||||
// For elements at the middle
|
||||
else
|
||||
printf("%d, ", e);
|
||||
}
|
||||
|
||||
// Index can also be used to iterate over a certain portion of a collection
|
||||
size_t limit = l_count(my_list) / 2;
|
||||
for (list_iter it = my_list->it_start(my_list); !l_iter_end(&it); l_iter_next(&it))
|
||||
{
|
||||
// Access the current element
|
||||
int e = l_iter_value(&it);
|
||||
|
||||
// Access the current index (index is relative to all the elements in the iteration)
|
||||
size_t i = l_iter_index(&it);
|
||||
|
||||
// Print list up until limit
|
||||
|
||||
// If it is the first element
|
||||
if (i == 0)
|
||||
printf("[ %d, ", e);
|
||||
// If it is the last element
|
||||
else if (i == limit - 1) // -1 because index is 0 based and we want half of the list
|
||||
{
|
||||
printf("%d ]\n", e);
|
||||
break;
|
||||
}
|
||||
// For elements at the middle
|
||||
else
|
||||
printf("%d, ", e);
|
||||
}
|
||||
|
||||
// Going backwards
|
||||
for (list_iter it = my_list->it_end(my_list); // Initialize iterator 'it' to the end of the list
|
||||
!l_iter_start(&it); // Conditional stop (until it is not at the start)
|
||||
l_iter_prev(&it)) // Iterator goes one position backwards
|
||||
{
|
||||
// Access the current element
|
||||
int e = l_iter_value(&it);
|
||||
|
||||
// Access the current index (index is relative to all the elements in the iteration)
|
||||
size_t i = l_iter_index(&it);
|
||||
|
||||
// Print list
|
||||
// Note how the conditions for the first and last elements are simply swapped
|
||||
// Because iterating backwards make the first element be the index count - 1
|
||||
// and the last one be the index 0
|
||||
|
||||
// If it is the first element
|
||||
if (i == l_count(my_list) - 1)
|
||||
printf("[ %d, ", e);
|
||||
// If it is the last element
|
||||
else if (i == 0)
|
||||
printf("%d ]\n", e);
|
||||
// For elements at the middle
|
||||
else
|
||||
printf("%d, ", e);
|
||||
}
|
||||
|
||||
// You can also use iterators in a while loop
|
||||
// But to do so you must declare the iterator struct outside the loop first
|
||||
list_iter it;
|
||||
|
||||
// You have three options:
|
||||
// - Initialize it using the functions provided by the list [ my_list->it_start() and my_list->it_end() ]
|
||||
// - Initialize it using the init() function (when the iterator is already allocated)
|
||||
// - Initialize it using the new() function (allocates on the heap, pointers only)
|
||||
|
||||
it = my_list->it_start(my_list);
|
||||
it = my_list->it_end(my_list);
|
||||
|
||||
// This is equivalent to it_start()
|
||||
l_iter_init(&it, my_list);
|
||||
|
||||
// For pointers
|
||||
// Also equivalent to it_start()
|
||||
list_iter *iter = l_iter_new(my_list);
|
||||
|
||||
// The actual while loop
|
||||
while (!l_iter_end(iter))
|
||||
{
|
||||
// Accessing elements
|
||||
int e = l_iter_value(iter);
|
||||
size_t i = l_iter_index(iter);
|
||||
|
||||
// Print index and element
|
||||
printf("list[%2" PRIuMAX "] = %2d\n", i, e);
|
||||
|
||||
// Move iterator forwards
|
||||
l_iter_next(iter);
|
||||
}
|
||||
|
||||
// Send the iterator to the start of the list
|
||||
l_iter_to_start(iter);
|
||||
|
||||
// Send the iterator to the end of the list
|
||||
l_iter_to_end(iter);
|
||||
|
||||
// Backwards loop
|
||||
while (!l_iter_start(iter))
|
||||
{
|
||||
// Accessing elements
|
||||
int e = l_iter_value(iter);
|
||||
size_t i = l_iter_index(iter);
|
||||
|
||||
// Print index and element
|
||||
printf("list[%2" PRIuMAX "] = %2d\n", i, e);
|
||||
|
||||
// Move iterator backwards
|
||||
l_iter_prev(iter);
|
||||
}
|
||||
|
||||
// Certain iterators also allow you to modify the contents it is iterating over
|
||||
// Exceptions are collections that depend of the current state of the element
|
||||
// like tree-based collections and heap (collections that have some kind of ordering).
|
||||
// You also can't change the keys of an associative collection
|
||||
|
||||
// Change every element that is divisible by 2 to the number 7
|
||||
for (l_iter_to_start(&it); !l_iter_end(&it); l_iter_next(&it))
|
||||
{
|
||||
// Get a reference to the current value
|
||||
int *r = l_iter_rvalue(&it);
|
||||
|
||||
if (r != NULL && *r % 2 == 0)
|
||||
*r = 7;
|
||||
}
|
||||
|
||||
// Now print it to see the difference
|
||||
for (list_iter it = my_list->it_start(my_list); !l_iter_end(&it); l_iter_next(&it))
|
||||
{
|
||||
int e = l_iter_value(&it);
|
||||
size_t i = l_iter_index(&it);
|
||||
|
||||
if (i == 0)
|
||||
printf("[ %d, ", e);
|
||||
else if (i == l_count(my_list) - 1)
|
||||
printf("%d ]\n", e);
|
||||
else
|
||||
printf("%d, ", e);
|
||||
}
|
||||
|
||||
// Dispose the iterator called by l_iter_new()
|
||||
l_iter_free(iter);
|
||||
// Dispose the list created
|
||||
l_free(my_list);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
* list.c
|
||||
*
|
||||
* Creation Date: 08/04/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
*/
|
||||
#include "list.h"
|
||||
#include <stdio.h>
|
||||
|
||||
LIST_GENERATE(l, list, /* FMOD */, int)
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
{
|
||||
// Create a list with internal capacity of 100
|
||||
list *my_list = l_new(100);
|
||||
|
||||
// - push_front (index: 0) [Complexity: O(N)]
|
||||
// - push (index: give) [Complexity: O(N)*]
|
||||
// - push_back (index: count) [Complexity: O(1)]
|
||||
//
|
||||
// - pop_front (index: 0) [Complexity: O(N)]
|
||||
// - pop (index: given) [Complexity: O(N)*]
|
||||
// - push_back (index: count - 1) [Complexity: O(1)]
|
||||
//
|
||||
// *average
|
||||
//
|
||||
// Average list Input/Output: O(N)
|
||||
|
||||
for (int i = 0; i < 200; i++)
|
||||
{
|
||||
// Add elements to the list
|
||||
l_push_back(my_list, i);
|
||||
}
|
||||
|
||||
// Erase all values from the list
|
||||
l_clear(my_list);
|
||||
|
||||
// Now that list is empty, add only even numbers
|
||||
for (int i = 0; i < 200; i++)
|
||||
{
|
||||
// Add even numbers to a given index. In this case they are being added
|
||||
// to the end of the list (count index == push_back). With a condition
|
||||
// of being even (i % 2 == 0)
|
||||
bool added = l_push_if(my_list, i, l_count(my_list), i % 2 == 0);
|
||||
|
||||
// If added is true, the element was added to the list
|
||||
}
|
||||
|
||||
// Iterator
|
||||
list_iter iter;
|
||||
int result, sum = 0;
|
||||
size_t index;
|
||||
|
||||
// Iterate over each element starting from the start (iter_new positions
|
||||
// the iterator to the start of the list) until the end of the list.
|
||||
for (l_iter_init(&iter, my_list); !l_iter_end(&iter); l_iter_next(&iter))
|
||||
{
|
||||
// Here index corresponds to the position of the result relative to all
|
||||
// other elements in the iteration. It is only a coincidence that the
|
||||
// index here is the same as the result's position in the list.
|
||||
index = l_iter_index(&iter);
|
||||
result = l_iter_value(&iter);
|
||||
|
||||
// Do whatever you want with result and index, e.g.
|
||||
sum += result * index;
|
||||
}
|
||||
|
||||
// Release resources
|
||||
l_free(my_list);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
/**
|
||||
* string.c
|
||||
*
|
||||
* Creation Date: 08/04/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
*/
|
||||
#include "list.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
LIST_GENERATE(str, string, /* FMOD */, char)
|
||||
|
||||
// Comparison function
|
||||
int chrcmp(char a, char b)
|
||||
{
|
||||
return (a > b) - (a < b);
|
||||
}
|
||||
|
||||
void print_str(string *str)
|
||||
{
|
||||
// If the buffer is not completely filled, there will be at least one null
|
||||
// byte in the end of the list's contents. This printf is possible but very
|
||||
// dangerous as you might end up printing something else from memory until
|
||||
// a null byte.
|
||||
printf("%s\n", str->buffer);
|
||||
|
||||
printf("Size: %llu\n", str_count(str));
|
||||
}
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
{
|
||||
// How to treat a list as a mutable string without \0 at the end
|
||||
char *example1 = "Lorem ipsum";
|
||||
char *example2 = "dolor sit amet";
|
||||
char *example3 = "consectetur";
|
||||
|
||||
string *my_str = str_new_from(example2, strlen(example2));
|
||||
|
||||
// Add a single character to the front of the list
|
||||
str_push_front(my_str, ' ');
|
||||
|
||||
// Add a sequence of characters to the front of the list
|
||||
str_prepend(my_str, example1, strlen(example1));
|
||||
|
||||
// Add a charater to the back of the list
|
||||
str_push_back(my_str, ' ');
|
||||
|
||||
// Add a sequence of characters to the back of the list
|
||||
str_append(my_str, example3, strlen(example3));
|
||||
|
||||
// Iterate through each letter and print it
|
||||
string_iter iter;
|
||||
str_iter_init(&iter, my_str);
|
||||
size_t index;
|
||||
char result;
|
||||
|
||||
// Printing each character
|
||||
for (str_iter_to_start(&iter); !str_iter_end(&iter); str_iter_next(&iter))
|
||||
{
|
||||
putchar(str_iter_value(&iter));
|
||||
}
|
||||
|
||||
printf("\n\n");
|
||||
|
||||
// You can also print it reversed
|
||||
for (str_iter_to_end(&iter); !str_iter_start(&iter); str_iter_prev(&iter))
|
||||
{
|
||||
putchar(str_iter_value(&iter));
|
||||
}
|
||||
|
||||
printf("\n\n");
|
||||
|
||||
// Now remove the first letter supposing we don't know where it starts
|
||||
index = str_indexof(my_str, ' ', chrcmp, true);
|
||||
|
||||
if (index == str_count(my_str))
|
||||
{
|
||||
// char not found...
|
||||
// Treat error
|
||||
}
|
||||
|
||||
// Now that we know where the first word is, remove it, including the
|
||||
// extra space. [from, to] are inclusive.
|
||||
str_remove(my_str, 0, index);
|
||||
|
||||
// Print it once again
|
||||
for (str_iter_to_start(&iter); !str_iter_end(&iter); str_iter_next(&iter))
|
||||
{
|
||||
putchar(str_iter_value(&iter));
|
||||
}
|
||||
|
||||
printf("\nString length: %lu\n\n", str_count(my_str));
|
||||
|
||||
print_str(my_str);
|
||||
|
||||
// Removing last word.
|
||||
// Finding last white space:
|
||||
index = str_indexof(my_str, ' ', chrcmp, false);
|
||||
|
||||
// Extract last word including white space
|
||||
string *str_out = str_extract(my_str, index, str_count(my_str) - 1);
|
||||
|
||||
if (!str_out)
|
||||
printf("Could not extract string\n");
|
||||
else
|
||||
{
|
||||
// Pop white space
|
||||
str_pop_front(str_out);
|
||||
|
||||
for (str_iter_init(&iter, my_str); !str_iter_end(&iter); str_iter_next(&iter))
|
||||
{
|
||||
putchar(str_iter_value(&iter));
|
||||
}
|
||||
|
||||
printf("\nString length: %lu\n\n", str_count(my_str));
|
||||
|
||||
for (str_iter_init(&iter, str_out); !str_iter_end(&iter); str_iter_next(&iter))
|
||||
{
|
||||
putchar(str_iter_value(&iter));
|
||||
}
|
||||
|
||||
printf("\nString length: %lu\n", str_count(str_out));
|
||||
}
|
||||
|
||||
// Free strings
|
||||
str_free(my_str);
|
||||
str_free(str_out);
|
||||
|
||||
printf("\n----------------------------------------\n\n");
|
||||
|
||||
// Another example follows
|
||||
// Using prepend, insert, append, remove and extract functions
|
||||
string *str = str_new(100);
|
||||
|
||||
str_prepend(str, "Hello World!", 12);
|
||||
|
||||
print_str(str);
|
||||
|
||||
str_insert(str, "Awesome ", 8, 6);
|
||||
|
||||
print_str(str);
|
||||
|
||||
str_append(str, " Indigo.", 8);
|
||||
|
||||
print_str(str);
|
||||
|
||||
str_remove(str, 14, 20);
|
||||
|
||||
print_str(str);
|
||||
|
||||
string *str_res = str_extract(str, 5, 12);
|
||||
|
||||
print_str(str);
|
||||
print_str(str_res);
|
||||
|
||||
str_free(str);
|
||||
str_free(str_res);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
# Queue examples
|
||||
|
||||
* ice_cream.c - Example of what happens when you get late to the queue and the ice creams are sold out!
|
||||
* iterator.c - A complete example of the queue iterator
|
||||
@@ -7,10 +7,10 @@
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
*/
|
||||
#include "queue.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include "queue.h"
|
||||
|
||||
QUEUE_GENERATE(q, queue, /* static */, const char *)
|
||||
|
||||
|
||||
@@ -0,0 +1,195 @@
|
||||
/**
|
||||
* iterator.c
|
||||
*
|
||||
* Creation Date: 15/05/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
* Iterator Example
|
||||
*/
|
||||
#include "queue.h"
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
// Creates a queue of integers
|
||||
QUEUE_GENERATE(q, queue, /* FMOD */, int)
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
{
|
||||
// Create a new queue with an initial capacity of 100
|
||||
queue *my_queue = q_new(100);
|
||||
|
||||
// Add elements to the queue
|
||||
for (int i = 0; i < 20; i++)
|
||||
{
|
||||
q_enqueue(my_queue, i);
|
||||
}
|
||||
|
||||
// Iterate from the start (front) to the end (rear) of the queue
|
||||
for (queue_iter it = my_queue->it_start(my_queue); // Initialize iterator 'it' to the start of the queue
|
||||
!q_iter_end(&it); // Conditional stop (until it is not at the end)
|
||||
q_iter_next(&it)) // Iterator goes one position forward
|
||||
{
|
||||
// Access the current element
|
||||
int e = q_iter_value(&it);
|
||||
|
||||
// Access the current index (index is relative to all the elements in the iteration)
|
||||
size_t i = q_iter_index(&it);
|
||||
|
||||
// Print queue
|
||||
|
||||
// Index is useful in situations like this
|
||||
// If it is the first element
|
||||
if (i == 0)
|
||||
printf("[ %d, ", e);
|
||||
// If it is the last element
|
||||
else if (i == q_count(my_queue) - 1)
|
||||
printf("%d ]\n", e);
|
||||
// For elements at the middle
|
||||
else
|
||||
printf("%d, ", e);
|
||||
}
|
||||
|
||||
// Index can also be used to iterate over a certain portion of a collection
|
||||
size_t limit = q_count(my_queue) / 2;
|
||||
for (queue_iter it = my_queue->it_start(my_queue); !q_iter_end(&it); q_iter_next(&it))
|
||||
{
|
||||
// Access the current element
|
||||
int e = q_iter_value(&it);
|
||||
|
||||
// Access the current index (index is relative to all the elements in the iteration)
|
||||
size_t i = q_iter_index(&it);
|
||||
|
||||
// Print queue up until limit
|
||||
|
||||
// If it is the first element
|
||||
if (i == 0)
|
||||
printf("[ %d, ", e);
|
||||
// If it is the last element
|
||||
else if (i == limit - 1) // -1 because index is 0 based and we want half of the queue
|
||||
{
|
||||
printf("%d ]\n", e);
|
||||
break;
|
||||
}
|
||||
// For elements at the middle
|
||||
else
|
||||
printf("%d, ", e);
|
||||
}
|
||||
|
||||
// Going backwards
|
||||
for (queue_iter it = my_queue->it_end(my_queue); // Initialize iterator 'it' to the end of the queue
|
||||
!q_iter_start(&it); // Conditional stop (until it is not at the start)
|
||||
q_iter_prev(&it)) // Iterator goes one position backwards
|
||||
{
|
||||
// Access the current element
|
||||
int e = q_iter_value(&it);
|
||||
|
||||
// Access the current index (index is relative to all the elements in the iteration)
|
||||
size_t i = q_iter_index(&it);
|
||||
|
||||
// Print queue
|
||||
// Note how the conditions for the first and last elements are simply swapped
|
||||
// Because iterating backwards make the first element be the index count - 1
|
||||
// and the last one be the index 0
|
||||
|
||||
// If it is the first element
|
||||
if (i == q_count(my_queue) - 1)
|
||||
printf("[ %d, ", e);
|
||||
// If it is the last element
|
||||
else if (i == 0)
|
||||
printf("%d ]\n", e);
|
||||
// For elements at the middle
|
||||
else
|
||||
printf("%d, ", e);
|
||||
}
|
||||
|
||||
// You can also use iterators in a while loop
|
||||
// But to do so you must declare the iterator struct outside the loop first
|
||||
queue_iter it;
|
||||
|
||||
// You have three options:
|
||||
// - Initialize it using the functions provided by the queue [ my_queue->it_start() and my_queue->it_end() ]
|
||||
// - Initialize it using the init() function (when the iterator is already allocated)
|
||||
// - Initialize it using the new() function (allocates on the heap, pointers only)
|
||||
|
||||
it = my_queue->it_start(my_queue);
|
||||
it = my_queue->it_end(my_queue);
|
||||
|
||||
// This is equivalent to it_start()
|
||||
q_iter_init(&it, my_queue);
|
||||
|
||||
// For pointers
|
||||
// Also equivalent to it_start()
|
||||
queue_iter *iter = q_iter_new(my_queue);
|
||||
|
||||
// The actual while loop
|
||||
while (!q_iter_end(iter))
|
||||
{
|
||||
// Accessing elements
|
||||
int e = q_iter_value(iter);
|
||||
size_t i = q_iter_index(iter);
|
||||
|
||||
// Print index and element
|
||||
printf("queue[%2" PRIuMAX "] = %2d\n", i, e);
|
||||
|
||||
// Move iterator forwards
|
||||
q_iter_next(iter);
|
||||
}
|
||||
|
||||
// Send the iterator to the start of the queue
|
||||
q_iter_to_start(iter);
|
||||
|
||||
// Send the iterator to the end of the queue
|
||||
q_iter_to_end(iter);
|
||||
|
||||
// Backwards loop
|
||||
while (!q_iter_start(iter))
|
||||
{
|
||||
// Accessing elements
|
||||
int e = q_iter_value(iter);
|
||||
size_t i = q_iter_index(iter);
|
||||
|
||||
// Print index and element
|
||||
printf("queue[%2" PRIuMAX "] = %2d\n", i, e);
|
||||
|
||||
// Move iterator backwards
|
||||
q_iter_prev(iter);
|
||||
}
|
||||
|
||||
// Certain iterators also allow you to modify the contents it is iterating over
|
||||
// Exceptions are collections that depend of the current state of the element
|
||||
// like tree-based collections and heap (collections that have some kind of ordering).
|
||||
// You also can't change the keys of an associative collection
|
||||
|
||||
// Change every element that is divisible by 3 to the number 7
|
||||
for (q_iter_to_start(&it); !q_iter_end(&it); q_iter_next(&it))
|
||||
{
|
||||
// Get a reference to the current value
|
||||
int *r = q_iter_rvalue(&it);
|
||||
|
||||
if (r != NULL && *r % 3 == 0)
|
||||
*r = 7;
|
||||
}
|
||||
|
||||
// Now print it to see the difference
|
||||
for (queue_iter it = my_queue->it_start(my_queue); !q_iter_end(&it); q_iter_next(&it))
|
||||
{
|
||||
int e = q_iter_value(&it);
|
||||
size_t i = q_iter_index(&it);
|
||||
|
||||
if (i == 0)
|
||||
printf("[ %d, ", e);
|
||||
else if (i == q_count(my_queue) - 1)
|
||||
printf("%d ]\n", e);
|
||||
else
|
||||
printf("%d, ", e);
|
||||
}
|
||||
|
||||
// Dispose the iterator called by q_iter_new()
|
||||
q_iter_free(iter);
|
||||
// Dispose the queue created
|
||||
q_free(my_queue);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
# Stack examples
|
||||
|
||||
* hanoi.c - Animated example of solving the hanoi tower.
|
||||
* iterator.c - A complete example of the stack iterator
|
||||
@@ -13,8 +13,6 @@
|
||||
|
||||
STACK_GENERATE(s, stack, /* static */, int)
|
||||
|
||||
#define MAX(a, b) a > b ? a : b
|
||||
|
||||
void print_hanoi(stack *t1, stack *t2, stack *t3);
|
||||
const char *draw(int value);
|
||||
void move_disc(stack *from, stack *to);
|
||||
|
||||
@@ -0,0 +1,195 @@
|
||||
/**
|
||||
* iterator.c
|
||||
*
|
||||
* Creation Date: 15/05/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
* Iterator Example
|
||||
*/
|
||||
#include "stack.h"
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
// Creates a stack of integers
|
||||
STACK_GENERATE(s, stack, /* FMOD */, int)
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
{
|
||||
// Create a new stack with an initial capacity of 100
|
||||
stack *my_stack = s_new(100);
|
||||
|
||||
// Add elements to the stack
|
||||
for (int i = 0; i < 20; i++)
|
||||
{
|
||||
s_push(my_stack, i);
|
||||
}
|
||||
|
||||
// Iterate from the start (top) to the end (bottom) of the stack
|
||||
for (stack_iter it = my_stack->it_start(my_stack); // Initialize iterator 'it' to the start of the stack
|
||||
!s_iter_end(&it); // Conditional stop (until it is not at the end)
|
||||
s_iter_next(&it)) // Iterator goes one position forward
|
||||
{
|
||||
// Access the current element
|
||||
int e = s_iter_value(&it);
|
||||
|
||||
// Access the current index (index is relative to all the elements in the iteration)
|
||||
size_t i = s_iter_index(&it);
|
||||
|
||||
// Print stack
|
||||
|
||||
// Index is useful in situations like this
|
||||
// If it is the first element
|
||||
if (i == 0)
|
||||
printf("[ %d, ", e);
|
||||
// If it is the last element
|
||||
else if (i == s_count(my_stack) - 1)
|
||||
printf("%d ]\n", e);
|
||||
// For elements at the middle
|
||||
else
|
||||
printf("%d, ", e);
|
||||
}
|
||||
|
||||
// Index can also be used to iterate over a certain portion of a collection
|
||||
size_t limit = s_count(my_stack) / 2;
|
||||
for (stack_iter it = my_stack->it_start(my_stack); !s_iter_end(&it); s_iter_next(&it))
|
||||
{
|
||||
// Access the current element
|
||||
int e = s_iter_value(&it);
|
||||
|
||||
// Access the current index (index is relative to all the elements in the iteration)
|
||||
size_t i = s_iter_index(&it);
|
||||
|
||||
// Print stack up until limit
|
||||
|
||||
// If it is the first element
|
||||
if (i == 0)
|
||||
printf("[ %d, ", e);
|
||||
// If it is the last element
|
||||
else if (i == limit - 1) // -1 because index is 0 based and we want half of the stack
|
||||
{
|
||||
printf("%d ]\n", e);
|
||||
break;
|
||||
}
|
||||
// For elements at the middle
|
||||
else
|
||||
printf("%d, ", e);
|
||||
}
|
||||
|
||||
// Going backwards
|
||||
for (stack_iter it = my_stack->it_end(my_stack); // Initialize iterator 'it' to the end of the stack
|
||||
!s_iter_start(&it); // Conditional stop (until it is not at the start)
|
||||
s_iter_prev(&it)) // Iterator goes one position backwards
|
||||
{
|
||||
// Access the current element
|
||||
int e = s_iter_value(&it);
|
||||
|
||||
// Access the current index (index is relative to all the elements in the iteration)
|
||||
size_t i = s_iter_index(&it);
|
||||
|
||||
// Print stack
|
||||
// Note how the conditions for the first and last elements are simply swapped
|
||||
// Because iterating backwards make the first element be the index count - 1
|
||||
// and the last one be the index 0
|
||||
|
||||
// If it is the first element
|
||||
if (i == s_count(my_stack) - 1)
|
||||
printf("[ %d, ", e);
|
||||
// If it is the last element
|
||||
else if (i == 0)
|
||||
printf("%d ]\n", e);
|
||||
// For elements at the middle
|
||||
else
|
||||
printf("%d, ", e);
|
||||
}
|
||||
|
||||
// You can also use iterators in a while loop
|
||||
// But to do so you must declare the iterator struct outside the loop first
|
||||
stack_iter it;
|
||||
|
||||
// You have three options:
|
||||
// - Initialize it using the functions provided by the stack [ my_stack->it_start() and my_stack->it_end() ]
|
||||
// - Initialize it using the init() function (when the iterator is already allocated)
|
||||
// - Initialize it using the new() function (allocates on the heap, pointers only)
|
||||
|
||||
it = my_stack->it_start(my_stack);
|
||||
it = my_stack->it_end(my_stack);
|
||||
|
||||
// This is equivalent to it_start()
|
||||
s_iter_init(&it, my_stack);
|
||||
|
||||
// For pointers
|
||||
// Also equivalent to it_start()
|
||||
stack_iter *iter = s_iter_new(my_stack);
|
||||
|
||||
// The actual while loop
|
||||
while (!s_iter_end(iter))
|
||||
{
|
||||
// Accessing elements
|
||||
int e = s_iter_value(iter);
|
||||
size_t i = s_iter_index(iter);
|
||||
|
||||
// Print index and element
|
||||
printf("stack[%2" PRIuMAX "] = %2d\n", i, e);
|
||||
|
||||
// Move iterator forwards
|
||||
s_iter_next(iter);
|
||||
}
|
||||
|
||||
// Send the iterator to the start of the stack
|
||||
s_iter_to_start(iter);
|
||||
|
||||
// Send the iterator to the end of the stack
|
||||
s_iter_to_end(iter);
|
||||
|
||||
// Backwards loop
|
||||
while (!s_iter_start(iter))
|
||||
{
|
||||
// Accessing elements
|
||||
int e = s_iter_value(iter);
|
||||
size_t i = s_iter_index(iter);
|
||||
|
||||
// Print index and element
|
||||
printf("stack[%2" PRIuMAX "] = %2d\n", i, e);
|
||||
|
||||
// Move iterator backwards
|
||||
s_iter_prev(iter);
|
||||
}
|
||||
|
||||
// Certain iterators also allow you to modify the contents it is iterating over
|
||||
// Exceptions are collections that depend of the current state of the element
|
||||
// like tree-based collections and heap (collections that have some kind of ordering).
|
||||
// You also can't change the keys of an associative collection
|
||||
|
||||
// Change every element that is divisible by 3 to the number 7
|
||||
for (s_iter_to_start(&it); !s_iter_end(&it); s_iter_next(&it))
|
||||
{
|
||||
// Get a reference to the current value
|
||||
int *r = s_iter_rvalue(&it);
|
||||
|
||||
if (r != NULL && *r % 3 == 0)
|
||||
*r = 7;
|
||||
}
|
||||
|
||||
// Now print it to see the difference
|
||||
for (stack_iter it = my_stack->it_start(my_stack); !s_iter_end(&it); s_iter_next(&it))
|
||||
{
|
||||
int e = s_iter_value(&it);
|
||||
size_t i = s_iter_index(&it);
|
||||
|
||||
if (i == 0)
|
||||
printf("[ %d, ", e);
|
||||
else if (i == s_count(my_stack) - 1)
|
||||
printf("%d ]\n", e);
|
||||
else
|
||||
printf("%d, ", e);
|
||||
}
|
||||
|
||||
// Dispose the iterator called by s_iter_new()
|
||||
s_iter_free(iter);
|
||||
// Dispose the stack created
|
||||
s_free(my_stack);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
# Treemap examples
|
||||
|
||||
Currently none
|
||||
* pseudo_multiset.c - An example of how to make a multiset using a map.
|
||||
* iterator.c - A complete example of the treemap iterator
|
||||
@@ -0,0 +1,217 @@
|
||||
/**
|
||||
* iterator.c
|
||||
*
|
||||
* Creation Date: 16/05/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
* Iterator Example
|
||||
*/
|
||||
#include "treemap.h"
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
// Int compare function
|
||||
int intcmp(int a, int b)
|
||||
{
|
||||
return a - b;
|
||||
}
|
||||
|
||||
// Creates a treemap of integers
|
||||
TREEMAP_GENERATE(tm, treemap, /* FMOD */, int, double)
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
{
|
||||
// Create a new treemap
|
||||
treemap *my_map = tm_new(intcmp);
|
||||
|
||||
// Add pairs to the treemap
|
||||
for (int i = 0; i < 20; i++)
|
||||
{
|
||||
// Map integers to doubles
|
||||
tm_insert(my_map, i, (double)i / 10.0);
|
||||
}
|
||||
|
||||
// Iterate from the start (left-most node) to the end (right-most node) of the treemap
|
||||
for (treemap_iter it = my_map->it_start(my_map); // Initialize iterator 'it' to the start of the treemap
|
||||
!tm_iter_end(&it); // Conditional stop (until it is not at the end)
|
||||
tm_iter_next(&it)) // Iterator goes one position forward
|
||||
{
|
||||
// Access the current key
|
||||
int k = tm_iter_key(&it);
|
||||
|
||||
// Access the current value
|
||||
double v = tm_iter_value(&it);
|
||||
|
||||
// Access the current index (index is relative to all the pairs in the iteration)
|
||||
size_t i = tm_iter_index(&it);
|
||||
|
||||
// Print treemap
|
||||
|
||||
// Index is useful in situations like this
|
||||
// If it is the first pair
|
||||
if (i == 0)
|
||||
printf("[ {%d:%.2lf}, ", k, v);
|
||||
// If it is the last pair
|
||||
else if (i == tm_count(my_map) - 1)
|
||||
printf("{%d:%.2lf} ]\n", k, v);
|
||||
// For pairs at the middle
|
||||
else
|
||||
printf("{%d:%.2lf}, ", k, v);
|
||||
}
|
||||
|
||||
// Index can also be used to iterate over a certain portion of a collection
|
||||
size_t limit = tm_count(my_map) / 2;
|
||||
for (treemap_iter it = my_map->it_start(my_map); !tm_iter_end(&it); tm_iter_next(&it))
|
||||
{
|
||||
// Access the current key
|
||||
int k = tm_iter_key(&it);
|
||||
|
||||
// Access the current value
|
||||
double v = tm_iter_value(&it);
|
||||
|
||||
// Access the current index (index is relative to all the pairs in the iteration)
|
||||
size_t i = tm_iter_index(&it);
|
||||
|
||||
// Print treemap up until limit
|
||||
|
||||
// If it is the first pair
|
||||
if (i == 0)
|
||||
printf("[ {%d:%.2lf}, ", k, v);
|
||||
// If it is the last pair
|
||||
else if (i == limit - 1) // -1 because index is 0 based and we want half of the treemap
|
||||
{
|
||||
printf("{%d:%.2lf} ]\n", k, v);
|
||||
break;
|
||||
}
|
||||
// For pairs at the middle
|
||||
else
|
||||
printf("{%d:%.2lf}, ", k, v);
|
||||
}
|
||||
|
||||
// Going backwards
|
||||
for (treemap_iter it = my_map->it_end(my_map); // Initialize iterator 'it' to the end of the treemap
|
||||
!tm_iter_start(&it); // Conditional stop (until it is not at the start)
|
||||
tm_iter_prev(&it)) // Iterator goes one position backwards
|
||||
{
|
||||
// Access the current key
|
||||
int k = tm_iter_key(&it);
|
||||
|
||||
// Access the current value
|
||||
double v = tm_iter_value(&it);
|
||||
|
||||
// Access the current index (index is relative to all the pairs in the iteration)
|
||||
size_t i = tm_iter_index(&it);
|
||||
|
||||
// Print treemap
|
||||
// Note how the conditions for the first and last pairs are simply swapped
|
||||
// Because iterating backwards make the first pair be the index count - 1
|
||||
// and the last one be the index 0
|
||||
|
||||
// If it is the first pair
|
||||
if (i == tm_count(my_map) - 1)
|
||||
printf("[ {%d:%.2lf}, ", k, v);
|
||||
// If it is the last pair
|
||||
else if (i == 0)
|
||||
printf("{%d:%.2lf} ]\n", k, v);
|
||||
// For pairs at the middle
|
||||
else
|
||||
printf("{%d:%.2lf}, ", k, v);
|
||||
}
|
||||
|
||||
// You can also use iterators in a while loop
|
||||
// But to do so you must declare the iterator struct outside the loop first
|
||||
treemap_iter it;
|
||||
|
||||
// You have three options:
|
||||
// - Initialize it using the functions provided by the treemap [ my_map->it_start() and my_map->it_end() ]
|
||||
// - Initialize it using the init() function (when the iterator is already allocated)
|
||||
// - Initialize it using the new() function (allocates on the heap, pointers only)
|
||||
|
||||
it = my_map->it_start(my_map);
|
||||
it = my_map->it_end(my_map);
|
||||
|
||||
// This is equivalent to it_start()
|
||||
tm_iter_init(&it, my_map);
|
||||
|
||||
// For pointers
|
||||
// Also equivalent to it_start()
|
||||
treemap_iter *iter = tm_iter_new(my_map);
|
||||
|
||||
// The actual while loop
|
||||
while (!tm_iter_end(iter))
|
||||
{
|
||||
// Accessing pairs
|
||||
int k = tm_iter_key(iter);
|
||||
double v = tm_iter_value(iter);
|
||||
size_t i = tm_iter_index(iter);
|
||||
|
||||
// Print index and key value pair
|
||||
printf("treemap[%2" PRIuMAX "] = { %2d : %.2lf }\n", i, k, v);
|
||||
|
||||
// Move iterator forwards
|
||||
tm_iter_next(iter);
|
||||
}
|
||||
|
||||
// Send the iterator to the start of the treemap
|
||||
tm_iter_to_start(iter);
|
||||
|
||||
// Send the iterator to the end of the treemap
|
||||
tm_iter_to_end(iter);
|
||||
|
||||
// Backwards loop
|
||||
while (!tm_iter_start(iter))
|
||||
{
|
||||
// Accessing pairs
|
||||
int k = tm_iter_key(iter);
|
||||
double v = tm_iter_value(iter);
|
||||
size_t i = tm_iter_index(iter);
|
||||
|
||||
// Print index and the key value pair
|
||||
printf("treemap[%2" PRIuMAX "] = { %2d : %.2lf }\n", i, k, v);
|
||||
|
||||
// Move iterator backwards
|
||||
tm_iter_prev(iter);
|
||||
}
|
||||
|
||||
// Certain iterators also allow you to modify the contents it is iterating over
|
||||
// Exceptions are collections that depend of the current state of the pair
|
||||
// like tree-based collections and heap (collections that have some kind of ordering).
|
||||
// You also can't change the keys of an associative collection
|
||||
|
||||
// Change every value where its key is divisible by 3 to the number 7
|
||||
for (tm_iter_to_start(&it); !tm_iter_end(&it); tm_iter_next(&it))
|
||||
{
|
||||
// Get current key
|
||||
int k = tm_iter_key(&it);
|
||||
|
||||
// Get a reference to the current value
|
||||
double *v = tm_iter_rvalue(&it);
|
||||
|
||||
if (k % 3 == 0)
|
||||
*v = 7;
|
||||
}
|
||||
|
||||
// Now print it to see the difference
|
||||
for (treemap_iter it = my_map->it_start(my_map); !tm_iter_end(&it); tm_iter_next(&it))
|
||||
{
|
||||
int k = tm_iter_key(&it);
|
||||
double v = tm_iter_value(&it);
|
||||
size_t i = tm_iter_index(&it);
|
||||
|
||||
if (i == 0)
|
||||
printf("[ {%d:%.2lf}, ", k, v);
|
||||
else if (i == tm_count(my_map) - 1)
|
||||
printf("{%d:%.2lf} ]\n", k, v);
|
||||
else
|
||||
printf("{%d:%.2lf}, ", k, v);
|
||||
}
|
||||
|
||||
// Dispose the iterator called by tm_iter_new()
|
||||
tm_iter_free(iter);
|
||||
// Dispose the treemap created
|
||||
tm_free(my_map);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
/**
|
||||
* pseudo_multiset.c
|
||||
*
|
||||
* Creation Date: 26/04/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
*/
|
||||
|
||||
// How to make a multiset using a map
|
||||
|
||||
#include "treemap.h"
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
// Mapping an integer by size_t which will represent the key's multiplicity
|
||||
// (key could be anything and multiplicity could be an integer, preferably
|
||||
// unsigned)
|
||||
TREEMAP_GENERATE(tm, tmap, , int, size_t)
|
||||
|
||||
// Compare function used by the treemap
|
||||
int intcmp(int a, int b)
|
||||
{
|
||||
return (a > b) - (a < b);
|
||||
}
|
||||
|
||||
// Little helper to print the tree
|
||||
void print_tree(tmap_node *root, int height)
|
||||
{
|
||||
if (!root)
|
||||
return;
|
||||
|
||||
print_tree(root->right, height + 1);
|
||||
|
||||
for (int i = 0; i < height; i++)
|
||||
printf("|------- ");
|
||||
|
||||
// Key:Multiplicity
|
||||
printf("%d:%" PRIuMAX "\n", root->key, root->value);
|
||||
|
||||
print_tree(root->left, height + 1);
|
||||
}
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
{
|
||||
tmap *map = tm_new(intcmp);
|
||||
|
||||
// Start adding elements
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
// Modulo of 8 so we get some repetition
|
||||
int key = i % 8;
|
||||
|
||||
// Get the reference to a value in the map with the key
|
||||
size_t *rvalue = tm_get_ref(map, key);
|
||||
|
||||
// If the key exists, rvalue is not null
|
||||
if (rvalue != NULL)
|
||||
{
|
||||
// Incrementing it means we have added another key to the set
|
||||
// The value represents the multiplicity, that is, how many times
|
||||
// we have added the key in the set
|
||||
(*rvalue)++;
|
||||
}
|
||||
else
|
||||
// Create a new entry with key with an initial multiplicity of 1
|
||||
tm_insert(map, key, 1);
|
||||
}
|
||||
|
||||
print_tree(map->root, 0);
|
||||
|
||||
// Summary
|
||||
printf("\n---------- SUMMARY ----------\n\n");
|
||||
|
||||
// Print using iterator
|
||||
for (tmap_iter it = map->it_start(map); !tm_iter_end(&it); tm_iter_next(&it))
|
||||
{
|
||||
// Map[key] = multiplicity
|
||||
printf("Map[%2d] = %" PRIuMAX "\n", tm_iter_key(&it), tm_iter_value(&it));
|
||||
}
|
||||
|
||||
tm_free(map);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
# Treeset examples
|
||||
|
||||
* iterator.c - A complete example of the treeset iterator
|
||||
* set_ops.c - Demonstrates common set operations like *union*, *intersection*, *difference* and *symmetric difference*.
|
||||
* tree_print.c - How to print a binary tree.
|
||||
@@ -0,0 +1,194 @@
|
||||
/**
|
||||
* iterator.c
|
||||
*
|
||||
* Creation Date: 16/05/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
* Iterator Example
|
||||
*/
|
||||
#include "treeset.h"
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
// Int hash function
|
||||
size_t inthash(int t)
|
||||
{
|
||||
size_t a = t;
|
||||
a += ~(a << 15);
|
||||
a ^= (a >> 10);
|
||||
a += (a << 3);
|
||||
a ^= (a >> 6);
|
||||
a += ~(a << 11);
|
||||
a ^= (a >> 16);
|
||||
return a;
|
||||
}
|
||||
|
||||
// Int compare function
|
||||
int intcmp(int a, int b)
|
||||
{
|
||||
return a - b;
|
||||
}
|
||||
|
||||
// Creates a treeset of integers
|
||||
TREESET_GENERATE(ts, treeset, /* FMOD */, int)
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
{
|
||||
// Create a new treeset with an initial capacity of 100 and load factor of 0.6
|
||||
treeset *my_treeset = ts_new(intcmp);
|
||||
|
||||
// Add elements to the treeset
|
||||
for (int i = 0; i < 20; i++)
|
||||
{
|
||||
ts_insert(my_treeset, i);
|
||||
}
|
||||
|
||||
// Iterate from the start (index 0) to the end (index count - 1) of the treeset
|
||||
for (treeset_iter it = my_treeset->it_start(my_treeset); // Initialize iterator 'it' to the start of the treeset
|
||||
!ts_iter_end(&it); // Conditional stop (until it is not at the end)
|
||||
ts_iter_next(&it)) // Iterator goes one position forward
|
||||
{
|
||||
// Access the current element
|
||||
int e = ts_iter_value(&it);
|
||||
|
||||
// Access the current index (index is relative to all the elements in the iteration)
|
||||
size_t i = ts_iter_index(&it);
|
||||
|
||||
// Print treeset
|
||||
|
||||
// Index is useful in situations like this
|
||||
// If it is the first element
|
||||
if (i == 0)
|
||||
printf("[ %d, ", e);
|
||||
// If it is the last element
|
||||
else if (i == ts_count(my_treeset) - 1)
|
||||
printf("%d ]\n", e);
|
||||
// For elements at the middle
|
||||
else
|
||||
printf("%d, ", e);
|
||||
}
|
||||
|
||||
// Index can also be used to iterate over a certain portion of a collection
|
||||
size_t limit = ts_count(my_treeset) / 2;
|
||||
for (treeset_iter it = my_treeset->it_start(my_treeset); !ts_iter_end(&it); ts_iter_next(&it))
|
||||
{
|
||||
// Access the current element
|
||||
int e = ts_iter_value(&it);
|
||||
|
||||
// Access the current index (index is relative to all the elements in the iteration)
|
||||
size_t i = ts_iter_index(&it);
|
||||
|
||||
// Print treeset up until limit
|
||||
|
||||
// If it is the first element
|
||||
if (i == 0)
|
||||
printf("[ %d, ", e);
|
||||
// If it is the last element
|
||||
else if (i == limit - 1) // -1 because index is 0 based and we want half of the treeset
|
||||
{
|
||||
printf("%d ]\n", e);
|
||||
break;
|
||||
}
|
||||
// For elements at the middle
|
||||
else
|
||||
printf("%d, ", e);
|
||||
}
|
||||
|
||||
// Going backwards
|
||||
for (treeset_iter it = my_treeset->it_end(my_treeset); // Initialize iterator 'it' to the end of the treeset
|
||||
!ts_iter_start(&it); // Conditional stop (until it is not at the start)
|
||||
ts_iter_prev(&it)) // Iterator goes one position backwards
|
||||
{
|
||||
// Access the current element
|
||||
int e = ts_iter_value(&it);
|
||||
|
||||
// Access the current index (index is relative to all the elements in the iteration)
|
||||
size_t i = ts_iter_index(&it);
|
||||
|
||||
// Print treeset
|
||||
// Note how the conditions for the first and last elements are simply swapped
|
||||
// Because iterating backwards make the first element be the index count - 1
|
||||
// and the last one be the index 0
|
||||
|
||||
// If it is the first element
|
||||
if (i == ts_count(my_treeset) - 1)
|
||||
printf("[ %d, ", e);
|
||||
// If it is the last element
|
||||
else if (i == 0)
|
||||
printf("%d ]\n", e);
|
||||
// For elements at the middle
|
||||
else
|
||||
printf("%d, ", e);
|
||||
}
|
||||
|
||||
// You can also use iterators in a while loop
|
||||
// But to do so you must declare the iterator struct outside the loop first
|
||||
treeset_iter it;
|
||||
|
||||
// You have three options:
|
||||
// - Initialize it using the functions provided by the treeset [ my_treeset->it_start() and my_treeset->it_end() ]
|
||||
// - Initialize it using the init() function (when the iterator is already allocated)
|
||||
// - Initialize it using the new() function (allocates on the heap, pointers only)
|
||||
|
||||
it = my_treeset->it_start(my_treeset);
|
||||
it = my_treeset->it_end(my_treeset);
|
||||
|
||||
// This is equivalent to it_start()
|
||||
ts_iter_init(&it, my_treeset);
|
||||
|
||||
// For pointers
|
||||
// Also equivalent to it_start()
|
||||
treeset_iter *iter = ts_iter_new(my_treeset);
|
||||
|
||||
// The actual while loop
|
||||
while (!ts_iter_end(iter))
|
||||
{
|
||||
// Accessing elements
|
||||
int e = ts_iter_value(iter);
|
||||
size_t i = ts_iter_index(iter);
|
||||
|
||||
// Print index and element
|
||||
printf("treeset[%2" PRIuMAX "] = %2d\n", i, e);
|
||||
|
||||
// Move iterator forwards
|
||||
ts_iter_next(iter);
|
||||
}
|
||||
|
||||
// Send the iterator to the start of the treeset
|
||||
ts_iter_to_start(iter);
|
||||
|
||||
// Send the iterator to the end of the treeset
|
||||
ts_iter_to_end(iter);
|
||||
|
||||
// Backwards loop
|
||||
while (!ts_iter_start(iter))
|
||||
{
|
||||
// Accessing elements
|
||||
int e = ts_iter_value(iter);
|
||||
size_t i = ts_iter_index(iter);
|
||||
|
||||
// Print index and element
|
||||
printf("treeset[%2" PRIuMAX "] = %2d\n", i, e);
|
||||
|
||||
// Move iterator backwards
|
||||
ts_iter_prev(iter);
|
||||
}
|
||||
|
||||
// Certain iterators also allow you to modify the contents it is iterating over
|
||||
// Exceptions are collections that depend of the current state of the element
|
||||
// like tree-based collections and heap (collections that have some kind of ordering).
|
||||
// You also can't change the keys of an associative collection
|
||||
|
||||
// In the case of a treeset or any set, this is not possible because the
|
||||
// values of a set are its keys. Changing the elements could cause the set
|
||||
// to be in an invalid state.
|
||||
|
||||
// Dispose the iterator called by ts_iter_new()
|
||||
ts_iter_free(iter);
|
||||
// Dispose the treeset created
|
||||
ts_free(my_treeset);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -22,13 +22,13 @@ TREESET_GENERATE(set, set, /* static */, int)
|
||||
|
||||
void print_set(set *s)
|
||||
{
|
||||
size_t index;
|
||||
int result;
|
||||
set_iter iter;
|
||||
set_iter_new(&iter, s);
|
||||
for (set_iter_tostart(&iter); !set_iter_end(&iter);)
|
||||
set_iter_init(&iter, s);
|
||||
for (set_iter_to_start(&iter); !set_iter_end(&iter); set_iter_next(&iter))
|
||||
{
|
||||
set_iter_next(&iter, &result, &index);
|
||||
int result = set_iter_value(&iter);
|
||||
size_t index = set_iter_index(&iter);
|
||||
|
||||
if (index == 0)
|
||||
printf("[ %2d, ", result);
|
||||
else if (index == s->count - 1)
|
||||
|
||||
@@ -24,7 +24,7 @@ void print_tree(set_node *root, int height)
|
||||
for (int i = 0; i < height; i++)
|
||||
printf("|------- ");
|
||||
|
||||
printf("%d\n", root->key);
|
||||
printf("%d\n", root->value);
|
||||
|
||||
print_tree(root->left, height + 1);
|
||||
}
|
||||
|
||||
+443
-331
@@ -37,339 +37,451 @@
|
||||
#define DEQUE_GENERATE_SOURCE_PUBLIC(PFX, SNAME, FMOD, K, V) \
|
||||
DEQUE_GENERATE_SOURCE(PFX, SNAME, FMOD, V)
|
||||
/* STRUCT ********************************************************************/
|
||||
#define DEQUE_GENERATE_STRUCT(PFX, SNAME, FMOD, V) \
|
||||
\
|
||||
struct SNAME##_s \
|
||||
{ \
|
||||
V *buffer; \
|
||||
size_t capacity; \
|
||||
size_t count; \
|
||||
size_t front; \
|
||||
size_t rear; \
|
||||
}; \
|
||||
\
|
||||
struct SNAME##_iter_s \
|
||||
{ \
|
||||
struct SNAME##_s *target; \
|
||||
size_t cursor; \
|
||||
size_t index; \
|
||||
bool start; \
|
||||
bool end; \
|
||||
}; \
|
||||
\
|
||||
#define DEQUE_GENERATE_STRUCT(PFX, SNAME, FMOD, V)
|
||||
|
||||
/* HEADER ********************************************************************/
|
||||
#define DEQUE_GENERATE_HEADER(PFX, SNAME, FMOD, V) \
|
||||
\
|
||||
typedef struct SNAME##_s SNAME; \
|
||||
typedef struct SNAME##_iter_s SNAME##_iter; \
|
||||
\
|
||||
FMOD SNAME *PFX##_new(size_t size); \
|
||||
FMOD void PFX##_clear(SNAME *_deque_); \
|
||||
FMOD void PFX##_free(SNAME *_deque_); \
|
||||
FMOD bool PFX##_push_front(SNAME *_deque_, V element); \
|
||||
FMOD bool PFX##_push_back(SNAME *_deque_, V element); \
|
||||
FMOD bool PFX##_pop_front(SNAME *_deque_); \
|
||||
FMOD bool PFX##_pop_back(SNAME *_deque_); \
|
||||
FMOD bool PFX##_push_front_if(SNAME *_deque_, V element, bool condition); \
|
||||
FMOD bool PFX##_push_back_if(SNAME *_deque_, V element, bool condition); \
|
||||
FMOD bool PFX##_pop_front_if(SNAME *_deque_, bool condition); \
|
||||
FMOD bool PFX##_pop_back_if(SNAME *_deque_, bool condition); \
|
||||
FMOD V PFX##_front(SNAME *_deque_); \
|
||||
FMOD V PFX##_back(SNAME *_deque_); \
|
||||
FMOD bool PFX##_empty(SNAME *_deque_); \
|
||||
FMOD bool PFX##_full(SNAME *_deque_); \
|
||||
FMOD size_t PFX##_count(SNAME *_deque_); \
|
||||
FMOD size_t PFX##_capacity(SNAME *_deque_); \
|
||||
\
|
||||
FMOD void PFX##_iter_new(SNAME##_iter *iter, SNAME *target); \
|
||||
FMOD bool PFX##_iter_start(SNAME##_iter *iter); \
|
||||
FMOD bool PFX##_iter_end(SNAME##_iter *iter); \
|
||||
FMOD void PFX##_iter_tostart(SNAME##_iter *iter); \
|
||||
FMOD void PFX##_iter_toend(SNAME##_iter *iter); \
|
||||
FMOD bool PFX##_iter_next(SNAME##_iter *iter, V *result, size_t *index); \
|
||||
FMOD bool PFX##_iter_prev(SNAME##_iter *iter, V *result, size_t *index); \
|
||||
\
|
||||
#define DEQUE_GENERATE_HEADER(PFX, SNAME, FMOD, V) \
|
||||
\
|
||||
/* Deque Structure */ \
|
||||
typedef struct SNAME##_s \
|
||||
{ \
|
||||
/* Dynamic circular array of elements */ \
|
||||
V *buffer; \
|
||||
\
|
||||
/* Current circular array capacity */ \
|
||||
size_t capacity; \
|
||||
\
|
||||
/* Current amount of elements */ \
|
||||
size_t count; \
|
||||
\
|
||||
/* Index representing the front of the deque */ \
|
||||
size_t front; \
|
||||
\
|
||||
/* Index representing the back of the deque */ \
|
||||
size_t back; \
|
||||
\
|
||||
/* Function that returns an iterator to the start of the deque */ \
|
||||
struct SNAME##_iter_s (*it_start)(struct SNAME##_s *); \
|
||||
\
|
||||
/* Function that returns an iterator to the end of the deque */ \
|
||||
struct SNAME##_iter_s (*it_end)(struct SNAME##_s *); \
|
||||
\
|
||||
} SNAME, *SNAME##_ptr; \
|
||||
\
|
||||
/* Deque Iterator */ \
|
||||
typedef struct SNAME##_iter_s \
|
||||
{ \
|
||||
/* Target deque */ \
|
||||
struct SNAME##_s *target; \
|
||||
\
|
||||
/* Cursor's position (index) */ \
|
||||
size_t cursor; \
|
||||
\
|
||||
/* Keeps track of relative index to the iteration of elements */ \
|
||||
size_t index; \
|
||||
\
|
||||
/* If the iterator has reached the start of the iteration */ \
|
||||
bool start; \
|
||||
\
|
||||
/* If the iterator has reached the end of the iteration */ \
|
||||
bool end; \
|
||||
\
|
||||
} SNAME##_iter, *SNAME##_iter_ptr; \
|
||||
\
|
||||
/* Collection Functions */ \
|
||||
/* Collection Allocation and Deallocation */ \
|
||||
FMOD SNAME *PFX##_new(size_t size); \
|
||||
FMOD void PFX##_clear(SNAME *_deque_); \
|
||||
FMOD void PFX##_free(SNAME *_deque_); \
|
||||
/* Collection Input and Output */ \
|
||||
FMOD bool PFX##_push_front(SNAME *_deque_, V element); \
|
||||
FMOD bool PFX##_push_back(SNAME *_deque_, V element); \
|
||||
FMOD bool PFX##_pop_front(SNAME *_deque_); \
|
||||
FMOD bool PFX##_pop_back(SNAME *_deque_); \
|
||||
/* Conditional Input and Output */ \
|
||||
FMOD bool PFX##_push_front_if(SNAME *_deque_, V element, bool condition); \
|
||||
FMOD bool PFX##_push_back_if(SNAME *_deque_, V element, bool condition); \
|
||||
FMOD bool PFX##_pop_front_if(SNAME *_deque_, bool condition); \
|
||||
FMOD bool PFX##_pop_back_if(SNAME *_deque_, bool condition); \
|
||||
/* Element Access */ \
|
||||
FMOD V PFX##_front(SNAME *_deque_); \
|
||||
FMOD V PFX##_back(SNAME *_deque_); \
|
||||
/* Collection State */ \
|
||||
FMOD bool PFX##_contains(SNAME *_deque_, V element, int (*comparator)(V, V)); \
|
||||
FMOD bool PFX##_empty(SNAME *_deque_); \
|
||||
FMOD bool PFX##_full(SNAME *_deque_); \
|
||||
FMOD size_t PFX##_count(SNAME *_deque_); \
|
||||
FMOD size_t PFX##_capacity(SNAME *_deque_); \
|
||||
\
|
||||
/* Iterator Functions */ \
|
||||
/* Iterator Allocation and Deallocation */ \
|
||||
FMOD SNAME##_iter *PFX##_iter_new(SNAME *target); \
|
||||
FMOD void PFX##_iter_free(SNAME##_iter *iter); \
|
||||
/* Iterator Initialization */ \
|
||||
FMOD void PFX##_iter_init(SNAME##_iter *iter, SNAME *target); \
|
||||
/* Iterator State */ \
|
||||
FMOD bool PFX##_iter_start(SNAME##_iter *iter); \
|
||||
FMOD bool PFX##_iter_end(SNAME##_iter *iter); \
|
||||
/* Iterator Movement */ \
|
||||
FMOD void PFX##_iter_to_start(SNAME##_iter *iter); \
|
||||
FMOD void PFX##_iter_to_end(SNAME##_iter *iter); \
|
||||
FMOD bool PFX##_iter_next(SNAME##_iter *iter); \
|
||||
FMOD bool PFX##_iter_prev(SNAME##_iter *iter); \
|
||||
/* Iterator Access */ \
|
||||
FMOD V PFX##_iter_value(SNAME##_iter *iter); \
|
||||
FMOD V *PFX##_iter_rvalue(SNAME##_iter *iter); \
|
||||
FMOD size_t PFX##_iter_index(SNAME##_iter *iter); \
|
||||
\
|
||||
/* SOURCE ********************************************************************/
|
||||
#define DEQUE_GENERATE_SOURCE(PFX, SNAME, FMOD, V) \
|
||||
\
|
||||
FMOD bool PFX##_grow(SNAME *_deque_); \
|
||||
\
|
||||
FMOD SNAME *PFX##_new(size_t size) \
|
||||
{ \
|
||||
if (size < 1) \
|
||||
return NULL; \
|
||||
\
|
||||
SNAME *_deque_ = malloc(sizeof(SNAME)); \
|
||||
\
|
||||
if (!_deque_) \
|
||||
return NULL; \
|
||||
\
|
||||
_deque_->buffer = malloc(sizeof(V) * size); \
|
||||
\
|
||||
if (!_deque_->buffer) \
|
||||
{ \
|
||||
free(_deque_); \
|
||||
return NULL; \
|
||||
} \
|
||||
\
|
||||
memset(_deque_->buffer, 0, sizeof(V) * size); \
|
||||
\
|
||||
_deque_->capacity = size; \
|
||||
_deque_->count = 0; \
|
||||
_deque_->front = 0; \
|
||||
_deque_->rear = 0; \
|
||||
\
|
||||
return _deque_; \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_clear(SNAME *_deque_) \
|
||||
{ \
|
||||
memset(_deque_->buffer, 0, sizeof(V) * _deque_->capacity); \
|
||||
\
|
||||
_deque_->count = 0; \
|
||||
_deque_->front = 0; \
|
||||
_deque_->rear = 0; \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_free(SNAME *_deque_) \
|
||||
{ \
|
||||
free(_deque_->buffer); \
|
||||
free(_deque_); \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_push_front(SNAME *_deque_, V element) \
|
||||
{ \
|
||||
if (PFX##_full(_deque_)) \
|
||||
{ \
|
||||
if (!PFX##_grow(_deque_)) \
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
_deque_->front = (_deque_->front == 0) ? _deque_->capacity - 1 : _deque_->front - 1; \
|
||||
\
|
||||
_deque_->buffer[_deque_->front] = element; \
|
||||
\
|
||||
_deque_->count++; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_push_back(SNAME *_deque_, V element) \
|
||||
{ \
|
||||
if (PFX##_full(_deque_)) \
|
||||
{ \
|
||||
if (!PFX##_grow(_deque_)) \
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
_deque_->buffer[_deque_->rear] = element; \
|
||||
\
|
||||
_deque_->rear = (_deque_->rear == _deque_->capacity - 1) ? 0 : _deque_->rear + 1; \
|
||||
\
|
||||
_deque_->count++; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_pop_front(SNAME *_deque_) \
|
||||
{ \
|
||||
if (PFX##_empty(_deque_)) \
|
||||
return false; \
|
||||
\
|
||||
_deque_->buffer[_deque_->front] = 0; \
|
||||
\
|
||||
_deque_->front = (_deque_->front == _deque_->capacity - 1) ? 0 : _deque_->front + 1; \
|
||||
\
|
||||
_deque_->count--; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_pop_back(SNAME *_deque_) \
|
||||
{ \
|
||||
if (PFX##_empty(_deque_)) \
|
||||
return false; \
|
||||
\
|
||||
_deque_->rear = (_deque_->rear == 0) ? _deque_->capacity - 1 : _deque_->rear - 1; \
|
||||
\
|
||||
_deque_->buffer[_deque_->rear] = 0; \
|
||||
\
|
||||
_deque_->count--; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_push_front_if(SNAME *_deque_, V element, bool condition) \
|
||||
{ \
|
||||
if (condition) \
|
||||
return PFX##_push_front(_deque_, element); \
|
||||
\
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_push_back_if(SNAME *_deque_, V element, bool condition) \
|
||||
{ \
|
||||
if (condition) \
|
||||
return PFX##_push_back(_deque_, element); \
|
||||
\
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_pop_front_if(SNAME *_deque_, bool condition) \
|
||||
{ \
|
||||
if (condition) \
|
||||
return PFX##_pop_front(_deque_); \
|
||||
\
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_pop_back_if(SNAME *_deque_, bool condition) \
|
||||
{ \
|
||||
if (condition) \
|
||||
return PFX##_pop_back(_deque_); \
|
||||
\
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
FMOD V PFX##_front(SNAME *_deque_) \
|
||||
{ \
|
||||
if (PFX##_empty(_deque_)) \
|
||||
return 0; \
|
||||
\
|
||||
return _deque_->buffer[_deque_->front]; \
|
||||
} \
|
||||
\
|
||||
FMOD V PFX##_back(SNAME *_deque_) \
|
||||
{ \
|
||||
if (PFX##_empty(_deque_)) \
|
||||
return 0; \
|
||||
\
|
||||
return _deque_->buffer[(_deque_->rear == 0) ? _deque_->capacity - 1 : _deque_->rear - 1]; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_empty(SNAME *_deque_) \
|
||||
{ \
|
||||
return _deque_->count == 0; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_full(SNAME *_deque_) \
|
||||
{ \
|
||||
return _deque_->count >= _deque_->capacity; \
|
||||
} \
|
||||
\
|
||||
FMOD size_t PFX##_count(SNAME *_deque_) \
|
||||
{ \
|
||||
return _deque_->count; \
|
||||
} \
|
||||
\
|
||||
FMOD size_t PFX##_capacity(SNAME *_deque_) \
|
||||
{ \
|
||||
return _deque_->capacity; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_grow(SNAME *_deque_) \
|
||||
{ \
|
||||
\
|
||||
size_t new_capacity = _deque_->capacity * 2; \
|
||||
\
|
||||
V *new_buffer = malloc(sizeof(V) * new_capacity); \
|
||||
\
|
||||
if (!new_buffer) \
|
||||
return false; \
|
||||
\
|
||||
for (size_t i = _deque_->front, j = 0; j < _deque_->count; i = (i + 1) % _deque_->capacity, j++) \
|
||||
{ \
|
||||
new_buffer[j] = _deque_->buffer[i]; \
|
||||
} \
|
||||
\
|
||||
free(_deque_->buffer); \
|
||||
\
|
||||
_deque_->buffer = new_buffer; \
|
||||
_deque_->capacity = new_capacity; \
|
||||
_deque_->front = 0; \
|
||||
_deque_->rear = _deque_->count; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_iter_new(SNAME##_iter *iter, SNAME *target) \
|
||||
{ \
|
||||
iter->target = target; \
|
||||
iter->cursor = target->front; \
|
||||
iter->index = 0; \
|
||||
iter->start = true; \
|
||||
iter->end = PFX##_empty(target); \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_iter_start(SNAME##_iter *iter) \
|
||||
{ \
|
||||
return iter->cursor == iter->target->front && iter->start; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_iter_end(SNAME##_iter *iter) \
|
||||
{ \
|
||||
size_t real_rear = iter->target->rear == 0 ? iter->target->capacity - 1 : iter->target->rear - 1; \
|
||||
return iter->cursor == real_rear && iter->end; \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_iter_tostart(SNAME##_iter *iter) \
|
||||
{ \
|
||||
iter->cursor = iter->target->front; \
|
||||
iter->index = 0; \
|
||||
iter->start = true; \
|
||||
iter->end = PFX##_empty(iter->target); \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_iter_toend(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (PFX##_empty(iter->target)) \
|
||||
iter->cursor = 0; \
|
||||
else \
|
||||
iter->cursor = (iter->target->rear == 0) ? iter->target->count - 1 : iter->target->rear - 1; \
|
||||
\
|
||||
iter->index = iter->target->count - 1; \
|
||||
iter->start = PFX##_empty(iter->target); \
|
||||
iter->end = true; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_iter_next(SNAME##_iter *iter, V *result, size_t *index) \
|
||||
{ \
|
||||
if (iter->end) \
|
||||
return false; \
|
||||
\
|
||||
*index = iter->index; \
|
||||
*result = iter->target->buffer[iter->cursor]; \
|
||||
iter->start = false; \
|
||||
\
|
||||
if (iter->index == iter->target->count - 1) \
|
||||
iter->end = true; \
|
||||
else \
|
||||
{ \
|
||||
iter->cursor = (iter->cursor + 1) % (iter->target->capacity); \
|
||||
iter->index++; \
|
||||
} \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_iter_prev(SNAME##_iter *iter, V *result, size_t *index) \
|
||||
{ \
|
||||
if (iter->start) \
|
||||
return false; \
|
||||
\
|
||||
*index = iter->index; \
|
||||
*result = iter->target->buffer[iter->cursor]; \
|
||||
iter->end = false; \
|
||||
\
|
||||
if (iter->index == 0) \
|
||||
iter->start = true; \
|
||||
else \
|
||||
{ \
|
||||
iter->cursor = (iter->cursor == 0) ? iter->target->capacity - 1 : iter->cursor - 1; \
|
||||
iter->index--; \
|
||||
} \
|
||||
\
|
||||
return true; \
|
||||
#define DEQUE_GENERATE_SOURCE(PFX, SNAME, FMOD, V) \
|
||||
\
|
||||
/* Implementation Detail Functions */ \
|
||||
FMOD bool PFX##_impl_grow(SNAME *_deque_); \
|
||||
SNAME##_iter PFX##_impl_it_start(SNAME *_deque_); \
|
||||
SNAME##_iter PFX##_impl_it_end(SNAME *_deque_); \
|
||||
\
|
||||
FMOD SNAME *PFX##_new(size_t size) \
|
||||
{ \
|
||||
if (size < 1) \
|
||||
return NULL; \
|
||||
\
|
||||
SNAME *_deque_ = malloc(sizeof(SNAME)); \
|
||||
\
|
||||
if (!_deque_) \
|
||||
return NULL; \
|
||||
\
|
||||
_deque_->buffer = malloc(sizeof(V) * size); \
|
||||
\
|
||||
if (!_deque_->buffer) \
|
||||
{ \
|
||||
free(_deque_); \
|
||||
return NULL; \
|
||||
} \
|
||||
\
|
||||
memset(_deque_->buffer, 0, sizeof(V) * size); \
|
||||
\
|
||||
_deque_->capacity = size; \
|
||||
_deque_->count = 0; \
|
||||
_deque_->front = 0; \
|
||||
_deque_->back = 0; \
|
||||
\
|
||||
_deque_->it_start = PFX##_impl_it_start; \
|
||||
_deque_->it_end = PFX##_impl_it_end; \
|
||||
\
|
||||
return _deque_; \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_clear(SNAME *_deque_) \
|
||||
{ \
|
||||
memset(_deque_->buffer, 0, sizeof(V) * _deque_->capacity); \
|
||||
\
|
||||
_deque_->count = 0; \
|
||||
_deque_->front = 0; \
|
||||
_deque_->back = 0; \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_free(SNAME *_deque_) \
|
||||
{ \
|
||||
free(_deque_->buffer); \
|
||||
free(_deque_); \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_push_front(SNAME *_deque_, V element) \
|
||||
{ \
|
||||
if (PFX##_full(_deque_)) \
|
||||
{ \
|
||||
if (!PFX##_impl_grow(_deque_)) \
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
_deque_->front = (_deque_->front == 0) ? _deque_->capacity - 1 : _deque_->front - 1; \
|
||||
\
|
||||
_deque_->buffer[_deque_->front] = element; \
|
||||
\
|
||||
_deque_->count++; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_push_back(SNAME *_deque_, V element) \
|
||||
{ \
|
||||
if (PFX##_full(_deque_)) \
|
||||
{ \
|
||||
if (!PFX##_impl_grow(_deque_)) \
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
_deque_->buffer[_deque_->back] = element; \
|
||||
\
|
||||
_deque_->back = (_deque_->back == _deque_->capacity - 1) ? 0 : _deque_->back + 1; \
|
||||
\
|
||||
_deque_->count++; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_pop_front(SNAME *_deque_) \
|
||||
{ \
|
||||
if (PFX##_empty(_deque_)) \
|
||||
return false; \
|
||||
\
|
||||
_deque_->buffer[_deque_->front] = 0; \
|
||||
\
|
||||
_deque_->front = (_deque_->front == _deque_->capacity - 1) ? 0 : _deque_->front + 1; \
|
||||
\
|
||||
_deque_->count--; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_pop_back(SNAME *_deque_) \
|
||||
{ \
|
||||
if (PFX##_empty(_deque_)) \
|
||||
return false; \
|
||||
\
|
||||
_deque_->back = (_deque_->back == 0) ? _deque_->capacity - 1 : _deque_->back - 1; \
|
||||
\
|
||||
_deque_->buffer[_deque_->back] = 0; \
|
||||
\
|
||||
_deque_->count--; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_push_front_if(SNAME *_deque_, V element, bool condition) \
|
||||
{ \
|
||||
if (condition) \
|
||||
return PFX##_push_front(_deque_, element); \
|
||||
\
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_push_back_if(SNAME *_deque_, V element, bool condition) \
|
||||
{ \
|
||||
if (condition) \
|
||||
return PFX##_push_back(_deque_, element); \
|
||||
\
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_pop_front_if(SNAME *_deque_, bool condition) \
|
||||
{ \
|
||||
if (condition) \
|
||||
return PFX##_pop_front(_deque_); \
|
||||
\
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_pop_back_if(SNAME *_deque_, bool condition) \
|
||||
{ \
|
||||
if (condition) \
|
||||
return PFX##_pop_back(_deque_); \
|
||||
\
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
FMOD V PFX##_front(SNAME *_deque_) \
|
||||
{ \
|
||||
if (PFX##_empty(_deque_)) \
|
||||
return 0; \
|
||||
\
|
||||
return _deque_->buffer[_deque_->front]; \
|
||||
} \
|
||||
\
|
||||
FMOD V PFX##_back(SNAME *_deque_) \
|
||||
{ \
|
||||
if (PFX##_empty(_deque_)) \
|
||||
return 0; \
|
||||
\
|
||||
return _deque_->buffer[(_deque_->back == 0) ? _deque_->capacity - 1 : _deque_->back - 1]; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_contains(SNAME *_deque_, V element, int (*comparator)(V, V)) \
|
||||
{ \
|
||||
for (size_t i = _deque_->front, j = 0; j < _deque_->count; i = (i + 1) % _deque_->count, j++) \
|
||||
{ \
|
||||
if (comparator(_deque_->buffer[i], element) == 0) \
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_empty(SNAME *_deque_) \
|
||||
{ \
|
||||
return _deque_->count == 0; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_full(SNAME *_deque_) \
|
||||
{ \
|
||||
return _deque_->count >= _deque_->capacity; \
|
||||
} \
|
||||
\
|
||||
FMOD size_t PFX##_count(SNAME *_deque_) \
|
||||
{ \
|
||||
return _deque_->count; \
|
||||
} \
|
||||
\
|
||||
FMOD size_t PFX##_capacity(SNAME *_deque_) \
|
||||
{ \
|
||||
return _deque_->capacity; \
|
||||
} \
|
||||
\
|
||||
FMOD SNAME##_iter *PFX##_iter_new(SNAME *target) \
|
||||
{ \
|
||||
SNAME##_iter *iter = malloc(sizeof(SNAME##_iter)); \
|
||||
\
|
||||
if (!iter) \
|
||||
return NULL; \
|
||||
\
|
||||
PFX##_iter_init(iter, target); \
|
||||
\
|
||||
return iter; \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_iter_free(SNAME##_iter *iter) \
|
||||
{ \
|
||||
free(iter); \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_iter_init(SNAME##_iter *iter, SNAME *target) \
|
||||
{ \
|
||||
iter->target = target; \
|
||||
iter->cursor = target->front; \
|
||||
iter->index = 0; \
|
||||
iter->start = true; \
|
||||
iter->end = PFX##_empty(target); \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_iter_start(SNAME##_iter *iter) \
|
||||
{ \
|
||||
return PFX##_empty(iter->target) || iter->start; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_iter_end(SNAME##_iter *iter) \
|
||||
{ \
|
||||
return PFX##_empty(iter->target) || iter->end; \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_iter_to_start(SNAME##_iter *iter) \
|
||||
{ \
|
||||
iter->cursor = iter->target->front; \
|
||||
iter->index = 0; \
|
||||
iter->start = true; \
|
||||
iter->end = PFX##_empty(iter->target); \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_iter_to_end(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (PFX##_empty(iter->target)) \
|
||||
iter->cursor = 0; \
|
||||
else \
|
||||
iter->cursor = (iter->target->back == 0) ? iter->target->capacity - 1 : iter->target->back - 1; \
|
||||
\
|
||||
iter->index = iter->target->count - 1; \
|
||||
iter->start = PFX##_empty(iter->target); \
|
||||
iter->end = true; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_iter_next(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (iter->end) \
|
||||
return false; \
|
||||
\
|
||||
iter->start = PFX##_empty(iter->target); \
|
||||
\
|
||||
if (iter->index == iter->target->count - 1) \
|
||||
iter->end = true; \
|
||||
else \
|
||||
{ \
|
||||
iter->cursor = (iter->cursor + 1) % (iter->target->capacity); \
|
||||
iter->index++; \
|
||||
} \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_iter_prev(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (iter->start) \
|
||||
return false; \
|
||||
\
|
||||
iter->end = PFX##_empty(iter->target); \
|
||||
\
|
||||
if (iter->index == 0) \
|
||||
iter->start = true; \
|
||||
else \
|
||||
{ \
|
||||
iter->cursor = (iter->cursor == 0) ? iter->target->capacity - 1 : iter->cursor - 1; \
|
||||
iter->index--; \
|
||||
} \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD V PFX##_iter_value(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (PFX##_empty(iter->target)) \
|
||||
return 0; \
|
||||
\
|
||||
return iter->target->buffer[iter->cursor]; \
|
||||
} \
|
||||
\
|
||||
FMOD V *PFX##_iter_rvalue(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (PFX##_empty(iter->target)) \
|
||||
return NULL; \
|
||||
\
|
||||
return &(iter->target->buffer[iter->cursor]); \
|
||||
} \
|
||||
\
|
||||
FMOD size_t PFX##_iter_index(SNAME##_iter *iter) \
|
||||
{ \
|
||||
return iter->index; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_impl_grow(SNAME *_deque_) \
|
||||
{ \
|
||||
\
|
||||
size_t new_capacity = _deque_->capacity * 2; \
|
||||
\
|
||||
V *new_buffer = malloc(sizeof(V) * new_capacity); \
|
||||
\
|
||||
if (!new_buffer) \
|
||||
return false; \
|
||||
\
|
||||
for (size_t i = _deque_->front, j = 0; j < _deque_->count; i = (i + 1) % _deque_->capacity, j++) \
|
||||
{ \
|
||||
new_buffer[j] = _deque_->buffer[i]; \
|
||||
} \
|
||||
\
|
||||
free(_deque_->buffer); \
|
||||
\
|
||||
_deque_->buffer = new_buffer; \
|
||||
_deque_->capacity = new_capacity; \
|
||||
_deque_->front = 0; \
|
||||
_deque_->back = _deque_->count; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
SNAME##_iter PFX##_impl_it_start(SNAME *_deque_) \
|
||||
{ \
|
||||
SNAME##_iter iter; \
|
||||
\
|
||||
PFX##_iter_init(&iter, _deque_); \
|
||||
\
|
||||
return iter; \
|
||||
} \
|
||||
\
|
||||
SNAME##_iter PFX##_impl_it_end(SNAME *_deque_) \
|
||||
{ \
|
||||
SNAME##_iter iter; \
|
||||
\
|
||||
PFX##_iter_init(&iter, _deque_); \
|
||||
PFX##_iter_to_end(&iter); \
|
||||
\
|
||||
return iter; \
|
||||
}
|
||||
|
||||
#endif /* CMC_DEQUE_H */
|
||||
+15
-56
@@ -11,63 +11,22 @@
|
||||
#ifndef CMC_FOR_EACH
|
||||
#define CMC_FOR_EACH
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define FOR_EACH(PFX, SNAME, V, TARGET, BODY) \
|
||||
do \
|
||||
{ \
|
||||
size_t index; \
|
||||
V value; \
|
||||
SNAME##_iter iter; \
|
||||
PFX##_iter_new(&iter, TARGET); \
|
||||
while (PFX##_iter_next(&iter, &value, &index)) \
|
||||
{ \
|
||||
BODY; \
|
||||
} \
|
||||
#define FOR_EACH(PFX, SNAME, TARGET, BODY) \
|
||||
do \
|
||||
{ \
|
||||
for (SNAME##_iter iter = TARGET->it_start(TARGET); !PFX##_iter_end(&iter); PFX##_iter_next(&iter)) \
|
||||
{ \
|
||||
BODY; \
|
||||
} \
|
||||
} while (0);
|
||||
|
||||
#define FOR_EACH_REV(PFX, SNAME, V, TARGET, BODY) \
|
||||
do \
|
||||
{ \
|
||||
size_t index; \
|
||||
V value; \
|
||||
SNAME##_iter iter; \
|
||||
PFX##_iter_new(&iter, TARGET); \
|
||||
PFX##_iter_toend(&iter); \
|
||||
while (PFX##_iter_prev(&iter, &value, &index)) \
|
||||
{ \
|
||||
BODY; \
|
||||
} \
|
||||
#define FOR_EACH_REV(PFX, SNAME, TARGET, BODY) \
|
||||
do \
|
||||
{ \
|
||||
for (SNAME##_iter iter = TARGET->it_end(TARGET); !PFX##_iter_start(&iter); PFX##_iter_prev(&iter)) \
|
||||
{ \
|
||||
BODY; \
|
||||
} \
|
||||
} while (0);
|
||||
|
||||
#define FOR_EACH_MAP(PFX, SNAME, K, V, TARGET, BODY) \
|
||||
do \
|
||||
{ \
|
||||
size_t index; \
|
||||
K key; \
|
||||
V value; \
|
||||
SNAME##_iter iter; \
|
||||
PFX##_iter_new(&iter, TARGET); \
|
||||
while (PFX##_iter_next(&iter, &key, &value, &index)) \
|
||||
{ \
|
||||
BODY; \
|
||||
} \
|
||||
} while (0);
|
||||
|
||||
#define FOR_EACH_MAP_REV(PFX, SNAME, K, V, TARGET, BODY) \
|
||||
do \
|
||||
{ \
|
||||
size_t index; \
|
||||
K key; \
|
||||
V value; \
|
||||
SNAME##_iter iter; \
|
||||
PFX##_iter_new(&iter, TARGET); \
|
||||
PFX##_iter_toend(&iter); \
|
||||
while (PFX##_iter_prev(&iter, &key, &value, &index)) \
|
||||
{ \
|
||||
BODY; \
|
||||
} \
|
||||
} while (0);
|
||||
|
||||
#endif /* CMC_FOR_EACH */
|
||||
#endif /* CMC_FOR_EACH */
|
||||
+329
-162
@@ -29,13 +29,37 @@ typedef enum EntryState_e
|
||||
ES_FILLED = 1
|
||||
} EntryState;
|
||||
|
||||
static const size_t cmc_hashtable_primes[] = {53, 97, 193, 389, 769, 1543, 3079,
|
||||
6151, 12289, 24593, 49157, 98317,
|
||||
196613, 393241, 786433, 1572869,
|
||||
3145739, 6291469, 12582917,
|
||||
25165843, 50331653, 100663319,
|
||||
201326611, 402653189, 805306457,
|
||||
1610612741};
|
||||
static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531,
|
||||
3067, 6143, 12289, 24571, 49157,
|
||||
98299, 196613, 393209, 786431,
|
||||
1572869, 3145721, 6291449,
|
||||
12582917, 25165813, 50331653,
|
||||
100663291, 201326611, 402653189,
|
||||
805306357, 1610612741,
|
||||
3221225473, 6442450939,
|
||||
12884901893, 25769803799,
|
||||
51539607551, 103079215111,
|
||||
206158430209, 412316860441,
|
||||
824633720831, 1649267441651,
|
||||
3298534883309, 6597069766657,
|
||||
13194139533299, 26388279066623,
|
||||
52776558133303, 105553116266489,
|
||||
211106232532969, 422212465066001,
|
||||
844424930131963,
|
||||
1688849860263953,
|
||||
3377699720527861,
|
||||
6755399441055731,
|
||||
13510798882111483,
|
||||
27021597764222939,
|
||||
54043195528445957,
|
||||
108086391056891903,
|
||||
216172782113783773,
|
||||
432345564227567621,
|
||||
864691128455135207,
|
||||
1729382256910270481,
|
||||
3458764513820540933,
|
||||
6917529027641081903,
|
||||
13835058055282163729llu};
|
||||
|
||||
#endif /* CMC_HASH_TABLE_SETUP */
|
||||
|
||||
@@ -57,78 +81,141 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 193, 389, 769, 1543, 3079,
|
||||
#define HASHMAP_GENERATE_SOURCE_PUBLIC(PFX, SNAME, FMOD, K, V) \
|
||||
HASHMAP_GENERATE_SOURCE(PFX, SNAME, FMOD, K, V)
|
||||
/* STRUCT ********************************************************************/
|
||||
#define HASHMAP_GENERATE_STRUCT(PFX, SNAME, FMOD, K, V) \
|
||||
\
|
||||
struct SNAME##_s \
|
||||
{ \
|
||||
struct SNAME##_entry_s *buffer; \
|
||||
size_t capacity; \
|
||||
size_t count; \
|
||||
double load; \
|
||||
int (*cmp)(K, K); \
|
||||
size_t (*hash)(K); \
|
||||
}; \
|
||||
\
|
||||
struct SNAME##_entry_s \
|
||||
{ \
|
||||
K key; \
|
||||
V value; \
|
||||
size_t dist; \
|
||||
enum EntryState_e state; \
|
||||
}; \
|
||||
\
|
||||
struct SNAME##_iter_s \
|
||||
{ \
|
||||
struct SNAME##_s *target; \
|
||||
size_t cursor; \
|
||||
size_t index; \
|
||||
size_t first; \
|
||||
size_t last; \
|
||||
bool start; \
|
||||
bool end; \
|
||||
}; \
|
||||
\
|
||||
#define HASHMAP_GENERATE_STRUCT(PFX, SNAME, FMOD, K, V)
|
||||
|
||||
/* HEADER ********************************************************************/
|
||||
#define HASHMAP_GENERATE_HEADER(PFX, SNAME, FMOD, K, V) \
|
||||
\
|
||||
typedef struct SNAME##_s SNAME; \
|
||||
typedef struct SNAME##_entry_s SNAME##_entry; \
|
||||
typedef struct SNAME##_iter_s SNAME##_iter; \
|
||||
/* Hashmap Structure */ \
|
||||
typedef struct SNAME##_s \
|
||||
{ \
|
||||
/* Array of Entries */ \
|
||||
struct SNAME##_entry_s *buffer; \
|
||||
\
|
||||
/* Current array capacity */ \
|
||||
size_t capacity; \
|
||||
\
|
||||
/* Current amount of keys */ \
|
||||
size_t count; \
|
||||
\
|
||||
/* Load factor in range (0.0, 1.0) */ \
|
||||
double load; \
|
||||
\
|
||||
/* Key comparison function */ \
|
||||
int (*cmp)(K, K); \
|
||||
\
|
||||
/* Key hash function */ \
|
||||
size_t (*hash)(K); \
|
||||
\
|
||||
/* Function that returns an iterator to the start of the hashmap */ \
|
||||
struct SNAME##_iter_s (*it_start)(struct SNAME##_s *); \
|
||||
\
|
||||
/* Function that returns an iterator to the end of the hashmap */ \
|
||||
struct SNAME##_iter_s (*it_end)(struct SNAME##_s *); \
|
||||
\
|
||||
} SNAME, *SNAME##_ptr; \
|
||||
\
|
||||
/* Hashmap Entry */ \
|
||||
typedef struct SNAME##_entry_s \
|
||||
{ \
|
||||
/* Entry Key */ \
|
||||
K key; \
|
||||
\
|
||||
/* Entry Value */ \
|
||||
V value; \
|
||||
\
|
||||
/* The distance of this node to its original position, used by robin-hood hashing */ \
|
||||
size_t dist; \
|
||||
\
|
||||
/* The sate of this node (DELETED, EMPTY, FILLED) */ \
|
||||
enum EntryState_e state; \
|
||||
\
|
||||
} SNAME##_entry, *SNAME##_entry_ptr; \
|
||||
\
|
||||
/* Hashmap Iterator */ \
|
||||
typedef struct SNAME##_iter_s \
|
||||
{ \
|
||||
/* Target hashmap */ \
|
||||
struct SNAME##_s *target; \
|
||||
\
|
||||
/* Cursor's position (index) */ \
|
||||
size_t cursor; \
|
||||
\
|
||||
/* Keeps track of relative index to the iteration of elements */ \
|
||||
size_t index; \
|
||||
\
|
||||
/* The index of the first element */ \
|
||||
size_t first; \
|
||||
\
|
||||
/* The index of the last element */ \
|
||||
size_t last; \
|
||||
\
|
||||
/* If the iterator has reached the start of the iteration */ \
|
||||
bool start; \
|
||||
\
|
||||
/* If the iterator has reached the end of the iteration */ \
|
||||
bool end; \
|
||||
\
|
||||
} SNAME##_iter, *SNAME##_iter_ptr; \
|
||||
\
|
||||
/* Collection Functions */ \
|
||||
/* Collection Allocation and Deallocation */ \
|
||||
FMOD SNAME *PFX##_new(size_t size, double load, int (*compare)(K, K), size_t (*hash)(K)); \
|
||||
FMOD void PFX##_clear(SNAME *_map_); \
|
||||
FMOD void PFX##_free(SNAME *_map_); \
|
||||
/* Collection Input and Output */ \
|
||||
FMOD bool PFX##_insert(SNAME *_map_, K key, V value); \
|
||||
FMOD bool PFX##_remove(SNAME *_map_, K key, V *value); \
|
||||
/* Conditional Input and Output */ \
|
||||
FMOD bool PFX##_insert_if(SNAME *_map_, K key, V value, bool condition); \
|
||||
FMOD bool PFX##_remove_if(SNAME *_map_, K key, V *value, bool condition); \
|
||||
/* Element Access */ \
|
||||
FMOD bool PFX##_max(SNAME *_map_, K *key, V *value); \
|
||||
FMOD bool PFX##_min(SNAME *_map_, K *key, V *value); \
|
||||
FMOD V PFX##_get(SNAME *_map_, K key); \
|
||||
FMOD V *PFX##_get_ref(SNAME *_map_, K key); \
|
||||
/* Collection State */ \
|
||||
FMOD bool PFX##_contains(SNAME *_map_, K key); \
|
||||
FMOD bool PFX##_empty(SNAME *_map_); \
|
||||
FMOD size_t PFX##_count(SNAME *_map_); \
|
||||
FMOD size_t PFX##_capacity(SNAME *_map_); \
|
||||
\
|
||||
FMOD void PFX##_iter_new(SNAME##_iter *iter, SNAME *target); \
|
||||
/* Iterator Functions */ \
|
||||
/* Iterator Allocation and Deallocation */ \
|
||||
FMOD SNAME##_iter *PFX##_iter_new(SNAME *target); \
|
||||
FMOD void PFX##_iter_free(SNAME##_iter *iter); \
|
||||
/* Iterator Initialization */ \
|
||||
FMOD void PFX##_iter_init(SNAME##_iter *iter, SNAME *target); \
|
||||
/* Iterator State */ \
|
||||
FMOD bool PFX##_iter_start(SNAME##_iter *iter); \
|
||||
FMOD bool PFX##_iter_end(SNAME##_iter *iter); \
|
||||
/* Iterator Movement */ \
|
||||
FMOD void PFX##_iter_tostart(SNAME##_iter *iter); \
|
||||
FMOD void PFX##_iter_toend(SNAME##_iter *iter); \
|
||||
FMOD bool PFX##_iter_next(SNAME##_iter *iter, K *key, V *value, size_t *index); \
|
||||
FMOD bool PFX##_iter_prev(SNAME##_iter *iter, K *key, V *value, size_t *index); \
|
||||
FMOD bool PFX##_iter_next(SNAME##_iter *iter); \
|
||||
FMOD bool PFX##_iter_prev(SNAME##_iter *iter); \
|
||||
/* Iterator Access */ \
|
||||
FMOD K PFX##_iter_key(SNAME##_iter *iter); \
|
||||
FMOD V PFX##_iter_value(SNAME##_iter *iter); \
|
||||
FMOD V *PFX##_iter_rvalue(SNAME##_iter *iter); \
|
||||
FMOD size_t PFX##_iter_index(SNAME##_iter *iter); \
|
||||
\
|
||||
/* SOURCE ********************************************************************/
|
||||
#define HASHMAP_GENERATE_SOURCE(PFX, SNAME, FMOD, K, V) \
|
||||
\
|
||||
FMOD bool PFX##_grow(SNAME *_map_); \
|
||||
FMOD SNAME##_entry *PFX##_get_entry(SNAME *_map_, K key); \
|
||||
FMOD size_t PFX##_calculate_size(size_t required); \
|
||||
/* Implementation Detail Functions */ \
|
||||
FMOD bool PFX##_impl_grow(SNAME *_map_); \
|
||||
FMOD SNAME##_entry *PFX##_impl_get_entry(SNAME *_map_, K key); \
|
||||
FMOD size_t PFX##_impl_calculate_size(size_t required); \
|
||||
SNAME##_iter PFX##_impl_it_start(SNAME *_map_); \
|
||||
SNAME##_iter PFX##_impl_it_end(SNAME *_map_); \
|
||||
\
|
||||
FMOD SNAME *PFX##_new(size_t size, double load, int (*compare)(K, K), size_t (*hash)(K)) \
|
||||
{ \
|
||||
if (size == 0 || load <= 0 || load >= 1) \
|
||||
return NULL; \
|
||||
\
|
||||
size_t real_size = PFX##_calculate_size(size); \
|
||||
size_t real_size = PFX##_impl_calculate_size(size); \
|
||||
\
|
||||
SNAME *_map_ = malloc(sizeof(SNAME)); \
|
||||
\
|
||||
@@ -151,6 +238,9 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 193, 389, 769, 1543, 3079,
|
||||
_map_->cmp = compare; \
|
||||
_map_->hash = hash; \
|
||||
\
|
||||
_map_->it_start = PFX##_impl_it_start; \
|
||||
_map_->it_end = PFX##_impl_it_end; \
|
||||
\
|
||||
return _map_; \
|
||||
} \
|
||||
\
|
||||
@@ -171,7 +261,7 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 193, 389, 769, 1543, 3079,
|
||||
{ \
|
||||
if ((double)_map_->capacity * _map_->load <= (double)_map_->count) \
|
||||
{ \
|
||||
if (!PFX##_grow(_map_)) \
|
||||
if (!PFX##_impl_grow(_map_)) \
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
@@ -181,7 +271,7 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 193, 389, 769, 1543, 3079,
|
||||
\
|
||||
SNAME##_entry *target = &(_map_->buffer[pos]); \
|
||||
\
|
||||
if (PFX##_get_entry(_map_, key) != NULL) \
|
||||
if (PFX##_impl_get_entry(_map_, key) != NULL) \
|
||||
return false; \
|
||||
\
|
||||
if (target->state == ES_EMPTY || target->state == ES_DELETED) \
|
||||
@@ -204,6 +294,7 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 193, 389, 769, 1543, 3079,
|
||||
target->value = value; \
|
||||
target->dist = pos - original_pos; \
|
||||
target->state = ES_FILLED; \
|
||||
\
|
||||
break; \
|
||||
} \
|
||||
else if (target->dist < original_pos - pos) \
|
||||
@@ -230,7 +321,7 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 193, 389, 769, 1543, 3079,
|
||||
\
|
||||
FMOD bool PFX##_remove(SNAME *_map_, K key, V *value) \
|
||||
{ \
|
||||
SNAME##_entry *result = PFX##_get_entry(_map_, key); \
|
||||
SNAME##_entry *result = PFX##_impl_get_entry(_map_, key); \
|
||||
\
|
||||
if (result == NULL) \
|
||||
return false; \
|
||||
@@ -268,23 +359,20 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 193, 389, 769, 1543, 3079,
|
||||
return false; \
|
||||
\
|
||||
SNAME##_iter iter; \
|
||||
K result_key, max_key; \
|
||||
V result_value; \
|
||||
size_t index; \
|
||||
\
|
||||
for (PFX##_iter_new(&iter, _map_); !PFX##_iter_end(&iter);) \
|
||||
for (PFX##_iter_init(&iter, _map_); !PFX##_iter_end(&iter); PFX##_iter_next(&iter)) \
|
||||
{ \
|
||||
PFX##_iter_next(&iter, &result_key, &result_value, &index); \
|
||||
K result_key = PFX##_iter_key(&iter); \
|
||||
V result_value = PFX##_iter_value(&iter); \
|
||||
size_t index = PFX##_iter_index(&iter); \
|
||||
\
|
||||
if (index == 0) \
|
||||
{ \
|
||||
max_key = result_key; \
|
||||
*key = result_key; \
|
||||
*value = result_value; \
|
||||
} \
|
||||
else if (_map_->cmp(result_key, max_key) > 0) \
|
||||
else if (_map_->cmp(result_key, *key) > 0) \
|
||||
{ \
|
||||
max_key = result_key; \
|
||||
*key = result_key; \
|
||||
*value = result_value; \
|
||||
} \
|
||||
@@ -299,24 +387,21 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 193, 389, 769, 1543, 3079,
|
||||
return false; \
|
||||
\
|
||||
SNAME##_iter iter; \
|
||||
K result_key, min_key; \
|
||||
V result_value; \
|
||||
size_t index; \
|
||||
\
|
||||
for (PFX##_iter_new(&iter, _map_); !PFX##_iter_end(&iter);) \
|
||||
for (PFX##_iter_init(&iter, _map_); !PFX##_iter_end(&iter); PFX##_iter_next(&iter)) \
|
||||
{ \
|
||||
PFX##_iter_next(&iter, &result_key, &result_value, &index); \
|
||||
K result_key = PFX##_iter_key(&iter); \
|
||||
V result_value = PFX##_iter_value(&iter); \
|
||||
size_t index = PFX##_iter_index(&iter); \
|
||||
\
|
||||
if (index == 0) \
|
||||
{ \
|
||||
min_key = result_key; \
|
||||
*key = result_key; \
|
||||
*value = result_value; \
|
||||
} \
|
||||
else if (_map_->cmp(result_key, min_key) < 0) \
|
||||
else if (_map_->cmp(result_key, *key) < 0) \
|
||||
{ \
|
||||
min_key = result_key; \
|
||||
*key = min_key; \
|
||||
*key = result_key; \
|
||||
*value = result_value; \
|
||||
} \
|
||||
} \
|
||||
@@ -326,7 +411,7 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 193, 389, 769, 1543, 3079,
|
||||
\
|
||||
FMOD V PFX##_get(SNAME *_map_, K key) \
|
||||
{ \
|
||||
SNAME##_entry *entry = PFX##_get_entry(_map_, key); \
|
||||
SNAME##_entry *entry = PFX##_impl_get_entry(_map_, key); \
|
||||
\
|
||||
if (!entry) \
|
||||
return 0; \
|
||||
@@ -334,6 +419,21 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 193, 389, 769, 1543, 3079,
|
||||
return entry->value; \
|
||||
} \
|
||||
\
|
||||
FMOD V *PFX##_get_ref(SNAME *_map_, K key) \
|
||||
{ \
|
||||
SNAME##_entry *entry = PFX##_impl_get_entry(_map_, key); \
|
||||
\
|
||||
if (!entry) \
|
||||
return NULL; \
|
||||
\
|
||||
return &(entry->value); \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_contains(SNAME *_map_, K key) \
|
||||
{ \
|
||||
return PFX##_impl_get_entry(_map_, key) != NULL; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_empty(SNAME *_map_) \
|
||||
{ \
|
||||
return _map_->count == 0; \
|
||||
@@ -344,77 +444,29 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 193, 389, 769, 1543, 3079,
|
||||
return _map_->count; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_grow(SNAME *_map_) \
|
||||
FMOD size_t PFX##_capacity(SNAME *_map_) \
|
||||
{ \
|
||||
size_t new_size = PFX##_calculate_size((size_t)((double)_map_->capacity * 1.5)); \
|
||||
\
|
||||
SNAME *_new_map_ = PFX##_new(new_size, _map_->load, _map_->cmp, _map_->hash); \
|
||||
\
|
||||
if (!_new_map_) \
|
||||
return false; \
|
||||
\
|
||||
SNAME##_iter iter; \
|
||||
K key; \
|
||||
V value; \
|
||||
size_t index; \
|
||||
\
|
||||
for (PFX##_iter_new(&iter, _map_); !PFX##_iter_end(&iter);) \
|
||||
{ \
|
||||
PFX##_iter_next(&iter, &key, &value, &index); \
|
||||
PFX##_insert(_new_map_, key, value); \
|
||||
} \
|
||||
\
|
||||
if (_map_->count != _new_map_->count) \
|
||||
{ \
|
||||
PFX##_free(_new_map_); \
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
SNAME##_entry *tmp = _map_->buffer; \
|
||||
_map_->buffer = _new_map_->buffer; \
|
||||
_new_map_->buffer = tmp; \
|
||||
\
|
||||
_map_->capacity = _new_map_->capacity; \
|
||||
\
|
||||
PFX##_free(_new_map_); \
|
||||
\
|
||||
return true; \
|
||||
return _map_->capacity; \
|
||||
} \
|
||||
\
|
||||
FMOD SNAME##_entry *PFX##_get_entry(SNAME *_map_, K key) \
|
||||
FMOD SNAME##_iter *PFX##_iter_new(SNAME *target) \
|
||||
{ \
|
||||
size_t hash = _map_->hash(key); \
|
||||
size_t pos = hash % _map_->capacity; \
|
||||
SNAME##_iter *iter = malloc(sizeof(SNAME##_iter)); \
|
||||
\
|
||||
SNAME##_entry *target = &(_map_->buffer[pos % _map_->capacity]); \
|
||||
if (!iter) \
|
||||
return NULL; \
|
||||
\
|
||||
while (target->state == ES_FILLED || target->state == ES_DELETED) \
|
||||
{ \
|
||||
if (_map_->cmp(target->key, key) == 0) \
|
||||
return target; \
|
||||
PFX##_iter_init(iter, target); \
|
||||
\
|
||||
pos++; \
|
||||
target = &(_map_->buffer[pos % _map_->capacity]); \
|
||||
} \
|
||||
\
|
||||
return NULL; \
|
||||
return iter; \
|
||||
} \
|
||||
\
|
||||
FMOD size_t PFX##_calculate_size(size_t required) \
|
||||
FMOD void PFX##_iter_free(SNAME##_iter *iter) \
|
||||
{ \
|
||||
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]; \
|
||||
free(iter); \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_iter_new(SNAME##_iter *iter, SNAME *target) \
|
||||
FMOD void PFX##_iter_init(SNAME##_iter *iter, SNAME *target) \
|
||||
{ \
|
||||
iter->target = target; \
|
||||
iter->cursor = 0; \
|
||||
@@ -448,15 +500,15 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 193, 389, 769, 1543, 3079,
|
||||
\
|
||||
FMOD bool PFX##_iter_start(SNAME##_iter *iter) \
|
||||
{ \
|
||||
return iter->start && iter->cursor == iter->first; \
|
||||
return PFX##_empty(iter->target) || iter->start; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_iter_end(SNAME##_iter *iter) \
|
||||
{ \
|
||||
return iter->end && iter->cursor == iter->last; \
|
||||
return PFX##_empty(iter->target) || iter->end; \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_iter_tostart(SNAME##_iter *iter) \
|
||||
FMOD void PFX##_iter_to_start(SNAME##_iter *iter) \
|
||||
{ \
|
||||
iter->cursor = iter->first; \
|
||||
iter->index = 0; \
|
||||
@@ -464,7 +516,7 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 193, 389, 769, 1543, 3079,
|
||||
iter->end = PFX##_empty(iter->target); \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_iter_toend(SNAME##_iter *iter) \
|
||||
FMOD void PFX##_iter_to_end(SNAME##_iter *iter) \
|
||||
{ \
|
||||
iter->cursor = iter->last; \
|
||||
iter->index = iter->target->count - 1; \
|
||||
@@ -472,30 +524,29 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 193, 389, 769, 1543, 3079,
|
||||
iter->end = true; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_iter_next(SNAME##_iter *iter, K *key, V *value, size_t *index) \
|
||||
FMOD bool PFX##_iter_next(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (iter->end) \
|
||||
return false; \
|
||||
\
|
||||
SNAME##_entry *scan = &(iter->target->buffer[iter->cursor]); \
|
||||
\
|
||||
*key = scan->key; \
|
||||
*value = scan->value; \
|
||||
*index = iter->index; \
|
||||
\
|
||||
if (iter->cursor == iter->last) \
|
||||
iter->end = true; \
|
||||
else \
|
||||
{ \
|
||||
iter->index++; \
|
||||
while (1) \
|
||||
{ \
|
||||
iter->cursor++; \
|
||||
scan = &(iter->target->buffer[iter->cursor]); \
|
||||
iter->end = true; \
|
||||
\
|
||||
if (scan->state == ES_FILLED) \
|
||||
break; \
|
||||
} \
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
iter->index++; \
|
||||
\
|
||||
while (1) \
|
||||
{ \
|
||||
iter->cursor++; \
|
||||
scan = &(iter->target->buffer[iter->cursor]); \
|
||||
\
|
||||
if (scan->state == ES_FILLED) \
|
||||
break; \
|
||||
} \
|
||||
\
|
||||
iter->start = PFX##_empty(iter->target); \
|
||||
@@ -503,35 +554,151 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 193, 389, 769, 1543, 3079,
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_iter_prev(SNAME##_iter *iter, K *key, V *value, size_t *index) \
|
||||
FMOD bool PFX##_iter_prev(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (iter->start) \
|
||||
return false; \
|
||||
\
|
||||
SNAME##_entry *scan = &(iter->target->buffer[iter->cursor]); \
|
||||
\
|
||||
*key = scan->key; \
|
||||
*value = scan->value; \
|
||||
*index = iter->index; \
|
||||
\
|
||||
if (iter->cursor == iter->first) \
|
||||
iter->start = true; \
|
||||
else \
|
||||
{ \
|
||||
iter->index--; \
|
||||
while (1) \
|
||||
{ \
|
||||
iter->cursor--; \
|
||||
scan = &(iter->target->buffer[iter->cursor]); \
|
||||
iter->start = true; \
|
||||
\
|
||||
if (scan->state == ES_FILLED) \
|
||||
break; \
|
||||
} \
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
iter->index--; \
|
||||
\
|
||||
while (1) \
|
||||
{ \
|
||||
iter->cursor--; \
|
||||
scan = &(iter->target->buffer[iter->cursor]); \
|
||||
\
|
||||
if (scan->state == ES_FILLED) \
|
||||
break; \
|
||||
} \
|
||||
\
|
||||
iter->end = PFX##_empty(iter->target); \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD K PFX##_iter_key(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (PFX##_empty(iter->target)) \
|
||||
return 0; \
|
||||
\
|
||||
return iter->target->buffer[iter->cursor].key; \
|
||||
} \
|
||||
\
|
||||
FMOD V PFX##_iter_value(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (PFX##_empty(iter->target)) \
|
||||
return 0; \
|
||||
\
|
||||
return iter->target->buffer[iter->cursor].value; \
|
||||
} \
|
||||
\
|
||||
FMOD V *PFX##_iter_rvalue(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (PFX##_empty(iter->target)) \
|
||||
return NULL; \
|
||||
\
|
||||
return &(iter->target->buffer[iter->cursor].value); \
|
||||
} \
|
||||
\
|
||||
FMOD size_t PFX##_iter_index(SNAME##_iter *iter) \
|
||||
{ \
|
||||
return iter->index; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_impl_grow(SNAME *_map_) \
|
||||
{ \
|
||||
size_t new_size = PFX##_impl_calculate_size(_map_->capacity + _map_->capacity / 2); \
|
||||
\
|
||||
SNAME *_new_map_ = PFX##_new(new_size, _map_->load, _map_->cmp, _map_->hash); \
|
||||
\
|
||||
if (!_new_map_) \
|
||||
return false; \
|
||||
\
|
||||
SNAME##_iter iter; \
|
||||
\
|
||||
for (PFX##_iter_init(&iter, _map_); !PFX##_iter_end(&iter); PFX##_iter_next(&iter)) \
|
||||
{ \
|
||||
K key = PFX##_iter_key(&iter); \
|
||||
V value = PFX##_iter_value(&iter); \
|
||||
\
|
||||
PFX##_insert(_new_map_, key, value); \
|
||||
} \
|
||||
\
|
||||
if (_map_->count != _new_map_->count) \
|
||||
{ \
|
||||
PFX##_free(_new_map_); \
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
SNAME##_entry *tmp = _map_->buffer; \
|
||||
_map_->buffer = _new_map_->buffer; \
|
||||
_new_map_->buffer = tmp; \
|
||||
\
|
||||
_map_->capacity = _new_map_->capacity; \
|
||||
\
|
||||
PFX##_free(_new_map_); \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD SNAME##_entry *PFX##_impl_get_entry(SNAME *_map_, K key) \
|
||||
{ \
|
||||
size_t hash = _map_->hash(key); \
|
||||
size_t pos = hash % _map_->capacity; \
|
||||
\
|
||||
SNAME##_entry *target = &(_map_->buffer[pos]); \
|
||||
\
|
||||
while (target->state == ES_FILLED || target->state == ES_DELETED) \
|
||||
{ \
|
||||
if (_map_->cmp(target->key, key) == 0) \
|
||||
return target; \
|
||||
\
|
||||
pos++; \
|
||||
target = &(_map_->buffer[pos % _map_->capacity]); \
|
||||
} \
|
||||
\
|
||||
return NULL; \
|
||||
} \
|
||||
\
|
||||
FMOD size_t PFX##_impl_calculate_size(size_t required) \
|
||||
{ \
|
||||
const size_t count = sizeof(cmc_hashtable_primes) / sizeof(cmc_hashtable_primes[0]); \
|
||||
\
|
||||
if (cmc_hashtable_primes[count - 1] < required) \
|
||||
return required; \
|
||||
\
|
||||
size_t i = 0; \
|
||||
while (cmc_hashtable_primes[i] < required) \
|
||||
i++; \
|
||||
\
|
||||
return cmc_hashtable_primes[i]; \
|
||||
} \
|
||||
\
|
||||
SNAME##_iter PFX##_impl_it_start(SNAME *_map_) \
|
||||
{ \
|
||||
SNAME##_iter iter; \
|
||||
\
|
||||
PFX##_iter_init(&iter, _map_); \
|
||||
\
|
||||
return iter; \
|
||||
} \
|
||||
\
|
||||
SNAME##_iter PFX##_impl_it_end(SNAME *_map_) \
|
||||
{ \
|
||||
SNAME##_iter iter; \
|
||||
\
|
||||
PFX##_iter_init(&iter, _map_); \
|
||||
PFX##_iter_to_end(&iter); \
|
||||
\
|
||||
return iter; \
|
||||
}
|
||||
|
||||
#endif /* CMC_HASHMAP_H */
|
||||
+310
-182
@@ -29,13 +29,37 @@ typedef enum EntryState_e
|
||||
ES_FILLED = 1
|
||||
} EntryState;
|
||||
|
||||
static const size_t cmc_hashtable_primes[] = {53, 97, 193, 389, 769, 1543, 3079,
|
||||
6151, 12289, 24593, 49157, 98317,
|
||||
196613, 393241, 786433, 1572869,
|
||||
3145739, 6291469, 12582917,
|
||||
25165843, 50331653, 100663319,
|
||||
201326611, 402653189, 805306457,
|
||||
1610612741};
|
||||
static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531,
|
||||
3067, 6143, 12289, 24571, 49157,
|
||||
98299, 196613, 393209, 786431,
|
||||
1572869, 3145721, 6291449,
|
||||
12582917, 25165813, 50331653,
|
||||
100663291, 201326611, 402653189,
|
||||
805306357, 1610612741,
|
||||
3221225473, 6442450939,
|
||||
12884901893, 25769803799,
|
||||
51539607551, 103079215111,
|
||||
206158430209, 412316860441,
|
||||
824633720831, 1649267441651,
|
||||
3298534883309, 6597069766657,
|
||||
13194139533299, 26388279066623,
|
||||
52776558133303, 105553116266489,
|
||||
211106232532969, 422212465066001,
|
||||
844424930131963,
|
||||
1688849860263953,
|
||||
3377699720527861,
|
||||
6755399441055731,
|
||||
13510798882111483,
|
||||
27021597764222939,
|
||||
54043195528445957,
|
||||
108086391056891903,
|
||||
216172782113783773,
|
||||
432345564227567621,
|
||||
864691128455135207,
|
||||
1729382256910270481,
|
||||
3458764513820540933,
|
||||
6917529027641081903,
|
||||
13835058055282163729llu};
|
||||
|
||||
#endif /* CMC_HASH_TABLE_SETUP */
|
||||
|
||||
@@ -57,74 +81,132 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 193, 389, 769, 1543, 3079,
|
||||
#define HASHSET_GENERATE_SOURCE_PUBLIC(PFX, SNAME, FMOD, K, V) \
|
||||
HASHSET_GENERATE_SOURCE(PFX, SNAME, FMOD, V)
|
||||
/* STRUCT ********************************************************************/
|
||||
#define HASHSET_GENERATE_STRUCT(PFX, SNAME, FMOD, V) \
|
||||
\
|
||||
struct SNAME##_s \
|
||||
{ \
|
||||
struct SNAME##_entry_s *buffer; \
|
||||
size_t capacity; \
|
||||
size_t count; \
|
||||
double load; \
|
||||
int (*cmp)(V, V); \
|
||||
size_t (*hash)(V); \
|
||||
}; \
|
||||
\
|
||||
struct SNAME##_entry_s \
|
||||
{ \
|
||||
V value; \
|
||||
size_t dist; \
|
||||
enum EntryState_e state; \
|
||||
}; \
|
||||
\
|
||||
struct SNAME##_iter_s \
|
||||
{ \
|
||||
struct SNAME##_s *target; \
|
||||
size_t cursor; \
|
||||
size_t index; \
|
||||
size_t first; \
|
||||
size_t last; \
|
||||
bool start; \
|
||||
bool end; \
|
||||
}; \
|
||||
\
|
||||
#define HASHSET_GENERATE_STRUCT(PFX, SNAME, FMOD, V)
|
||||
|
||||
/* HEADER ********************************************************************/
|
||||
#define HASHSET_GENERATE_HEADER(PFX, SNAME, FMOD, V) \
|
||||
\
|
||||
typedef struct SNAME##_s SNAME; \
|
||||
typedef struct SNAME##_entry_s SNAME##_entry; \
|
||||
typedef struct SNAME##_iter_s SNAME##_iter; \
|
||||
/* Hashset Structure */ \
|
||||
typedef struct SNAME##_s \
|
||||
{ \
|
||||
/* Array of Entries */ \
|
||||
struct SNAME##_entry_s *buffer; \
|
||||
\
|
||||
/* Current Array Capcity */ \
|
||||
size_t capacity; \
|
||||
\
|
||||
/* Current amount of elements */ \
|
||||
size_t count; \
|
||||
\
|
||||
/* Load factor in range (0.0, 1.0) */ \
|
||||
double load; \
|
||||
\
|
||||
/* Element comparison function */ \
|
||||
int (*cmp)(V, V); \
|
||||
\
|
||||
/* Element hash function */ \
|
||||
size_t (*hash)(V); \
|
||||
\
|
||||
/* Function that returns an iterator to the start of the hashset */ \
|
||||
struct SNAME##_iter_s (*it_start)(struct SNAME##_s *); \
|
||||
\
|
||||
/* Function that returns an iterator to the end of the hashset */ \
|
||||
struct SNAME##_iter_s (*it_end)(struct SNAME##_s *); \
|
||||
\
|
||||
} SNAME, *SNAME##_ptr; \
|
||||
\
|
||||
typedef struct SNAME##_entry_s \
|
||||
{ \
|
||||
/* Entry element */ \
|
||||
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 EntryState_e state; \
|
||||
\
|
||||
} SNAME##_entry, *SNAME##_entry_ptr; \
|
||||
\
|
||||
/* Hashset Iterator */ \
|
||||
typedef struct SNAME##_iter_s \
|
||||
{ \
|
||||
/* Target Hashset */ \
|
||||
struct SNAME##_s *target; \
|
||||
\
|
||||
/* Cursor's position (index) */ \
|
||||
size_t cursor; \
|
||||
\
|
||||
/* Keeps track of relative index to the iteration of elements */ \
|
||||
size_t index; \
|
||||
\
|
||||
/* The index of the first element */ \
|
||||
size_t first; \
|
||||
\
|
||||
/* The index of the last element */ \
|
||||
size_t last; \
|
||||
\
|
||||
/* If the iterator has reached the start of the iteration */ \
|
||||
bool start; \
|
||||
\
|
||||
/* If the iterator has reached the end of the iteration */ \
|
||||
bool end; \
|
||||
\
|
||||
} SNAME##_iter, *SNAME##_iter_ptr; \
|
||||
\
|
||||
/* Collection Functions */ \
|
||||
/* Collection Allocation and Deallocation */ \
|
||||
FMOD SNAME *PFX##_new(size_t size, double load, int (*compare)(V, V), size_t (*hash)(V)); \
|
||||
FMOD void PFX##_clear(SNAME *_set_); \
|
||||
FMOD void PFX##_free(SNAME *_set_); \
|
||||
/* Collection Input and Output */ \
|
||||
FMOD bool PFX##_insert(SNAME *_set_, V element); \
|
||||
FMOD bool PFX##_remove(SNAME *_set_, V element); \
|
||||
/* Conditional Input and Output */ \
|
||||
FMOD bool PFX##_insert_if(SNAME *_set_, V element, bool condition); \
|
||||
FMOD bool PFX##_remove_if(SNAME *_set_, V element, bool condition); \
|
||||
FMOD V PFX##_max(SNAME *_set_); \
|
||||
FMOD V PFX##_min(SNAME *_set_); \
|
||||
/* Element Access */ \
|
||||
FMOD bool PFX##_max(SNAME *_set_, V *value); \
|
||||
FMOD bool PFX##_min(SNAME *_set_, V *value); \
|
||||
/* Collection State */ \
|
||||
FMOD bool PFX##_contains(SNAME *_set_, V element); \
|
||||
FMOD bool PFX##_empty(SNAME *_set_); \
|
||||
FMOD size_t PFX##_count(SNAME *_set_); \
|
||||
FMOD size_t PFX##_capacity(SNAME *_set_); \
|
||||
\
|
||||
/* Set Operations */ \
|
||||
FMOD SNAME *PFX##_union(SNAME *_set1_, SNAME *_set2_); \
|
||||
FMOD SNAME *PFX##_intersection(SNAME *_set1_, SNAME *_set2_); \
|
||||
FMOD SNAME *PFX##_difference(SNAME *_set1_, SNAME *_set2_); \
|
||||
FMOD SNAME *PFX##_symmetric_difference(SNAME *_set1_, SNAME *_set2_); \
|
||||
\
|
||||
FMOD void PFX##_iter_new(SNAME##_iter *iter, SNAME *target); \
|
||||
/* Iterator Functions */ \
|
||||
/* Iterator Allocation and Deallocation */ \
|
||||
FMOD SNAME##_iter *PFX##_iter_new(SNAME *target); \
|
||||
FMOD void PFX##_iter_free(SNAME##_iter *iter); \
|
||||
/* Iterator Initialization */ \
|
||||
FMOD void PFX##_iter_init(SNAME##_iter *iter, SNAME *target); \
|
||||
/* Iterator State */ \
|
||||
FMOD bool PFX##_iter_start(SNAME##_iter *iter); \
|
||||
FMOD bool PFX##_iter_end(SNAME##_iter *iter); \
|
||||
FMOD void PFX##_iter_tostart(SNAME##_iter *iter); \
|
||||
FMOD void PFX##_iter_toend(SNAME##_iter *iter); \
|
||||
FMOD bool PFX##_iter_next(SNAME##_iter *iter, V *value, size_t *index); \
|
||||
FMOD bool PFX##_iter_prev(SNAME##_iter *iter, V *value, size_t *index); \
|
||||
/* Iterator Movement */ \
|
||||
FMOD void PFX##_iter_to_start(SNAME##_iter *iter); \
|
||||
FMOD void PFX##_iter_to_end(SNAME##_iter *iter); \
|
||||
FMOD bool PFX##_iter_next(SNAME##_iter *iter); \
|
||||
FMOD bool PFX##_iter_prev(SNAME##_iter *iter); \
|
||||
/* Iterator Access */ \
|
||||
FMOD V PFX##_iter_value(SNAME##_iter *iter); \
|
||||
FMOD size_t PFX##_iter_index(SNAME##_iter *iter); \
|
||||
\
|
||||
/* SOURCE ********************************************************************/
|
||||
#define HASHSET_GENERATE_SOURCE(PFX, SNAME, FMOD, V) \
|
||||
\
|
||||
/* Implementation Detail Functions */ \
|
||||
FMOD bool PFX##_grow(SNAME *_set_); \
|
||||
FMOD SNAME##_entry *PFX##_get_entry(SNAME *_set_, V element); \
|
||||
FMOD size_t PFX##_calculate_size(size_t required); \
|
||||
SNAME##_iter PFX##_impl_it_start(SNAME *_set_); \
|
||||
SNAME##_iter PFX##_impl_it_end(SNAME *_set_); \
|
||||
\
|
||||
FMOD SNAME *PFX##_new(size_t size, double load, int (*compare)(V, V), size_t (*hash)(V)) \
|
||||
{ \
|
||||
@@ -154,6 +236,9 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 193, 389, 769, 1543, 3079,
|
||||
_set_->cmp = compare; \
|
||||
_set_->hash = hash; \
|
||||
\
|
||||
_set_->it_start = PFX##_impl_it_start; \
|
||||
_set_->it_end = PFX##_impl_it_end; \
|
||||
\
|
||||
return _set_; \
|
||||
} \
|
||||
\
|
||||
@@ -190,7 +275,7 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 193, 389, 769, 1543, 3079,
|
||||
if (target->state == ES_EMPTY || target->state == ES_DELETED) \
|
||||
{ \
|
||||
target->value = element; \
|
||||
target->dist = original_pos - pos; \
|
||||
target->dist = pos - original_pos; \
|
||||
target->state = ES_FILLED; \
|
||||
} \
|
||||
else \
|
||||
@@ -205,9 +290,10 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 193, 389, 769, 1543, 3079,
|
||||
target->value = element; \
|
||||
target->dist = pos - original_pos; \
|
||||
target->state = ES_FILLED; \
|
||||
\
|
||||
break; \
|
||||
} \
|
||||
else if (target->dist < original_pos - pos) \
|
||||
else if (target->dist < pos - original_pos) \
|
||||
{ \
|
||||
V tmp = target->value; \
|
||||
size_t tmp_dist = target->dist; \
|
||||
@@ -258,48 +344,51 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 193, 389, 769, 1543, 3079,
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
FMOD V PFX##_max(SNAME *_set_) \
|
||||
FMOD bool PFX##_max(SNAME *_set_, V *value) \
|
||||
{ \
|
||||
if (PFX##_empty(_set_)) \
|
||||
return 0; \
|
||||
return false; \
|
||||
\
|
||||
SNAME##_iter iter; \
|
||||
V result, max; \
|
||||
size_t index; \
|
||||
\
|
||||
for (PFX##_iter_new(&iter, _set_); !PFX##_iter_end(&iter);) \
|
||||
for (PFX##_iter_init(&iter, _set_); !PFX##_iter_end(&iter); PFX##_iter_next(&iter)) \
|
||||
{ \
|
||||
PFX##_iter_next(&iter, &result, &index); \
|
||||
V result = PFX##_iter_value(&iter); \
|
||||
size_t index = PFX##_iter_index(&iter); \
|
||||
\
|
||||
if (index == 0) \
|
||||
max = result; \
|
||||
else if (_set_->cmp(result, max) > 0) \
|
||||
max = result; \
|
||||
*value = result; \
|
||||
else if (_set_->cmp(result, *value) > 0) \
|
||||
*value = result; \
|
||||
} \
|
||||
\
|
||||
return max; \
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD V PFX##_min(SNAME *_set_) \
|
||||
FMOD bool PFX##_min(SNAME *_set_, V *value) \
|
||||
{ \
|
||||
if (PFX##_empty(_set_)) \
|
||||
return 0; \
|
||||
return false; \
|
||||
\
|
||||
SNAME##_iter iter; \
|
||||
V result, min; \
|
||||
size_t index; \
|
||||
\
|
||||
for (PFX##_iter_new(&iter, _set_); !PFX##_iter_end(&iter);) \
|
||||
for (PFX##_iter_init(&iter, _set_); !PFX##_iter_end(&iter); PFX##_iter_next(&iter)) \
|
||||
{ \
|
||||
PFX##_iter_next(&iter, &result, &index); \
|
||||
V result = PFX##_iter_value(&iter); \
|
||||
size_t index = PFX##_iter_index(&iter); \
|
||||
\
|
||||
if (index == 0) \
|
||||
min = result; \
|
||||
else if (_set_->cmp(result, min) < 0) \
|
||||
min = result; \
|
||||
*value = result; \
|
||||
else if (_set_->cmp(result, *value) < 0) \
|
||||
*value = result; \
|
||||
} \
|
||||
\
|
||||
return min; \
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_contains(SNAME *_set_, V element) \
|
||||
{ \
|
||||
return PFX##_get_entry(_set_, element) != NULL; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_empty(SNAME *_set_) \
|
||||
@@ -312,99 +401,30 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 193, 389, 769, 1543, 3079,
|
||||
return _set_->count; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_grow(SNAME *_set_) \
|
||||
FMOD size_t PFX##_capacity(SNAME *_set_) \
|
||||
{ \
|
||||
size_t new_size = PFX##_calculate_size((size_t)((double)_set_->capacity * 1.5)); \
|
||||
\
|
||||
SNAME *_new_set_ = PFX##_new(new_size, _set_->load, _set_->cmp, _set_->hash); \
|
||||
\
|
||||
if (!_new_set_) \
|
||||
return false; \
|
||||
\
|
||||
SNAME##_iter iter; \
|
||||
V value; \
|
||||
size_t index; \
|
||||
\
|
||||
for (PFX##_iter_new(&iter, _set_); !PFX##_iter_end(&iter);) \
|
||||
{ \
|
||||
PFX##_iter_next(&iter, &value, &index); \
|
||||
PFX##_insert(_new_set_, value); \
|
||||
} \
|
||||
\
|
||||
if (_set_->count != _new_set_->count) \
|
||||
{ \
|
||||
PFX##_free(_new_set_); \
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
SNAME##_entry *tmp = _set_->buffer; \
|
||||
_set_->buffer = _new_set_->buffer; \
|
||||
_new_set_->buffer = tmp; \
|
||||
\
|
||||
_set_->capacity = _new_set_->capacity; \
|
||||
\
|
||||
PFX##_free(_new_set_); \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD SNAME##_entry *PFX##_get_entry(SNAME *_set_, V element) \
|
||||
{ \
|
||||
size_t hash = _set_->hash(element); \
|
||||
size_t pos = hash % _set_->capacity; \
|
||||
\
|
||||
SNAME##_entry *target = &(_set_->buffer[pos % _set_->capacity]); \
|
||||
\
|
||||
while (target->state == ES_FILLED || target->state == ES_DELETED) \
|
||||
{ \
|
||||
if (_set_->cmp(target->value, element) == 0) \
|
||||
return target; \
|
||||
\
|
||||
pos++; \
|
||||
target = &(_set_->buffer[pos % _set_->capacity]); \
|
||||
} \
|
||||
\
|
||||
return NULL; \
|
||||
} \
|
||||
\
|
||||
FMOD size_t PFX##_calculate_size(size_t required) \
|
||||
{ \
|
||||
const size_t count = sizeof(cmc_hashtable_primes) / sizeof(cmc_hashtable_primes[0]); \
|
||||
\
|
||||
if (cmc_hashtable_primes[count - 1] < required) \
|
||||
return required; \
|
||||
\
|
||||
size_t i = 0; \
|
||||
while (cmc_hashtable_primes[i] < required) \
|
||||
i++; \
|
||||
\
|
||||
return cmc_hashtable_primes[i]; \
|
||||
return _set_->capacity; \
|
||||
} \
|
||||
\
|
||||
FMOD SNAME *PFX##_union(SNAME *_set1_, SNAME *_set2_) \
|
||||
{ \
|
||||
SNAME##_iter iter1, iter2; \
|
||||
size_t index; \
|
||||
V value; \
|
||||
\
|
||||
SNAME *_set_r_ = PFX##_new(_set1_->capacity, _set1_->load, _set1_->cmp, _set1_->hash); \
|
||||
\
|
||||
if (!_set_r_) \
|
||||
return false; \
|
||||
\
|
||||
PFX##_iter_new(&iter1, _set1_); \
|
||||
PFX##_iter_new(&iter2, _set2_); \
|
||||
SNAME##_iter iter1, iter2; \
|
||||
PFX##_iter_init(&iter1, _set1_); \
|
||||
PFX##_iter_init(&iter2, _set2_); \
|
||||
\
|
||||
for (PFX##_iter_tostart(&iter1); !PFX##_iter_end(&iter1);) \
|
||||
for (PFX##_iter_to_start(&iter1); !PFX##_iter_end(&iter1); PFX##_iter_next(&iter1)) \
|
||||
{ \
|
||||
PFX##_iter_next(&iter1, &value, &index); \
|
||||
PFX##_insert(_set_r_, value); \
|
||||
PFX##_insert(_set_r_, PFX##_iter_value(&iter1)); \
|
||||
} \
|
||||
\
|
||||
for (PFX##_iter_tostart(&iter2); !PFX##_iter_end(&iter2);) \
|
||||
for (PFX##_iter_to_start(&iter2); !PFX##_iter_end(&iter2); PFX##_iter_next(&iter2)) \
|
||||
{ \
|
||||
PFX##_iter_next(&iter2, &value, &index); \
|
||||
PFX##_insert(_set_r_, value); \
|
||||
PFX##_insert(_set_r_, PFX##_iter_value(&iter2)); \
|
||||
} \
|
||||
\
|
||||
return _set_r_; \
|
||||
@@ -412,10 +432,6 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 193, 389, 769, 1543, 3079,
|
||||
\
|
||||
FMOD SNAME *PFX##_intersection(SNAME *_set1_, SNAME *_set2_) \
|
||||
{ \
|
||||
SNAME##_iter iter; \
|
||||
size_t index; \
|
||||
V value; \
|
||||
\
|
||||
SNAME *_set_r_ = PFX##_new(_set1_->capacity, _set1_->load, _set1_->cmp, _set1_->hash); \
|
||||
\
|
||||
if (!_set_r_) \
|
||||
@@ -424,11 +440,13 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 193, 389, 769, 1543, 3079,
|
||||
SNAME *_set_A_ = _set1_->count < _set2_->count ? _set1_ : _set2_; \
|
||||
SNAME *_set_B_ = _set_A_ == _set1_ ? _set2_ : _set1_; \
|
||||
\
|
||||
PFX##_iter_new(&iter, _set_A_); \
|
||||
SNAME##_iter iter; \
|
||||
PFX##_iter_init(&iter, _set_A_); \
|
||||
\
|
||||
for (PFX##_iter_tostart(&iter); !PFX##_iter_end(&iter);) \
|
||||
for (PFX##_iter_to_start(&iter); !PFX##_iter_end(&iter); PFX##_iter_next(&iter)) \
|
||||
{ \
|
||||
PFX##_iter_next(&iter, &value, &index); \
|
||||
V value = PFX##_iter_value(&iter); \
|
||||
\
|
||||
if (PFX##_get_entry(_set_B_, value) != NULL) \
|
||||
PFX##_insert(_set_r_, value); \
|
||||
} \
|
||||
@@ -438,20 +456,18 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 193, 389, 769, 1543, 3079,
|
||||
\
|
||||
FMOD SNAME *PFX##_difference(SNAME *_set1_, SNAME *_set2_) \
|
||||
{ \
|
||||
SNAME##_iter iter; \
|
||||
size_t index; \
|
||||
V value; \
|
||||
\
|
||||
SNAME *_set_r_ = PFX##_new(_set1_->capacity, _set1_->load, _set1_->cmp, _set1_->hash); \
|
||||
\
|
||||
if (!_set_r_) \
|
||||
return false; \
|
||||
\
|
||||
PFX##_iter_new(&iter, _set1_); \
|
||||
SNAME##_iter iter; \
|
||||
PFX##_iter_init(&iter, _set1_); \
|
||||
\
|
||||
for (PFX##_iter_tostart(&iter); !PFX##_iter_end(&iter);) \
|
||||
for (PFX##_iter_to_start(&iter); !PFX##_iter_end(&iter); PFX##_iter_next(&iter)) \
|
||||
{ \
|
||||
PFX##_iter_next(&iter, &value, &index); \
|
||||
V value = PFX##_iter_value(&iter); \
|
||||
\
|
||||
if (PFX##_get_entry(_set2_, value) == NULL) \
|
||||
PFX##_insert(_set_r_, value); \
|
||||
} \
|
||||
@@ -462,27 +478,27 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 193, 389, 769, 1543, 3079,
|
||||
FMOD SNAME *PFX##_symmetric_difference(SNAME *_set1_, SNAME *_set2_) \
|
||||
{ \
|
||||
SNAME##_iter iter1, iter2; \
|
||||
size_t index; \
|
||||
V value; \
|
||||
\
|
||||
SNAME *_set_r_ = PFX##_new(_set1_->capacity, _set1_->load, _set1_->cmp, _set1_->hash); \
|
||||
\
|
||||
if (!_set_r_) \
|
||||
return false; \
|
||||
\
|
||||
PFX##_iter_new(&iter1, _set1_); \
|
||||
PFX##_iter_new(&iter2, _set2_); \
|
||||
PFX##_iter_init(&iter1, _set1_); \
|
||||
PFX##_iter_init(&iter2, _set2_); \
|
||||
\
|
||||
for (PFX##_iter_tostart(&iter1); !PFX##_iter_end(&iter1);) \
|
||||
for (PFX##_iter_to_start(&iter1); !PFX##_iter_end(&iter1); PFX##_iter_next(&iter1)) \
|
||||
{ \
|
||||
PFX##_iter_next(&iter1, &value, &index); \
|
||||
V value = PFX##_iter_value(&iter1); \
|
||||
\
|
||||
if (PFX##_get_entry(_set2_, value) == NULL) \
|
||||
PFX##_insert(_set_r_, value); \
|
||||
} \
|
||||
\
|
||||
for (PFX##_iter_tostart(&iter2); !PFX##_iter_end(&iter2);) \
|
||||
for (PFX##_iter_to_start(&iter2); !PFX##_iter_end(&iter2); PFX##_iter_next(&iter2)) \
|
||||
{ \
|
||||
PFX##_iter_next(&iter2, &value, &index); \
|
||||
V value = PFX##_iter_value(&iter2); \
|
||||
\
|
||||
if (PFX##_get_entry(_set1_, value) == NULL) \
|
||||
PFX##_insert(_set_r_, value); \
|
||||
} \
|
||||
@@ -490,7 +506,24 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 193, 389, 769, 1543, 3079,
|
||||
return _set_r_; \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_iter_new(SNAME##_iter *iter, SNAME *target) \
|
||||
FMOD SNAME##_iter *PFX##_iter_new(SNAME *target) \
|
||||
{ \
|
||||
SNAME##_iter *iter = malloc(sizeof(SNAME##_iter)); \
|
||||
\
|
||||
if (!iter) \
|
||||
return NULL; \
|
||||
\
|
||||
PFX##_iter_init(iter, target); \
|
||||
\
|
||||
return iter; \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_iter_free(SNAME##_iter *iter) \
|
||||
{ \
|
||||
free(iter); \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_iter_init(SNAME##_iter *iter, SNAME *target) \
|
||||
{ \
|
||||
iter->target = target; \
|
||||
iter->cursor = 0; \
|
||||
@@ -524,15 +557,15 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 193, 389, 769, 1543, 3079,
|
||||
\
|
||||
FMOD bool PFX##_iter_start(SNAME##_iter *iter) \
|
||||
{ \
|
||||
return iter->start && iter->cursor == iter->first; \
|
||||
return PFX##_empty(iter->target) || iter->start; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_iter_end(SNAME##_iter *iter) \
|
||||
{ \
|
||||
return iter->end && iter->cursor == iter->last; \
|
||||
return PFX##_empty(iter->target) || iter->end; \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_iter_tostart(SNAME##_iter *iter) \
|
||||
FMOD void PFX##_iter_to_start(SNAME##_iter *iter) \
|
||||
{ \
|
||||
iter->cursor = iter->first; \
|
||||
iter->index = 0; \
|
||||
@@ -540,7 +573,7 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 193, 389, 769, 1543, 3079,
|
||||
iter->end = PFX##_empty(iter->target); \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_iter_toend(SNAME##_iter *iter) \
|
||||
FMOD void PFX##_iter_to_end(SNAME##_iter *iter) \
|
||||
{ \
|
||||
iter->cursor = iter->last; \
|
||||
iter->index = iter->target->count - 1; \
|
||||
@@ -548,21 +581,19 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 193, 389, 769, 1543, 3079,
|
||||
iter->end = true; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_iter_next(SNAME##_iter *iter, V *value, size_t *index) \
|
||||
FMOD bool PFX##_iter_next(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (iter->end) \
|
||||
return false; \
|
||||
\
|
||||
SNAME##_entry *scan = &(iter->target->buffer[iter->cursor]); \
|
||||
\
|
||||
*value = scan->value; \
|
||||
*index = iter->index; \
|
||||
\
|
||||
if (iter->cursor == iter->last) \
|
||||
iter->end = true; \
|
||||
else \
|
||||
{ \
|
||||
iter->index++; \
|
||||
\
|
||||
while (1) \
|
||||
{ \
|
||||
iter->cursor++; \
|
||||
@@ -578,21 +609,19 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 193, 389, 769, 1543, 3079,
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_iter_prev(SNAME##_iter *iter, V *value, size_t *index) \
|
||||
FMOD bool PFX##_iter_prev(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (iter->start) \
|
||||
return false; \
|
||||
\
|
||||
SNAME##_entry *scan = &(iter->target->buffer[iter->cursor]); \
|
||||
\
|
||||
*value = scan->value; \
|
||||
*index = iter->index; \
|
||||
\
|
||||
if (iter->cursor == iter->first) \
|
||||
iter->start = true; \
|
||||
else \
|
||||
{ \
|
||||
iter->index--; \
|
||||
\
|
||||
while (1) \
|
||||
{ \
|
||||
iter->cursor--; \
|
||||
@@ -606,6 +635,105 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 193, 389, 769, 1543, 3079,
|
||||
iter->end = PFX##_empty(iter->target); \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD V PFX##_iter_value(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (PFX##_empty(iter->target)) \
|
||||
return 0; \
|
||||
\
|
||||
return iter->target->buffer[iter->cursor].value; \
|
||||
} \
|
||||
\
|
||||
FMOD size_t PFX##_iter_index(SNAME##_iter *iter) \
|
||||
{ \
|
||||
return iter->index; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_grow(SNAME *_set_) \
|
||||
{ \
|
||||
size_t new_size = PFX##_calculate_size(_set_->capacity + _set_->capacity / 2); \
|
||||
\
|
||||
SNAME *_new_set_ = PFX##_new(new_size, _set_->load, _set_->cmp, _set_->hash); \
|
||||
\
|
||||
if (!_new_set_) \
|
||||
return false; \
|
||||
\
|
||||
SNAME##_iter iter; \
|
||||
\
|
||||
for (PFX##_iter_init(&iter, _set_); !PFX##_iter_end(&iter); PFX##_iter_next(&iter)) \
|
||||
{ \
|
||||
PFX##_insert(_new_set_, PFX##_iter_value(&iter)); \
|
||||
} \
|
||||
\
|
||||
if (_set_->count != _new_set_->count) \
|
||||
{ \
|
||||
PFX##_free(_new_set_); \
|
||||
\
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
SNAME##_entry *tmp = _set_->buffer; \
|
||||
_set_->buffer = _new_set_->buffer; \
|
||||
_new_set_->buffer = tmp; \
|
||||
\
|
||||
_set_->capacity = _new_set_->capacity; \
|
||||
\
|
||||
PFX##_free(_new_set_); \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD SNAME##_entry *PFX##_get_entry(SNAME *_set_, V element) \
|
||||
{ \
|
||||
size_t hash = _set_->hash(element); \
|
||||
size_t pos = hash % _set_->capacity; \
|
||||
\
|
||||
SNAME##_entry *target = &(_set_->buffer[pos]); \
|
||||
\
|
||||
while (target->state == ES_FILLED || target->state == ES_DELETED) \
|
||||
{ \
|
||||
if (_set_->cmp(target->value, element) == 0) \
|
||||
return target; \
|
||||
\
|
||||
pos++; \
|
||||
target = &(_set_->buffer[pos % _set_->capacity]); \
|
||||
} \
|
||||
\
|
||||
return NULL; \
|
||||
} \
|
||||
\
|
||||
FMOD size_t PFX##_calculate_size(size_t required) \
|
||||
{ \
|
||||
const size_t count = sizeof(cmc_hashtable_primes) / sizeof(cmc_hashtable_primes[0]); \
|
||||
\
|
||||
if (cmc_hashtable_primes[count - 1] < required) \
|
||||
return required; \
|
||||
\
|
||||
size_t i = 0; \
|
||||
while (cmc_hashtable_primes[i] < required) \
|
||||
i++; \
|
||||
\
|
||||
return cmc_hashtable_primes[i]; \
|
||||
} \
|
||||
\
|
||||
SNAME##_iter PFX##_impl_it_start(SNAME *_set_) \
|
||||
{ \
|
||||
SNAME##_iter iter; \
|
||||
\
|
||||
PFX##_iter_init(&iter, _set_); \
|
||||
\
|
||||
return iter; \
|
||||
} \
|
||||
\
|
||||
SNAME##_iter PFX##_impl_it_end(SNAME *_set_) \
|
||||
{ \
|
||||
SNAME##_iter iter; \
|
||||
\
|
||||
PFX##_iter_init(&iter, _set_); \
|
||||
PFX##_iter_to_end(&iter); \
|
||||
\
|
||||
return iter; \
|
||||
}
|
||||
|
||||
#endif /* CMC_HASHSET_H */
|
||||
+237
-125
@@ -43,61 +43,105 @@ typedef enum HeapOrder
|
||||
#define HEAP_GENERATE_SOURCE_PUBLIC(PFX, SNAME, FMOD, K, V) \
|
||||
HEAP_GENERATE_SOURCE(PFX, SNAME, FMOD, V)
|
||||
/* STRUCT ********************************************************************/
|
||||
#define HEAP_GENERATE_STRUCT(PFX, SNAME, FMOD, V) \
|
||||
\
|
||||
struct SNAME##_s \
|
||||
{ \
|
||||
V *buffer; \
|
||||
size_t capacity; \
|
||||
size_t count; \
|
||||
enum HeapOrder HO; \
|
||||
int (*cmp)(V, V); \
|
||||
}; \
|
||||
\
|
||||
struct SNAME##_iter_s \
|
||||
{ \
|
||||
struct SNAME##_s *target; \
|
||||
size_t cursor; \
|
||||
bool start; \
|
||||
bool end; \
|
||||
}; \
|
||||
\
|
||||
#define HEAP_GENERATE_STRUCT(PFX, SNAME, FMOD, V)
|
||||
|
||||
/* HEADER ********************************************************************/
|
||||
#define HEAP_GENERATE_HEADER(PFX, SNAME, FMOD, V) \
|
||||
\
|
||||
typedef struct SNAME##_s SNAME; \
|
||||
typedef struct SNAME##_iter_s SNAME##_iter; \
|
||||
\
|
||||
FMOD SNAME *PFX##_new(size_t size, HeapOrder HO, int (*compare)(V, V)); \
|
||||
FMOD void PFX##_clear(SNAME *_heap_); \
|
||||
FMOD void PFX##_free(SNAME *_heap_); \
|
||||
FMOD bool PFX##_insert(SNAME *_heap_, V element); \
|
||||
FMOD bool PFX##_remove(SNAME *_heap_, V *result); \
|
||||
FMOD bool PFX##_insert_if(SNAME *_heap_, V element, bool condition); \
|
||||
FMOD bool PFX##_remove_if(SNAME *_heap_, V *result, bool condition); \
|
||||
FMOD V PFX##_peek(SNAME *_heap_); \
|
||||
FMOD bool PFX##_empty(SNAME *_heap_); \
|
||||
FMOD bool PFX##_full(SNAME *_heap_); \
|
||||
FMOD size_t PFX##_count(SNAME *_heap_); \
|
||||
FMOD size_t PFX##_capacity(SNAME *_heap_); \
|
||||
\
|
||||
FMOD void PFX##_iter_new(SNAME##_iter *iter, SNAME *target); \
|
||||
FMOD bool PFX##_iter_start(SNAME##_iter *iter); \
|
||||
FMOD bool PFX##_iter_end(SNAME##_iter *iter); \
|
||||
FMOD void PFX##_iter_tostart(SNAME##_iter *iter); \
|
||||
FMOD void PFX##_iter_toend(SNAME##_iter *iter); \
|
||||
FMOD bool PFX##_iter_next(SNAME##_iter *iter, V *result, size_t *index); \
|
||||
FMOD bool PFX##_iter_prev(SNAME##_iter *iter, V *result, size_t *index); \
|
||||
\
|
||||
#define HEAP_GENERATE_HEADER(PFX, SNAME, FMOD, V) \
|
||||
\
|
||||
/* Heap Structure */ \
|
||||
typedef struct SNAME##_s \
|
||||
{ \
|
||||
/* Dynamic array of elements */ \
|
||||
V *buffer; \
|
||||
\
|
||||
/* Current array capacity */ \
|
||||
size_t capacity; \
|
||||
\
|
||||
/* Current amount of elements in the heap */ \
|
||||
size_t count; \
|
||||
\
|
||||
/* Heap order (MaxHeap or MinHeap) */ \
|
||||
enum HeapOrder HO; \
|
||||
\
|
||||
/* Element comparison function */ \
|
||||
int (*cmp)(V, V); \
|
||||
\
|
||||
/* Function that returns an iterator to the start of the heap */ \
|
||||
struct SNAME##_iter_s (*it_start)(struct SNAME##_s *); \
|
||||
\
|
||||
/* Function that returns an iterator to the end of the heap */ \
|
||||
struct SNAME##_iter_s (*it_end)(struct SNAME##_s *); \
|
||||
\
|
||||
} SNAME, *SNAME##_ptr; \
|
||||
\
|
||||
/* Heap Iterator */ \
|
||||
typedef struct SNAME##_iter_s \
|
||||
{ \
|
||||
/* Target heap */ \
|
||||
struct SNAME##_s *target; \
|
||||
\
|
||||
/* Cursor's position (index) */ \
|
||||
size_t cursor; \
|
||||
\
|
||||
/* If the iterator has reached the start of the iteration */ \
|
||||
bool start; \
|
||||
\
|
||||
/* If the iterator has reached the end of the iteration */ \
|
||||
bool end; \
|
||||
\
|
||||
} SNAME##_iter, *SNAME##_iter_ptr; \
|
||||
\
|
||||
/* Collection Functions */ \
|
||||
/* Collection Allocation and Deallocation */ \
|
||||
FMOD SNAME *PFX##_new(size_t size, HeapOrder HO, int (*compare)(V, V)); \
|
||||
FMOD void PFX##_clear(SNAME *_heap_); \
|
||||
FMOD void PFX##_free(SNAME *_heap_); \
|
||||
/* Collection Input and Output */ \
|
||||
FMOD bool PFX##_insert(SNAME *_heap_, V element); \
|
||||
FMOD bool PFX##_remove(SNAME *_heap_, V *result); \
|
||||
/* Conditional Input and Output */ \
|
||||
FMOD bool PFX##_insert_if(SNAME *_heap_, V element, bool condition); \
|
||||
FMOD bool PFX##_remove_if(SNAME *_heap_, V *result, bool condition); \
|
||||
/* Element Access */ \
|
||||
FMOD V PFX##_peek(SNAME *_heap_); \
|
||||
FMOD V *PFX##_peek_ref(SNAME *_heap_); \
|
||||
/* Collection State */ \
|
||||
FMOD bool PFX##_contains(SNAME *_heap_, V element); \
|
||||
FMOD bool PFX##_empty(SNAME *_heap_); \
|
||||
FMOD bool PFX##_full(SNAME *_heap_); \
|
||||
FMOD size_t PFX##_count(SNAME *_heap_); \
|
||||
FMOD size_t PFX##_capacity(SNAME *_heap_); \
|
||||
\
|
||||
/* Iterator Functions */ \
|
||||
/* Iterator Allocation and Deallocation */ \
|
||||
FMOD SNAME##_iter *PFX##_iter_new(SNAME *target); \
|
||||
FMOD void PFX##_iter_free(SNAME##_iter *iter); \
|
||||
/* Iterator Initialization */ \
|
||||
FMOD void PFX##_iter_init(SNAME##_iter *iter, SNAME *target); \
|
||||
/* Iterator State */ \
|
||||
FMOD bool PFX##_iter_start(SNAME##_iter *iter); \
|
||||
FMOD bool PFX##_iter_end(SNAME##_iter *iter); \
|
||||
/* Iterator Movement */ \
|
||||
FMOD void PFX##_iter_to_start(SNAME##_iter *iter); \
|
||||
FMOD void PFX##_iter_to_end(SNAME##_iter *iter); \
|
||||
FMOD bool PFX##_iter_next(SNAME##_iter *iter); \
|
||||
FMOD bool PFX##_iter_prev(SNAME##_iter *iter); \
|
||||
/* Iterator Access */ \
|
||||
FMOD V PFX##_iter_value(SNAME##_iter *iter); \
|
||||
FMOD size_t PFX##_iter_index(SNAME##_iter *iter); \
|
||||
\
|
||||
/* SOURCE ********************************************************************/
|
||||
#define HEAP_GENERATE_SOURCE(PFX, SNAME, FMOD, V) \
|
||||
\
|
||||
FMOD bool PFX##_grow(SNAME *_heap_); \
|
||||
FMOD size_t PFX##_p(size_t index); \
|
||||
FMOD size_t PFX##_l(size_t index); \
|
||||
FMOD size_t PFX##_r(size_t index); \
|
||||
FMOD bool PFX##_float_up(SNAME *_heap_, size_t index); \
|
||||
FMOD bool PFX##_float_down(SNAME *_heap_, size_t index); \
|
||||
/* Implementation Detail Functions */ \
|
||||
FMOD bool PFX##_impl_grow(SNAME *_heap_); \
|
||||
FMOD size_t PFX##_impl_p(size_t index); \
|
||||
FMOD size_t PFX##_impl_l(size_t index); \
|
||||
FMOD size_t PFX##_impl_r(size_t index); \
|
||||
FMOD bool PFX##_impl_float_up(SNAME *_heap_, size_t index); \
|
||||
FMOD bool PFX##_impl_float_down(SNAME *_heap_, size_t index); \
|
||||
SNAME##_iter PFX##_impl_it_start(SNAME *_heap_); \
|
||||
SNAME##_iter PFX##_impl_it_end(SNAME *_heap_); \
|
||||
\
|
||||
FMOD SNAME *PFX##_new(size_t size, HeapOrder HO, int (*compare)(V, V)) \
|
||||
{ \
|
||||
@@ -127,6 +171,9 @@ typedef enum HeapOrder
|
||||
_heap_->HO = HO; \
|
||||
_heap_->cmp = compare; \
|
||||
\
|
||||
_heap_->it_start = PFX##_impl_it_start; \
|
||||
_heap_->it_end = PFX##_impl_it_end; \
|
||||
\
|
||||
return _heap_; \
|
||||
} \
|
||||
\
|
||||
@@ -147,7 +194,7 @@ typedef enum HeapOrder
|
||||
{ \
|
||||
if (PFX##_full(_heap_)) \
|
||||
{ \
|
||||
if (!PFX##_grow(_heap_)) \
|
||||
if (!PFX##_impl_grow(_heap_)) \
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
@@ -159,7 +206,7 @@ typedef enum HeapOrder
|
||||
\
|
||||
_heap_->buffer[_heap_->count++] = element; \
|
||||
\
|
||||
if (!PFX##_float_up(_heap_, _heap_->count - 1)) \
|
||||
if (!PFX##_impl_float_up(_heap_, _heap_->count - 1)) \
|
||||
return false; \
|
||||
\
|
||||
return true; \
|
||||
@@ -176,7 +223,7 @@ typedef enum HeapOrder
|
||||
\
|
||||
_heap_->count--; \
|
||||
\
|
||||
if (!PFX##_float_down(_heap_, 0)) \
|
||||
if (!PFX##_impl_float_down(_heap_, 0)) \
|
||||
return false; \
|
||||
\
|
||||
return true; \
|
||||
@@ -206,6 +253,25 @@ typedef enum HeapOrder
|
||||
return _heap_->buffer[0]; \
|
||||
} \
|
||||
\
|
||||
FMOD V *PFX##_peek_ref(SNAME *_heap_) \
|
||||
{ \
|
||||
if (PFX##_empty(_heap_)) \
|
||||
return NULL; \
|
||||
\
|
||||
return &(_heap_->buffer[0]); \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_contains(SNAME *_heap_, V element) \
|
||||
{ \
|
||||
for (size_t i = 0; i < _heap_->count; i++) \
|
||||
{ \
|
||||
if (_heap_->cmp(_heap_->buffer[i], element) == 0) \
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_empty(SNAME *_heap_) \
|
||||
{ \
|
||||
return _heap_->count == 0; \
|
||||
@@ -226,7 +292,99 @@ typedef enum HeapOrder
|
||||
return _heap_->capacity; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_grow(SNAME *_heap_) \
|
||||
FMOD SNAME##_iter *PFX##_iter_new(SNAME *target) \
|
||||
{ \
|
||||
SNAME##_iter *iter = malloc(sizeof(SNAME##_iter)); \
|
||||
\
|
||||
if (!iter) \
|
||||
return NULL; \
|
||||
\
|
||||
PFX##_iter_init(iter, target); \
|
||||
\
|
||||
return iter; \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_iter_free(SNAME##_iter *iter) \
|
||||
{ \
|
||||
free(iter); \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_iter_init(SNAME##_iter *iter, SNAME *target) \
|
||||
{ \
|
||||
iter->target = target; \
|
||||
iter->cursor = 0; \
|
||||
iter->start = true; \
|
||||
iter->end = PFX##_empty(target); \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_iter_start(SNAME##_iter *iter) \
|
||||
{ \
|
||||
return PFX##_empty(iter->target) || iter->start; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_iter_end(SNAME##_iter *iter) \
|
||||
{ \
|
||||
return PFX##_empty(iter->target) || iter->end; \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_iter_to_start(SNAME##_iter *iter) \
|
||||
{ \
|
||||
iter->cursor = 0; \
|
||||
iter->start = true; \
|
||||
iter->end = PFX##_empty(iter->target); \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_iter_to_end(SNAME##_iter *iter) \
|
||||
{ \
|
||||
iter->cursor = iter->target->count - 1; \
|
||||
iter->start = PFX##_empty(iter->target); \
|
||||
iter->end = true; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_iter_next(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (iter->end) \
|
||||
return false; \
|
||||
\
|
||||
iter->start = false; \
|
||||
\
|
||||
if (iter->cursor == iter->target->count - 1) \
|
||||
iter->end = true; \
|
||||
else \
|
||||
iter->cursor++; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_iter_prev(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (iter->start) \
|
||||
return false; \
|
||||
\
|
||||
iter->end = false; \
|
||||
\
|
||||
if (iter->cursor == 0) \
|
||||
iter->start = true; \
|
||||
else \
|
||||
iter->cursor--; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD V PFX##_iter_value(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (PFX##_empty(iter->target)) \
|
||||
return 0; \
|
||||
\
|
||||
return iter->target->buffer[iter->cursor]; \
|
||||
} \
|
||||
\
|
||||
FMOD size_t PFX##_iter_index(SNAME##_iter *iter) \
|
||||
{ \
|
||||
return iter->cursor; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_impl_grow(SNAME *_heap_) \
|
||||
{ \
|
||||
size_t new_capacity = _heap_->capacity * 2; \
|
||||
\
|
||||
@@ -241,7 +399,7 @@ typedef enum HeapOrder
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD size_t PFX##_p(size_t index) \
|
||||
FMOD size_t PFX##_impl_p(size_t index) \
|
||||
{ \
|
||||
if (index == 0) \
|
||||
return 0; \
|
||||
@@ -249,47 +407,47 @@ typedef enum HeapOrder
|
||||
return (index - 1) / 2; \
|
||||
} \
|
||||
\
|
||||
FMOD size_t PFX##_l(size_t index) \
|
||||
FMOD size_t PFX##_impl_l(size_t index) \
|
||||
{ \
|
||||
return 2 * index + 1; \
|
||||
} \
|
||||
\
|
||||
FMOD size_t PFX##_r(size_t index) \
|
||||
FMOD size_t PFX##_impl_r(size_t index) \
|
||||
{ \
|
||||
return 2 * index + 2; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_float_up(SNAME *_heap_, size_t index) \
|
||||
FMOD bool PFX##_impl_float_up(SNAME *_heap_, size_t index) \
|
||||
{ \
|
||||
size_t C = index; \
|
||||
V child = _heap_->buffer[C]; \
|
||||
V parent = _heap_->buffer[PFX##_p(C)]; \
|
||||
V parent = _heap_->buffer[PFX##_impl_p(C)]; \
|
||||
\
|
||||
int mod = _heap_->HO; \
|
||||
\
|
||||
while (C > 0 && _heap_->cmp(child, parent) * mod > 0) \
|
||||
{ \
|
||||
V tmp = _heap_->buffer[C]; \
|
||||
_heap_->buffer[C] = _heap_->buffer[PFX##_p(C)]; \
|
||||
_heap_->buffer[PFX##_p(C)] = tmp; \
|
||||
_heap_->buffer[C] = _heap_->buffer[PFX##_impl_p(C)]; \
|
||||
_heap_->buffer[PFX##_impl_p(C)] = tmp; \
|
||||
\
|
||||
C = PFX##_p(C); \
|
||||
C = PFX##_impl_p(C); \
|
||||
\
|
||||
child = _heap_->buffer[C]; \
|
||||
parent = _heap_->buffer[PFX##_p(C)]; \
|
||||
parent = _heap_->buffer[PFX##_impl_p(C)]; \
|
||||
} \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_float_down(SNAME *_heap_, size_t index) \
|
||||
FMOD bool PFX##_impl_float_down(SNAME *_heap_, size_t index) \
|
||||
{ \
|
||||
int mod = _heap_->HO; \
|
||||
\
|
||||
while (index < _heap_->count) \
|
||||
{ \
|
||||
size_t L = PFX##_l(index); \
|
||||
size_t R = PFX##_r(index); \
|
||||
size_t L = PFX##_impl_l(index); \
|
||||
size_t R = PFX##_impl_r(index); \
|
||||
size_t C = index; \
|
||||
\
|
||||
if (L < _heap_->count && _heap_->cmp(_heap_->buffer[L], _heap_->buffer[C]) * mod > 0) \
|
||||
@@ -317,70 +475,24 @@ typedef enum HeapOrder
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_iter_new(SNAME##_iter *iter, SNAME *target) \
|
||||
SNAME##_iter PFX##_impl_it_start(SNAME *_heap_) \
|
||||
{ \
|
||||
iter->target = target; \
|
||||
iter->cursor = 0; \
|
||||
iter->start = true; \
|
||||
iter->end = PFX##_empty(target); \
|
||||
SNAME##_iter iter; \
|
||||
\
|
||||
PFX##_iter_init(&iter, _heap_); \
|
||||
PFX##_iter_to_start(&iter); \
|
||||
\
|
||||
return iter; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_iter_start(SNAME##_iter *iter) \
|
||||
SNAME##_iter PFX##_impl_it_end(SNAME *_heap_) \
|
||||
{ \
|
||||
return iter->cursor == 0 && iter->start; \
|
||||
} \
|
||||
SNAME##_iter iter; \
|
||||
\
|
||||
FMOD bool PFX##_iter_end(SNAME##_iter *iter) \
|
||||
{ \
|
||||
return iter->cursor == iter->target->count - 1 && iter->end; \
|
||||
} \
|
||||
PFX##_iter_init(&iter, _heap_); \
|
||||
PFX##_iter_to_end(&iter); \
|
||||
\
|
||||
FMOD void PFX##_iter_tostart(SNAME##_iter *iter) \
|
||||
{ \
|
||||
iter->cursor = 0; \
|
||||
iter->start = true; \
|
||||
iter->end = PFX##_empty(iter->target); \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_iter_toend(SNAME##_iter *iter) \
|
||||
{ \
|
||||
iter->cursor = iter->target->count - 1; \
|
||||
iter->start = PFX##_empty(iter->target); \
|
||||
iter->end = true; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_iter_next(SNAME##_iter *iter, V *result, size_t *index) \
|
||||
{ \
|
||||
if (iter->end) \
|
||||
return false; \
|
||||
\
|
||||
*index = iter->cursor; \
|
||||
*result = iter->target->buffer[iter->cursor]; \
|
||||
iter->start = false; \
|
||||
\
|
||||
if (iter->cursor == iter->target->count - 1) \
|
||||
iter->end = true; \
|
||||
else \
|
||||
iter->cursor++; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_iter_prev(SNAME##_iter *iter, V *result, size_t *index) \
|
||||
{ \
|
||||
if (iter->start) \
|
||||
return false; \
|
||||
\
|
||||
*index = iter->cursor; \
|
||||
*result = iter->target->buffer[iter->cursor]; \
|
||||
iter->end = false; \
|
||||
\
|
||||
if (iter->cursor == 0) \
|
||||
iter->start = true; \
|
||||
else \
|
||||
iter->cursor--; \
|
||||
\
|
||||
return true; \
|
||||
return iter; \
|
||||
}
|
||||
|
||||
#endif /* CMC_HEAP_H */
|
||||
+315
-158
@@ -36,79 +36,135 @@
|
||||
#define LINKEDLIST_GENERATE_SOURCE_PUBLIC(PFX, SNAME, FMOD, K, V) \
|
||||
LINKEDLIST_GENERATE_SOURCE(PFX, SNAME, FMOD, V)
|
||||
/* STRUCT ********************************************************************/
|
||||
#define LINKEDLIST_GENERATE_STRUCT(PFX, SNAME, FMOD, V) \
|
||||
\
|
||||
struct SNAME##_s \
|
||||
{ \
|
||||
struct SNAME##_node_s *head; \
|
||||
struct SNAME##_node_s *tail; \
|
||||
size_t count; \
|
||||
}; \
|
||||
\
|
||||
struct SNAME##_node_s \
|
||||
{ \
|
||||
V data; \
|
||||
struct SNAME##_s *owner; \
|
||||
struct SNAME##_node_s *next; \
|
||||
struct SNAME##_node_s *prev; \
|
||||
}; \
|
||||
\
|
||||
struct SNAME##_iter_s \
|
||||
{ \
|
||||
struct SNAME##_s *target; \
|
||||
struct SNAME##_node_s *cursor; \
|
||||
size_t index; \
|
||||
bool start; \
|
||||
bool end; \
|
||||
}; \
|
||||
\
|
||||
#define LINKEDLIST_GENERATE_STRUCT(PFX, SNAME, FMOD, V)
|
||||
|
||||
/* HEADER ********************************************************************/
|
||||
#define LINKEDLIST_GENERATE_HEADER(PFX, SNAME, FMOD, V) \
|
||||
\
|
||||
typedef struct SNAME##_s SNAME; \
|
||||
typedef struct SNAME##_node_s SNAME##_node; \
|
||||
typedef struct SNAME##_iter_s SNAME##_iter; \
|
||||
/* Linked List Structure */ \
|
||||
typedef struct SNAME##_s \
|
||||
{ \
|
||||
/* First node in the list */ \
|
||||
struct SNAME##_node_s *head; \
|
||||
\
|
||||
/* Last node in the list */ \
|
||||
struct SNAME##_node_s *tail; \
|
||||
\
|
||||
/* Current amount of elements in the list */ \
|
||||
size_t count; \
|
||||
\
|
||||
/* Function that returns an iterator to the start of the list */ \
|
||||
struct SNAME##_iter_s (*it_start)(struct SNAME##_s *); \
|
||||
\
|
||||
/* Function that returns an iterator to the end of the list */ \
|
||||
struct SNAME##_iter_s (*it_end)(struct SNAME##_s *); \
|
||||
\
|
||||
} SNAME, *SNAME_ptr; \
|
||||
\
|
||||
/* Doubly-linked list node */ \
|
||||
typedef struct SNAME##_node_s \
|
||||
{ \
|
||||
/* Node's data */ \
|
||||
V data; \
|
||||
\
|
||||
/* Pointer to the next node on the linked list */ \
|
||||
struct SNAME##_node_s *next; \
|
||||
\
|
||||
/* Pointer to the previous node on the linked list */ \
|
||||
struct SNAME##_node_s *prev; \
|
||||
\
|
||||
} SNAME##_node, *SNAME##_node_ptr; \
|
||||
\
|
||||
/* Linked List Iterator */ \
|
||||
typedef struct SNAME##_iter_s \
|
||||
{ \
|
||||
/* Target Linked List */ \
|
||||
struct SNAME##_s *target; \
|
||||
\
|
||||
/* Cursor's current node */ \
|
||||
struct SNAME##_node_s *cursor; \
|
||||
\
|
||||
/* Keeps track of relative index to the iteration of elements */ \
|
||||
size_t index; \
|
||||
\
|
||||
/* If the iterator has reached the start of the iteration */ \
|
||||
bool start; \
|
||||
\
|
||||
/* If the iterator has reached the end of the iteration */ \
|
||||
bool end; \
|
||||
\
|
||||
} SNAME##_iter, *SNAME##_iter_ptr; \
|
||||
\
|
||||
/* Collection Functions */ \
|
||||
/* Collection Allocation and Deallocation */ \
|
||||
FMOD SNAME *PFX##_new(void); \
|
||||
FMOD void PFX##_clear(SNAME *_list_); \
|
||||
FMOD void PFX##_free(SNAME *_list_); \
|
||||
/* Collection Input and Output */ \
|
||||
FMOD bool PFX##_push_front(SNAME *_list_, V element); \
|
||||
FMOD bool PFX##_push(SNAME *_list_, V element, size_t index); \
|
||||
FMOD bool PFX##_push_back(SNAME *_list_, V element); \
|
||||
FMOD bool PFX##_pop_front(SNAME *_list_); \
|
||||
FMOD bool PFX##_pop(SNAME *_list_, size_t index); \
|
||||
FMOD bool PFX##_pop_back(SNAME *_list_); \
|
||||
/* Conditional Input and Output */ \
|
||||
FMOD bool PFX##_push_if(SNAME *_list_, V element, size_t index, bool condition); \
|
||||
FMOD bool PFX##_pop_if(SNAME *_list_, size_t index, bool condition); \
|
||||
/* Element Access */ \
|
||||
FMOD V PFX##_front(SNAME *_list_); \
|
||||
FMOD V PFX##_get(SNAME *_list_, size_t index); \
|
||||
FMOD V *PFX##_get_ref(SNAME *_list_, size_t index); \
|
||||
FMOD V PFX##_back(SNAME *_list_); \
|
||||
/* Collection State */ \
|
||||
FMOD bool PFX##_contains(SNAME *_list_, V element, int (*comparator)(V, V)); \
|
||||
FMOD bool PFX##_empty(SNAME *_list_); \
|
||||
FMOD size_t PFX##_count(SNAME *_list_); \
|
||||
\
|
||||
FMOD SNAME##_node *PFX##_new_node(SNAME *_owner_, V element); \
|
||||
FMOD SNAME##_node *PFX##_front_node(SNAME *_list_); \
|
||||
/* Node Related Functions */ \
|
||||
/* Node Allocation and Deallocation */ \
|
||||
FMOD SNAME##_node *PFX##_new_node(V element); \
|
||||
FMOD void PFX##_free_node(SNAME##_node *_node_); \
|
||||
/* Node Access Relative to a Linked List */ \
|
||||
FMOD SNAME##_node *PFX##_head(SNAME *_list_); \
|
||||
FMOD SNAME##_node *PFX##_get_node(SNAME *_list_, size_t index); \
|
||||
FMOD SNAME##_node *PFX##_back_node(SNAME *_list_); \
|
||||
FMOD bool PFX##_insert_nxt(SNAME##_node *node, V element); \
|
||||
FMOD bool PFX##_insert_prv(SNAME##_node *node, V element); \
|
||||
FMOD bool PFX##_remove_nxt(SNAME##_node *node); \
|
||||
FMOD bool PFX##_remove_cur(SNAME##_node *node); \
|
||||
FMOD bool PFX##_remove_prv(SNAME##_node *node); \
|
||||
FMOD SNAME##_node *PFX##_next_node(SNAME##_node *node); \
|
||||
FMOD SNAME##_node *PFX##_prev_node(SNAME##_node *node); \
|
||||
FMOD SNAME##_node *PFX##_tail(SNAME *_list_); \
|
||||
/* Input and Output Relative to a Node */ \
|
||||
FMOD bool PFX##_insert_after(SNAME *_owner_, SNAME##_node *_node_, V element); \
|
||||
FMOD bool PFX##_insert_before(SNAME *_owner_, SNAME##_node *_node_, V element); \
|
||||
FMOD bool PFX##_remove_after(SNAME *_owner_, SNAME##_node *_node_); \
|
||||
FMOD bool PFX##_remove_current(SNAME *_owner_, SNAME##_node *_node_); \
|
||||
FMOD bool PFX##_remove_before(SNAME *_owner_, SNAME##_node *_node_); \
|
||||
/* Node Access Relative to a Linked List Node */ \
|
||||
FMOD SNAME##_node *PFX##_next_node(SNAME##_node *_node_); \
|
||||
FMOD SNAME##_node *PFX##_prev_node(SNAME##_node *_node_); \
|
||||
\
|
||||
FMOD void PFX##_iter_new(SNAME##_iter *iter, SNAME *target); \
|
||||
/* Iterator Functions */ \
|
||||
/* Iterator Allocation and Deallocation */ \
|
||||
FMOD SNAME##_iter *PFX##_iter_new(SNAME *target); \
|
||||
FMOD void PFX##_iter_free(SNAME##_iter *iter); \
|
||||
/* Iterator Initialization */ \
|
||||
FMOD void PFX##_iter_init(SNAME##_iter *iter, SNAME *target); \
|
||||
/* Iterator State */ \
|
||||
FMOD bool PFX##_iter_start(SNAME##_iter *iter); \
|
||||
FMOD bool PFX##_iter_end(SNAME##_iter *iter); \
|
||||
FMOD void PFX##_iter_tostart(SNAME##_iter *iter); \
|
||||
FMOD void PFX##_iter_toend(SNAME##_iter *iter); \
|
||||
FMOD bool PFX##_iter_next(SNAME##_iter *iter, V *result, size_t *index); \
|
||||
FMOD bool PFX##_iter_prev(SNAME##_iter *iter, V *result, size_t *index); \
|
||||
/* Iterator Movement */ \
|
||||
FMOD void PFX##_iter_to_start(SNAME##_iter *iter); \
|
||||
FMOD void PFX##_iter_to_end(SNAME##_iter *iter); \
|
||||
FMOD bool PFX##_iter_next(SNAME##_iter *iter); \
|
||||
FMOD bool PFX##_iter_prev(SNAME##_iter *iter); \
|
||||
/* Iterator Access */ \
|
||||
FMOD V PFX##_iter_value(SNAME##_iter *iter); \
|
||||
FMOD V *PFX##_iter_rvalue(SNAME##_iter *iter); \
|
||||
FMOD size_t PFX##_iter_index(SNAME##_iter *iter); \
|
||||
FMOD SNAME##_node *PFX##_iter_node(SNAME##_iter *iter); \
|
||||
\
|
||||
/* SOURCE ********************************************************************/
|
||||
#define LINKEDLIST_GENERATE_SOURCE(PFX, SNAME, FMOD, V) \
|
||||
\
|
||||
/* Implementation Detail Functions */ \
|
||||
SNAME##_iter PFX##_impl_it_start(SNAME *_list_); \
|
||||
SNAME##_iter PFX##_impl_it_end(SNAME *_list_); \
|
||||
\
|
||||
FMOD SNAME *PFX##_new(void) \
|
||||
{ \
|
||||
SNAME *_list_ = malloc(sizeof(SNAME)); \
|
||||
@@ -120,6 +176,9 @@
|
||||
_list_->head = NULL; \
|
||||
_list_->tail = NULL; \
|
||||
\
|
||||
_list_->it_start = PFX##_impl_it_start; \
|
||||
_list_->it_end = PFX##_impl_it_end; \
|
||||
\
|
||||
return _list_; \
|
||||
} \
|
||||
\
|
||||
@@ -148,21 +207,21 @@
|
||||
\
|
||||
FMOD bool PFX##_push_front(SNAME *_list_, V element) \
|
||||
{ \
|
||||
SNAME##_node *node = PFX##_new_node(_list_, element); \
|
||||
SNAME##_node *_node_ = PFX##_new_node(element); \
|
||||
\
|
||||
if (!node) \
|
||||
if (!_node_) \
|
||||
return false; \
|
||||
\
|
||||
if (PFX##_empty(_list_)) \
|
||||
{ \
|
||||
_list_->head = node; \
|
||||
_list_->tail = node; \
|
||||
_list_->head = _node_; \
|
||||
_list_->tail = _node_; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
node->next = _list_->head; \
|
||||
_list_->head->prev = node; \
|
||||
_list_->head = node; \
|
||||
_node_->next = _list_->head; \
|
||||
_list_->head->prev = _node_; \
|
||||
_list_->head = _node_; \
|
||||
} \
|
||||
\
|
||||
_list_->count++; \
|
||||
@@ -184,17 +243,17 @@
|
||||
return PFX##_push_back(_list_, element); \
|
||||
} \
|
||||
\
|
||||
SNAME##_node *node = PFX##_new_node(_list_, element); \
|
||||
SNAME##_node *_node_ = PFX##_new_node(element); \
|
||||
\
|
||||
if (!node) \
|
||||
if (!_node_) \
|
||||
return false; \
|
||||
\
|
||||
SNAME##_node *scan = PFX##_get_node(_list_, index - 1); \
|
||||
\
|
||||
node->next = scan->next; \
|
||||
node->prev = scan; \
|
||||
node->next->prev = node; \
|
||||
node->prev->next = node; \
|
||||
_node_->next = scan->next; \
|
||||
_node_->prev = scan; \
|
||||
_node_->next->prev = _node_; \
|
||||
_node_->prev->next = _node_; \
|
||||
\
|
||||
_list_->count++; \
|
||||
\
|
||||
@@ -203,21 +262,21 @@
|
||||
\
|
||||
FMOD bool PFX##_push_back(SNAME *_list_, V element) \
|
||||
{ \
|
||||
SNAME##_node *node = PFX##_new_node(_list_, element); \
|
||||
SNAME##_node *_node_ = PFX##_new_node(element); \
|
||||
\
|
||||
if (!node) \
|
||||
if (!_node_) \
|
||||
return false; \
|
||||
\
|
||||
if (PFX##_empty(_list_)) \
|
||||
{ \
|
||||
_list_->head = node; \
|
||||
_list_->tail = node; \
|
||||
_list_->head = _node_; \
|
||||
_list_->tail = _node_; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
node->prev = _list_->tail; \
|
||||
_list_->tail->next = node; \
|
||||
_list_->tail = node; \
|
||||
_node_->prev = _list_->tail; \
|
||||
_list_->tail->next = _node_; \
|
||||
_list_->tail = _node_; \
|
||||
} \
|
||||
\
|
||||
_list_->count++; \
|
||||
@@ -230,10 +289,10 @@
|
||||
if (PFX##_empty(_list_)) \
|
||||
return false; \
|
||||
\
|
||||
SNAME##_node *node = _list_->head; \
|
||||
SNAME##_node *_node_ = _list_->head; \
|
||||
_list_->head = _list_->head->next; \
|
||||
\
|
||||
free(node); \
|
||||
free(_node_); \
|
||||
\
|
||||
if (_list_->head == NULL) \
|
||||
_list_->tail = NULL; \
|
||||
@@ -262,15 +321,15 @@
|
||||
return PFX##_pop_back(_list_); \
|
||||
} \
|
||||
\
|
||||
SNAME##_node *node = PFX##_get_node(_list_, index); \
|
||||
SNAME##_node *_node_ = PFX##_get_node(_list_, index); \
|
||||
\
|
||||
if (!node) \
|
||||
if (!_node_) \
|
||||
return false; \
|
||||
\
|
||||
node->next->prev = node->prev; \
|
||||
node->prev->next = node->next; \
|
||||
_node_->next->prev = _node_->prev; \
|
||||
_node_->prev->next = _node_->next; \
|
||||
\
|
||||
free(node); \
|
||||
free(_node_); \
|
||||
\
|
||||
_list_->count--; \
|
||||
\
|
||||
@@ -282,10 +341,10 @@
|
||||
if (PFX##_empty(_list_)) \
|
||||
return false; \
|
||||
\
|
||||
SNAME##_node *node = _list_->tail; \
|
||||
SNAME##_node *_node_ = _list_->tail; \
|
||||
_list_->tail = _list_->tail->prev; \
|
||||
\
|
||||
free(node); \
|
||||
free(_node_); \
|
||||
\
|
||||
if (_list_->tail == NULL) \
|
||||
_list_->head = NULL; \
|
||||
@@ -337,6 +396,22 @@
|
||||
return scan->data; \
|
||||
} \
|
||||
\
|
||||
FMOD V *PFX##_get_ref(SNAME *_list_, size_t index) \
|
||||
{ \
|
||||
if (index >= _list_->count) \
|
||||
return NULL; \
|
||||
\
|
||||
if (PFX##_empty(_list_)) \
|
||||
return NULL; \
|
||||
\
|
||||
SNAME##_node *scan = PFX##_get_node(_list_, index); \
|
||||
\
|
||||
if (scan == NULL) \
|
||||
return NULL; \
|
||||
\
|
||||
return &(scan->data); \
|
||||
} \
|
||||
\
|
||||
FMOD V PFX##_back(SNAME *_list_) \
|
||||
{ \
|
||||
if (PFX##_empty(_list_)) \
|
||||
@@ -345,6 +420,21 @@
|
||||
return _list_->tail->data; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_contains(SNAME *_list_, V element, int (*comparator)(V, V)) \
|
||||
{ \
|
||||
SNAME##_node *scan = _list_->head; \
|
||||
\
|
||||
while (scan != NULL) \
|
||||
{ \
|
||||
if (comparator(scan->data, element) == 0) \
|
||||
return true; \
|
||||
\
|
||||
scan = scan->next; \
|
||||
} \
|
||||
\
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_empty(SNAME *_list_) \
|
||||
{ \
|
||||
return _list_->count == 0; \
|
||||
@@ -355,22 +445,26 @@
|
||||
return _list_->count; \
|
||||
} \
|
||||
\
|
||||
FMOD SNAME##_node *PFX##_new_node(SNAME *_owner_, V element) \
|
||||
FMOD SNAME##_node *PFX##_new_node(V element) \
|
||||
{ \
|
||||
SNAME##_node *node = malloc(sizeof(SNAME##_node)); \
|
||||
SNAME##_node *_node_ = malloc(sizeof(SNAME##_node)); \
|
||||
\
|
||||
if (!node) \
|
||||
if (!_node_) \
|
||||
return NULL; \
|
||||
\
|
||||
node->owner = _owner_; \
|
||||
node->data = element; \
|
||||
node->next = NULL; \
|
||||
node->prev = NULL; \
|
||||
_node_->data = element; \
|
||||
_node_->next = NULL; \
|
||||
_node_->prev = NULL; \
|
||||
\
|
||||
return node; \
|
||||
return _node_; \
|
||||
} \
|
||||
\
|
||||
FMOD SNAME##_node *PFX##_front_node(SNAME *_list_) \
|
||||
FMOD void PFX##_free_node(SNAME##_node *_node_) \
|
||||
{ \
|
||||
free(_node_); \
|
||||
} \
|
||||
\
|
||||
FMOD SNAME##_node *PFX##_head(SNAME *_list_) \
|
||||
{ \
|
||||
return _list_->head; \
|
||||
} \
|
||||
@@ -383,147 +477,168 @@
|
||||
if (PFX##_empty(_list_)) \
|
||||
return NULL; \
|
||||
\
|
||||
SNAME##_node *scan = NULL; \
|
||||
SNAME##_node *_node_ = NULL; \
|
||||
\
|
||||
if (index <= _list_->count / 2) \
|
||||
{ \
|
||||
scan = _list_->head; \
|
||||
_node_ = _list_->head; \
|
||||
for (size_t i = 0; i < index; i++) \
|
||||
{ \
|
||||
scan = scan->next; \
|
||||
_node_ = _node_->next; \
|
||||
} \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
scan = _list_->tail; \
|
||||
_node_ = _list_->tail; \
|
||||
for (size_t i = _list_->count - 1; i > index; i--) \
|
||||
{ \
|
||||
scan = scan->prev; \
|
||||
_node_ = _node_->prev; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
return scan; \
|
||||
return _node_; \
|
||||
} \
|
||||
\
|
||||
FMOD SNAME##_node *PFX##_back_node(SNAME *_list_) \
|
||||
FMOD SNAME##_node *PFX##_tail(SNAME *_list_) \
|
||||
{ \
|
||||
return _list_->tail; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_insert_nxt(SNAME##_node *node, V element) \
|
||||
FMOD bool PFX##_insert_after(SNAME *_owner_, SNAME##_node *_node_, V element) \
|
||||
{ \
|
||||
SNAME##_node *new_node = PFX##_new_node(node->owner, element); \
|
||||
SNAME##_node *new_node = PFX##_new_node(element); \
|
||||
\
|
||||
if (!new_node) \
|
||||
return false; \
|
||||
\
|
||||
new_node->next = node->next; \
|
||||
if (node->next != NULL) \
|
||||
node->next->prev = new_node; \
|
||||
new_node->next = _node_->next; \
|
||||
\
|
||||
if (_node_->next != NULL) \
|
||||
_node_->next->prev = new_node; \
|
||||
else \
|
||||
node->owner->tail = new_node; \
|
||||
_owner_->tail = new_node; \
|
||||
\
|
||||
new_node->prev = node; \
|
||||
node->next = new_node; \
|
||||
new_node->prev = _node_; \
|
||||
_node_->next = new_node; \
|
||||
\
|
||||
node->owner->count++; \
|
||||
_owner_->count++; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_insert_prv(SNAME##_node *node, V element) \
|
||||
FMOD bool PFX##_insert_before(SNAME *_owner_, SNAME##_node *_node_, V element) \
|
||||
{ \
|
||||
SNAME##_node *new_node = PFX##_new_node(node->owner, element); \
|
||||
SNAME##_node *new_node = PFX##_new_node(element); \
|
||||
\
|
||||
if (!new_node) \
|
||||
return false; \
|
||||
\
|
||||
new_node->prev = node->prev; \
|
||||
if (node->prev != NULL) \
|
||||
node->prev->next = new_node; \
|
||||
new_node->prev = _node_->prev; \
|
||||
\
|
||||
if (_node_->prev != NULL) \
|
||||
_node_->prev->next = new_node; \
|
||||
else \
|
||||
node->owner->head = new_node; \
|
||||
_owner_->head = new_node; \
|
||||
\
|
||||
new_node->next = node; \
|
||||
node->prev = new_node; \
|
||||
new_node->next = _node_; \
|
||||
_node_->prev = new_node; \
|
||||
\
|
||||
node->owner->count++; \
|
||||
_owner_->count++; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_remove_nxt(SNAME##_node *node) \
|
||||
FMOD bool PFX##_remove_after(SNAME *_owner_, SNAME##_node *_node_) \
|
||||
{ \
|
||||
if (node->next == NULL) \
|
||||
if (_node_->next == NULL) \
|
||||
return false; \
|
||||
\
|
||||
SNAME##_node *tmp = node->next; \
|
||||
SNAME##_node *tmp = _node_->next; \
|
||||
\
|
||||
if (node->next != NULL) \
|
||||
if (tmp->next != NULL) \
|
||||
{ \
|
||||
node->next = node->next->next; \
|
||||
node->next->prev = node; \
|
||||
_node_->next = _node_->next->next; \
|
||||
_node_->next->prev = _node_; \
|
||||
} \
|
||||
else \
|
||||
node->owner->tail = node; \
|
||||
\
|
||||
node->owner->count--; \
|
||||
_owner_->tail = _node_; \
|
||||
\
|
||||
free(tmp); \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_remove_cur(SNAME##_node *node) \
|
||||
{ \
|
||||
if (node->prev != NULL) \
|
||||
node->prev->next = node->next; \
|
||||
else \
|
||||
node->owner->head = node->next; \
|
||||
\
|
||||
if (node->next != NULL) \
|
||||
node->next->prev = node->prev; \
|
||||
else \
|
||||
node->owner->tail = node->prev; \
|
||||
\
|
||||
node->owner->count--; \
|
||||
\
|
||||
free(node); \
|
||||
_owner_->count--; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_remove_prv(SNAME##_node *node) \
|
||||
FMOD bool PFX##_remove_current(SNAME *_owner_, SNAME##_node *_node_) \
|
||||
{ \
|
||||
if (node->prev == NULL) \
|
||||
if (_node_->prev != NULL) \
|
||||
_node_->prev->next = _node_->next; \
|
||||
else \
|
||||
_owner_->head = _node_->next; \
|
||||
\
|
||||
if (_node_->next != NULL) \
|
||||
_node_->next->prev = _node_->prev; \
|
||||
else \
|
||||
_owner_->tail = _node_->prev; \
|
||||
\
|
||||
free(_node_); \
|
||||
\
|
||||
_owner_->count--; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_remove_before(SNAME *_owner_, SNAME##_node *_node_) \
|
||||
{ \
|
||||
if (_node_->prev == NULL) \
|
||||
return false; \
|
||||
\
|
||||
SNAME##_node *tmp = node->prev; \
|
||||
SNAME##_node *tmp = _node_->prev; \
|
||||
\
|
||||
if (node->prev != NULL) \
|
||||
if (tmp->prev != NULL) \
|
||||
{ \
|
||||
node->prev = node->prev->prev; \
|
||||
node->prev->next = node; \
|
||||
_node_->prev = _node_->prev->prev; \
|
||||
_node_->prev->next = _node_; \
|
||||
} \
|
||||
else \
|
||||
node->owner->head = node; \
|
||||
_owner_->head = _node_; \
|
||||
\
|
||||
free(tmp); \
|
||||
\
|
||||
_owner_->count--; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD SNAME##_node *PFX##_next_node(SNAME##_node *node) \
|
||||
FMOD SNAME##_node *PFX##_next_node(SNAME##_node *_node_) \
|
||||
{ \
|
||||
return node->next; \
|
||||
return _node_->next; \
|
||||
} \
|
||||
\
|
||||
FMOD SNAME##_node *PFX##_prev_node(SNAME##_node *node) \
|
||||
FMOD SNAME##_node *PFX##_prev_node(SNAME##_node *_node_) \
|
||||
{ \
|
||||
return node->prev; \
|
||||
return _node_->prev; \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_iter_new(SNAME##_iter *iter, SNAME *target) \
|
||||
FMOD SNAME##_iter *PFX##_iter_new(SNAME *target) \
|
||||
{ \
|
||||
SNAME##_iter *iter = malloc(sizeof(SNAME##_iter)); \
|
||||
\
|
||||
if (!iter) \
|
||||
return NULL; \
|
||||
\
|
||||
PFX##_iter_init(iter, target); \
|
||||
\
|
||||
return iter; \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_iter_free(SNAME##_iter *iter) \
|
||||
{ \
|
||||
free(iter); \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_iter_init(SNAME##_iter *iter, SNAME *target) \
|
||||
{ \
|
||||
iter->target = target; \
|
||||
iter->cursor = target->head; \
|
||||
@@ -534,15 +649,15 @@
|
||||
\
|
||||
FMOD bool PFX##_iter_start(SNAME##_iter *iter) \
|
||||
{ \
|
||||
return iter->cursor->prev == NULL && iter->start; \
|
||||
return PFX##_empty(iter->target) || iter->start; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_iter_end(SNAME##_iter *iter) \
|
||||
{ \
|
||||
return iter->cursor->next == NULL && iter->end; \
|
||||
return PFX##_empty(iter->target) || iter->end; \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_iter_tostart(SNAME##_iter *iter) \
|
||||
FMOD void PFX##_iter_to_start(SNAME##_iter *iter) \
|
||||
{ \
|
||||
iter->cursor = iter->target->head; \
|
||||
iter->index = 0; \
|
||||
@@ -550,7 +665,7 @@
|
||||
iter->end = PFX##_empty(iter->target); \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_iter_toend(SNAME##_iter *iter) \
|
||||
FMOD void PFX##_iter_to_end(SNAME##_iter *iter) \
|
||||
{ \
|
||||
iter->cursor = iter->target->tail; \
|
||||
iter->index = iter->target->count - 1; \
|
||||
@@ -558,14 +673,12 @@
|
||||
iter->end = true; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_iter_next(SNAME##_iter *iter, V *result, size_t *index) \
|
||||
FMOD bool PFX##_iter_next(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (iter->end) \
|
||||
return false; \
|
||||
\
|
||||
*index = iter->index; \
|
||||
*result = iter->cursor->data; \
|
||||
iter->start = false; \
|
||||
iter->start = PFX##_empty(iter->target); \
|
||||
\
|
||||
if (iter->cursor->next == NULL) \
|
||||
iter->end = true; \
|
||||
@@ -578,14 +691,12 @@
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_iter_prev(SNAME##_iter *iter, V *result, size_t *index) \
|
||||
FMOD bool PFX##_iter_prev(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (iter->start) \
|
||||
return false; \
|
||||
\
|
||||
*index = iter->index; \
|
||||
*result = iter->cursor->data; \
|
||||
iter->end = false; \
|
||||
iter->end = PFX##_empty(iter->target); \
|
||||
\
|
||||
if (iter->cursor->prev == NULL) \
|
||||
iter->start = true; \
|
||||
@@ -596,6 +707,52 @@
|
||||
} \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD V PFX##_iter_value(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (PFX##_empty(iter->target)) \
|
||||
return 0; \
|
||||
\
|
||||
return iter->cursor->data; \
|
||||
} \
|
||||
\
|
||||
FMOD V *PFX##_iter_rvalue(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (PFX##_empty(iter->target)) \
|
||||
return NULL; \
|
||||
\
|
||||
return &(iter->cursor->data); \
|
||||
} \
|
||||
\
|
||||
FMOD size_t PFX##_iter_index(SNAME##_iter *iter) \
|
||||
{ \
|
||||
return iter->index; \
|
||||
} \
|
||||
\
|
||||
FMOD SNAME##_node *PFX##_iter_node(SNAME##_iter *iter) \
|
||||
{ \
|
||||
return iter->cursor; \
|
||||
} \
|
||||
\
|
||||
SNAME##_iter PFX##_impl_it_start(SNAME *_list_) \
|
||||
{ \
|
||||
SNAME##_iter iter; \
|
||||
\
|
||||
PFX##_iter_init(&iter, _list_); \
|
||||
PFX##_iter_to_start(&iter); \
|
||||
\
|
||||
return iter; \
|
||||
} \
|
||||
\
|
||||
SNAME##_iter PFX##_impl_it_end(SNAME *_list_) \
|
||||
{ \
|
||||
SNAME##_iter iter; \
|
||||
\
|
||||
PFX##_iter_init(&iter, _list_); \
|
||||
PFX##_iter_to_end(&iter); \
|
||||
\
|
||||
return iter; \
|
||||
}
|
||||
|
||||
#endif /* CMC_LINKEDLIST_H */
|
||||
+620
-359
@@ -37,367 +37,628 @@
|
||||
#define LIST_GENERATE_SOURCE_PUBLIC(PFX, SNAME, FMOD, K, V) \
|
||||
LIST_GENERATE_SOURCE(PFX, SNAME, FMOD, V)
|
||||
/* STRUCT ********************************************************************/
|
||||
#define LIST_GENERATE_STRUCT(PFX, SNAME, FMOD, V) \
|
||||
\
|
||||
struct SNAME##_s \
|
||||
{ \
|
||||
V *buffer; \
|
||||
size_t capacity; \
|
||||
size_t count; \
|
||||
}; \
|
||||
\
|
||||
struct SNAME##_iter_s \
|
||||
{ \
|
||||
struct SNAME##_s *target; \
|
||||
size_t cursor; \
|
||||
bool start; \
|
||||
bool end; \
|
||||
}; \
|
||||
\
|
||||
#define LIST_GENERATE_STRUCT(PFX, SNAME, FMOD, V)
|
||||
|
||||
/* HEADER ********************************************************************/
|
||||
#define LIST_GENERATE_HEADER(PFX, SNAME, FMOD, V) \
|
||||
\
|
||||
typedef struct SNAME##_s SNAME; \
|
||||
typedef struct SNAME##_iter_s SNAME##_iter; \
|
||||
\
|
||||
FMOD SNAME *PFX##_new(size_t size); \
|
||||
FMOD void PFX##_clear(SNAME *_list_); \
|
||||
FMOD void PFX##_free(SNAME *_list_); \
|
||||
FMOD bool PFX##_push_front(SNAME *_list_, V element); \
|
||||
FMOD bool PFX##_push(SNAME *_list_, V element, size_t index); \
|
||||
FMOD bool PFX##_push_back(SNAME *_list_, V element); \
|
||||
FMOD bool PFX##_pop_front(SNAME *_list_); \
|
||||
FMOD bool PFX##_pop(SNAME *_list_, size_t index); \
|
||||
FMOD bool PFX##_pop_back(SNAME *_list_); \
|
||||
FMOD bool PFX##_push_if(SNAME *_list_, V element, size_t index, bool condition); \
|
||||
FMOD bool PFX##_pop_if(SNAME *_list_, size_t index, bool condition); \
|
||||
FMOD V PFX##_front(SNAME *_list_); \
|
||||
FMOD V PFX##_get(SNAME *_list_, size_t index); \
|
||||
FMOD V PFX##_back(SNAME *_list_); \
|
||||
FMOD bool PFX##_empty(SNAME *_list_); \
|
||||
FMOD bool PFX##_full(SNAME *_list_); \
|
||||
FMOD size_t PFX##_count(SNAME *_list_); \
|
||||
FMOD size_t PFX##_capacity(SNAME *_list_); \
|
||||
\
|
||||
FMOD void PFX##_iter_new(SNAME##_iter *iter, SNAME *target); \
|
||||
FMOD bool PFX##_iter_start(SNAME##_iter *iter); \
|
||||
FMOD bool PFX##_iter_end(SNAME##_iter *iter); \
|
||||
FMOD void PFX##_iter_tostart(SNAME##_iter *iter); \
|
||||
FMOD void PFX##_iter_toend(SNAME##_iter *iter); \
|
||||
FMOD bool PFX##_iter_next(SNAME##_iter *iter, V *result, size_t *index); \
|
||||
FMOD bool PFX##_iter_prev(SNAME##_iter *iter, V *result, size_t *index); \
|
||||
\
|
||||
#define LIST_GENERATE_HEADER(PFX, SNAME, FMOD, V) \
|
||||
\
|
||||
/* List Structure */ \
|
||||
typedef struct SNAME##_s \
|
||||
{ \
|
||||
/* Dynamic array of elements */ \
|
||||
V *buffer; \
|
||||
\
|
||||
/* Current array capacity */ \
|
||||
size_t capacity; \
|
||||
\
|
||||
/* Current amount of elements */ \
|
||||
size_t count; \
|
||||
\
|
||||
/* Function that returns an iterator to the start of the list */ \
|
||||
struct SNAME##_iter_s (*it_start)(struct SNAME##_s *); \
|
||||
\
|
||||
/* Function that returns an iterator to the end of the list */ \
|
||||
struct SNAME##_iter_s (*it_end)(struct SNAME##_s *); \
|
||||
\
|
||||
} SNAME, *SNAME##_ptr; \
|
||||
\
|
||||
/* List Iterator */ \
|
||||
typedef struct SNAME##_iter_s \
|
||||
{ \
|
||||
/* Target list */ \
|
||||
struct SNAME##_s *target; \
|
||||
\
|
||||
/* Cursor's position (index) */ \
|
||||
size_t cursor; \
|
||||
\
|
||||
/* If the iterator has reached the start of the iteration */ \
|
||||
bool start; \
|
||||
\
|
||||
/* If the iterator has reached the end of the iteration */ \
|
||||
bool end; \
|
||||
\
|
||||
} SNAME##_iter, *SNAME##_iter_ptr; \
|
||||
\
|
||||
/* Collection Functions */ \
|
||||
/* Collection Allocation and Deallocation */ \
|
||||
FMOD SNAME *PFX##_new(size_t capacity); \
|
||||
FMOD SNAME *PFX##_new_from(V *elements, size_t size); \
|
||||
FMOD void PFX##_clear(SNAME *_list_); \
|
||||
FMOD void PFX##_free(SNAME *_list_); \
|
||||
/* Collection Input and Output */ \
|
||||
FMOD bool PFX##_push_front(SNAME *_list_, V element); \
|
||||
FMOD bool PFX##_push(SNAME *_list_, V element, size_t index); \
|
||||
FMOD bool PFX##_push_back(SNAME *_list_, V element); \
|
||||
FMOD bool PFX##_pop_front(SNAME *_list_); \
|
||||
FMOD bool PFX##_pop(SNAME *_list_, size_t index); \
|
||||
FMOD bool PFX##_pop_back(SNAME *_list_); \
|
||||
/* Conditional Input and Output */ \
|
||||
FMOD bool PFX##_push_if(SNAME *_list_, V element, size_t index, bool condition); \
|
||||
FMOD bool PFX##_pop_if(SNAME *_list_, size_t index, bool condition); \
|
||||
/* Collection Range Input and Output */ \
|
||||
FMOD bool PFX##_prepend(SNAME *_list_, V *elements, size_t size); \
|
||||
FMOD bool PFX##_insert(SNAME *_list_, V *elements, size_t size, size_t index); \
|
||||
FMOD bool PFX##_append(SNAME *_list_, V *elements, size_t size); \
|
||||
FMOD bool PFX##_remove(SNAME *_list_, size_t from, size_t to); \
|
||||
FMOD SNAME *PFX##_extract(SNAME *_list_, size_t from, size_t to); \
|
||||
/* Element Access */ \
|
||||
FMOD V PFX##_front(SNAME *_list_); \
|
||||
FMOD V PFX##_get(SNAME *_list_, size_t index); \
|
||||
FMOD V *PFX##_get_ref(SNAME *_list_, size_t index); \
|
||||
FMOD V PFX##_back(SNAME *_list_); \
|
||||
FMOD size_t PFX##_indexof(SNAME *_list_, V element, int (*comparator)(V, V), bool from_start); \
|
||||
/* Collection State */ \
|
||||
FMOD bool PFX##_contains(SNAME *_list_, V element, int (*comparator)(V, V)); \
|
||||
FMOD bool PFX##_empty(SNAME *_list_); \
|
||||
FMOD bool PFX##_full(SNAME *_list_); \
|
||||
FMOD size_t PFX##_count(SNAME *_list_); \
|
||||
FMOD bool PFX##_fits(SNAME *_list_, size_t size); \
|
||||
FMOD size_t PFX##_capacity(SNAME *_list_); \
|
||||
\
|
||||
/* Iterator Functions */ \
|
||||
/* Iterator Allocation and Deallocation */ \
|
||||
FMOD SNAME##_iter *PFX##_iter_new(SNAME *target); \
|
||||
FMOD void PFX##_iter_free(SNAME##_iter *iter); \
|
||||
/* Iterator Initialization */ \
|
||||
FMOD void PFX##_iter_init(SNAME##_iter *iter, SNAME *target); \
|
||||
/* Iterator State */ \
|
||||
FMOD bool PFX##_iter_start(SNAME##_iter *iter); \
|
||||
FMOD bool PFX##_iter_end(SNAME##_iter *iter); \
|
||||
/* Iterator Movement */ \
|
||||
FMOD void PFX##_iter_to_start(SNAME##_iter *iter); \
|
||||
FMOD void PFX##_iter_to_end(SNAME##_iter *iter); \
|
||||
FMOD bool PFX##_iter_next(SNAME##_iter *iter); \
|
||||
FMOD bool PFX##_iter_prev(SNAME##_iter *iter); \
|
||||
/* Iterator Access */ \
|
||||
FMOD V PFX##_iter_value(SNAME##_iter *iter); \
|
||||
FMOD V *PFX##_iter_rvalue(SNAME##_iter *iter); \
|
||||
FMOD size_t PFX##_iter_index(SNAME##_iter *iter); \
|
||||
\
|
||||
/* SOURCE ********************************************************************/
|
||||
#define LIST_GENERATE_SOURCE(PFX, SNAME, FMOD, V) \
|
||||
\
|
||||
FMOD bool PFX##_grow(SNAME *_list_); \
|
||||
\
|
||||
FMOD SNAME *PFX##_new(size_t size) \
|
||||
{ \
|
||||
if (size < 1) \
|
||||
return NULL; \
|
||||
\
|
||||
SNAME *_list_ = malloc(sizeof(SNAME)); \
|
||||
\
|
||||
if (!_list_) \
|
||||
return NULL; \
|
||||
\
|
||||
_list_->buffer = malloc(sizeof(V) * size); \
|
||||
\
|
||||
if (!_list_->buffer) \
|
||||
{ \
|
||||
free(_list_); \
|
||||
return NULL; \
|
||||
} \
|
||||
\
|
||||
memset(_list_->buffer, 0, sizeof(V) * size); \
|
||||
\
|
||||
for (size_t i = 0; i < size; i++) \
|
||||
{ \
|
||||
_list_->buffer[i] = 0; \
|
||||
} \
|
||||
\
|
||||
_list_->capacity = size; \
|
||||
_list_->count = 0; \
|
||||
\
|
||||
return _list_; \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_clear(SNAME *_list_) \
|
||||
{ \
|
||||
memset(_list_->buffer, 0, sizeof(V) * _list_->capacity); \
|
||||
\
|
||||
_list_->count = 0; \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_free(SNAME *_list_) \
|
||||
{ \
|
||||
free(_list_->buffer); \
|
||||
free(_list_); \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_push_front(SNAME *_list_, V element) \
|
||||
{ \
|
||||
if (PFX##_full(_list_)) \
|
||||
{ \
|
||||
if (!PFX##_grow(_list_)) \
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
if (!PFX##_empty(_list_)) \
|
||||
{ \
|
||||
for (size_t i = _list_->count; i > 0; i--) \
|
||||
{ \
|
||||
_list_->buffer[i] = _list_->buffer[i - 1]; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
_list_->buffer[0] = element; \
|
||||
\
|
||||
_list_->count++; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_push(SNAME *_list_, V element, size_t index) \
|
||||
{ \
|
||||
if (index > _list_->count) \
|
||||
return false; \
|
||||
\
|
||||
if (index == 0) \
|
||||
{ \
|
||||
return PFX##_push_front(_list_, element); \
|
||||
} \
|
||||
else if (index == _list_->count) \
|
||||
{ \
|
||||
return PFX##_push_back(_list_, element); \
|
||||
} \
|
||||
\
|
||||
if (PFX##_full(_list_)) \
|
||||
{ \
|
||||
if (!PFX##_grow(_list_)) \
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
for (size_t i = _list_->count; i > index; i--) \
|
||||
{ \
|
||||
_list_->buffer[i] = _list_->buffer[i - 1]; \
|
||||
} \
|
||||
\
|
||||
_list_->buffer[index] = element; \
|
||||
\
|
||||
_list_->count++; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_push_back(SNAME *_list_, V element) \
|
||||
{ \
|
||||
if (PFX##_full(_list_)) \
|
||||
{ \
|
||||
if (!PFX##_grow(_list_)) \
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
_list_->buffer[_list_->count++] = element; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_pop_front(SNAME *_list_) \
|
||||
{ \
|
||||
if (PFX##_empty(_list_)) \
|
||||
return false; \
|
||||
\
|
||||
for (size_t i = 0; i < _list_->count; i++) \
|
||||
{ \
|
||||
_list_->buffer[i] = _list_->buffer[i + 1]; \
|
||||
} \
|
||||
\
|
||||
_list_->buffer[--_list_->count] = 0; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_pop(SNAME *_list_, size_t index) \
|
||||
{ \
|
||||
if (PFX##_empty(_list_)) \
|
||||
return false; \
|
||||
\
|
||||
if (index >= _list_->count) \
|
||||
return false; \
|
||||
\
|
||||
if (index == 0) \
|
||||
{ \
|
||||
return PFX##_pop_front(_list_); \
|
||||
} \
|
||||
else if (index == _list_->count - 1) \
|
||||
{ \
|
||||
return PFX##_pop_back(_list_); \
|
||||
} \
|
||||
\
|
||||
for (size_t i = index; i < _list_->count - 1; i++) \
|
||||
{ \
|
||||
_list_->buffer[i] = _list_->buffer[i + 1]; \
|
||||
} \
|
||||
\
|
||||
_list_->buffer[--_list_->count] = 0; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_pop_back(SNAME *_list_) \
|
||||
{ \
|
||||
if (PFX##_empty(_list_)) \
|
||||
return false; \
|
||||
\
|
||||
_list_->buffer[--_list_->count] = 0; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_push_if(SNAME *_list_, V element, size_t index, bool condition) \
|
||||
{ \
|
||||
if (condition) \
|
||||
return PFX##_push(_list_, element, index); \
|
||||
\
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_pop_if(SNAME *_list_, size_t index, bool condition) \
|
||||
{ \
|
||||
if (condition) \
|
||||
return PFX##_pop(_list_, index); \
|
||||
\
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
FMOD V PFX##_front(SNAME *_list_) \
|
||||
{ \
|
||||
if (PFX##_empty(_list_)) \
|
||||
return 0; \
|
||||
\
|
||||
return _list_->buffer[0]; \
|
||||
} \
|
||||
\
|
||||
FMOD V PFX##_get(SNAME *_list_, size_t index) \
|
||||
{ \
|
||||
if (index >= _list_->count) \
|
||||
return 0; \
|
||||
\
|
||||
if (PFX##_empty(_list_)) \
|
||||
return 0; \
|
||||
\
|
||||
return _list_->buffer[index]; \
|
||||
} \
|
||||
\
|
||||
FMOD V PFX##_back(SNAME *_list_) \
|
||||
{ \
|
||||
if (PFX##_empty(_list_)) \
|
||||
return 0; \
|
||||
\
|
||||
return _list_->buffer[_list_->count - 1]; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_empty(SNAME *_list_) \
|
||||
{ \
|
||||
return _list_->count == 0; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_full(SNAME *_list_) \
|
||||
{ \
|
||||
return _list_->count >= _list_->capacity; \
|
||||
} \
|
||||
\
|
||||
FMOD size_t PFX##_count(SNAME *_list_) \
|
||||
{ \
|
||||
return _list_->count; \
|
||||
} \
|
||||
\
|
||||
FMOD size_t PFX##_capacity(SNAME *_list_) \
|
||||
{ \
|
||||
return _list_->capacity; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_grow(SNAME *_list_) \
|
||||
{ \
|
||||
size_t new_capacity = _list_->capacity * 2; \
|
||||
\
|
||||
V *new_buffer = realloc(_list_->buffer, sizeof(V) * new_capacity); \
|
||||
\
|
||||
if (!new_buffer) \
|
||||
return false; \
|
||||
\
|
||||
_list_->buffer = new_buffer; \
|
||||
_list_->capacity = new_capacity; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_iter_new(SNAME##_iter *iter, SNAME *target) \
|
||||
{ \
|
||||
iter->target = target; \
|
||||
iter->cursor = 0; \
|
||||
iter->start = true; \
|
||||
iter->end = PFX##_empty(target); \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_iter_start(SNAME##_iter *iter) \
|
||||
{ \
|
||||
return iter->cursor == 0 && iter->start; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_iter_end(SNAME##_iter *iter) \
|
||||
{ \
|
||||
return iter->cursor == iter->target->count - 1 && iter->end; \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_iter_tostart(SNAME##_iter *iter) \
|
||||
{ \
|
||||
iter->cursor = 0; \
|
||||
iter->start = true; \
|
||||
iter->end = PFX##_empty(iter->target); \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_iter_toend(SNAME##_iter *iter) \
|
||||
{ \
|
||||
iter->cursor = iter->target->count - 1; \
|
||||
iter->start = PFX##_empty(iter->target); \
|
||||
iter->end = true; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_iter_next(SNAME##_iter *iter, V *result, size_t *index) \
|
||||
{ \
|
||||
if (iter->end) \
|
||||
return false; \
|
||||
\
|
||||
*index = iter->cursor; \
|
||||
*result = iter->target->buffer[iter->cursor]; \
|
||||
iter->start = false; \
|
||||
\
|
||||
if (iter->cursor == iter->target->count - 1) \
|
||||
iter->end = true; \
|
||||
else \
|
||||
iter->cursor++; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_iter_prev(SNAME##_iter *iter, V *result, size_t *index) \
|
||||
{ \
|
||||
if (iter->start) \
|
||||
return false; \
|
||||
\
|
||||
*index = iter->cursor; \
|
||||
*result = iter->target->buffer[iter->cursor]; \
|
||||
iter->end = false; \
|
||||
\
|
||||
if (iter->cursor == 0) \
|
||||
iter->start = true; \
|
||||
else \
|
||||
iter->cursor--; \
|
||||
\
|
||||
return true; \
|
||||
#define LIST_GENERATE_SOURCE(PFX, SNAME, FMOD, V) \
|
||||
\
|
||||
/* Implementation Detail Functions */ \
|
||||
FMOD bool PFX##_impl_grow(SNAME *_list_, size_t required); \
|
||||
SNAME##_iter PFX##_impl_it_start(SNAME *_list_); \
|
||||
SNAME##_iter PFX##_impl_it_end(SNAME *_list_); \
|
||||
\
|
||||
FMOD SNAME *PFX##_new(size_t capacity) \
|
||||
{ \
|
||||
if (capacity < 1) \
|
||||
return NULL; \
|
||||
\
|
||||
SNAME *_list_ = malloc(sizeof(SNAME)); \
|
||||
\
|
||||
if (!_list_) \
|
||||
return NULL; \
|
||||
\
|
||||
_list_->buffer = malloc(capacity * sizeof(V)); \
|
||||
\
|
||||
if (!_list_->buffer) \
|
||||
{ \
|
||||
free(_list_); \
|
||||
return NULL; \
|
||||
} \
|
||||
\
|
||||
memset(_list_->buffer, 0, capacity * sizeof(V)); \
|
||||
\
|
||||
_list_->capacity = capacity; \
|
||||
_list_->count = 0; \
|
||||
\
|
||||
_list_->it_start = PFX##_impl_it_start; \
|
||||
_list_->it_end = PFX##_impl_it_end; \
|
||||
\
|
||||
return _list_; \
|
||||
} \
|
||||
\
|
||||
FMOD SNAME *PFX##_new_from(V *elements, size_t size) \
|
||||
{ \
|
||||
if (size == 0) \
|
||||
return NULL; \
|
||||
\
|
||||
SNAME *_list_ = PFX##_new(size + size / 2); \
|
||||
\
|
||||
if (!_list_) \
|
||||
return NULL; \
|
||||
\
|
||||
memcpy(_list_->buffer, elements, size * sizeof(V)); \
|
||||
\
|
||||
_list_->count = size; \
|
||||
\
|
||||
return _list_; \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_clear(SNAME *_list_) \
|
||||
{ \
|
||||
memset(_list_->buffer, 0, sizeof(V) * _list_->capacity); \
|
||||
\
|
||||
_list_->count = 0; \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_free(SNAME *_list_) \
|
||||
{ \
|
||||
free(_list_->buffer); \
|
||||
free(_list_); \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_push_front(SNAME *_list_, V element) \
|
||||
{ \
|
||||
if (PFX##_full(_list_)) \
|
||||
{ \
|
||||
if (!PFX##_impl_grow(_list_, _list_->count + 1)) \
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
if (!PFX##_empty(_list_)) \
|
||||
{ \
|
||||
memmove(_list_->buffer + 1, _list_->buffer, _list_->count * sizeof(V)); \
|
||||
} \
|
||||
\
|
||||
_list_->buffer[0] = element; \
|
||||
\
|
||||
_list_->count++; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_push(SNAME *_list_, V element, size_t index) \
|
||||
{ \
|
||||
if (index > _list_->count) \
|
||||
return false; \
|
||||
\
|
||||
if (index == 0) \
|
||||
{ \
|
||||
return PFX##_push_front(_list_, element); \
|
||||
} \
|
||||
else if (index == _list_->count) \
|
||||
{ \
|
||||
return PFX##_push_back(_list_, element); \
|
||||
} \
|
||||
\
|
||||
if (PFX##_full(_list_)) \
|
||||
{ \
|
||||
if (!PFX##_impl_grow(_list_, _list_->count + 1)) \
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
memmove(_list_->buffer + index + 1, _list_->buffer + index, (_list_->count - index) * sizeof(V)); \
|
||||
\
|
||||
_list_->buffer[index] = element; \
|
||||
\
|
||||
_list_->count++; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_push_back(SNAME *_list_, V element) \
|
||||
{ \
|
||||
if (PFX##_full(_list_)) \
|
||||
{ \
|
||||
if (!PFX##_impl_grow(_list_, _list_->count + 1)) \
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
_list_->buffer[_list_->count++] = element; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_pop_front(SNAME *_list_) \
|
||||
{ \
|
||||
if (PFX##_empty(_list_)) \
|
||||
return false; \
|
||||
\
|
||||
memmove(_list_->buffer, _list_->buffer + 1, _list_->count * sizeof(V)); \
|
||||
\
|
||||
_list_->buffer[--_list_->count] = 0; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_pop(SNAME *_list_, size_t index) \
|
||||
{ \
|
||||
if (PFX##_empty(_list_)) \
|
||||
return false; \
|
||||
\
|
||||
if (index >= _list_->count) \
|
||||
return false; \
|
||||
\
|
||||
if (index == 0) \
|
||||
{ \
|
||||
return PFX##_pop_front(_list_); \
|
||||
} \
|
||||
else if (index == _list_->count - 1) \
|
||||
{ \
|
||||
return PFX##_pop_back(_list_); \
|
||||
} \
|
||||
\
|
||||
memmove(_list_->buffer + index, _list_->buffer + index + 1, (_list_->count - index) * sizeof(V)); \
|
||||
\
|
||||
_list_->buffer[--_list_->count] = 0; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_pop_back(SNAME *_list_) \
|
||||
{ \
|
||||
if (PFX##_empty(_list_)) \
|
||||
return false; \
|
||||
\
|
||||
_list_->buffer[--_list_->count] = 0; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_push_if(SNAME *_list_, V element, size_t index, bool condition) \
|
||||
{ \
|
||||
if (condition) \
|
||||
return PFX##_push(_list_, element, index); \
|
||||
\
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_pop_if(SNAME *_list_, size_t index, bool condition) \
|
||||
{ \
|
||||
if (condition) \
|
||||
return PFX##_pop(_list_, index); \
|
||||
\
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_prepend(SNAME *_list_, V *elements, size_t size) \
|
||||
{ \
|
||||
if (size == 0) \
|
||||
return false; \
|
||||
\
|
||||
if (!PFX##_fits(_list_, size)) \
|
||||
{ \
|
||||
if (!PFX##_impl_grow(_list_, _list_->count + size)) \
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
memmove(_list_->buffer + size, _list_->buffer, _list_->count * sizeof(V)); \
|
||||
\
|
||||
memcpy(_list_->buffer, elements, size * sizeof(V)); \
|
||||
\
|
||||
_list_->count += size; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_insert(SNAME *_list_, V *elements, size_t size, size_t index) \
|
||||
{ \
|
||||
if (size == 0 || index > _list_->count) \
|
||||
return false; \
|
||||
\
|
||||
if (index == 0) \
|
||||
return PFX##_prepend(_list_, elements, size); \
|
||||
else if (index == _list_->count) \
|
||||
return PFX##_append(_list_, elements, size); \
|
||||
else \
|
||||
{ \
|
||||
if (!PFX##_fits(_list_, size)) \
|
||||
{ \
|
||||
if (!PFX##_impl_grow(_list_, _list_->count + size)) \
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
memmove(_list_->buffer + index + size, _list_->buffer + index, (_list_->count - index) * sizeof(V)); \
|
||||
\
|
||||
memcpy(_list_->buffer + index, elements, size * sizeof(V)); \
|
||||
\
|
||||
_list_->count += size; \
|
||||
} \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_append(SNAME *_list_, V *elements, size_t size) \
|
||||
{ \
|
||||
if (size == 0) \
|
||||
return false; \
|
||||
\
|
||||
if (!PFX##_fits(_list_, size)) \
|
||||
{ \
|
||||
if (!PFX##_impl_grow(_list_, _list_->count + size)) \
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
memcpy(_list_->buffer + _list_->count, elements, size * sizeof(V)); \
|
||||
\
|
||||
_list_->count += size; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_remove(SNAME *_list_, size_t from, size_t to) \
|
||||
{ \
|
||||
if (from > to || to >= _list_->count) \
|
||||
return false; \
|
||||
\
|
||||
size_t length = (to - from + 1); \
|
||||
\
|
||||
memmove(_list_->buffer + from, _list_->buffer + to + 1, (_list_->count - to - 1) * sizeof(V)); \
|
||||
\
|
||||
memset(_list_->buffer + _list_->count - length, 0, length * sizeof(V)); \
|
||||
\
|
||||
_list_->count -= to - from + 1; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD SNAME *PFX##_extract(SNAME *_list_, size_t from, size_t to) \
|
||||
{ \
|
||||
if (from > to || to >= _list_->count) \
|
||||
return false; \
|
||||
\
|
||||
size_t length = to - from + 1; \
|
||||
\
|
||||
SNAME *result = PFX##_new_from(_list_->buffer + from, length); \
|
||||
\
|
||||
if (!result) \
|
||||
return NULL; \
|
||||
\
|
||||
memmove(_list_->buffer + from, _list_->buffer + to + 1, (_list_->count - to - 1) * sizeof(V)); \
|
||||
\
|
||||
memset(_list_->buffer + _list_->count - length, 0, length * sizeof(V)); \
|
||||
\
|
||||
_list_->count -= length; \
|
||||
\
|
||||
return result; \
|
||||
} \
|
||||
\
|
||||
FMOD V PFX##_front(SNAME *_list_) \
|
||||
{ \
|
||||
if (PFX##_empty(_list_)) \
|
||||
return 0; \
|
||||
\
|
||||
return _list_->buffer[0]; \
|
||||
} \
|
||||
\
|
||||
FMOD V PFX##_get(SNAME *_list_, size_t index) \
|
||||
{ \
|
||||
if (index >= _list_->count) \
|
||||
return 0; \
|
||||
\
|
||||
if (PFX##_empty(_list_)) \
|
||||
return 0; \
|
||||
\
|
||||
return _list_->buffer[index]; \
|
||||
} \
|
||||
\
|
||||
FMOD V *PFX##_get_ref(SNAME *_list_, size_t index) \
|
||||
{ \
|
||||
if (index >= _list_->count) \
|
||||
return NULL; \
|
||||
\
|
||||
if (PFX##_empty(_list_)) \
|
||||
return NULL; \
|
||||
\
|
||||
return &(_list_->buffer[index]); \
|
||||
} \
|
||||
\
|
||||
FMOD V PFX##_back(SNAME *_list_) \
|
||||
{ \
|
||||
if (PFX##_empty(_list_)) \
|
||||
return 0; \
|
||||
\
|
||||
return _list_->buffer[_list_->count - 1]; \
|
||||
} \
|
||||
\
|
||||
FMOD size_t PFX##_indexof(SNAME *_list_, V element, int (*comparator)(V, V), bool from_start) \
|
||||
{ \
|
||||
if (from_start) \
|
||||
{ \
|
||||
for (size_t i = 0; i < _list_->count; i++) \
|
||||
{ \
|
||||
if (comparator(_list_->buffer[i], element) == 0) \
|
||||
return i; \
|
||||
} \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
for (size_t i = _list_->count; i > 0; i--) \
|
||||
{ \
|
||||
if (comparator(_list_->buffer[i - 1], element) == 0) \
|
||||
return i - 1; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
return _list_->count; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_contains(SNAME *_list_, V element, int (*comparator)(V, V)) \
|
||||
{ \
|
||||
for (size_t i = 0; i < _list_->count; i++) \
|
||||
{ \
|
||||
if (comparator(_list_->buffer[i], element) == 0) \
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_empty(SNAME *_list_) \
|
||||
{ \
|
||||
return _list_->count == 0; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_full(SNAME *_list_) \
|
||||
{ \
|
||||
return _list_->count >= _list_->capacity; \
|
||||
} \
|
||||
\
|
||||
FMOD size_t PFX##_count(SNAME *_list_) \
|
||||
{ \
|
||||
return _list_->count; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_fits(SNAME *_list_, size_t size) \
|
||||
{ \
|
||||
return _list_->count + size <= _list_->capacity; \
|
||||
} \
|
||||
\
|
||||
FMOD size_t PFX##_capacity(SNAME *_list_) \
|
||||
{ \
|
||||
return _list_->capacity; \
|
||||
} \
|
||||
\
|
||||
FMOD SNAME##_iter *PFX##_iter_new(SNAME *target) \
|
||||
{ \
|
||||
SNAME##_iter *iter = malloc(sizeof(SNAME##_iter)); \
|
||||
\
|
||||
if (!iter) \
|
||||
return NULL; \
|
||||
\
|
||||
PFX##_iter_init(iter, target); \
|
||||
\
|
||||
return iter; \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_iter_free(SNAME##_iter *iter) \
|
||||
{ \
|
||||
free(iter); \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_iter_init(SNAME##_iter *iter, SNAME *target) \
|
||||
{ \
|
||||
iter->target = target; \
|
||||
iter->cursor = 0; \
|
||||
iter->start = true; \
|
||||
iter->end = PFX##_empty(target); \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_iter_start(SNAME##_iter *iter) \
|
||||
{ \
|
||||
return PFX##_empty(iter->target) || iter->start; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_iter_end(SNAME##_iter *iter) \
|
||||
{ \
|
||||
return PFX##_empty(iter->target) || iter->end; \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_iter_to_start(SNAME##_iter *iter) \
|
||||
{ \
|
||||
iter->cursor = 0; \
|
||||
iter->start = true; \
|
||||
iter->end = PFX##_empty(iter->target); \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_iter_to_end(SNAME##_iter *iter) \
|
||||
{ \
|
||||
iter->start = PFX##_empty(iter->target); \
|
||||
iter->cursor = PFX##_empty(iter->target) ? 0 : iter->target->count - 1; \
|
||||
iter->end = true; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_iter_next(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (iter->end) \
|
||||
return false; \
|
||||
\
|
||||
iter->start = PFX##_empty(iter->target); \
|
||||
\
|
||||
if (iter->cursor == iter->target->count - 1) \
|
||||
iter->end = true; \
|
||||
else \
|
||||
iter->cursor++; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_iter_prev(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (iter->start) \
|
||||
return false; \
|
||||
\
|
||||
iter->end = PFX##_empty(iter->target); \
|
||||
\
|
||||
if (iter->cursor == 0) \
|
||||
iter->start = true; \
|
||||
else \
|
||||
iter->cursor--; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD V PFX##_iter_value(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (PFX##_empty(iter->target)) \
|
||||
return 0; \
|
||||
\
|
||||
return iter->target->buffer[iter->cursor]; \
|
||||
} \
|
||||
\
|
||||
FMOD V *PFX##_iter_rvalue(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (PFX##_empty(iter->target)) \
|
||||
return NULL; \
|
||||
\
|
||||
return &(iter->target->buffer[iter->cursor]); \
|
||||
} \
|
||||
\
|
||||
FMOD size_t PFX##_iter_index(SNAME##_iter *iter) \
|
||||
{ \
|
||||
return iter->cursor; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_impl_grow(SNAME *_list_, size_t required) \
|
||||
{ \
|
||||
size_t new_capacity = _list_->capacity * 2; \
|
||||
\
|
||||
if (new_capacity < required) \
|
||||
new_capacity = required; \
|
||||
\
|
||||
V *new_buffer = realloc(_list_->buffer, sizeof(V) * new_capacity); \
|
||||
\
|
||||
if (!new_buffer) \
|
||||
return false; \
|
||||
\
|
||||
_list_->buffer = new_buffer; \
|
||||
_list_->capacity = new_capacity; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
SNAME##_iter PFX##_impl_it_start(SNAME *_list_) \
|
||||
{ \
|
||||
SNAME##_iter iter; \
|
||||
\
|
||||
PFX##_iter_init(&iter, _list_); \
|
||||
PFX##_iter_to_start(&iter); \
|
||||
\
|
||||
return iter; \
|
||||
} \
|
||||
\
|
||||
SNAME##_iter PFX##_impl_it_end(SNAME *_list_) \
|
||||
{ \
|
||||
SNAME##_iter iter; \
|
||||
\
|
||||
PFX##_iter_init(&iter, _list_); \
|
||||
PFX##_iter_to_end(&iter); \
|
||||
\
|
||||
return iter; \
|
||||
}
|
||||
|
||||
#endif /* CMC_LIST_H */
|
||||
+382
-269
@@ -37,277 +37,390 @@
|
||||
#define QUEUE_GENERATE_SOURCE_PUBLIC(PFX, SNAME, FMOD, K, V) \
|
||||
QUEUE_GENERATE_SOURCE(PFX, SNAME, FMOD, V)
|
||||
/* STRUCT ********************************************************************/
|
||||
#define QUEUE_GENERATE_STRUCT(PFX, SNAME, FMOD, V) \
|
||||
\
|
||||
struct SNAME##_s \
|
||||
{ \
|
||||
V *buffer; \
|
||||
size_t capacity; \
|
||||
size_t count; \
|
||||
size_t front; \
|
||||
size_t rear; \
|
||||
}; \
|
||||
\
|
||||
struct SNAME##_iter_s \
|
||||
{ \
|
||||
struct SNAME##_s *target; \
|
||||
size_t cursor; \
|
||||
size_t index; \
|
||||
bool start; \
|
||||
bool end; \
|
||||
}; \
|
||||
\
|
||||
#define QUEUE_GENERATE_STRUCT(PFX, SNAME, FMOD, V)
|
||||
|
||||
/* HEADER ********************************************************************/
|
||||
#define QUEUE_GENERATE_HEADER(PFX, SNAME, FMOD, V) \
|
||||
\
|
||||
typedef struct SNAME##_s SNAME; \
|
||||
typedef struct SNAME##_iter_s SNAME##_iter; \
|
||||
\
|
||||
FMOD SNAME *PFX##_new(size_t size); \
|
||||
FMOD void PFX##_clear(SNAME *_queue_); \
|
||||
FMOD void PFX##_free(SNAME *_queue_); \
|
||||
FMOD bool PFX##_enqueue(SNAME *_queue_, V element); \
|
||||
FMOD bool PFX##_dequeue(SNAME *_queue_); \
|
||||
FMOD bool PFX##_enqueue_if(SNAME *_queue_, V element, bool condition); \
|
||||
FMOD bool PFX##_dequeue_if(SNAME *_queue_, bool condition); \
|
||||
FMOD V PFX##_peek(SNAME *_queue_); \
|
||||
FMOD bool PFX##_empty(SNAME *_queue_); \
|
||||
FMOD bool PFX##_full(SNAME *_queue_); \
|
||||
FMOD size_t PFX##_count(SNAME *_queue_); \
|
||||
FMOD size_t PFX##_capacity(SNAME *_queue_); \
|
||||
\
|
||||
FMOD void PFX##_iter_new(SNAME##_iter *iter, SNAME *target); \
|
||||
FMOD bool PFX##_iter_start(SNAME##_iter *iter); \
|
||||
FMOD bool PFX##_iter_end(SNAME##_iter *iter); \
|
||||
FMOD void PFX##_iter_tostart(SNAME##_iter *iter); \
|
||||
FMOD void PFX##_iter_toend(SNAME##_iter *iter); \
|
||||
FMOD bool PFX##_iter_next(SNAME##_iter *iter, V *result, size_t *index); \
|
||||
FMOD bool PFX##_iter_prev(SNAME##_iter *iter, V *result, size_t *index); \
|
||||
\
|
||||
#define QUEUE_GENERATE_HEADER(PFX, SNAME, FMOD, V) \
|
||||
\
|
||||
/* Queue Structure */ \
|
||||
typedef struct SNAME##_s \
|
||||
{ \
|
||||
/* Dynamic circular array of elements */ \
|
||||
V *buffer; \
|
||||
\
|
||||
/* Current circular array capacity */ \
|
||||
size_t capacity; \
|
||||
\
|
||||
/* Current amount of elements */ \
|
||||
size_t count; \
|
||||
\
|
||||
/* Index representing the front of the queue */ \
|
||||
size_t front; \
|
||||
\
|
||||
/* Index representing the back of the queue */ \
|
||||
size_t rear; \
|
||||
\
|
||||
/* Function that returns an iterator to the start of the queue */ \
|
||||
struct SNAME##_iter_s (*it_start)(struct SNAME##_s *); \
|
||||
\
|
||||
/* Function that returns an iterator to the end of the queue */ \
|
||||
struct SNAME##_iter_s (*it_end)(struct SNAME##_s *); \
|
||||
\
|
||||
} SNAME, *SNAME##_ptr; \
|
||||
\
|
||||
/* Queue Iterator */ \
|
||||
typedef struct SNAME##_iter_s \
|
||||
{ \
|
||||
/* Target queue */ \
|
||||
struct SNAME##_s *target; \
|
||||
\
|
||||
/* Cursor's position (index) */ \
|
||||
size_t cursor; \
|
||||
\
|
||||
/* Keeps track of relative index to the iteration of elements */ \
|
||||
size_t index; \
|
||||
\
|
||||
/* If the iterator has reached the start of the iteration */ \
|
||||
bool start; \
|
||||
\
|
||||
/* If the iterator has reached the end of the iteration */ \
|
||||
bool end; \
|
||||
\
|
||||
} SNAME##_iter, *SNAME##_iter_ptr; \
|
||||
\
|
||||
/* Collection Functions */ \
|
||||
/* Collection Allocation and Deallocation */ \
|
||||
FMOD SNAME *PFX##_new(size_t size); \
|
||||
FMOD void PFX##_clear(SNAME *_queue_); \
|
||||
FMOD void PFX##_free(SNAME *_queue_); \
|
||||
/* Collection Input and Output */ \
|
||||
FMOD bool PFX##_enqueue(SNAME *_queue_, V element); \
|
||||
FMOD bool PFX##_dequeue(SNAME *_queue_); \
|
||||
/* Conditional Input and Output */ \
|
||||
FMOD bool PFX##_enqueue_if(SNAME *_queue_, V element, bool condition); \
|
||||
FMOD bool PFX##_dequeue_if(SNAME *_queue_, bool condition); \
|
||||
/* Element Access */ \
|
||||
FMOD V PFX##_peek(SNAME *_queue_); \
|
||||
/* Collection State */ \
|
||||
FMOD bool PFX##_contains(SNAME *_queue_, V element, int (*comparator)(V, V)); \
|
||||
FMOD bool PFX##_empty(SNAME *_queue_); \
|
||||
FMOD bool PFX##_full(SNAME *_queue_); \
|
||||
FMOD size_t PFX##_count(SNAME *_queue_); \
|
||||
FMOD size_t PFX##_capacity(SNAME *_queue_); \
|
||||
\
|
||||
/* Iterator Functions */ \
|
||||
/* Iterator Allocation and Deallocation */ \
|
||||
FMOD SNAME##_iter *PFX##_iter_new(SNAME *target); \
|
||||
FMOD void PFX##_iter_free(SNAME##_iter *iter); \
|
||||
/* Iterator Initialization */ \
|
||||
FMOD void PFX##_iter_init(SNAME##_iter *iter, SNAME *target); \
|
||||
/* Iterator State */ \
|
||||
FMOD bool PFX##_iter_start(SNAME##_iter *iter); \
|
||||
FMOD bool PFX##_iter_end(SNAME##_iter *iter); \
|
||||
/* Iterator Movement */ \
|
||||
FMOD void PFX##_iter_to_start(SNAME##_iter *iter); \
|
||||
FMOD void PFX##_iter_to_end(SNAME##_iter *iter); \
|
||||
FMOD bool PFX##_iter_next(SNAME##_iter *iter); \
|
||||
FMOD bool PFX##_iter_prev(SNAME##_iter *iter); \
|
||||
/* Iterator Access */ \
|
||||
FMOD V PFX##_iter_value(SNAME##_iter *iter); \
|
||||
FMOD V *PFX##_iter_rvalue(SNAME##_iter *iter); \
|
||||
FMOD size_t PFX##_iter_index(SNAME##_iter *iter); \
|
||||
\
|
||||
/* SOURCE ********************************************************************/
|
||||
#define QUEUE_GENERATE_SOURCE(PFX, SNAME, FMOD, V) \
|
||||
\
|
||||
FMOD bool PFX##_grow(SNAME *_queue_); \
|
||||
\
|
||||
FMOD SNAME *PFX##_new(size_t size) \
|
||||
{ \
|
||||
if (size < 1) \
|
||||
return NULL; \
|
||||
\
|
||||
SNAME *_queue_ = malloc(sizeof(SNAME)); \
|
||||
\
|
||||
if (!_queue_) \
|
||||
return NULL; \
|
||||
\
|
||||
_queue_->buffer = malloc(sizeof(V) * size); \
|
||||
\
|
||||
if (!_queue_->buffer) \
|
||||
{ \
|
||||
free(_queue_); \
|
||||
return NULL; \
|
||||
} \
|
||||
\
|
||||
memset(_queue_->buffer, 0, sizeof(V) * size); \
|
||||
\
|
||||
_queue_->capacity = size; \
|
||||
_queue_->count = 0; \
|
||||
_queue_->front = 0; \
|
||||
_queue_->rear = 0; \
|
||||
\
|
||||
return _queue_; \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_clear(SNAME *_queue_) \
|
||||
{ \
|
||||
memset(_queue_->buffer, 0, sizeof(V) * _queue_->capacity); \
|
||||
\
|
||||
_queue_->count = 0; \
|
||||
_queue_->front = 0; \
|
||||
_queue_->rear = 0; \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_free(SNAME *_queue_) \
|
||||
{ \
|
||||
free(_queue_->buffer); \
|
||||
free(_queue_); \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_enqueue(SNAME *_queue_, V element) \
|
||||
{ \
|
||||
if (PFX##_full(_queue_)) \
|
||||
{ \
|
||||
if (!PFX##_grow(_queue_)) \
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
_queue_->buffer[_queue_->rear] = element; \
|
||||
\
|
||||
_queue_->rear = (_queue_->rear == _queue_->capacity - 1) ? 0 : _queue_->rear + 1; \
|
||||
_queue_->count++; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_dequeue(SNAME *_queue_) \
|
||||
{ \
|
||||
if (PFX##_empty(_queue_)) \
|
||||
return false; \
|
||||
\
|
||||
_queue_->buffer[_queue_->front] = 0; \
|
||||
\
|
||||
_queue_->front = (_queue_->front == _queue_->capacity - 1) ? 0 : _queue_->front + 1; \
|
||||
_queue_->count--; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_enqueue_if(SNAME *_queue_, V element, bool condition) \
|
||||
{ \
|
||||
if (condition) \
|
||||
return PFX##_enqueue(_queue_, element); \
|
||||
\
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_dequeue_if(SNAME *_queue_, bool condition) \
|
||||
{ \
|
||||
if (condition) \
|
||||
return PFX##_dequeue(_queue_); \
|
||||
\
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
FMOD V PFX##_peek(SNAME *_queue_) \
|
||||
{ \
|
||||
if (PFX##_empty(_queue_)) \
|
||||
return 0; \
|
||||
\
|
||||
return _queue_->buffer[_queue_->front]; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_empty(SNAME *_queue_) \
|
||||
{ \
|
||||
return _queue_->count == 0; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_full(SNAME *_queue_) \
|
||||
{ \
|
||||
return _queue_->count >= _queue_->capacity; \
|
||||
} \
|
||||
\
|
||||
FMOD size_t PFX##_count(SNAME *_queue_) \
|
||||
{ \
|
||||
return _queue_->count; \
|
||||
} \
|
||||
\
|
||||
FMOD size_t PFX##_capacity(SNAME *_queue_) \
|
||||
{ \
|
||||
return _queue_->capacity; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_grow(SNAME *_queue_) \
|
||||
{ \
|
||||
\
|
||||
size_t new_capacity = _queue_->capacity * 2; \
|
||||
\
|
||||
V *new_buffer = malloc(sizeof(V) * new_capacity); \
|
||||
\
|
||||
if (!new_buffer) \
|
||||
return false; \
|
||||
\
|
||||
for (size_t i = _queue_->front, j = 0; j < _queue_->count; i = (i + 1) % _queue_->capacity, j++) \
|
||||
{ \
|
||||
new_buffer[j] = _queue_->buffer[i]; \
|
||||
} \
|
||||
\
|
||||
free(_queue_->buffer); \
|
||||
\
|
||||
_queue_->buffer = new_buffer; \
|
||||
_queue_->capacity = new_capacity; \
|
||||
_queue_->front = 0; \
|
||||
_queue_->rear = _queue_->count; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_iter_new(SNAME##_iter *iter, SNAME *target) \
|
||||
{ \
|
||||
iter->target = target; \
|
||||
iter->cursor = target->front; \
|
||||
iter->index = 0; \
|
||||
iter->start = true; \
|
||||
iter->end = PFX##_empty(target); \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_iter_start(SNAME##_iter *iter) \
|
||||
{ \
|
||||
return iter->cursor == iter->target->front && iter->start; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_iter_end(SNAME##_iter *iter) \
|
||||
{ \
|
||||
size_t real_rear = iter->target->rear == 0 ? iter->target->capacity - 1 : iter->target->rear - 1; \
|
||||
return iter->cursor == real_rear && iter->end; \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_iter_tostart(SNAME##_iter *iter) \
|
||||
{ \
|
||||
iter->cursor = iter->target->front; \
|
||||
iter->index = 0; \
|
||||
iter->start = true; \
|
||||
iter->end = PFX##_empty(iter->target); \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_iter_toend(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (PFX##_empty(iter->target)) \
|
||||
iter->cursor = 0; \
|
||||
else \
|
||||
iter->cursor = (iter->target->rear == 0) ? iter->target->count - 1 : iter->target->rear - 1; \
|
||||
\
|
||||
iter->index = iter->target->count - 1; \
|
||||
iter->start = PFX##_empty(iter->target); \
|
||||
iter->end = true; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_iter_next(SNAME##_iter *iter, V *result, size_t *index) \
|
||||
{ \
|
||||
if (iter->end) \
|
||||
return false; \
|
||||
\
|
||||
*index = iter->index; \
|
||||
*result = iter->target->buffer[iter->cursor]; \
|
||||
iter->start = false; \
|
||||
\
|
||||
if (iter->index == iter->target->count - 1) \
|
||||
iter->end = true; \
|
||||
else \
|
||||
{ \
|
||||
iter->cursor = (iter->cursor + 1) % (iter->target->capacity); \
|
||||
iter->index++; \
|
||||
} \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_iter_prev(SNAME##_iter *iter, V *result, size_t *index) \
|
||||
{ \
|
||||
if (iter->start) \
|
||||
return false; \
|
||||
\
|
||||
*index = iter->index; \
|
||||
*result = iter->target->buffer[iter->cursor]; \
|
||||
iter->end = false; \
|
||||
\
|
||||
if (iter->index == 0) \
|
||||
iter->start = true; \
|
||||
else \
|
||||
{ \
|
||||
iter->cursor = (iter->cursor == 0) ? iter->target->capacity - 1 : iter->cursor - 1; \
|
||||
iter->index--; \
|
||||
} \
|
||||
\
|
||||
return true; \
|
||||
#define QUEUE_GENERATE_SOURCE(PFX, SNAME, FMOD, V) \
|
||||
\
|
||||
/* Implementation Detail Functions */ \
|
||||
FMOD bool PFX##_grow(SNAME *_queue_); \
|
||||
SNAME##_iter PFX##_impl_it_start(SNAME *_queue_); \
|
||||
SNAME##_iter PFX##_impl_it_end(SNAME *_queue_); \
|
||||
\
|
||||
FMOD SNAME *PFX##_new(size_t size) \
|
||||
{ \
|
||||
if (size < 1) \
|
||||
return NULL; \
|
||||
\
|
||||
SNAME *_queue_ = malloc(sizeof(SNAME)); \
|
||||
\
|
||||
if (!_queue_) \
|
||||
return NULL; \
|
||||
\
|
||||
_queue_->buffer = malloc(sizeof(V) * size); \
|
||||
\
|
||||
if (!_queue_->buffer) \
|
||||
{ \
|
||||
free(_queue_); \
|
||||
return NULL; \
|
||||
} \
|
||||
\
|
||||
memset(_queue_->buffer, 0, sizeof(V) * size); \
|
||||
\
|
||||
_queue_->capacity = size; \
|
||||
_queue_->count = 0; \
|
||||
_queue_->front = 0; \
|
||||
_queue_->rear = 0; \
|
||||
\
|
||||
_queue_->it_start = PFX##_impl_it_start; \
|
||||
_queue_->it_end = PFX##_impl_it_end; \
|
||||
\
|
||||
return _queue_; \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_clear(SNAME *_queue_) \
|
||||
{ \
|
||||
memset(_queue_->buffer, 0, sizeof(V) * _queue_->capacity); \
|
||||
\
|
||||
_queue_->count = 0; \
|
||||
_queue_->front = 0; \
|
||||
_queue_->rear = 0; \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_free(SNAME *_queue_) \
|
||||
{ \
|
||||
free(_queue_->buffer); \
|
||||
free(_queue_); \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_enqueue(SNAME *_queue_, V element) \
|
||||
{ \
|
||||
if (PFX##_full(_queue_)) \
|
||||
{ \
|
||||
if (!PFX##_grow(_queue_)) \
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
_queue_->buffer[_queue_->rear] = element; \
|
||||
\
|
||||
_queue_->rear = (_queue_->rear == _queue_->capacity - 1) ? 0 : _queue_->rear + 1; \
|
||||
_queue_->count++; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_dequeue(SNAME *_queue_) \
|
||||
{ \
|
||||
if (PFX##_empty(_queue_)) \
|
||||
return false; \
|
||||
\
|
||||
_queue_->buffer[_queue_->front] = 0; \
|
||||
\
|
||||
_queue_->front = (_queue_->front == _queue_->capacity - 1) ? 0 : _queue_->front + 1; \
|
||||
_queue_->count--; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_enqueue_if(SNAME *_queue_, V element, bool condition) \
|
||||
{ \
|
||||
if (condition) \
|
||||
return PFX##_enqueue(_queue_, element); \
|
||||
\
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_dequeue_if(SNAME *_queue_, bool condition) \
|
||||
{ \
|
||||
if (condition) \
|
||||
return PFX##_dequeue(_queue_); \
|
||||
\
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
FMOD V PFX##_peek(SNAME *_queue_) \
|
||||
{ \
|
||||
if (PFX##_empty(_queue_)) \
|
||||
return 0; \
|
||||
\
|
||||
return _queue_->buffer[_queue_->front]; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_contains(SNAME *_queue_, V element, int (*comparator)(V, V)) \
|
||||
{ \
|
||||
for (size_t i = _queue_->front, j = 0; j < _queue_->count; i = (i + 1) % _queue_->count, j++) \
|
||||
{ \
|
||||
if (comparator(_queue_->buffer[i], element) == 0) \
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_empty(SNAME *_queue_) \
|
||||
{ \
|
||||
return _queue_->count == 0; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_full(SNAME *_queue_) \
|
||||
{ \
|
||||
return _queue_->count >= _queue_->capacity; \
|
||||
} \
|
||||
\
|
||||
FMOD size_t PFX##_count(SNAME *_queue_) \
|
||||
{ \
|
||||
return _queue_->count; \
|
||||
} \
|
||||
\
|
||||
FMOD size_t PFX##_capacity(SNAME *_queue_) \
|
||||
{ \
|
||||
return _queue_->capacity; \
|
||||
} \
|
||||
\
|
||||
FMOD SNAME##_iter *PFX##_iter_new(SNAME *target) \
|
||||
{ \
|
||||
SNAME##_iter *iter = malloc(sizeof(SNAME##_iter)); \
|
||||
\
|
||||
if (!iter) \
|
||||
return NULL; \
|
||||
\
|
||||
PFX##_iter_init(iter, target); \
|
||||
\
|
||||
return iter; \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_iter_free(SNAME##_iter *iter) \
|
||||
{ \
|
||||
free(iter); \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_iter_init(SNAME##_iter *iter, SNAME *target) \
|
||||
{ \
|
||||
iter->target = target; \
|
||||
iter->cursor = target->front; \
|
||||
iter->index = 0; \
|
||||
iter->start = true; \
|
||||
iter->end = PFX##_empty(target); \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_iter_start(SNAME##_iter *iter) \
|
||||
{ \
|
||||
return PFX##_empty(iter->target) || iter->start; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_iter_end(SNAME##_iter *iter) \
|
||||
{ \
|
||||
return PFX##_empty(iter->target) || iter->end; \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_iter_to_start(SNAME##_iter *iter) \
|
||||
{ \
|
||||
iter->cursor = iter->target->front; \
|
||||
iter->index = 0; \
|
||||
iter->start = true; \
|
||||
iter->end = PFX##_empty(iter->target); \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_iter_to_end(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (PFX##_empty(iter->target)) \
|
||||
iter->cursor = 0; \
|
||||
else \
|
||||
iter->cursor = (iter->target->rear == 0) ? iter->target->capacity - 1 : iter->target->rear - 1; \
|
||||
\
|
||||
iter->index = iter->target->count - 1; \
|
||||
iter->start = PFX##_empty(iter->target); \
|
||||
iter->end = true; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_iter_next(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (iter->end) \
|
||||
return false; \
|
||||
\
|
||||
iter->start = PFX##_empty(iter->target); \
|
||||
\
|
||||
if (iter->index == iter->target->count - 1) \
|
||||
iter->end = true; \
|
||||
else \
|
||||
{ \
|
||||
iter->cursor = (iter->cursor + 1) % (iter->target->capacity); \
|
||||
iter->index++; \
|
||||
} \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_iter_prev(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (iter->start) \
|
||||
return false; \
|
||||
\
|
||||
iter->end = PFX##_empty(iter->target); \
|
||||
\
|
||||
if (iter->index == 0) \
|
||||
iter->start = true; \
|
||||
else \
|
||||
{ \
|
||||
iter->cursor = (iter->cursor == 0) ? iter->target->capacity - 1 : iter->cursor - 1; \
|
||||
iter->index--; \
|
||||
} \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD V PFX##_iter_value(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (PFX##_empty(iter->target)) \
|
||||
return 0; \
|
||||
\
|
||||
return iter->target->buffer[iter->cursor]; \
|
||||
} \
|
||||
\
|
||||
FMOD V *PFX##_iter_rvalue(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (PFX##_empty(iter->target)) \
|
||||
return NULL; \
|
||||
\
|
||||
return &(iter->target->buffer[iter->cursor]); \
|
||||
} \
|
||||
\
|
||||
FMOD size_t PFX##_iter_index(SNAME##_iter *iter) \
|
||||
{ \
|
||||
return iter->index; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_grow(SNAME *_queue_) \
|
||||
{ \
|
||||
\
|
||||
size_t new_capacity = _queue_->capacity * 2; \
|
||||
\
|
||||
V *new_buffer = malloc(sizeof(V) * new_capacity); \
|
||||
\
|
||||
if (!new_buffer) \
|
||||
return false; \
|
||||
\
|
||||
for (size_t i = _queue_->front, j = 0; j < _queue_->count; i = (i + 1) % _queue_->capacity, j++) \
|
||||
{ \
|
||||
new_buffer[j] = _queue_->buffer[i]; \
|
||||
} \
|
||||
\
|
||||
free(_queue_->buffer); \
|
||||
\
|
||||
_queue_->buffer = new_buffer; \
|
||||
_queue_->capacity = new_capacity; \
|
||||
_queue_->front = 0; \
|
||||
_queue_->rear = _queue_->count; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
SNAME##_iter PFX##_impl_it_start(SNAME *_queue_) \
|
||||
{ \
|
||||
SNAME##_iter iter; \
|
||||
\
|
||||
PFX##_iter_init(&iter, _queue_); \
|
||||
PFX##_iter_to_start(&iter); \
|
||||
\
|
||||
return iter; \
|
||||
} \
|
||||
\
|
||||
SNAME##_iter PFX##_impl_it_end(SNAME *_queue_) \
|
||||
{ \
|
||||
SNAME##_iter iter; \
|
||||
\
|
||||
PFX##_iter_init(&iter, _queue_); \
|
||||
PFX##_iter_to_end(&iter); \
|
||||
\
|
||||
return iter; \
|
||||
}
|
||||
|
||||
#endif /* CMC_QUEUE_H */
|
||||
+340
-232
@@ -37,240 +37,348 @@
|
||||
#define STACK_GENERATE_SOURCE_PUBLIC(PFX, SNAME, FMOD, K, V) \
|
||||
STACK_GENERATE_SOURCE(PFX, SNAME, FMOD, V)
|
||||
/* STRUCT ********************************************************************/
|
||||
#define STACK_GENERATE_STRUCT(PFX, SNAME, FMOD, V) \
|
||||
\
|
||||
struct SNAME##_s \
|
||||
{ \
|
||||
V *buffer; \
|
||||
size_t capacity; \
|
||||
size_t count; \
|
||||
}; \
|
||||
\
|
||||
struct SNAME##_iter_s \
|
||||
{ \
|
||||
struct SNAME##_s *target; \
|
||||
size_t cursor; \
|
||||
bool start; \
|
||||
bool end; \
|
||||
}; \
|
||||
\
|
||||
#define STACK_GENERATE_STRUCT(PFX, SNAME, FMOD, V)
|
||||
|
||||
/* HEADER ********************************************************************/
|
||||
#define STACK_GENERATE_HEADER(PFX, SNAME, FMOD, V) \
|
||||
\
|
||||
typedef struct SNAME##_s SNAME; \
|
||||
typedef struct SNAME##_iter_s SNAME##_iter; \
|
||||
\
|
||||
FMOD SNAME *PFX##_new(size_t size); \
|
||||
FMOD void PFX##_clear(SNAME *_stack_); \
|
||||
FMOD void PFX##_free(SNAME *_stack_); \
|
||||
FMOD bool PFX##_push(SNAME *_stack_, V element); \
|
||||
FMOD bool PFX##_pop(SNAME *_stack_); \
|
||||
FMOD bool PFX##_push_if(SNAME *_stack_, V element, bool condition); \
|
||||
FMOD bool PFX##_pop_if(SNAME *_stack_, bool condition); \
|
||||
FMOD V PFX##_top(SNAME *_stack_); \
|
||||
FMOD bool PFX##_empty(SNAME *_stack_); \
|
||||
FMOD bool PFX##_full(SNAME *_stack_); \
|
||||
FMOD size_t PFX##_count(SNAME *_stack_); \
|
||||
FMOD size_t PFX##_capacity(SNAME *_stack_); \
|
||||
\
|
||||
FMOD void PFX##_iter_new(SNAME##_iter *iter, SNAME *target); \
|
||||
FMOD bool PFX##_iter_start(SNAME##_iter *iter); \
|
||||
FMOD bool PFX##_iter_end(SNAME##_iter *iter); \
|
||||
FMOD void PFX##_iter_tostart(SNAME##_iter *iter); \
|
||||
FMOD void PFX##_iter_toend(SNAME##_iter *iter); \
|
||||
FMOD bool PFX##_iter_next(SNAME##_iter *iter, V *result, size_t *index); \
|
||||
FMOD bool PFX##_iter_prev(SNAME##_iter *iter, V *result, size_t *index); \
|
||||
\
|
||||
#define STACK_GENERATE_HEADER(PFX, SNAME, FMOD, V) \
|
||||
\
|
||||
/* Stack Structure */ \
|
||||
typedef struct SNAME##_s \
|
||||
{ \
|
||||
/* Dynamic array of elements */ \
|
||||
V *buffer; \
|
||||
\
|
||||
/* Current array capacity */ \
|
||||
size_t capacity; \
|
||||
\
|
||||
/* Current amount of elements */ \
|
||||
size_t count; \
|
||||
\
|
||||
/* Function that returns an iterator to the start of the stack */ \
|
||||
struct SNAME##_iter_s (*it_start)(struct SNAME##_s *); \
|
||||
\
|
||||
/* Function that returns an iterator to the end of the stack */ \
|
||||
struct SNAME##_iter_s (*it_end)(struct SNAME##_s *); \
|
||||
\
|
||||
} SNAME, *SNAME##_ptr; \
|
||||
\
|
||||
/* Stack Iterator */ \
|
||||
typedef struct SNAME##_iter_s \
|
||||
{ \
|
||||
/* Target stack */ \
|
||||
struct SNAME##_s *target; \
|
||||
\
|
||||
/* Cursor's position (index) */ \
|
||||
size_t cursor; \
|
||||
\
|
||||
/* If the iterator has reached the start of the iteration */ \
|
||||
bool start; \
|
||||
\
|
||||
/* If the iterator has reached the end of the iteration */ \
|
||||
bool end; \
|
||||
\
|
||||
} SNAME##_iter, *SNAME##_iter_ptr; \
|
||||
\
|
||||
/* Collection Functions */ \
|
||||
/* Collection Allocation and Deallocation */ \
|
||||
FMOD SNAME *PFX##_new(size_t size); \
|
||||
FMOD void PFX##_clear(SNAME *_stack_); \
|
||||
FMOD void PFX##_free(SNAME *_stack_); \
|
||||
/* Collection Input and Output */ \
|
||||
FMOD bool PFX##_push(SNAME *_stack_, V element); \
|
||||
FMOD bool PFX##_pop(SNAME *_stack_); \
|
||||
/* Conditional Input and Output */ \
|
||||
FMOD bool PFX##_push_if(SNAME *_stack_, V element, bool condition); \
|
||||
FMOD bool PFX##_pop_if(SNAME *_stack_, bool condition); \
|
||||
/* Element Access */ \
|
||||
FMOD V PFX##_top(SNAME *_stack_); \
|
||||
/* Collection State */ \
|
||||
FMOD bool PFX##_contains(SNAME *_stack_, V element, int (*comparator)(V, V)); \
|
||||
FMOD bool PFX##_empty(SNAME *_stack_); \
|
||||
FMOD bool PFX##_full(SNAME *_stack_); \
|
||||
FMOD size_t PFX##_count(SNAME *_stack_); \
|
||||
FMOD size_t PFX##_capacity(SNAME *_stack_); \
|
||||
\
|
||||
/* Iterator Functions */ \
|
||||
/* Iterator Allocation and Deallocation */ \
|
||||
FMOD SNAME##_iter *PFX##_iter_new(SNAME *target); \
|
||||
FMOD void PFX##_iter_free(SNAME##_iter *iter); \
|
||||
/* Iterator Initialization */ \
|
||||
FMOD void PFX##_iter_init(SNAME##_iter *iter, SNAME *target); \
|
||||
/* Iterator State */ \
|
||||
FMOD bool PFX##_iter_start(SNAME##_iter *iter); \
|
||||
FMOD bool PFX##_iter_end(SNAME##_iter *iter); \
|
||||
/* Iterator Movement */ \
|
||||
FMOD void PFX##_iter_to_start(SNAME##_iter *iter); \
|
||||
FMOD void PFX##_iter_to_end(SNAME##_iter *iter); \
|
||||
FMOD bool PFX##_iter_next(SNAME##_iter *iter); \
|
||||
FMOD bool PFX##_iter_prev(SNAME##_iter *iter); \
|
||||
/* Iterator Access */ \
|
||||
FMOD V PFX##_iter_value(SNAME##_iter *iter); \
|
||||
FMOD V *PFX##_iter_rvalue(SNAME##_iter *iter); \
|
||||
FMOD size_t PFX##_iter_index(SNAME##_iter *iter); \
|
||||
\
|
||||
/* SOURCE ********************************************************************/
|
||||
#define STACK_GENERATE_SOURCE(PFX, SNAME, FMOD, V) \
|
||||
\
|
||||
FMOD bool PFX##_grow(SNAME *_stack_); \
|
||||
\
|
||||
FMOD SNAME *PFX##_new(size_t size) \
|
||||
{ \
|
||||
if (size < 1) \
|
||||
return NULL; \
|
||||
\
|
||||
SNAME *_stack_ = malloc(sizeof(SNAME)); \
|
||||
\
|
||||
if (!_stack_) \
|
||||
return NULL; \
|
||||
\
|
||||
_stack_->buffer = malloc(sizeof(V) * size); \
|
||||
\
|
||||
if (!_stack_->buffer) \
|
||||
{ \
|
||||
free(_stack_); \
|
||||
return NULL; \
|
||||
} \
|
||||
\
|
||||
memset(_stack_->buffer, 0, sizeof(V) * size); \
|
||||
\
|
||||
_stack_->capacity = size; \
|
||||
_stack_->count = 0; \
|
||||
\
|
||||
return _stack_; \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_clear(SNAME *_stack_) \
|
||||
{ \
|
||||
memset(_stack_->buffer, 0, sizeof(V) * _stack_->capacity); \
|
||||
\
|
||||
_stack_->count = 0; \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_free(SNAME *_stack_) \
|
||||
{ \
|
||||
free(_stack_->buffer); \
|
||||
free(_stack_); \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_push(SNAME *_stack_, V element) \
|
||||
{ \
|
||||
if (PFX##_full(_stack_)) \
|
||||
{ \
|
||||
if (!PFX##_grow(_stack_)) \
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
_stack_->buffer[_stack_->count++] = element; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_pop(SNAME *_stack_) \
|
||||
{ \
|
||||
if (PFX##_empty(_stack_)) \
|
||||
return false; \
|
||||
\
|
||||
_stack_->buffer[--_stack_->count] = 0; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_push_if(SNAME *_stack_, V element, bool condition) \
|
||||
{ \
|
||||
if (condition) \
|
||||
return PFX##_push(_stack_, element); \
|
||||
\
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_pop_if(SNAME *_stack_, bool condition) \
|
||||
{ \
|
||||
if (condition) \
|
||||
return PFX##_pop(_stack_); \
|
||||
\
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
FMOD V PFX##_top(SNAME *_stack_) \
|
||||
{ \
|
||||
if (PFX##_empty(_stack_)) \
|
||||
return 0; \
|
||||
\
|
||||
return _stack_->buffer[_stack_->count - 1]; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_empty(SNAME *_stack_) \
|
||||
{ \
|
||||
return _stack_->count == 0; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_full(SNAME *_stack_) \
|
||||
{ \
|
||||
return _stack_->count >= _stack_->capacity; \
|
||||
} \
|
||||
\
|
||||
FMOD size_t PFX##_count(SNAME *_stack_) \
|
||||
{ \
|
||||
return _stack_->count; \
|
||||
} \
|
||||
\
|
||||
FMOD size_t PFX##_capacity(SNAME *_stack_) \
|
||||
{ \
|
||||
return _stack_->capacity; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_grow(SNAME *_stack_) \
|
||||
{ \
|
||||
size_t new_capacity = _stack_->capacity * 2; \
|
||||
\
|
||||
V *new_buffer = realloc(_stack_->buffer, sizeof(V) * new_capacity); \
|
||||
\
|
||||
if (!new_buffer) \
|
||||
return false; \
|
||||
\
|
||||
_stack_->buffer = new_buffer; \
|
||||
_stack_->capacity = new_capacity; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_iter_new(SNAME##_iter *iter, SNAME *target) \
|
||||
{ \
|
||||
iter->target = target; \
|
||||
iter->cursor = iter->target->count - 1; \
|
||||
iter->start = true; \
|
||||
iter->end = PFX##_empty(target); \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_iter_start(SNAME##_iter *iter) \
|
||||
{ \
|
||||
return iter->cursor == iter->target->count - 1 && iter->start; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_iter_end(SNAME##_iter *iter) \
|
||||
{ \
|
||||
return iter->cursor == 0 && iter->end; \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_iter_tostart(SNAME##_iter *iter) \
|
||||
{ \
|
||||
iter->cursor = iter->target->count - 1; \
|
||||
iter->start = true; \
|
||||
iter->end = PFX##_empty(iter->target); \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_iter_toend(SNAME##_iter *iter) \
|
||||
{ \
|
||||
iter->cursor = 0; \
|
||||
iter->start = PFX##_empty(iter->target); \
|
||||
iter->end = true; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_iter_next(SNAME##_iter *iter, V *result, size_t *index) \
|
||||
{ \
|
||||
if (iter->end) \
|
||||
return false; \
|
||||
\
|
||||
*index = iter->target->count - iter->cursor - 1; \
|
||||
*result = iter->target->buffer[iter->cursor]; \
|
||||
iter->start = false; \
|
||||
\
|
||||
if (iter->cursor == 0) \
|
||||
iter->end = true; \
|
||||
else \
|
||||
iter->cursor--; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_iter_prev(SNAME##_iter *iter, V *result, size_t *index) \
|
||||
{ \
|
||||
if (iter->start) \
|
||||
return false; \
|
||||
\
|
||||
*index = iter->target->count - iter->cursor - 1; \
|
||||
*result = iter->target->buffer[iter->cursor]; \
|
||||
iter->end = false; \
|
||||
\
|
||||
if (iter->cursor == iter->target->count - 1) \
|
||||
iter->start = true; \
|
||||
else \
|
||||
iter->cursor++; \
|
||||
\
|
||||
return true; \
|
||||
#define STACK_GENERATE_SOURCE(PFX, SNAME, FMOD, V) \
|
||||
\
|
||||
/* Implementation Detail Functions */ \
|
||||
FMOD bool PFX##_impl_grow(SNAME *_stack_); \
|
||||
SNAME##_iter PFX##_impl_it_start(SNAME *_stack_); \
|
||||
SNAME##_iter PFX##_impl_it_end(SNAME *_stack_); \
|
||||
\
|
||||
FMOD SNAME *PFX##_new(size_t size) \
|
||||
{ \
|
||||
if (size < 1) \
|
||||
return NULL; \
|
||||
\
|
||||
SNAME *_stack_ = malloc(sizeof(SNAME)); \
|
||||
\
|
||||
if (!_stack_) \
|
||||
return NULL; \
|
||||
\
|
||||
_stack_->buffer = malloc(sizeof(V) * size); \
|
||||
\
|
||||
if (!_stack_->buffer) \
|
||||
{ \
|
||||
free(_stack_); \
|
||||
return NULL; \
|
||||
} \
|
||||
\
|
||||
memset(_stack_->buffer, 0, sizeof(V) * size); \
|
||||
\
|
||||
_stack_->capacity = size; \
|
||||
_stack_->count = 0; \
|
||||
\
|
||||
_stack_->it_start = PFX##_impl_it_start; \
|
||||
_stack_->it_end = PFX##_impl_it_end; \
|
||||
\
|
||||
return _stack_; \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_clear(SNAME *_stack_) \
|
||||
{ \
|
||||
memset(_stack_->buffer, 0, sizeof(V) * _stack_->capacity); \
|
||||
\
|
||||
_stack_->count = 0; \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_free(SNAME *_stack_) \
|
||||
{ \
|
||||
free(_stack_->buffer); \
|
||||
free(_stack_); \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_push(SNAME *_stack_, V element) \
|
||||
{ \
|
||||
if (PFX##_full(_stack_)) \
|
||||
{ \
|
||||
if (!PFX##_impl_grow(_stack_)) \
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
_stack_->buffer[_stack_->count++] = element; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_pop(SNAME *_stack_) \
|
||||
{ \
|
||||
if (PFX##_empty(_stack_)) \
|
||||
return false; \
|
||||
\
|
||||
_stack_->buffer[--_stack_->count] = 0; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_push_if(SNAME *_stack_, V element, bool condition) \
|
||||
{ \
|
||||
if (condition) \
|
||||
return PFX##_push(_stack_, element); \
|
||||
\
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_pop_if(SNAME *_stack_, bool condition) \
|
||||
{ \
|
||||
if (condition) \
|
||||
return PFX##_pop(_stack_); \
|
||||
\
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
FMOD V PFX##_top(SNAME *_stack_) \
|
||||
{ \
|
||||
if (PFX##_empty(_stack_)) \
|
||||
return 0; \
|
||||
\
|
||||
return _stack_->buffer[_stack_->count - 1]; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_contains(SNAME *_stack_, V element, int (*comparator)(V, V)) \
|
||||
{ \
|
||||
for (size_t i = 0; i < _stack_->count; i++) \
|
||||
{ \
|
||||
if (comparator(_stack_->buffer[i], element) == 0) \
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_empty(SNAME *_stack_) \
|
||||
{ \
|
||||
return _stack_->count == 0; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_full(SNAME *_stack_) \
|
||||
{ \
|
||||
return _stack_->count >= _stack_->capacity; \
|
||||
} \
|
||||
\
|
||||
FMOD size_t PFX##_count(SNAME *_stack_) \
|
||||
{ \
|
||||
return _stack_->count; \
|
||||
} \
|
||||
\
|
||||
FMOD size_t PFX##_capacity(SNAME *_stack_) \
|
||||
{ \
|
||||
return _stack_->capacity; \
|
||||
} \
|
||||
\
|
||||
FMOD SNAME##_iter *PFX##_iter_new(SNAME *target) \
|
||||
{ \
|
||||
SNAME##_iter *iter = malloc(sizeof(SNAME##_iter)); \
|
||||
\
|
||||
if (!iter) \
|
||||
return NULL; \
|
||||
\
|
||||
PFX##_iter_init(iter, target); \
|
||||
\
|
||||
return iter; \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_iter_free(SNAME##_iter *iter) \
|
||||
{ \
|
||||
free(iter); \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_iter_init(SNAME##_iter *iter, SNAME *target) \
|
||||
{ \
|
||||
iter->target = target; \
|
||||
iter->cursor = iter->target->count - 1; \
|
||||
iter->start = true; \
|
||||
iter->end = PFX##_empty(target); \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_iter_start(SNAME##_iter *iter) \
|
||||
{ \
|
||||
return PFX##_empty(iter->target) || iter->start; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_iter_end(SNAME##_iter *iter) \
|
||||
{ \
|
||||
return PFX##_empty(iter->target) || iter->end; \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_iter_to_start(SNAME##_iter *iter) \
|
||||
{ \
|
||||
iter->cursor = iter->target->count - 1; \
|
||||
iter->start = true; \
|
||||
iter->end = PFX##_empty(iter->target); \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_iter_to_end(SNAME##_iter *iter) \
|
||||
{ \
|
||||
iter->cursor = 0; \
|
||||
iter->start = PFX##_empty(iter->target); \
|
||||
iter->end = true; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_iter_next(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (iter->end) \
|
||||
return false; \
|
||||
\
|
||||
iter->start = PFX##_empty(iter->target); \
|
||||
\
|
||||
if (iter->cursor == 0) \
|
||||
iter->end = true; \
|
||||
else \
|
||||
iter->cursor--; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_iter_prev(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (iter->start) \
|
||||
return false; \
|
||||
\
|
||||
iter->end = PFX##_empty(iter->target); \
|
||||
\
|
||||
if (iter->cursor == iter->target->count - 1) \
|
||||
iter->start = true; \
|
||||
else \
|
||||
iter->cursor++; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD V PFX##_iter_value(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (PFX##_empty(iter->target)) \
|
||||
return 0; \
|
||||
\
|
||||
return iter->target->buffer[iter->cursor]; \
|
||||
} \
|
||||
\
|
||||
FMOD V *PFX##_iter_rvalue(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (PFX##_empty(iter->target)) \
|
||||
return NULL; \
|
||||
\
|
||||
return &(iter->target->buffer[iter->cursor]); \
|
||||
} \
|
||||
\
|
||||
FMOD size_t PFX##_iter_index(SNAME##_iter *iter) \
|
||||
{ \
|
||||
return iter->target->count - 1 - iter->cursor; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_impl_grow(SNAME *_stack_) \
|
||||
{ \
|
||||
size_t new_capacity = _stack_->capacity * 2; \
|
||||
\
|
||||
V *new_buffer = realloc(_stack_->buffer, sizeof(V) * new_capacity); \
|
||||
\
|
||||
if (!new_buffer) \
|
||||
return false; \
|
||||
\
|
||||
_stack_->buffer = new_buffer; \
|
||||
_stack_->capacity = new_capacity; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
SNAME##_iter PFX##_impl_it_start(SNAME *_stack_) \
|
||||
{ \
|
||||
SNAME##_iter iter; \
|
||||
\
|
||||
PFX##_iter_init(&iter, _stack_); \
|
||||
PFX##_iter_to_start(&iter); \
|
||||
\
|
||||
return iter; \
|
||||
} \
|
||||
\
|
||||
SNAME##_iter PFX##_impl_it_end(SNAME *_stack_) \
|
||||
{ \
|
||||
SNAME##_iter iter; \
|
||||
\
|
||||
PFX##_iter_init(&iter, _stack_); \
|
||||
PFX##_iter_to_end(&iter); \
|
||||
\
|
||||
return iter; \
|
||||
}
|
||||
|
||||
#endif /* CMC_STACK_H */
|
||||
+820
-675
File diff suppressed because it is too large.
Load diff
+851
-741
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,204 @@
|
||||
#include "../src/macro_collections.h"
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
int intcmp(int a, int b)
|
||||
{
|
||||
return (a > b) - (a < b);
|
||||
}
|
||||
|
||||
size_t inthash(int t)
|
||||
{
|
||||
size_t a = t;
|
||||
a += ~(a << 15);
|
||||
a ^= (a >> 10);
|
||||
a += (a << 3);
|
||||
a ^= (a >> 6);
|
||||
a += ~(a << 11);
|
||||
a ^= (a >> 16);
|
||||
return a;
|
||||
}
|
||||
|
||||
COLLECTION_GENERATE(LIST, PUBLIC, l, list, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE(STACK, PUBLIC, s, stack, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE(QUEUE, PUBLIC, q, queue, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE(DEQUE, PUBLIC, d, deque, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE(LINKEDLIST, PUBLIC, ll, linked, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE(HEAP, PUBLIC, h, heap, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE(TREESET, PUBLIC, ts, tset, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE(TREEMAP, PUBLIC, tm, tmap, /* FMOD */, int, int)
|
||||
COLLECTION_GENERATE(HASHSET, PUBLIC, hs, hset, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE(HASHMAP, PUBLIC, hm, hmap, /* FMOD */, int, int)
|
||||
|
||||
int main(void)
|
||||
{
|
||||
list *l = l_new(1000);
|
||||
stack *s = s_new(1000);
|
||||
queue *q = q_new(1000);
|
||||
deque *d = d_new(1000);
|
||||
linked *ll = ll_new();
|
||||
heap *h = h_new(1000, MaxHeap, intcmp);
|
||||
tset *ts = ts_new(intcmp);
|
||||
tmap *tm = tm_new(intcmp);
|
||||
hset *hs = hs_new(1000, 0.9, intcmp, inthash);
|
||||
hmap *hm = hm_new(1000, 0.9, intcmp, inthash);
|
||||
|
||||
bool a[10] = {false, false, false, false, false, false, false, false, false, false},
|
||||
b[10] = {false, false, false, false, false, false, false, false, false, false},
|
||||
c[10] = {true, true, true, true, true, true, true, true, true, true};
|
||||
|
||||
b[0] = d_contains(d, 1, intcmp);
|
||||
b[1] = hm_contains(hm, 1);
|
||||
b[2] = hs_contains(hs, 1);
|
||||
b[3] = h_contains(h, 1);
|
||||
b[4] = ll_contains(ll, 1, intcmp);
|
||||
b[5] = l_contains(l, 1, intcmp);
|
||||
b[6] = q_contains(q, 1, intcmp);
|
||||
b[7] = s_contains(s, 1, intcmp);
|
||||
b[8] = tm_contains(tm, 1);
|
||||
b[9] = ts_contains(ts, 1);
|
||||
|
||||
for (int i = 1; i < 1001; i++)
|
||||
{
|
||||
if (i % 2 == 0)
|
||||
{
|
||||
d_push_front(d, i);
|
||||
l_push_front(l, i);
|
||||
ll_push_front(ll, i);
|
||||
}
|
||||
else
|
||||
{
|
||||
d_push_back(d, i);
|
||||
l_push_back(l, i);
|
||||
ll_push_back(ll, i);
|
||||
}
|
||||
|
||||
s_push(s, i);
|
||||
q_enqueue(q, i);
|
||||
h_insert(h, i);
|
||||
ts_insert(ts, i);
|
||||
tm_insert(tm, i, i);
|
||||
hs_insert(hs, i);
|
||||
hm_insert(hm, i, i);
|
||||
}
|
||||
|
||||
for (int i = 1; i < 1001; i++)
|
||||
{
|
||||
c[0] = c[0] && d_contains(d, i, intcmp);
|
||||
c[1] = c[1] && hm_contains(hm, i);
|
||||
c[2] = c[2] && hs_contains(hs, i);
|
||||
c[3] = c[3] && h_contains(h, i);
|
||||
c[4] = c[4] && ll_contains(ll, i, intcmp);
|
||||
c[5] = c[5] && l_contains(l, i, intcmp);
|
||||
c[6] = c[6] && q_contains(q, i, intcmp);
|
||||
c[7] = c[7] && s_contains(s, i, intcmp);
|
||||
c[8] = c[8] && tm_contains(tm, i);
|
||||
c[9] = c[9] && ts_contains(ts, i);
|
||||
}
|
||||
|
||||
for (int i = -500; i < 1; i++)
|
||||
{
|
||||
a[0] = a[0] || d_contains(d, i, intcmp);
|
||||
a[1] = a[1] || hm_contains(hm, i);
|
||||
a[2] = a[2] || hs_contains(hs, i);
|
||||
a[3] = a[3] || h_contains(h, i);
|
||||
a[4] = a[4] || ll_contains(ll, i, intcmp);
|
||||
a[5] = a[5] || l_contains(l, i, intcmp);
|
||||
a[6] = a[6] || q_contains(q, i, intcmp);
|
||||
a[7] = a[7] || s_contains(s, i, intcmp);
|
||||
a[8] = a[8] || tm_contains(tm, i);
|
||||
a[9] = a[9] || ts_contains(ts, i);
|
||||
}
|
||||
|
||||
for (int i = 1001; i < 1500; i++)
|
||||
{
|
||||
a[0] = a[0] || d_contains(d, i, intcmp);
|
||||
a[1] = a[1] || hm_contains(hm, i);
|
||||
a[2] = a[2] || hs_contains(hs, i);
|
||||
a[3] = a[3] || h_contains(h, i);
|
||||
a[4] = a[4] || ll_contains(ll, i, intcmp);
|
||||
a[5] = a[5] || l_contains(l, i, intcmp);
|
||||
a[6] = a[6] || q_contains(q, i, intcmp);
|
||||
a[7] = a[7] || s_contains(s, i, intcmp);
|
||||
a[8] = a[8] || tm_contains(tm, i);
|
||||
a[9] = a[9] || ts_contains(ts, i);
|
||||
}
|
||||
|
||||
d_clear(d);
|
||||
hm_clear(hm);
|
||||
hs_clear(hs);
|
||||
h_clear(h);
|
||||
ll_clear(ll);
|
||||
l_clear(l);
|
||||
q_clear(q);
|
||||
s_clear(s);
|
||||
tm_clear(tm);
|
||||
ts_clear(ts);
|
||||
|
||||
b[0] = b[0] || d_contains(d, 1, intcmp);
|
||||
b[1] = b[1] || hm_contains(hm, 1);
|
||||
b[2] = b[2] || hs_contains(hs, 1);
|
||||
b[3] = b[3] || h_contains(h, 1);
|
||||
b[4] = b[4] || ll_contains(ll, 1, intcmp);
|
||||
b[5] = b[5] || l_contains(l, 1, intcmp);
|
||||
b[6] = b[6] || q_contains(q, 1, intcmp);
|
||||
b[7] = b[7] || s_contains(s, 1, intcmp);
|
||||
b[8] = b[8] || tm_contains(tm, 1);
|
||||
b[9] = b[9] || ts_contains(ts, 1);
|
||||
|
||||
printf("-------------------- CONTAINS --------------------\n");
|
||||
if (c[0] && !a[0] && !b[0])
|
||||
printf("%10s PASSED\n", "DEQUE");
|
||||
else
|
||||
printf("%10s FAILED\n", "DEQUE");
|
||||
if (c[1] && !a[1] && !b[1])
|
||||
printf("%10s PASSED\n", "HASHMAP");
|
||||
else
|
||||
printf("%10s FAILED\n", "HASHMAP");
|
||||
if (c[2] && !a[2] && !b[2])
|
||||
printf("%10s PASSED\n", "HASHSET");
|
||||
else
|
||||
printf("%10s FAILED\n", "HASHSET");
|
||||
if (c[3] && !a[3] && !b[3])
|
||||
printf("%10s PASSED\n", "HEAP");
|
||||
else
|
||||
printf("%10s FAILED\n", "HEAP");
|
||||
if (c[4] && !a[4] && !b[4])
|
||||
printf("%10s PASSED\n", "LINKEDLIST");
|
||||
else
|
||||
printf("%10s FAILED\n", "LINKEDLIST");
|
||||
if (c[5] && !a[5] && !b[5])
|
||||
printf("%10s PASSED\n", "LIST");
|
||||
else
|
||||
printf("%10s FAILED\n", "LIST");
|
||||
if (c[6] && !a[6] && !b[6])
|
||||
printf("%10s PASSED\n", "QUEUE");
|
||||
else
|
||||
printf("%10s FAILED\n", "QUEUE");
|
||||
if (c[7] && !a[7] && !b[7])
|
||||
printf("%10s PASSED\n", "STACK");
|
||||
else
|
||||
printf("%10s FAILED\n", "STACK");
|
||||
if (c[8] && !a[8] && !b[8])
|
||||
printf("%10s PASSED\n", "TREEMAP");
|
||||
else
|
||||
printf("%10s FAILED\n", "TREEMAP");
|
||||
if (c[9] && !a[9] && !b[9])
|
||||
printf("%10s PASSED\n", "TREESET");
|
||||
else
|
||||
printf("%10s FAILED\n", "TREESET");
|
||||
|
||||
l_free(l);
|
||||
ll_free(ll);
|
||||
s_free(s);
|
||||
q_free(q);
|
||||
d_free(d);
|
||||
h_free(h);
|
||||
ts_free(ts);
|
||||
tm_free(tm);
|
||||
hs_free(hs);
|
||||
hm_free(hm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
+127
-85
@@ -1,6 +1,6 @@
|
||||
#include "../src/macro_collections.h"
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include "../src/macro_collections.h"
|
||||
|
||||
int intcmp(int a, int b)
|
||||
{
|
||||
@@ -19,18 +19,18 @@ size_t inthash(int t)
|
||||
return a;
|
||||
}
|
||||
|
||||
COLLECTION_GENERATE( LIST, PUBLIC, l, list, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE( STACK, PUBLIC, s, stack, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE( QUEUE, PUBLIC, q, queue, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE( DEQUE, PUBLIC, d, deque, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE(LIST, PUBLIC, l, list, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE(STACK, PUBLIC, s, stack, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE(QUEUE, PUBLIC, q, queue, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE(DEQUE, PUBLIC, d, deque, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE(LINKEDLIST, PUBLIC, ll, linked, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE( HEAP, PUBLIC, h, heap, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE( TREESET, PUBLIC, ts, tset, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE( TREEMAP, PUBLIC, tm, tmap, /* FMOD */, int, int)
|
||||
COLLECTION_GENERATE( HASHSET, PUBLIC, hs, hset, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE( HASHMAP, PUBLIC, hm, hmap, /* FMOD */, int, int)
|
||||
COLLECTION_GENERATE(HEAP, PUBLIC, h, heap, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE(TREESET, PUBLIC, ts, tset, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE(TREEMAP, PUBLIC, tm, tmap, /* FMOD */, int, int)
|
||||
COLLECTION_GENERATE(HASHSET, PUBLIC, hs, hset, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE(HASHMAP, PUBLIC, hm, hmap, /* FMOD */, int, int)
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
int main(void)
|
||||
{
|
||||
list *l = l_new(1000);
|
||||
stack *s = s_new(1000);
|
||||
@@ -70,136 +70,178 @@ int main(int argc, char const *argv[])
|
||||
int sum0 = 0, sum1 = 0, sum2 = 0, sum3 = 0, sum4 = 0, sum5 = 0, sum6 = 0,
|
||||
sum7 = 0, sum8 = 0, sum9 = 0, sum10 = 0, sum11 = 0;
|
||||
|
||||
FOR_EACH(l, list, int, l, {
|
||||
sum0 += value;
|
||||
FOR_EACH(d, deque, d, {
|
||||
sum3 += d_iter_value(&iter);
|
||||
})
|
||||
|
||||
FOR_EACH(s, stack, int, s, {
|
||||
sum1 += value;
|
||||
FOR_EACH(hm, hmap, hm, {
|
||||
sum10 += hm_iter_key(&iter);
|
||||
sum11 += hm_iter_value(&iter);
|
||||
})
|
||||
|
||||
FOR_EACH(q, queue, int, q, {
|
||||
sum2 += value;
|
||||
FOR_EACH(hs, hset, hs, {
|
||||
sum9 += hs_iter_value(&iter);
|
||||
})
|
||||
|
||||
FOR_EACH(d, deque, int, d, {
|
||||
sum3 += value;
|
||||
FOR_EACH(h, heap, h, {
|
||||
sum5 += h_iter_value(&iter);
|
||||
})
|
||||
|
||||
FOR_EACH(ll, linked, int, ll, {
|
||||
sum4 += value;
|
||||
FOR_EACH(ll, linked, ll, {
|
||||
sum4 += ll_iter_value(&iter);
|
||||
})
|
||||
|
||||
FOR_EACH(h, heap, int, h, {
|
||||
sum5 += value;
|
||||
FOR_EACH(l, list, l, {
|
||||
sum0 += l_iter_value(&iter);
|
||||
})
|
||||
|
||||
FOR_EACH(ts, tset, int, ts, {
|
||||
sum6 += value;
|
||||
FOR_EACH(q, queue, q, {
|
||||
sum2 += q_iter_value(&iter);
|
||||
})
|
||||
|
||||
FOR_EACH_MAP(tm, tmap, int, int, tm, {
|
||||
sum7 += key;
|
||||
sum8 += value;
|
||||
FOR_EACH(s, stack, s, {
|
||||
sum1 += s_iter_value(&iter);
|
||||
})
|
||||
|
||||
FOR_EACH(hs, hset, int, hs, {
|
||||
sum9 += value;
|
||||
FOR_EACH(tm, tmap, tm, {
|
||||
sum7 += tm_iter_key(&iter);
|
||||
sum8 += tm_iter_value(&iter);
|
||||
})
|
||||
|
||||
FOR_EACH_MAP(hm, hmap, int, int, hm, {
|
||||
sum10 += key;
|
||||
sum11 += value;
|
||||
FOR_EACH(ts, tset, ts, {
|
||||
sum6 += ts_iter_value(&iter);
|
||||
})
|
||||
|
||||
if (sum0 == 50005000)
|
||||
printf("%10s PASSED\n", "LIST");
|
||||
if (sum1 == 50005000)
|
||||
printf("%10s PASSED\n", "STACK");
|
||||
if (sum2 == 50005000)
|
||||
printf("%10s PASSED\n", "QUEUE");
|
||||
printf("\n-------------------- FOR_EACH --------------------\n");
|
||||
if (sum3 == 50005000)
|
||||
printf("%10s PASSED\n", "DEQUE");
|
||||
if (sum4 == 50005000)
|
||||
printf("%10s PASSED\n", "LINKEDLIST");
|
||||
if (sum5 == 50005000)
|
||||
printf("%10s PASSED\n", "HEAP");
|
||||
if (sum6 == 50005000)
|
||||
printf("%10s PASSED\n", "TREESET");
|
||||
if (sum7 == 50005000 && sum8 == 50005000)
|
||||
printf("%10s PASSED\n", "TREEMAP");
|
||||
else
|
||||
printf("%10s FAILED\n", "DEQUE");
|
||||
if (sum9 == 50005000)
|
||||
printf("%10s PASSED\n", "HASHSET");
|
||||
else
|
||||
printf("%10s FAILED\n", "HASHSET");
|
||||
if (sum10 == 50005000 && sum11 == 50005000)
|
||||
printf("%10s PASSED\n", "HASHMAP");
|
||||
else
|
||||
printf("%10s FAILED\n", "HASHMAP");
|
||||
if (sum5 == 50005000)
|
||||
printf("%10s PASSED\n", "HEAP");
|
||||
else
|
||||
printf("%10s FAILED\n", "HEAP");
|
||||
if (sum4 == 50005000)
|
||||
printf("%10s PASSED\n", "LINKEDLIST");
|
||||
else
|
||||
printf("%10s FAILED\n", "LINKEDLIST");
|
||||
if (sum0 == 50005000)
|
||||
printf("%10s PASSED\n", "LIST");
|
||||
else
|
||||
printf("%10s FAILED\n", "LIST");
|
||||
if (sum2 == 50005000)
|
||||
printf("%10s PASSED\n", "QUEUE");
|
||||
else
|
||||
printf("%10s FAILED\n", "QUEUE");
|
||||
if (sum1 == 50005000)
|
||||
printf("%10s PASSED\n", "STACK");
|
||||
else
|
||||
printf("%10s FAILED\n", "STACK");
|
||||
if (sum7 == 50005000 && sum8 == 50005000)
|
||||
printf("%10s PASSED\n", "TREEMAP");
|
||||
else
|
||||
printf("%10s FAILED\n", "TREEMAP");
|
||||
if (sum6 == 50005000)
|
||||
printf("%10s PASSED\n", "TREESET");
|
||||
else
|
||||
printf("%10s FAILED\n", "TREESET");
|
||||
|
||||
printf("\n\n");
|
||||
|
||||
sum0 = 0, sum1 = 0, sum2 = 0, sum3 = 0, sum4 = 0, sum5 = 0, sum6 = 0,
|
||||
sum7 = 0, sum8 = 0, sum9 = 0, sum10 = 0, sum11 = 0;
|
||||
|
||||
FOR_EACH_REV(l, list, int, l, {
|
||||
sum0 += value;
|
||||
FOR_EACH_REV(d, deque, d, {
|
||||
sum3 += d_iter_value(&iter);
|
||||
})
|
||||
|
||||
FOR_EACH_REV(s, stack, int, s, {
|
||||
sum1 += value;
|
||||
FOR_EACH_REV(hm, hmap, hm, {
|
||||
sum10 += hm_iter_key(&iter);
|
||||
sum11 += hm_iter_value(&iter);
|
||||
})
|
||||
|
||||
FOR_EACH_REV(q, queue, int, q, {
|
||||
sum2 += value;
|
||||
FOR_EACH_REV(hs, hset, hs, {
|
||||
sum9 += hs_iter_value(&iter);
|
||||
})
|
||||
|
||||
FOR_EACH_REV(d, deque, int, d, {
|
||||
sum3 += value;
|
||||
FOR_EACH_REV(h, heap, h, {
|
||||
sum5 += h_iter_value(&iter);
|
||||
})
|
||||
|
||||
FOR_EACH_REV(ll, linked, int, ll, {
|
||||
sum4 += value;
|
||||
FOR_EACH_REV(ll, linked, ll, {
|
||||
sum4 += ll_iter_value(&iter);
|
||||
})
|
||||
|
||||
FOR_EACH_REV(h, heap, int, h, {
|
||||
sum5 += value;
|
||||
FOR_EACH_REV(l, list, l, {
|
||||
sum0 += l_iter_value(&iter);
|
||||
})
|
||||
|
||||
FOR_EACH_REV(ts, tset, int, ts, {
|
||||
sum6 += value;
|
||||
FOR_EACH_REV(q, queue, q, {
|
||||
sum2 += q_iter_value(&iter);
|
||||
})
|
||||
|
||||
FOR_EACH_MAP_REV(tm, tmap, int, int, tm, {
|
||||
sum7 += key;
|
||||
sum8 += value;
|
||||
FOR_EACH_REV(s, stack, s, {
|
||||
sum1 += s_iter_value(&iter);
|
||||
})
|
||||
|
||||
FOR_EACH_REV(hs, hset, int, hs, {
|
||||
sum9 += value;
|
||||
FOR_EACH_REV(tm, tmap, tm, {
|
||||
sum7 += tm_iter_key(&iter);
|
||||
sum8 += tm_iter_value(&iter);
|
||||
})
|
||||
|
||||
FOR_EACH_MAP_REV(tm, tmap, int, int, tm, {
|
||||
sum10 += key;
|
||||
sum11 += value;
|
||||
FOR_EACH_REV(ts, tset, ts, {
|
||||
sum6 += ts_iter_value(&iter);
|
||||
})
|
||||
|
||||
if (sum0 == 50005000)
|
||||
printf("%10s PASSED\n", "LIST");
|
||||
if (sum1 == 50005000)
|
||||
printf("%10s PASSED\n", "STACK");
|
||||
if (sum2 == 50005000)
|
||||
printf("%10s PASSED\n", "QUEUE");
|
||||
printf("-------------------- FOR_EACH_REV --------------------\n");
|
||||
if (sum3 == 50005000)
|
||||
printf("%10s PASSED\n", "DEQUE");
|
||||
if (sum4 == 50005000)
|
||||
printf("%10s PASSED\n", "LINKEDLIST");
|
||||
if (sum5 == 50005000)
|
||||
printf("%10s PASSED\n", "HEAP");
|
||||
if (sum6 == 50005000)
|
||||
printf("%10s PASSED\n", "TREESET");
|
||||
if (sum7 == 50005000 && sum8 == 50005000)
|
||||
printf("%10s PASSED\n", "TREEMAP");
|
||||
if (sum9 == 50005000)
|
||||
printf("%10s PASSED\n", "HASHSET");
|
||||
else
|
||||
printf("%10s FAILED\n", "DEQUE");
|
||||
if (sum10 == 50005000 && sum11 == 50005000)
|
||||
printf("%10s PASSED\n", "HASHMAP");
|
||||
else
|
||||
printf("%10s FAILED\n", "HASHMAP");
|
||||
if (sum9 == 50005000)
|
||||
printf("%10s PASSED\n", "HASHSET");
|
||||
else
|
||||
printf("%10s FAILED\n", "HASHSET");
|
||||
if (sum5 == 50005000)
|
||||
printf("%10s PASSED\n", "HEAP");
|
||||
else
|
||||
printf("%10s FAILED\n", "HEAP");
|
||||
if (sum4 == 50005000)
|
||||
printf("%10s PASSED\n", "LINKEDLIST");
|
||||
else
|
||||
printf("%10s FAILED\n", "LINKEDLIST");
|
||||
if (sum0 == 50005000)
|
||||
printf("%10s PASSED\n", "LIST");
|
||||
else
|
||||
printf("%10s FAILED\n", "LIST");
|
||||
if (sum2 == 50005000)
|
||||
printf("%10s PASSED\n", "QUEUE");
|
||||
else
|
||||
printf("%10s FAILED\n", "QUEUE");
|
||||
if (sum1 == 50005000)
|
||||
printf("%10s PASSED\n", "STACK");
|
||||
else
|
||||
printf("%10s FAILED\n", "STACK");
|
||||
if (sum7 == 50005000 && sum8 == 50005000)
|
||||
printf("%10s PASSED\n", "TREEMAP");
|
||||
else
|
||||
printf("%10s FAILED\n", "TREEMAP");
|
||||
if (sum6 == 50005000)
|
||||
printf("%10s PASSED\n", "TREESET");
|
||||
else
|
||||
printf("%10s FAILED\n", "TREESET");
|
||||
|
||||
l_free(l);
|
||||
ll_free(ll);
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
#include "../src/macro_collections.h"
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
|
||||
int intcmp(int a, int b)
|
||||
{
|
||||
return a - b;
|
||||
}
|
||||
|
||||
size_t inthash(int t)
|
||||
{
|
||||
size_t a = t;
|
||||
a += ~(a << 15);
|
||||
a ^= (a >> 10);
|
||||
a += (a << 3);
|
||||
a ^= (a >> 6);
|
||||
a += ~(a << 11);
|
||||
a ^= (a >> 16);
|
||||
return a;
|
||||
}
|
||||
|
||||
COLLECTION_GENERATE(LIST, PUBLIC, l, list, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE(STACK, PUBLIC, s, stack, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE(QUEUE, PUBLIC, q, queue, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE(DEQUE, PUBLIC, d, deque, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE(LINKEDLIST, PUBLIC, ll, linked, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE(HEAP, PUBLIC, h, heap, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE(TREESET, PUBLIC, ts, tset, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE(TREEMAP, PUBLIC, tm, tmap, /* FMOD */, int, double)
|
||||
COLLECTION_GENERATE(HASHSET, PUBLIC, hs, hset, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE(HASHMAP, PUBLIC, hm, hmap, /* FMOD */, int, double)
|
||||
|
||||
#define ITERATOR_TEST(NAME, PFX, sname, initfunc, insertbody, sumbody, validation1, validation2) \
|
||||
void NAME##_iterator_test(void) \
|
||||
{ \
|
||||
int sum1 = 0; \
|
||||
double sum2 = 0.0; \
|
||||
\
|
||||
sname *coll = initfunc; \
|
||||
for (int i = 0; i < 10; i++) \
|
||||
{ \
|
||||
insertbody; \
|
||||
} \
|
||||
\
|
||||
sname##_iter iter; \
|
||||
PFX##_iter_init(&iter, coll); \
|
||||
\
|
||||
for (int j = 0; j < 4; j++) \
|
||||
{ \
|
||||
while (!PFX##_iter_end(&iter)) \
|
||||
{ \
|
||||
sumbody; \
|
||||
PFX##_iter_next(&iter); \
|
||||
} \
|
||||
while (!PFX##_iter_start(&iter)) \
|
||||
{ \
|
||||
sumbody; \
|
||||
PFX##_iter_prev(&iter); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
for (PFX##_iter_to_start(&iter); !PFX##_iter_end(&iter); PFX##_iter_next(&iter)) \
|
||||
{ \
|
||||
sumbody; \
|
||||
} \
|
||||
\
|
||||
for (PFX##_iter_to_end(&iter); !PFX##_iter_start(&iter); PFX##_iter_prev(&iter)) \
|
||||
{ \
|
||||
sumbody; \
|
||||
} \
|
||||
\
|
||||
PFX##_free(coll); \
|
||||
\
|
||||
if (validation1 && validation2) \
|
||||
printf("%10s PASSED\n", #NAME); \
|
||||
else \
|
||||
printf("%10s FAILED\n", #NAME); \
|
||||
}
|
||||
|
||||
ITERATOR_TEST(DEQUE, d, deque, d_new(20), d_push_front(coll, i), sum1 += d_iter_value(&iter), sum1 == 450, 1)
|
||||
ITERATOR_TEST(HASHMAP, hm, hmap, hm_new(50, 0.6, intcmp, inthash), hm_insert(coll, i, (double)i / 10.0), sum1 += hm_iter_key(&iter); sum2 += hm_iter_value(&iter), sum1 == 450, sum2 == 45.0)
|
||||
ITERATOR_TEST(HASHSET, hs, hset, hs_new(50, 0.6, intcmp, inthash), hs_insert(coll, i), sum1 += hs_iter_value(&iter), sum1 == 450, 1)
|
||||
ITERATOR_TEST(HEAP, h, heap, h_new(20, MaxHeap, intcmp), h_insert(coll, i), sum1 += h_iter_value(&iter), sum1 == 450, 1)
|
||||
ITERATOR_TEST(LINKEDLIST, ll, linked, ll_new(), ll_push_back(coll, i), sum1 += ll_iter_value(&iter), sum1 == 450, 1)
|
||||
ITERATOR_TEST(LIST, l, list, l_new(20), l_push_back(coll, i), sum1 += l_iter_value(&iter), sum1 == 450, 1)
|
||||
ITERATOR_TEST(QUEUE, q, queue, q_new(20), q_enqueue(coll, i), sum1 += q_iter_value(&iter), sum1 == 450, 1)
|
||||
ITERATOR_TEST(STACK, s, stack, s_new(20), s_push(coll, i), sum1 += s_iter_value(&iter), sum1 == 450, 1)
|
||||
ITERATOR_TEST(TREEMAP, tm, tmap, tm_new(intcmp), tm_insert(coll, i, (double)i / 10.0), sum1 += tm_iter_key(&iter); sum2 += tm_iter_value(&iter), sum1 == 450, sum2 == 45.0)
|
||||
ITERATOR_TEST(TREESET, ts, tset, ts_new(intcmp), ts_insert(coll, i), sum1 += ts_iter_value(&iter), sum1 == 450, 1)
|
||||
|
||||
int main(void)
|
||||
{
|
||||
printf("\n-------------------- ITERATORS --------------------\n");
|
||||
DEQUE_iterator_test();
|
||||
HASHMAP_iterator_test();
|
||||
HASHSET_iterator_test();
|
||||
HEAP_iterator_test();
|
||||
LINKEDLIST_iterator_test();
|
||||
LIST_iterator_test();
|
||||
QUEUE_iterator_test();
|
||||
STACK_iterator_test();
|
||||
TREEMAP_iterator_test();
|
||||
TREESET_iterator_test();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
// Checks if the deque iterator can go back and forward in the deque without
|
||||
// hitting invalid states or a null pointer. Check is done visually.
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "../../src/deque.h"
|
||||
|
||||
DEQUE_GENERATE(d, deque, static, int)
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
{
|
||||
size_t i;
|
||||
int r;
|
||||
|
||||
// Initialize deque and add some elements
|
||||
deque *d = d_new(10);
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
i % 2 == 0 ? d_push_back(d, i) : d_push_front(d, i);
|
||||
}
|
||||
|
||||
// Initialize iterator
|
||||
deque_iter iter;
|
||||
d_iter_new(&iter, d);
|
||||
|
||||
// Make the iterator go back and forward
|
||||
for (int j = 0; j < 4; j++)
|
||||
{
|
||||
while (d_iter_next(&iter, &r, &i))
|
||||
printf("C[%2d] = %2d\n", i, r);
|
||||
printf("\n");
|
||||
while (d_iter_prev(&iter, &r, &i))
|
||||
printf("C[%2d] = %2d\n", i, r);
|
||||
printf("\n\n");
|
||||
}
|
||||
|
||||
for (d_iter_tostart(&iter); !d_iter_end(&iter); /**/)
|
||||
{
|
||||
d_iter_next(&iter, &r, &i);
|
||||
printf("D[%2d] = %2d\n", i, r);
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
|
||||
for (d_iter_toend(&iter); !d_iter_start(&iter); /**/)
|
||||
{
|
||||
d_iter_prev(&iter, &r, &i);
|
||||
printf("D[%2d] = %2d\n", i, r);
|
||||
}
|
||||
|
||||
d_free(d);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
// Checks if the hashmap iterator can go back and forward in the hashmap without
|
||||
// hitting invalid states or a null pointer. Check is done visually.
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "../../src/hashmap.h"
|
||||
|
||||
HASHMAP_GENERATE(hm, hmap, static, int, double)
|
||||
|
||||
size_t inthash(int t)
|
||||
{
|
||||
size_t a = t;
|
||||
a += ~(a << 15);
|
||||
a ^= (a >> 10);
|
||||
a += (a << 3);
|
||||
a ^= (a >> 6);
|
||||
a += ~(a << 11);
|
||||
a ^= (a >> 16);
|
||||
return a;
|
||||
}
|
||||
|
||||
int intcmp(int a, int b)
|
||||
{
|
||||
return a - b;
|
||||
}
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
{
|
||||
size_t i;
|
||||
int k;
|
||||
double v, varr[10] = {0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9};
|
||||
|
||||
// Initialize hashmap and add some element
|
||||
hmap *hm = hm_new(50, 0.9, intcmp, inthash);
|
||||
for (int i = 0; i < 10; i++)
|
||||
hm_insert(hm, i, varr[i]);
|
||||
|
||||
// Initialize iterator
|
||||
hmap_iter iter;
|
||||
hm_iter_new(&iter, hm);
|
||||
|
||||
// Make the iterator go back and forward
|
||||
for (int j = 0; j < 4; j++)
|
||||
{
|
||||
while (hm_iter_next(&iter, &k, &v, &i))
|
||||
printf("S[%2d] = { %2d : %2.2lf }\n", i, k, v);
|
||||
printf("\n");
|
||||
while (hm_iter_prev(&iter, &k, &v, &i))
|
||||
printf("S[%2d] = { %2d : %2.2lf }\n", i, k, v);
|
||||
printf("\n\n");
|
||||
}
|
||||
|
||||
for (hm_iter_tostart(&iter); !hm_iter_end(&iter); /**/)
|
||||
{
|
||||
hm_iter_next(&iter, &k, &v, &i);
|
||||
printf("M[%2d] = { %2d : %2.2lf }\n", i, k, v);
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
|
||||
for (hm_iter_toend(&iter); !hm_iter_start(&iter); /**/)
|
||||
{
|
||||
hm_iter_prev(&iter, &k, &v, &i);
|
||||
printf("M[%2d] = { %2d : %2.2lf }\n", i, k, v);
|
||||
}
|
||||
|
||||
hm_free(hm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
// Checks if the hash set iterator can go back and forward in the hash set without
|
||||
// hitting invalid states or a null pointer. Check is done visually.
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "../../src/hashset.h"
|
||||
|
||||
HASHSET_GENERATE(hs, hash_set, static, int)
|
||||
|
||||
size_t inthash(int t)
|
||||
{
|
||||
size_t a = t;
|
||||
a += ~(a << 15);
|
||||
a ^= (a >> 10);
|
||||
a += (a << 3);
|
||||
a ^= (a >> 6);
|
||||
a += ~(a << 11);
|
||||
a ^= (a >> 16);
|
||||
return a;
|
||||
}
|
||||
|
||||
int intcmp(int a, int b)
|
||||
{
|
||||
return a - b;
|
||||
}
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
{
|
||||
size_t i;
|
||||
int r;
|
||||
|
||||
// Initialize hash set and add some elements
|
||||
hash_set *hs = hs_new(10, 0.9, intcmp, inthash);
|
||||
for (int i = 0; i < 10; i++)
|
||||
hs_insert(hs, i);
|
||||
|
||||
// Initialize iterator
|
||||
hash_set_iter iter;
|
||||
hs_iter_new(&iter, hs);
|
||||
|
||||
// Make the iterator go back and forward
|
||||
for (int j = 0; j < 4; j++)
|
||||
{
|
||||
while (hs_iter_next(&iter, &r, &i))
|
||||
printf("C[%2d] = %2d\n", i, r);
|
||||
printf("\n");
|
||||
while (hs_iter_prev(&iter, &r, &i))
|
||||
printf("C[%2d] = %2d\n", i, r);
|
||||
printf("\n\n");
|
||||
}
|
||||
|
||||
for (hs_iter_tostart(&iter); !hs_iter_end(&iter); /**/)
|
||||
{
|
||||
hs_iter_next(&iter, &r, &i);
|
||||
printf("S[%2d] = %2d\n", i, r);
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
|
||||
for (hs_iter_toend(&iter); !hs_iter_start(&iter); /**/)
|
||||
{
|
||||
hs_iter_prev(&iter, &r, &i);
|
||||
printf("S[%2d] = %2d\n", i, r);
|
||||
}
|
||||
|
||||
hs_free(hs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
// Checks if the heap iterator can go back and forward in the heap without
|
||||
// hitting invalid states or a null pointer. Check is done visually.
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "../../src/heap.h"
|
||||
|
||||
int intcmp(int a, int b)
|
||||
{
|
||||
return a - b;
|
||||
}
|
||||
|
||||
HEAP_GENERATE(h, heap, static, int)
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
{
|
||||
size_t i;
|
||||
int r;
|
||||
|
||||
// Initialize heap and add some elements
|
||||
heap *h = h_new(10, MinHeap, intcmp);
|
||||
for (int i = 9; i >= 0; i--)
|
||||
h_insert(h, i);
|
||||
|
||||
// Initialize iterator
|
||||
heap_iter iter;
|
||||
h_iter_new(&iter, h);
|
||||
|
||||
// Make the iterator go back and forward
|
||||
for (int j = 0; j < 4; j++)
|
||||
{
|
||||
while (h_iter_next(&iter, &r, &i))
|
||||
printf("C[%2d] = %2d\n", i, r);
|
||||
printf("\n");
|
||||
while (h_iter_prev(&iter, &r, &i))
|
||||
printf("C[%2d] = %2d\n", i, r);
|
||||
printf("\n\n");
|
||||
}
|
||||
|
||||
for (h_iter_tostart(&iter); !h_iter_end(&iter); /**/)
|
||||
{
|
||||
h_iter_next(&iter, &r, &i);
|
||||
printf("L[%2d] = %2d\n", i, r);
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
|
||||
for (h_iter_toend(&iter); !h_iter_start(&iter); /**/)
|
||||
{
|
||||
h_iter_prev(&iter, &r, &i);
|
||||
printf("L[%2d] = %2d\n", i, r);
|
||||
}
|
||||
|
||||
h_free(h);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
// Checks if the linked list iterator can go back and forward in the list
|
||||
// without hitting invalid states or a null pointer. Check is done visually.
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "../../src/linkedlist.h"
|
||||
|
||||
LINKEDLIST_GENERATE(ll, linked, static, int)
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
{
|
||||
size_t i;
|
||||
int r;
|
||||
|
||||
// Initialize linked list and add some elements
|
||||
linked *ll = ll_new();
|
||||
for (int i = 0; i < 10; i++)
|
||||
ll_push_back(ll, i);
|
||||
|
||||
// Initialize iterator
|
||||
linked_iter iter;
|
||||
ll_iter_new(&iter, ll);
|
||||
|
||||
// Make the iterator go back and forward
|
||||
for (int j = 0; j < 4; j++)
|
||||
{
|
||||
while (ll_iter_next(&iter, &r, &i))
|
||||
printf("C[%2d] = %2d\n", i, r);
|
||||
printf("\n");
|
||||
while (ll_iter_prev(&iter, &r, &i))
|
||||
printf("C[%2d] = %2d\n", i, r);
|
||||
printf("\n\n");
|
||||
}
|
||||
|
||||
for (ll_iter_tostart(&iter); !ll_iter_end(&iter); /**/)
|
||||
{
|
||||
ll_iter_next(&iter, &r, &i);
|
||||
printf("LL[%2d] = %2d\n", i, r);
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
|
||||
for (ll_iter_toend(&iter); !ll_iter_start(&iter); /**/)
|
||||
{
|
||||
ll_iter_prev(&iter, &r, &i);
|
||||
printf("LL[%2d] = %2d\n", i, r);
|
||||
}
|
||||
|
||||
ll_free(ll);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
// Checks if the list iterator can go back and forward in the list without
|
||||
// hitting invalid states or a null pointer. Check is done visually.
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "../../src/list.h"
|
||||
|
||||
LIST_GENERATE(l, list, static, int)
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
{
|
||||
size_t i;
|
||||
int r;
|
||||
|
||||
// Initialize list and add some elements
|
||||
list *l = l_new(10);
|
||||
for (int i = 0; i < 10; i++)
|
||||
l_push_back(l, i);
|
||||
|
||||
// Initialize iterator
|
||||
list_iter iter;
|
||||
l_iter_new(&iter, l);
|
||||
|
||||
// Make the iterator go back and forward
|
||||
for (int j = 0; j < 4; j++)
|
||||
{
|
||||
while (l_iter_next(&iter, &r, &i))
|
||||
printf("C[%2d] = %2d\n", i, r);
|
||||
printf("\n");
|
||||
while (l_iter_prev(&iter, &r, &i))
|
||||
printf("C[%2d] = %2d\n", i, r);
|
||||
printf("\n\n");
|
||||
}
|
||||
|
||||
for (l_iter_tostart(&iter); !l_iter_end(&iter); /**/)
|
||||
{
|
||||
l_iter_next(&iter, &r, &i);
|
||||
printf("L[%2d] = %2d\n", i, r);
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
|
||||
for (l_iter_toend(&iter); !l_iter_start(&iter); /**/)
|
||||
{
|
||||
l_iter_prev(&iter, &r, &i);
|
||||
printf("L[%2d] = %2d\n", i, r);
|
||||
}
|
||||
|
||||
l_free(l);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
// Tests all containers if they accept a pinter type
|
||||
// Compile with -Wall -Wextra
|
||||
#include "../src/macro_collections.h"
|
||||
#include <stdio.h>
|
||||
|
||||
typedef struct my_struct_s
|
||||
{
|
||||
int a, b;
|
||||
} my_struct;
|
||||
|
||||
COLLECTION_GENERATE(LIST, PUBLIC, l, list, /* FMOD */, /* K */, my_struct *)
|
||||
COLLECTION_GENERATE(STACK, PUBLIC, s, stack, /* FMOD */, /* K */, my_struct *)
|
||||
COLLECTION_GENERATE(QUEUE, PUBLIC, q, queue, /* FMOD */, /* K */, my_struct *)
|
||||
COLLECTION_GENERATE(DEQUE, PUBLIC, d, deque, /* FMOD */, /* K */, my_struct *)
|
||||
COLLECTION_GENERATE(LINKEDLIST, PUBLIC, ll, linked, /* FMOD */, /* K */, my_struct *)
|
||||
COLLECTION_GENERATE(HEAP, PUBLIC, h, heap, /* FMOD */, /* K */, my_struct *)
|
||||
COLLECTION_GENERATE(TREESET, PUBLIC, ts, tset, /* FMOD */, /* K */, my_struct *)
|
||||
COLLECTION_GENERATE(TREEMAP, PUBLIC, tm, tmap, /* FMOD */, my_struct *, my_struct *)
|
||||
COLLECTION_GENERATE(HASHSET, PUBLIC, hs, hset, /* FMOD */, /* K */, my_struct *)
|
||||
COLLECTION_GENERATE(HASHMAP, PUBLIC, hm, hmap, /* FMOD */, my_struct *, my_struct *)
|
||||
|
||||
int main(void)
|
||||
{
|
||||
printf("+--------------------------------------------------+\n");
|
||||
printf("| Pointer Data Type is Working |\n");
|
||||
printf("+--------------------------------------------------+\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in new issue
Block a user