Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
de744f5822 | ||
|
|
5583ca38b3 | ||
|
|
2d3b441d74 | ||
|
|
99cd01ba1e | ||
|
|
1f11b6d2da | ||
|
|
e41fe14502 | ||
|
|
63d0453341 | ||
|
|
5e1a26b72e | ||
|
|
e06e795ed8 | ||
|
|
b9b507bf07 | ||
|
|
9f8671f75f | ||
|
|
f0b7b125b9 | ||
|
|
8483eda701 | ||
|
|
b870649627 | ||
|
|
93ac623ffe | ||
|
|
5997302a8c | ||
|
|
f52a9ff702 | ||
|
|
376c0ad4e7 | ||
|
|
34e649d82a | ||
|
|
bfb8426183 | ||
|
|
4f755f0915 | ||
|
|
dea77b5ca2 | ||
|
|
b300c889f3 | ||
|
|
2126da3f25 | ||
|
|
fb7854ef5d | ||
|
|
1ff3142769 | ||
|
|
331fb32b73 | ||
|
|
fa03379580 | ||
|
|
43f4ae9f16 | ||
|
|
d9171a11cf | ||
|
|
344e9f77fe | ||
|
|
2c84c35264 | ||
|
|
c27edd53f6 | ||
|
|
a0db76b50d | ||
|
|
bb3efd75ff | ||
|
|
3d7e218195 | ||
|
|
191c47fc7c | ||
|
|
f2f806612f | ||
|
|
5e2e001265 | ||
|
|
2ca2210a77 | ||
|
|
747aa8cb4e | ||
|
|
4fe4e96811 | ||
|
|
0df0ebbdeb | ||
|
|
e834aaee81 | ||
|
|
1928fdd6d5 | ||
|
|
abdbfa2018 | ||
|
|
a1a940399a | ||
|
|
855e085996 | ||
|
|
e95379bdd7 | ||
|
|
762b95db26 | ||
|
|
396066f289 | ||
|
|
f070d274f4 | ||
|
|
1f50add1bb | ||
|
|
e68b8a8e0e | ||
|
|
5ee7bfa23a | ||
|
|
8ec768d30e | ||
|
|
35d27ffb39 | ||
|
|
613392ae76 |
No files matched your search
+3
-4
@@ -12,9 +12,8 @@ addons:
|
||||
script:
|
||||
- sudo ln -s /usr/bin/gcc-6 /usr/local/bin/gcc
|
||||
- export CC=gcc-7
|
||||
- cd ./tests
|
||||
- make --always-make
|
||||
- cd ./main
|
||||
- make --always-make
|
||||
- make -C ./tests/
|
||||
- make -C ./tests/main/
|
||||
- make -C ./tests/codecov/
|
||||
after_success:
|
||||
- bash <(curl -s https://codecov.io/bash)
|
||||
@@ -1,5 +1,47 @@
|
||||
# RELEASE.MAJOR.MINOR
|
||||
|
||||
1.7.2
|
||||
- Added resize function to array based collections
|
||||
- Added the following functions to hashtable based collections:
|
||||
- load
|
||||
- full
|
||||
- Added more assert macros utility
|
||||
- Added plenty more tests
|
||||
- Substituted impl_default_value / key by compound literals
|
||||
- Removed unnecessary conditional input and output functions
|
||||
- Minor fixes throughout the library
|
||||
|
||||
1.7.1
|
||||
- Added new assert macro cmc_assert_sorted
|
||||
- Fixed some include guards for hashtables
|
||||
- Moved the cmc string format to each file
|
||||
- Renamed some list functions (sequence input/output)
|
||||
- Renamed list and linkedlist functions push and pop to push_at and pop_at
|
||||
|
||||
1.7.0
|
||||
- Removed FMOD (function modifier)
|
||||
- Added CMC prefix to all macros defined within the library
|
||||
|
||||
1.6.3
|
||||
- Added iterator functions to all collections:
|
||||
- iter_advance
|
||||
- iter_rewind
|
||||
- iter_go_to
|
||||
- Added cmc prefix to the logging utility
|
||||
- Integrated the assert utility with the test utility. Now any assertion that fails inside the unit test will trigger failure and is no longer needed to manually pass or fail tests.
|
||||
|
||||
1.6.2
|
||||
Added new functions to all collections:
|
||||
- copy_of
|
||||
- equals
|
||||
Added the new collections to the tests
|
||||
Fixed some collections and some improvements to the hashtables
|
||||
Unified the functions set and update from the map implementations
|
||||
|
||||
1.6.1
|
||||
Removed ./ext/linkedqueue.h
|
||||
Added a deallocator parameter to all _free and _clear functions
|
||||
|
||||
1.6.0
|
||||
Added ./ext/intervalheap.h
|
||||
Added ./ext/multimap.h
|
||||
|
||||
@@ -1,11 +1,31 @@
|
||||
# C-Macro-Collections
|
||||
# C Macro Collections
|
||||
|
||||
Generate Simple Data Structures of any type in C for you to use in your projects.
|
||||
<p align="center">
|
||||
<img src="https://leoven.github.io/C-Macro-Collections/images/logo.png" alt="C Macro Collections Logo" width="300"/>
|
||||
</p>
|
||||
|
||||

|
||||

|
||||
[](https://travis-ci.org/LeoVen/C-Macro-Collections)
|
||||
[](https://codecov.io/gh/LeoVen/C-Macro-Collections)
|
||||
<p align="center">Header only, macro generated, generic and type-safe Collections in C.</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/LeoVen/C-Macro-Collections"><img src="https://img.shields.io/badge/GitHub-C%20Macro%20Collections-lightgrey.svg?logo=github" alt="LinkToRepo"/></a>
|
||||
<a href="https://leoven.github.io/C-Macro-Collections/"><img style="color: #ffffff;" src="https://img.shields.io/badge/Read%20the%20Docs-5A5A5A.svg?logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHN0eWxlPSIiPjxyZWN0IGlkPSJiYWNrZ3JvdW5kcmVjdCIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgeD0iMCIgeT0iMCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSJub25lIi8%2BPHRpdGxlPmljbi9kb2MtdGV4dDwvdGl0bGU%2BPGcgY2xhc3M9ImN1cnJlbnRMYXllciIgc3R5bGU9IiI%2BPHRpdGxlPkxheWVyIDE8L3RpdGxlPjxwYXRoIGQ9Ik01IDFoNC4yNDRhMiAyIDAgMCAxIDEuNDM0LjYwNmwyLjc1NiAyLjgzNEEyIDIgMCAwIDEgMTQgNS44MzVWMTJhMyAzIDAgMCAxLTMgM0g1YTMgMyAwIDAgMS0zLTNWNGEzIDMgMCAwIDEgMy0zem0wIDJhMSAxIDAgMCAwLTEgMXY4YTEgMSAwIDAgMCAxIDFoNmExIDEgMCAwIDAgMS0xVjUuODM1TDkuMjQ0IDNINXptMS41IDdoM2EuNS41IDAgMSAxIDAgMWgtM2EuNS41IDAgMSAxIDAtMXptMC0yaDJhLjUuNSAwIDAgMSAwIDFoLTJhLjUuNSAwIDAgMSAwLTF6TTggMmwzIDEuOTk1TDEzIDdIOWExIDEgMCAwIDEtMS0xVjJ6IiBpZD0iYSIgY2xhc3M9IiIgZmlsbD0iI2ZmZmZmZiIgZmlsbC1vcGFjaXR5PSIxIi8%2BPC9nPjwvc3ZnPg%3D%3D" alt="LinkToDocs"/></a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/LeoVen/C-Macro-Collections/blob/master/LICENSE"><img src="https://img.shields.io/badge/License-MIT-blue.svg" alt="License"/></a>
|
||||
<a href="#"><img src="https://img.shields.io/badge/Version-v1.7.2-orange.svg" alt="Version"/></a>
|
||||
<a href="https://travis-ci.org/LeoVen/C-Macro-Collections"><img src="https://travis-ci.org/LeoVen/C-Macro-Collections.svg?branch=master" alt="travis-ci"/></a>
|
||||
<a href="https://codecov.io/gh/LeoVen/C-Macro-Collections"><img src="https://codecov.io/gh/LeoVen/C-Macro-Collections/branch/master/graph/badge.svg" alt="codecov"/></a>
|
||||
</p>
|
||||
|
||||
## Table of Contents
|
||||
|
||||
* Project Structure
|
||||
* Available Collections
|
||||
* Overall To-Do
|
||||
* Design Decisions
|
||||
* What to use
|
||||
* How to use
|
||||
|
||||
## Project Structure
|
||||
|
||||
@@ -15,38 +35,51 @@ Generate Simple Data Structures of any type in C for you to use in your projects
|
||||
* __cmc__ - The main C Macro Collections Library
|
||||
* __dev__ - The main C Macro Collections Library for development (containing logging)
|
||||
* __ext__ - Extra collections
|
||||
* __sac__ - Stack Allocated Collections
|
||||
* __sac__ - Statically Allocated Collections
|
||||
* __utl__ - Utility like ForEach macros, logging, etc
|
||||
* __macro\_collections.h__ - Master header containing all collections and utilities
|
||||
* __tests__ - Where all tests are hosted
|
||||
|
||||
Only Collections located in __cmc__ are to be documented at *Documentation.md*.
|
||||
|
||||
## Available Collections
|
||||
|
||||
* Main C Macro Collections Library
|
||||
* Deque
|
||||
* HashMap
|
||||
* HashSet
|
||||
* Heap
|
||||
* LinkedList
|
||||
* List
|
||||
* Queue
|
||||
* Stack
|
||||
* TreeMap
|
||||
* TreeSet
|
||||
* Extra Collections Library
|
||||
* IntervalHeap
|
||||
* LinkedQueue
|
||||
* MultiMap
|
||||
* MultiSet
|
||||
* Stack Allocated Collections Library
|
||||
* Queue
|
||||
* Stack
|
||||
* Development Collections Library
|
||||
* Deque
|
||||
* Linear Collections
|
||||
* List, LinkedList, Deque, Stack, Queue
|
||||
* Sets
|
||||
* HashSet, TreeSet, MultiSet
|
||||
* Maps
|
||||
* HashMap, TreeMap, MultiMap
|
||||
* Heaps
|
||||
* Heap, IntervalHeap
|
||||
* Coming Soon
|
||||
* BidiMap, SortedList
|
||||
|
||||
Check out **Documentation.md** for more information about each collection.
|
||||
| Collection <img width=250/> | Abstract Data Type <img width=250/> | Data Structure <img width=250/> | Details |
|
||||
| :--------------------------------: | :---------------------------------: | :-----------------------------: | :-----------------------------------: |
|
||||
| BidiMap <br> _bidimap.h_ | Bidirectional Map | Two Hashtables | A bijection between two sets of unique keys and unique values `K <-> V` using two hashtables |
|
||||
| Deque <br> _deque.h_ | Double-Ended Queue | Dynamic Circular Array | A circular array that allows `push` and `pop` on both ends (only) at constant time |
|
||||
| HashMap <br> _hashmap.h_ | Map | Hashtable | A unique set of keys associated with a value `K -> V` with constant time look up using a hashtable with open addressing and robin hood hashing |
|
||||
| HashSet <br> _hashset.h_ | Set | Hashtable | A unique set of values with constant time look up using a hashtable with open addressing and robin hood hashing |
|
||||
| Heap <br> _heap.h_ | Priority Queue | Dynamic Array | A binary heap as a dynamic array as an implicit data structure |
|
||||
| IntervalHeap <br> _intervalheap.h_ | Double-Ended Priority Queue | Custom Dynamic Array | A dynamic array of nodes, each hosting one value from the MinHeap and one from the MaxHeap |
|
||||
| LinkedList <br> _linkedlist.h_ | List | Doubly-Linked List | A default doubly-linked list |
|
||||
| List <br> _list.h_ | List | Dynamic Array | A dynamic array with `push` and `pop` anywhere on the array |
|
||||
| MultiMap <br> _multimap.h_ | Multimap | Custom Hashtable | A mapping of multiple keys with one node per key using a hashtable with separate chaining |
|
||||
| Multiset <br> _multiset.h_ | Multiset | Hashtable | A mapping of a value and its multiplicity using a hashtable with open addressing and robin hood hashing |
|
||||
| Queue <br> _queue.h_ | FIFO | Dynamic Circular Array | A queue using a circular array with `enqueue` at the `back` index and `dequeue` at the `front` index |
|
||||
| SortedList <br> _sortedlist.h_ | Sorted List | Sorted Dynamic Array | A lazily sorted dynamic array that is sorted only when necessary |
|
||||
| Stack <br> _stack.h_ | FILO | Dynamic Array | A stack with push and pop at the end of a dynamic array |
|
||||
| TreeMap <br> _treemap.h_ | Sorted Map | AVL Tree | A unique set of keys associated with a value `K -> V` using an AVL tree with `log(n)` look up and sorted iteration |
|
||||
| TreeSet <br> _treeset.h_ | Sorted Set | AVL Tree | A unique set of keys using an AVL tree with `log(n)` look up and sorted iteration |
|
||||
|
||||
## Overall To-Do
|
||||
|
||||
In the long term, these are the steps left for the completion of this library:
|
||||
|
||||
* Complete the implementation of all the functions in the scope of the TODO file for the main collections (all those included in `cmc` and `ext`);
|
||||
* Reorganize and complete all tests for `cmc` and `ext`;
|
||||
* Make an exact copy of all collections to `dev` with many logging utility, for them to be used under development;
|
||||
* Port all of these collections to be statically allocated and be part of the `sac` library;
|
||||
* Complete all tests for `sac`.
|
||||
|
||||
## Design Decisions
|
||||
|
||||
@@ -101,36 +134,31 @@ Every collection is separated by two parts:
|
||||
|
||||
All collections have three main macros:
|
||||
|
||||
* `SNAME_GENERATE` - Generates `SNAME_GENERATE_HEADER` and `SNAME_GENERATE_SOURCE`.
|
||||
* `CMC_GENERATE_SNAME` - Generates `CMC_GENERATE_SNAME_HEADER` and `CMC_GENERATE_SNAME_SOURCE`.
|
||||
|
||||
Or you can generate each part individually:
|
||||
|
||||
* `SNAME_GENERATE_HEADER` - Generates all struct definitions and function definitions.
|
||||
* `SNAME_GENERATE_SOURCE` - Generates all function implementations.
|
||||
* `CMC_GENERATE_SNAME_HEADER` - Generates all struct definitions and function definitions.
|
||||
* `CMC_GENERATE_SNAME_SOURCE` - Generates all function implementations.
|
||||
|
||||
### Parameters
|
||||
|
||||
When including `macro_collections.h` in your source code you gain access to a macro called `CMC_COLLECTION_GENERATE` with the following parameters:
|
||||
|
||||
* __C__ - Container name in uppercase (*LIST*, *LINKEDLIST*, *STACK*, *QUEUE*, *DEQUE*, *HEAP*, *TREESET*, *TREEMAP*, *HASHSET*, *HASHMAP*).
|
||||
* __PFX__ - Functions prefix or namespace.
|
||||
* __SNAME__ - Structure name (`typedef struct SNAME##_s SNAME`).
|
||||
* __K__ - Key type. Only used in *HASHMAP*, *TREEMAP*, *MULTIMAP* and *BIDIMAP*; ignored by others.
|
||||
* __V__ - Value type. Primary type for most collections, or value to be mapped by *HASHMAP*, *TREEMAP*, *MULTIMAP* and *BIDIMAP*.
|
||||
|
||||
**In fact, all macros follow this pattern.** So whenever you see a macro with a bunch of parameters and you don't know what they are, you can check out the above list.
|
||||
|
||||
### For Each
|
||||
|
||||
There are 2 for-each macros:
|
||||
|
||||
* `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 collection.
|
||||
|
||||
### Parameters
|
||||
|
||||
When including `macro_collections.h` in your source code you gain access to a macro called `COLLECTION_GENERATE` with the following parameters:
|
||||
|
||||
* __C__ - Container name in uppercase (*LIST*, *LINKEDLIST*, *STACK*, *QUEUE*, *DEQUE*, *HEAP*, *TREESET*, *TREEMAP*, *HASHSET*, *HASHMAP*).
|
||||
* __PFX__ - Functions prefix or namespace.
|
||||
* __SNAME__ - Structure name (`typedef struct SNAME##_s SNAME`).
|
||||
* __FMOD__ - Function modifier (`static` or empty).
|
||||
* \*__K__ - Key type. Only used in *HASHMAP* and *TREEMAP*; ignored by others.
|
||||
* __V__ - Value type. Primary type for most collections, or value to be mapped by *HASHMAP* and *TREEMAP*.
|
||||
|
||||
\* Required only by *HASHMAP* and *TREEMAP*
|
||||
|
||||
**In fact, all macros follow this pattern.** So whenever you see a macro with a bunch of parameters and you don't know what they are, you can check out the above list.
|
||||
* `CMC_FOR_EACH` - Starts at the start of the collection towards the end.
|
||||
* `CMC_FOR_EACH_REV` - Starts at the end of the collection towards the start.
|
||||
|
||||
When including `foreach.h` in your source code you gain access to all for-each macros with the following parameters:
|
||||
|
||||
@@ -139,7 +167,7 @@ When including `foreach.h` in your source code you gain access to all for-each m
|
||||
* __TARGET__ - The variable name of the collection you wish to iterate over.
|
||||
* __BODY__ - Block of code.
|
||||
|
||||
Inside body you will have access to the iterator variable. With it you can use functions to access the key, value or index from the iterator. Checkout the documentation for more details.
|
||||
Inside body you will have access to the iterator variable `iter`. With it you can use functions to access the key, value or index from the iterator. Checkout the documentation for more details.
|
||||
|
||||
<hr>
|
||||
|
||||
|
||||
@@ -5,43 +5,34 @@ TODO
|
||||
[~] - Needs to be reviewed
|
||||
|
||||
[/] Documentation
|
||||
[/] Tests
|
||||
[X] Remove PUBLIC and PRIVATE
|
||||
[ ] Extra Collections
|
||||
[X] Extra Collections
|
||||
[X] Add MultiSet
|
||||
[X] Add MultiMap
|
||||
[X] Add IntervalHeap
|
||||
[ ] Add TreeHashMap
|
||||
[ ] Add functions
|
||||
[/] Add SortedList
|
||||
[/] Add BiDiMap
|
||||
[/] Add functions
|
||||
[X] update {hashmap, treemap, multimap}
|
||||
[/] to_string {all}
|
||||
[ ] iter_advance {all} (iterators)
|
||||
[ ] iter_rewind {all} (iterators)
|
||||
[ ] iter_go_to {all} (iterators)
|
||||
[X] set {hashmap, treemap, multimap}
|
||||
[X] to_string {all}
|
||||
[X] iter_advance {all} (iterators)
|
||||
[X] iter_rewind {all} (iterators)
|
||||
[X] iter_go_to {all} (iterators)
|
||||
[ ] from_array {all}
|
||||
[ ] to_array {all}
|
||||
[ ] equals {all}
|
||||
[ ] resize {dynamic arrays and circular buffers}
|
||||
[ ] dispose {all}
|
||||
[ ] copy_of {all}
|
||||
[ ] save {all} (serialization)
|
||||
[ ] load {all} (serialization)
|
||||
[ ] read {all} (serialization)
|
||||
[ ] write {all} (serialization)
|
||||
[ ] Range IO
|
||||
[ ] Sequences
|
||||
[ ] seq_push_front
|
||||
[ ] seq_push_at
|
||||
[ ] seq_push_back
|
||||
[ ] seq_remove
|
||||
[ ] seq_extract
|
||||
[ ] Others
|
||||
[ ] seq_insert
|
||||
[ ] seq_remove (attention on how to treat this)
|
||||
[ ] seq_extract (attention on how to treat this)
|
||||
[ ] Iterator IO
|
||||
[ ] range_insert
|
||||
[ ] range_remove
|
||||
[ ] Stack Allocated Collections
|
||||
[X] equals {all}
|
||||
[X] copy_of {all}
|
||||
[X] resize {array based collections}
|
||||
[ ] Serialization
|
||||
[ ] save {all}
|
||||
[ ] load {all}
|
||||
[ ] serialize {all}
|
||||
[ ] deserialize {all}
|
||||
[ ] Callback utility
|
||||
[ ] Zip Iterators
|
||||
[ ] Statically Allocated Collections
|
||||
[ ] Deque
|
||||
[ ] HashMap
|
||||
[ ] HashSet
|
||||
@@ -69,3 +60,8 @@ TODO
|
||||
[X] log.h
|
||||
[X] test.h
|
||||
[X] timer.h
|
||||
|
||||
[ ] Optimizations
|
||||
[ ] Hashtable insertion can avoid a call to impl_get_entry to check if a key already exists
|
||||
[ ] Use binary search to find optimum hashtable prime size inside impl_calculate_size
|
||||
|
||||
+39
-29
@@ -59,20 +59,20 @@ void shuffle(int *array, mt_state_ptr st)
|
||||
}
|
||||
}
|
||||
|
||||
COLLECTION_GENERATE(DEQUE, d, deque, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE(HASHMAP, hm, hmap, /* FMOD */, int, int)
|
||||
COLLECTION_GENERATE(HASHSET, hs, hset, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE(HEAP, h, heap, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE(LINKEDLIST, ll, linked, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE(LIST, l, list, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE(QUEUE, q, queue, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE(STACK, s, stack, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE(TREEMAP, tm, tmap, /* FMOD */, int, int)
|
||||
COLLECTION_GENERATE(TREESET, ts, tset, /* FMOD */, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE(DEQUE, d, deque, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE(HASHMAP, hm, hmap, int, int)
|
||||
CMC_COLLECTION_GENERATE(HASHSET, hs, hset, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE(HEAP, h, heap, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE(LINKEDLIST, ll, linked, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE(LIST, l, list, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE(QUEUE, q, queue, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE(STACK, s, stack, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE(TREEMAP, tm, tmap, int, int)
|
||||
CMC_COLLECTION_GENERATE(TREESET, ts, tset, /* K */, int)
|
||||
|
||||
COLLECTION_GENERATE(INTERVALHEAP, ih, iheap, , , int)
|
||||
COLLECTION_GENERATE(MULTIMAP, mm, mmap, /* FMOD */, int, int)
|
||||
COLLECTION_GENERATE(MULTISET, ms, mset, /* FMOD */, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE(INTERVALHEAP, ih, iheap, /* k */, int)
|
||||
CMC_COLLECTION_GENERATE(MULTIMAP, mm, mmap, int, int)
|
||||
CMC_COLLECTION_GENERATE(MULTISET, ms, mset, /* K */, int)
|
||||
|
||||
#define BENCHMARK(NAME, PFX, sname, initfunc, insertbody, removebody, searchbody) \
|
||||
void NAME##_io_benchmark(int *array, int *sarray, size_t s) \
|
||||
@@ -85,17 +85,17 @@ COLLECTION_GENERATE(MULTISET, ms, mset, /* FMOD */, /* K */, int)
|
||||
\
|
||||
sname *coll = initfunc; \
|
||||
\
|
||||
timer_start(total); \
|
||||
timer_start(timer); \
|
||||
cmc_timer_start(total); \
|
||||
cmc_timer_start(timer); \
|
||||
\
|
||||
for (size_t i = 0; i < NTOTAL; i++) \
|
||||
{ \
|
||||
insertbody; \
|
||||
} \
|
||||
\
|
||||
timer_stop(timer); \
|
||||
cmc_timer_stop(timer); \
|
||||
\
|
||||
timer_calc(timer); \
|
||||
cmc_timer_calc(timer); \
|
||||
\
|
||||
size_t s1 = PFX##_count(coll); \
|
||||
\
|
||||
@@ -103,16 +103,16 @@ COLLECTION_GENERATE(MULTISET, ms, mset, /* FMOD */, /* K */, int)
|
||||
\
|
||||
double input_time = timer.result; \
|
||||
\
|
||||
timer_start(timer); \
|
||||
cmc_timer_start(timer); \
|
||||
\
|
||||
for (size_t i = 0; i < s; i++) \
|
||||
{ \
|
||||
searchbody; \
|
||||
} \
|
||||
\
|
||||
timer_stop(timer); \
|
||||
cmc_timer_stop(timer); \
|
||||
\
|
||||
timer_calc(timer); \
|
||||
cmc_timer_calc(timer); \
|
||||
\
|
||||
printf(" SEARCH %10s TOOK %8.0lf milliseconds for %8" PRIuMAX " elements\n", #NAME, timer.result, s); \
|
||||
\
|
||||
@@ -120,30 +120,30 @@ COLLECTION_GENERATE(MULTISET, ms, mset, /* FMOD */, /* K */, int)
|
||||
\
|
||||
sname##_iter iter; \
|
||||
\
|
||||
timer_start(timer); \
|
||||
cmc_timer_start(timer); \
|
||||
\
|
||||
for (PFX##_iter_init(&iter, coll); !PFX##_iter_end(&iter); PFX##_iter_next(&iter)) \
|
||||
{ \
|
||||
} \
|
||||
\
|
||||
timer_stop(timer); \
|
||||
cmc_timer_stop(timer); \
|
||||
\
|
||||
timer_calc(timer); \
|
||||
cmc_timer_calc(timer); \
|
||||
\
|
||||
printf("ITERATION %10s TOOK %8.0lf milliseconds for %8" PRIuMAX " elements\n", #NAME, timer.result, s1); \
|
||||
\
|
||||
double iter_time = timer.result; \
|
||||
\
|
||||
timer_start(timer); \
|
||||
cmc_timer_start(timer); \
|
||||
\
|
||||
for (size_t i = 0; i < NTOTAL; i++) \
|
||||
{ \
|
||||
removebody; \
|
||||
} \
|
||||
\
|
||||
timer_stop(timer); \
|
||||
cmc_timer_stop(timer); \
|
||||
\
|
||||
timer_calc(timer); \
|
||||
cmc_timer_calc(timer); \
|
||||
\
|
||||
size_t s2 = PFX##_count(coll); \
|
||||
\
|
||||
@@ -151,10 +151,10 @@ COLLECTION_GENERATE(MULTISET, ms, mset, /* FMOD */, /* K */, int)
|
||||
\
|
||||
double output_time = timer.result; \
|
||||
\
|
||||
timer_stop(total); \
|
||||
timer_calc(total); \
|
||||
cmc_timer_stop(total); \
|
||||
cmc_timer_calc(total); \
|
||||
\
|
||||
PFX##_free(coll); \
|
||||
PFX##_free(coll, NULL); \
|
||||
\
|
||||
double adj_search_time = (total.result - search_time) + (search_time * (double)NTOTAL) / (double)s; \
|
||||
double no_search = input_time + iter_time + output_time; \
|
||||
@@ -221,6 +221,9 @@ int main(void)
|
||||
|
||||
// Linear containers have to search for NMIN elements and non-linear (hash
|
||||
// and tree) have to search for all elements.
|
||||
cmc_timer timer;
|
||||
cmc_timer_start(timer);
|
||||
|
||||
DEQUE_io_benchmark(array, sarray, NMIN);
|
||||
HASHMAP_io_benchmark(array, sarray, NTOTAL);
|
||||
HASHSET_io_benchmark(array, sarray, NTOTAL);
|
||||
@@ -236,6 +239,13 @@ int main(void)
|
||||
MULTIMAP_io_benchmark(array, array, NTOTAL);
|
||||
MULTISET_io_benchmark(array, array, NTOTAL);
|
||||
|
||||
cmc_timer_stop(timer);
|
||||
cmc_timer_calc(timer);
|
||||
|
||||
printf("+-----------------------------------------------------------+ \n");
|
||||
printf("| Total Benchmark Running Time : %12.0lf seconds | \n", timer.result / 1000);
|
||||
printf("+-----------------------------------------------------------+ \n");
|
||||
|
||||
free(array);
|
||||
free(sarray);
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
__Check out the new documentation at__ https://leoven.github.io/C-Macro-Collections/
|
||||
|
||||
<span id="collections_index"> Collections Documentation </span>
|
||||
|
||||
* [Deque](#Deque)
|
||||
@@ -0,0 +1,247 @@
|
||||
THIS IS A SAFE COPY OF THE MARKDOWN FOR THE DOCUMENTATION LOCATED AT https://leoven.github.io/C-Macro-Collections/
|
||||
|
||||
|
||||
|
||||
|
||||
---
|
||||
title: CMC Documentation
|
||||
|
||||
toc_footers:
|
||||
- <a href='https://github.com/lord/slate'>Documentation Powered by Slate</a>
|
||||
|
||||
language_tabs:
|
||||
- C
|
||||
|
||||
search: true
|
||||
---
|
||||
|
||||
# Introduction
|
||||
|
||||
[](https://github.com/LeoVen/C-Macro-Collections)
|
||||
|
||||

|
||||

|
||||
[](https://travis-ci.org/LeoVen/C-Macro-Collections)
|
||||
[](https://codecov.io/gh/LeoVen/C-Macro-Collections)
|
||||
|
||||
The C Macro Collections Library is a compilation of macros that can be used to generate common data structures for any desired type. These data structures are [type safe](https://en.wikipedia.org/wiki/Type_safety).
|
||||
|
||||
The documentation is currently being written in hopes that in the future it can be used to help you get to know better this amazing C library.
|
||||
|
||||
## Why this library
|
||||
|
||||
C is a low level language and lacks all the data structures that we commonly use. Many high level languages already come with these collections so that we don't have to implement everything ourselves. This is why the C Macro Collections Library was created.
|
||||
|
||||
The library currently provides many data structures, such as:
|
||||
|
||||
* Linear Collections
|
||||
* List, LinkedList, Deque, Stack, Queue
|
||||
* Sets
|
||||
* HashSet, TreeSet, MultiSet
|
||||
* Maps
|
||||
* HashMap, TreeMap, MultiMap
|
||||
* Heaps
|
||||
* Heap, IntervalHeap
|
||||
|
||||
All with the following features:
|
||||
|
||||
* __Type-safe__ - No `void *` pointers are used. A collection of type `int` will only accept integers;
|
||||
* __Customization__ - Custom struct name and function namespace;
|
||||
* __Bidirectional Iterators__ - Full support for iterators;
|
||||
* __Nesting__ - Collections can be nested (List of Lists, HashSet of Stacks, etc).
|
||||
|
||||
## Library Structure
|
||||
|
||||
The `src` folder is subdivided in 5 other folders and one file:
|
||||
|
||||
> The `dev` folder is an exact copy of `cmc` but it is filled with logging information regarding the code execution and debugging.
|
||||
|
||||
> The `sac` library contains fixed-length collections with an internal C array.
|
||||
|
||||
* __cmc__ - The main C Macro Collections Library
|
||||
* __dev__ - The main C Macro Collections Library for development
|
||||
* __ext__ - Extra collections
|
||||
* __sac__ - Statically Allocated Collections
|
||||
* __utl__ - Utility like ForEach macros, logging, etc
|
||||
* __macro\_collections.h__ - Master header containing all collections and utilities
|
||||
|
||||
## How to install
|
||||
|
||||
> Include header files like this
|
||||
|
||||
```c
|
||||
#include <cmc/list.h>
|
||||
#include <dev/deque.h>
|
||||
#include <utl/assert.h>
|
||||
```
|
||||
> Not like this
|
||||
|
||||
```c
|
||||
#include <list.h>
|
||||
#include <deque.h> // dev or cmc?
|
||||
#include <assert.h> // this will import from the standard library
|
||||
```
|
||||
|
||||
No installation is required. All you have to do is include the appropriate header files, generate any collections that you desire and then compile your program. It is recommended that you include the headers relative to the `src` folder and include it with `-I path/to/library/src` as shown in the following example.
|
||||
|
||||
The library has no external dependencies other than the C standard library.
|
||||
|
||||
## Minimal Example
|
||||
|
||||
Lets create a list of type `int`, add some elements to it and get the sum of all the elements printed on the screen.
|
||||
|
||||
### Include headers
|
||||
|
||||
```c
|
||||
#include <cmc/list.h>
|
||||
```
|
||||
|
||||
First you need to include only the necessary headers. It is not recommended that you include everything with `macro_collections.h`, only in cases where you might be using almost all features from the library.
|
||||
|
||||
### Generating a list
|
||||
|
||||
```c
|
||||
// CMC_GENERATE_LIST(PFX, SNAME, V)
|
||||
CMC_GENERATE_LIST(il, int_list, int)
|
||||
```
|
||||
|
||||
The List is also known as `vector`, `ArrayList` and dynamic array. In fact the latter is the best description for this collection. It is a dynamic array that can grow and shrink as needed. To generate it we can simply call the macro `CMC_GENERATE_LIST` after our includes. It has three parameters:
|
||||
|
||||
| Parameter name | Purpose |
|
||||
| :------------: | ------- |
|
||||
| __PFX__ | Functions prefix (namespace) |
|
||||
| __SNAME__ | Struct name |
|
||||
| __V__ | The list value type (can be any valid data type) |
|
||||
|
||||
<aside class="notice">
|
||||
All collections can be generated by using the macro CMC_GENERATE_ and then the name of the include (in this case list.h) but in uppercase without the `.h`.
|
||||
</aside>
|
||||
|
||||
### Initializing and adding elements
|
||||
|
||||
```c
|
||||
// Allocate an int_list with an initial capacity of 100
|
||||
int_list *list = il_new(100);
|
||||
|
||||
// Adding elements to the back of the list
|
||||
for (int i = 0; i <= 1000; i++)
|
||||
{
|
||||
if (!il_push_back(list, i))
|
||||
{
|
||||
// Something went wrong (check out documentation)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
To initialize any collection we call a function `_new`. Since the `PFX` parameter is set to `il` all functions related to our list of integer will be prefixed by `il`, so `_new` becomes `il_new`.
|
||||
|
||||
The list name is `int_list` as defined by `SNAME`. This type is a typedef like:
|
||||
|
||||
`typedef struct SNAME##_s SNAME;`
|
||||
|
||||
Which expands to:
|
||||
|
||||
`typedef struct int_list_s int_list`
|
||||
|
||||
To add elements to the back of a list we can use `il_push_back`. This function will first check if the list has enough space for a new element. If not, reallocate the internal buffer with doubled size and then add the new element.
|
||||
|
||||
### Iteration
|
||||
|
||||
> It is recommended that the iterator is allocated on the stack
|
||||
|
||||
```c
|
||||
// Resulting sum will be stored here
|
||||
int sum = 0;
|
||||
|
||||
// Declare our iterator (allocating it on the stack)
|
||||
int_list_iter it;
|
||||
|
||||
// Loop for each element
|
||||
for (il_iter_init(&it, list); !il_iter_end(&it); il_iter_next(&it))
|
||||
{
|
||||
// Accessing the value
|
||||
int elem = il_iter_value(&it);
|
||||
|
||||
sum += elem;
|
||||
}
|
||||
|
||||
printf("%d\n", sum);
|
||||
```
|
||||
|
||||
There are 6 (2 optional) steps to iterate over the elements of any collection:
|
||||
|
||||
| Step | Description | Function |
|
||||
| :--: | ----------- | -------- |
|
||||
| 1 | Allocate the iterator (optional) | `il_iter_new` |
|
||||
| 2 | Initialize the iterator given a target list | `il_iter_init` |
|
||||
| 3 | Access the iterator's elements (value, index, etc) | `il_iter_value` |
|
||||
| 4 | Go to the next element | `il_iter_next` |
|
||||
| 5 | Check if we haven't reached the end of the list | `il_iter_end` |
|
||||
| 6 | Free the iterator if it was allocated on the heap | `il_iter_free` |
|
||||
|
||||
Note that all iterator functions are prefixed by the user defined prefix and then by `iter` (`il + iter = il_iter`). Also, the steps __1__ and __6__ are optional so `il_iter_new` and `il_iter_free` are not used in the example.
|
||||
|
||||
By the end of the example we have the variable `sum` with the sum of all integers inside our list. We can then print it and this example is almost done.
|
||||
|
||||
### Freeing resources
|
||||
|
||||
```c
|
||||
// void il_free(int_list *_list_, void(*deallocator)(int))
|
||||
il_free(list, NULL);
|
||||
```
|
||||
|
||||
The list is currently allocated in memory. To deallocate it we call `il_free`. This function takes a pointer to the allocated list and a pointer to a `deallocator` function that will be responsible for deallocating each element in the list. This last parameter is optional and we won't be using it since our data type `int` is not allocated in the heap. This optional parameter can be set to `NULL` to be ignored by the `il_free` function.
|
||||
|
||||
### Compile and run
|
||||
|
||||
> source.c
|
||||
|
||||
```c
|
||||
#include <cmc/list.h>
|
||||
|
||||
CMC_GENERATE_LIST(il, int_list, int)
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int_list *list = il_new(100);
|
||||
|
||||
for (int i = 0; i <= 1000; i++)
|
||||
{
|
||||
if (!il_push_back(list, i))
|
||||
{
|
||||
// Something went wrong (check out documentation)
|
||||
}
|
||||
}
|
||||
|
||||
int sum = 0;
|
||||
|
||||
int_list_iter it;
|
||||
|
||||
for (il_iter_init(&it, list); !il_iter_end(&it); il_iter_next(&it))
|
||||
{
|
||||
int elem = il_iter_value(&it);
|
||||
sum += elem;
|
||||
}
|
||||
|
||||
printf("%d\n", sum);
|
||||
|
||||
il_free(list, NULL);
|
||||
}
|
||||
```
|
||||
|
||||
If the source file is `source.c`, all you have to do is to include the `src` folder to the include path and compile. The following example uses `gcc`:
|
||||
|
||||
`gcc source.c -I path/to/library/src`
|
||||
|
||||
### Conclusion
|
||||
|
||||
The C Macro Collections Library is prepared to accept any data type and is highly customizable. It is also very easy to integrate and no previous compilation is required. The library also comes with many utilities in the `utl` folder that are designed to work well with all collections.
|
||||
|
||||
# Upcoming
|
||||
|
||||
This documentation is still being written. Here is some of the things you will be able to find here:
|
||||
|
||||
* Full explanation about data structures
|
||||
* Full documentation about all current collections and others to come
|
||||
* Fully explained examples
|
||||
* Benchmark examples
|
||||
@@ -0,0 +1,73 @@
|
||||
#include <cmc/stack.h>
|
||||
#include <utl/log.h>
|
||||
|
||||
CMC_GENERATE_STACK(stk, stack, int)
|
||||
|
||||
struct
|
||||
{
|
||||
stack *from;
|
||||
stack *aux;
|
||||
stack *to;
|
||||
} print_aux = {NULL};
|
||||
|
||||
void print_stacks()
|
||||
{
|
||||
for (int i = 9; i >= 0; i--)
|
||||
{
|
||||
int ia = print_aux.from->buffer[i];
|
||||
int ib = print_aux.aux->buffer[i];
|
||||
int ic = print_aux.to->buffer[i];
|
||||
|
||||
printf("| %c | %c | %c |\n",
|
||||
ia == 0 ? 32 : ia + 48,
|
||||
ib == 0 ? 32 : ib + 48,
|
||||
ic == 0 ? 32 : ic + 48);
|
||||
}
|
||||
|
||||
printf("+---+---+---+\n\n");
|
||||
}
|
||||
|
||||
void move(stack *from, stack *to)
|
||||
{
|
||||
stk_push(to, stk_top(from));
|
||||
|
||||
stk_pop(from);
|
||||
}
|
||||
|
||||
void hanoi(int n, stack *from, stack *aux, stack *to)
|
||||
{
|
||||
if (n == 0)
|
||||
return;
|
||||
|
||||
hanoi(n - 1, from, to, aux);
|
||||
|
||||
move(from, to);
|
||||
|
||||
print_stacks();
|
||||
|
||||
hanoi(n - 1, aux, from, to);
|
||||
}
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
{
|
||||
stack *from = stk_new(10);
|
||||
stack *to = stk_new(10);
|
||||
stack *aux = stk_new(10);
|
||||
|
||||
for (int i = 4; i >= 1; i--)
|
||||
stk_push(from, i);
|
||||
|
||||
print_aux.from = from;
|
||||
print_aux.aux = aux;
|
||||
print_aux.to = to;
|
||||
|
||||
print_stacks();
|
||||
|
||||
hanoi(stk_count(from), from, aux, to);
|
||||
|
||||
stk_free(from, NULL);
|
||||
stk_free(to, NULL);
|
||||
stk_free(aux, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,208 @@
|
||||
#include <cmc/list.h>
|
||||
#include <utl/log.h>
|
||||
|
||||
#define TAB_SIZE 4
|
||||
#define ROW_INI_CAP DOC_LETTERS_IN_ROW
|
||||
#define DOC_LETTERS_IN_ROW 100
|
||||
#define DOC_ROWS_IN_PAGE 50
|
||||
#define DOC_MARGIN 4
|
||||
|
||||
CMC_GENERATE_LIST(row, row, char)
|
||||
CMC_GENERATE_LIST(doc, document, row *)
|
||||
|
||||
void row_deallocator(row *r)
|
||||
{
|
||||
row_free(r, NULL);
|
||||
}
|
||||
|
||||
document *document_load(const char *file_name);
|
||||
void document_empty_line(FILE *fptr);
|
||||
void document_page_outline(FILE *fptr, int outline);
|
||||
void document_page_margin(FILE *fptr, int margin);
|
||||
void document_print(document *doc, FILE *fptr);
|
||||
|
||||
document *document_load(const char *file_name)
|
||||
{
|
||||
FILE *file = fopen(file_name, "r");
|
||||
|
||||
if (!file)
|
||||
{
|
||||
cmc_log_error("File %s not found\n", file_name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
row *initial_row = row_new(ROW_INI_CAP);
|
||||
|
||||
document *doc = doc_new(100);
|
||||
doc_push_back(doc, initial_row);
|
||||
|
||||
int ch;
|
||||
|
||||
while ((ch = getc(file)) != EOF)
|
||||
{
|
||||
char c = (char)ch;
|
||||
|
||||
row *current_row = doc_back(doc);
|
||||
|
||||
if (c == '\n')
|
||||
{
|
||||
row *new_row = row_new(ROW_INI_CAP);
|
||||
doc_push_back(doc, new_row);
|
||||
}
|
||||
else if (c == '\t')
|
||||
{
|
||||
intmax_t left = TAB_SIZE;
|
||||
|
||||
while (left > 0 && row_count(current_row) < DOC_LETTERS_IN_ROW)
|
||||
{
|
||||
row_push_back(current_row, ' ');
|
||||
left--;
|
||||
}
|
||||
|
||||
if (left > 0)
|
||||
{
|
||||
row *new_row = row_new(ROW_INI_CAP);
|
||||
doc_push_back(doc, new_row);
|
||||
|
||||
while (left > 0)
|
||||
{
|
||||
row_push_back(new_row, ' ');
|
||||
left--;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (DOC_LETTERS_IN_ROW == row_count(current_row))
|
||||
{
|
||||
row *new_row = row_new(ROW_INI_CAP);
|
||||
row_push_back(new_row, c);
|
||||
doc_push_back(doc, new_row);
|
||||
}
|
||||
else
|
||||
row_push_back(current_row, c);
|
||||
}
|
||||
|
||||
return doc;
|
||||
}
|
||||
|
||||
void document_empty_line(FILE *fptr)
|
||||
{
|
||||
fputs("|", fptr);
|
||||
for (size_t i = 0; i < DOC_LETTERS_IN_ROW + DOC_MARGIN * 2; i++)
|
||||
{
|
||||
fputc(' ', fptr);
|
||||
}
|
||||
fputs("|\n", fptr);
|
||||
}
|
||||
|
||||
void document_page_outline(FILE *fptr, int outline /* 0 - header, 1 - footer */)
|
||||
{
|
||||
if (outline == 1)
|
||||
{
|
||||
document_empty_line(fptr);
|
||||
#ifdef DOC_PAGE_NUMBER
|
||||
static intmax_t page = 1;
|
||||
|
||||
fputs("|", fptr);
|
||||
for (size_t i = 0; i < (DOC_LETTERS_IN_ROW + DOC_MARGIN) - 8; i++)
|
||||
{
|
||||
fputc(' ', fptr);
|
||||
}
|
||||
|
||||
fprintf(fptr, "%8" PRIdMAX "", page);
|
||||
page++;
|
||||
|
||||
document_page_margin(fptr, 1);
|
||||
document_empty_line(fptr);
|
||||
#endif
|
||||
}
|
||||
|
||||
fputs("+", fptr);
|
||||
for (size_t i = 0; i < DOC_LETTERS_IN_ROW + DOC_MARGIN * 2; i++)
|
||||
{
|
||||
fputc('-', fptr);
|
||||
}
|
||||
fputs("+\n", fptr);
|
||||
|
||||
if (outline == 0)
|
||||
document_empty_line(fptr);
|
||||
}
|
||||
|
||||
void document_page_margin(FILE *fptr, int margin /* 0 - first margin, 1 - second margin */)
|
||||
{
|
||||
if (margin == 0)
|
||||
fputs("|", fptr);
|
||||
|
||||
for (size_t i = 0; i < DOC_MARGIN; i++)
|
||||
{
|
||||
fputc(' ', fptr);
|
||||
}
|
||||
|
||||
if (margin == 1)
|
||||
fputs("|\n", fptr);
|
||||
}
|
||||
|
||||
void document_print(document *doc, FILE *fptr)
|
||||
{
|
||||
fputc('\n', fptr);
|
||||
|
||||
intmax_t current_page_row = 0, total_rows = doc_count(doc);
|
||||
|
||||
// Print document
|
||||
for (intmax_t i = 0; i < total_rows; i++, current_page_row++)
|
||||
{
|
||||
if (current_page_row == 0)
|
||||
document_page_outline(fptr, 0);
|
||||
|
||||
row *current_row = doc_get(doc, i);
|
||||
|
||||
if (!current_row)
|
||||
cmc_log_fatal("Unexpected NULL pointer for %s", "current_row");
|
||||
|
||||
document_page_margin(fptr, 0);
|
||||
|
||||
for (size_t k = 0; k < row_count(current_row); k++)
|
||||
fputc(row_get(current_row, k), fptr);
|
||||
|
||||
// Trailing margin
|
||||
for (size_t k = 0; k < DOC_LETTERS_IN_ROW - row_count(current_row); k++)
|
||||
fputc(' ', fptr);
|
||||
|
||||
document_page_margin(fptr, 1);
|
||||
|
||||
// Print the end of the page and reset
|
||||
if (current_page_row == DOC_ROWS_IN_PAGE - 1)
|
||||
{
|
||||
document_page_outline(fptr, 1);
|
||||
current_page_row = -1;
|
||||
fputc('\n', fptr);
|
||||
}
|
||||
}
|
||||
|
||||
// Print trailing page
|
||||
if (total_rows % DOC_ROWS_IN_PAGE != 0)
|
||||
{
|
||||
for (size_t i = 0; i < DOC_ROWS_IN_PAGE - current_page_row; i++)
|
||||
document_empty_line(fptr);
|
||||
|
||||
document_page_outline(fptr, 1);
|
||||
}
|
||||
|
||||
fputc('\n', fptr);
|
||||
}
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
{
|
||||
if (argc != 2)
|
||||
{
|
||||
cmc_log_error("Please define one argument only for %s", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
document *doc = document_load(argv[1]);
|
||||
|
||||
document_print(doc, stdout);
|
||||
|
||||
doc_free(doc, row_deallocator);
|
||||
|
||||
return 0;
|
||||
}
|
||||
+525
-410
@@ -31,24 +31,28 @@
|
||||
#ifndef CMC_DEQUE_H
|
||||
#define CMC_DEQUE_H
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "../utl/cmc_string.h"
|
||||
|
||||
#define DEQUE_GENERATE(PFX, SNAME, FMOD, V) \
|
||||
DEQUE_GENERATE_HEADER(PFX, SNAME, FMOD, V) \
|
||||
DEQUE_GENERATE_SOURCE(PFX, SNAME, FMOD, V)
|
||||
/* to_string format */
|
||||
static const char *cmc_string_fmt_deque = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", count:%" PRIuMAX ", front:%" PRIuMAX ", back:%" PRIuMAX " }";
|
||||
|
||||
#define DEQUE_WRAPGEN_HEADER(PFX, SNAME, FMOD, K, V) \
|
||||
DEQUE_GENERATE_HEADER(PFX, SNAME, FMOD, V)
|
||||
#define CMC_GENERATE_DEQUE(PFX, SNAME, V) \
|
||||
CMC_GENERATE_DEQUE_HEADER(PFX, SNAME, V) \
|
||||
CMC_GENERATE_DEQUE_SOURCE(PFX, SNAME, V)
|
||||
|
||||
#define DEQUE_WRAPGEN_SOURCE(PFX, SNAME, FMOD, K, V) \
|
||||
DEQUE_GENERATE_SOURCE(PFX, SNAME, FMOD, V)
|
||||
#define CMC_WRAPGEN_DEQUE_HEADER(PFX, SNAME, K, V) \
|
||||
CMC_GENERATE_DEQUE_HEADER(PFX, SNAME, V)
|
||||
|
||||
#define CMC_WRAPGEN_DEQUE_SOURCE(PFX, SNAME, K, V) \
|
||||
CMC_GENERATE_DEQUE_SOURCE(PFX, SNAME, V)
|
||||
|
||||
/* HEADER ********************************************************************/
|
||||
#define DEQUE_GENERATE_HEADER(PFX, SNAME, FMOD, V) \
|
||||
#define CMC_GENERATE_DEQUE_HEADER(PFX, SNAME, V) \
|
||||
\
|
||||
/* Deque Structure */ \
|
||||
typedef struct SNAME##_s \
|
||||
@@ -98,421 +102,532 @@
|
||||
\
|
||||
/* Collection Functions */ \
|
||||
/* Collection Allocation and Deallocation */ \
|
||||
FMOD SNAME *PFX##_new(size_t capacity); \
|
||||
FMOD void PFX##_clear(SNAME *_deque_); \
|
||||
FMOD void PFX##_free(SNAME *_deque_); \
|
||||
SNAME *PFX##_new(size_t capacity); \
|
||||
void PFX##_clear(SNAME *_deque_, void (*deallocator)(V)); \
|
||||
void PFX##_free(SNAME *_deque_, void (*deallocator)(V)); \
|
||||
/* Collection Input and Output */ \
|
||||
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); \
|
||||
bool PFX##_push_front(SNAME *_deque_, V element); \
|
||||
bool PFX##_push_back(SNAME *_deque_, V element); \
|
||||
bool PFX##_pop_front(SNAME *_deque_); \
|
||||
bool PFX##_pop_back(SNAME *_deque_); \
|
||||
/* Element Access */ \
|
||||
FMOD V PFX##_front(SNAME *_deque_); \
|
||||
FMOD V PFX##_back(SNAME *_deque_); \
|
||||
V PFX##_front(SNAME *_deque_); \
|
||||
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_); \
|
||||
bool PFX##_contains(SNAME *_deque_, V element, int (*comparator)(V, V)); \
|
||||
bool PFX##_empty(SNAME *_deque_); \
|
||||
bool PFX##_full(SNAME *_deque_); \
|
||||
size_t PFX##_count(SNAME *_deque_); \
|
||||
size_t PFX##_capacity(SNAME *_deque_); \
|
||||
/* Collection Utility */ \
|
||||
FMOD cmc_string PFX##_to_string(SNAME *_deque_); \
|
||||
bool PFX##_resize(SNAME *_deque_, size_t capacity); \
|
||||
SNAME *PFX##_copy_of(SNAME *_deque_, V (*copy_func)(V)); \
|
||||
bool PFX##_equals(SNAME *_deque1_, SNAME *_deque2_, int (*comparator)(V, V)); \
|
||||
cmc_string PFX##_to_string(SNAME *_deque_); \
|
||||
\
|
||||
/* Iterator Functions */ \
|
||||
/* Iterator Allocation and Deallocation */ \
|
||||
FMOD SNAME##_iter *PFX##_iter_new(SNAME *target); \
|
||||
FMOD void PFX##_iter_free(SNAME##_iter *iter); \
|
||||
SNAME##_iter *PFX##_iter_new(SNAME *target); \
|
||||
void PFX##_iter_free(SNAME##_iter *iter); \
|
||||
/* Iterator Initialization */ \
|
||||
FMOD void PFX##_iter_init(SNAME##_iter *iter, SNAME *target); \
|
||||
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); \
|
||||
bool PFX##_iter_start(SNAME##_iter *iter); \
|
||||
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); \
|
||||
void PFX##_iter_to_start(SNAME##_iter *iter); \
|
||||
void PFX##_iter_to_end(SNAME##_iter *iter); \
|
||||
bool PFX##_iter_next(SNAME##_iter *iter); \
|
||||
bool PFX##_iter_prev(SNAME##_iter *iter); \
|
||||
bool PFX##_iter_advance(SNAME##_iter *iter, size_t steps); \
|
||||
bool PFX##_iter_rewind(SNAME##_iter *iter, size_t steps); \
|
||||
bool PFX##_iter_go_to(SNAME##_iter *iter, size_t index); \
|
||||
/* Iterator Access */ \
|
||||
FMOD V PFX##_iter_value(SNAME##_iter *iter); \
|
||||
FMOD V *PFX##_iter_rvalue(SNAME##_iter *iter); \
|
||||
FMOD size_t PFX##_iter_index(SNAME##_iter *iter); \
|
||||
\
|
||||
/* Default Value */ \
|
||||
static inline V PFX##_impl_default_value(void) \
|
||||
{ \
|
||||
V _empty_value_; \
|
||||
\
|
||||
memset(&_empty_value_, 0, sizeof(V)); \
|
||||
\
|
||||
return _empty_value_; \
|
||||
} \
|
||||
V PFX##_iter_value(SNAME##_iter *iter); \
|
||||
V *PFX##_iter_rvalue(SNAME##_iter *iter); \
|
||||
size_t PFX##_iter_index(SNAME##_iter *iter); \
|
||||
\
|
||||
/* SOURCE ********************************************************************/
|
||||
#define DEQUE_GENERATE_SOURCE(PFX, SNAME, FMOD, V) \
|
||||
\
|
||||
/* Implementation Detail Functions */ \
|
||||
static bool PFX##_impl_grow(SNAME *_deque_); \
|
||||
static SNAME##_iter PFX##_impl_it_start(SNAME *_deque_); \
|
||||
static SNAME##_iter PFX##_impl_it_end(SNAME *_deque_); \
|
||||
\
|
||||
FMOD SNAME *PFX##_new(size_t capacity) \
|
||||
{ \
|
||||
if (capacity < 1) \
|
||||
return NULL; \
|
||||
\
|
||||
SNAME *_deque_ = malloc(sizeof(SNAME)); \
|
||||
\
|
||||
if (!_deque_) \
|
||||
return NULL; \
|
||||
\
|
||||
_deque_->buffer = malloc(sizeof(V) * capacity); \
|
||||
\
|
||||
if (!_deque_->buffer) \
|
||||
{ \
|
||||
free(_deque_); \
|
||||
return NULL; \
|
||||
} \
|
||||
\
|
||||
memset(_deque_->buffer, 0, sizeof(V) * capacity); \
|
||||
\
|
||||
_deque_->capacity = capacity; \
|
||||
_deque_->count = 0; \
|
||||
_deque_->front = 0; \
|
||||
_deque_->back = 0; \
|
||||
\
|
||||
_deque_->it_start = PFX##_impl_it_start; \
|
||||
_deque_->it_end = PFX##_impl_it_end; \
|
||||
\
|
||||
return _deque_; \
|
||||
} \
|
||||
\
|
||||
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] = PFX##_impl_default_value(); \
|
||||
\
|
||||
_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] = PFX##_impl_default_value(); \
|
||||
\
|
||||
_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 PFX##_impl_default_value(); \
|
||||
\
|
||||
return _deque_->buffer[_deque_->front]; \
|
||||
} \
|
||||
\
|
||||
FMOD V PFX##_back(SNAME *_deque_) \
|
||||
{ \
|
||||
if (PFX##_empty(_deque_)) \
|
||||
return PFX##_impl_default_value(); \
|
||||
\
|
||||
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 cmc_string PFX##_to_string(SNAME *_deque_) \
|
||||
{ \
|
||||
cmc_string str; \
|
||||
SNAME *d_ = _deque_; \
|
||||
const char *name = #SNAME; \
|
||||
\
|
||||
snprintf(str.s, cmc_string_len, cmc_string_fmt_deque, \
|
||||
name, d_, d_->buffer, d_->capacity, d_->count, d_->front, d_->back); \
|
||||
\
|
||||
return str; \
|
||||
} \
|
||||
\
|
||||
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 PFX##_impl_default_value(); \
|
||||
\
|
||||
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; \
|
||||
} \
|
||||
\
|
||||
static bool PFX##_impl_grow(SNAME *_deque_) \
|
||||
{ \
|
||||
size_t new_capacity = _deque_->capacity * 2; \
|
||||
\
|
||||
V *new_buffer = malloc(sizeof(V) * new_capacity); \
|
||||
\
|
||||
if (!new_buffer) \
|
||||
return false; \
|
||||
\
|
||||
for (size_t i = _deque_->front, j = 0; j < _deque_->count; i = (i + 1) % _deque_->capacity, j++) \
|
||||
{ \
|
||||
new_buffer[j] = _deque_->buffer[i]; \
|
||||
} \
|
||||
\
|
||||
free(_deque_->buffer); \
|
||||
\
|
||||
_deque_->buffer = new_buffer; \
|
||||
_deque_->capacity = new_capacity; \
|
||||
_deque_->front = 0; \
|
||||
_deque_->back = _deque_->count; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
static SNAME##_iter PFX##_impl_it_start(SNAME *_deque_) \
|
||||
{ \
|
||||
SNAME##_iter iter; \
|
||||
\
|
||||
PFX##_iter_init(&iter, _deque_); \
|
||||
\
|
||||
return iter; \
|
||||
} \
|
||||
\
|
||||
static SNAME##_iter PFX##_impl_it_end(SNAME *_deque_) \
|
||||
{ \
|
||||
SNAME##_iter iter; \
|
||||
\
|
||||
PFX##_iter_init(&iter, _deque_); \
|
||||
PFX##_iter_to_end(&iter); \
|
||||
\
|
||||
return iter; \
|
||||
#define CMC_GENERATE_DEQUE_SOURCE(PFX, SNAME, V) \
|
||||
\
|
||||
/* Implementation Detail Functions */ \
|
||||
static SNAME##_iter PFX##_impl_it_start(SNAME *_deque_); \
|
||||
static SNAME##_iter PFX##_impl_it_end(SNAME *_deque_); \
|
||||
\
|
||||
SNAME *PFX##_new(size_t capacity) \
|
||||
{ \
|
||||
if (capacity < 1) \
|
||||
return NULL; \
|
||||
\
|
||||
SNAME *_deque_ = malloc(sizeof(SNAME)); \
|
||||
\
|
||||
if (!_deque_) \
|
||||
return NULL; \
|
||||
\
|
||||
_deque_->buffer = malloc(sizeof(V) * capacity); \
|
||||
\
|
||||
if (!_deque_->buffer) \
|
||||
{ \
|
||||
free(_deque_); \
|
||||
return NULL; \
|
||||
} \
|
||||
\
|
||||
memset(_deque_->buffer, 0, sizeof(V) * capacity); \
|
||||
\
|
||||
_deque_->capacity = capacity; \
|
||||
_deque_->count = 0; \
|
||||
_deque_->front = 0; \
|
||||
_deque_->back = 0; \
|
||||
\
|
||||
_deque_->it_start = PFX##_impl_it_start; \
|
||||
_deque_->it_end = PFX##_impl_it_end; \
|
||||
\
|
||||
return _deque_; \
|
||||
} \
|
||||
\
|
||||
void PFX##_clear(SNAME *_deque_, void (*deallocator)(V)) \
|
||||
{ \
|
||||
if (deallocator) \
|
||||
{ \
|
||||
for (size_t i = _deque_->front, j = 0; j < _deque_->count; j++) \
|
||||
{ \
|
||||
deallocator(_deque_->buffer[i]); \
|
||||
\
|
||||
i = (i + 1) % _deque_->capacity; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
memset(_deque_->buffer, 0, sizeof(V) * _deque_->capacity); \
|
||||
\
|
||||
_deque_->count = 0; \
|
||||
_deque_->front = 0; \
|
||||
_deque_->back = 0; \
|
||||
} \
|
||||
\
|
||||
void PFX##_free(SNAME *_deque_, void (*deallocator)(V)) \
|
||||
{ \
|
||||
if (deallocator) \
|
||||
{ \
|
||||
for (size_t i = _deque_->front, j = 0; j < _deque_->count; j++) \
|
||||
{ \
|
||||
deallocator(_deque_->buffer[i]); \
|
||||
\
|
||||
i = (i + 1) % _deque_->capacity; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
free(_deque_->buffer); \
|
||||
free(_deque_); \
|
||||
} \
|
||||
\
|
||||
bool PFX##_push_front(SNAME *_deque_, V element) \
|
||||
{ \
|
||||
if (PFX##_full(_deque_)) \
|
||||
{ \
|
||||
if (!PFX##_resize(_deque_, PFX##_capacity(_deque_) * 2)) \
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
_deque_->front = (_deque_->front == 0) ? _deque_->capacity - 1 : _deque_->front - 1; \
|
||||
\
|
||||
_deque_->buffer[_deque_->front] = element; \
|
||||
\
|
||||
_deque_->count++; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
bool PFX##_push_back(SNAME *_deque_, V element) \
|
||||
{ \
|
||||
if (PFX##_full(_deque_)) \
|
||||
{ \
|
||||
if (!PFX##_resize(_deque_, PFX##_capacity(_deque_) * 2)) \
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
_deque_->buffer[_deque_->back] = element; \
|
||||
\
|
||||
_deque_->back = (_deque_->back == _deque_->capacity - 1) ? 0 : _deque_->back + 1; \
|
||||
\
|
||||
_deque_->count++; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
bool PFX##_pop_front(SNAME *_deque_) \
|
||||
{ \
|
||||
if (PFX##_empty(_deque_)) \
|
||||
return false; \
|
||||
\
|
||||
_deque_->buffer[_deque_->front] = (V){0}; \
|
||||
\
|
||||
_deque_->front = (_deque_->front == _deque_->capacity - 1) ? 0 : _deque_->front + 1; \
|
||||
\
|
||||
_deque_->count--; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
bool PFX##_pop_back(SNAME *_deque_) \
|
||||
{ \
|
||||
if (PFX##_empty(_deque_)) \
|
||||
return false; \
|
||||
\
|
||||
_deque_->back = (_deque_->back == 0) ? _deque_->capacity - 1 : _deque_->back - 1; \
|
||||
\
|
||||
_deque_->buffer[_deque_->back] = (V){0}; \
|
||||
\
|
||||
_deque_->count--; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
V PFX##_front(SNAME *_deque_) \
|
||||
{ \
|
||||
if (PFX##_empty(_deque_)) \
|
||||
return (V){0}; \
|
||||
\
|
||||
return _deque_->buffer[_deque_->front]; \
|
||||
} \
|
||||
\
|
||||
V PFX##_back(SNAME *_deque_) \
|
||||
{ \
|
||||
if (PFX##_empty(_deque_)) \
|
||||
return (V){0}; \
|
||||
\
|
||||
return _deque_->buffer[(_deque_->back == 0) ? _deque_->capacity - 1 : _deque_->back - 1]; \
|
||||
} \
|
||||
\
|
||||
bool PFX##_contains(SNAME *_deque_, V element, int (*comparator)(V, V)) \
|
||||
{ \
|
||||
for (size_t i = _deque_->front, j = 0; j < _deque_->count; j++) \
|
||||
{ \
|
||||
if (comparator(_deque_->buffer[i], element) == 0) \
|
||||
return true; \
|
||||
\
|
||||
i = (i + 1) % _deque_->capacity; \
|
||||
} \
|
||||
\
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
bool PFX##_empty(SNAME *_deque_) \
|
||||
{ \
|
||||
return _deque_->count == 0; \
|
||||
} \
|
||||
\
|
||||
bool PFX##_full(SNAME *_deque_) \
|
||||
{ \
|
||||
return _deque_->count >= _deque_->capacity; \
|
||||
} \
|
||||
\
|
||||
size_t PFX##_count(SNAME *_deque_) \
|
||||
{ \
|
||||
return _deque_->count; \
|
||||
} \
|
||||
\
|
||||
size_t PFX##_capacity(SNAME *_deque_) \
|
||||
{ \
|
||||
return _deque_->capacity; \
|
||||
} \
|
||||
\
|
||||
bool PFX##_resize(SNAME *_deque_, size_t capacity) \
|
||||
{ \
|
||||
if (PFX##_capacity(_deque_) == capacity) \
|
||||
return true; \
|
||||
\
|
||||
if (capacity < PFX##_count(_deque_)) \
|
||||
return false; \
|
||||
\
|
||||
V *new_buffer = malloc(sizeof(V) * capacity); \
|
||||
\
|
||||
if (!new_buffer) \
|
||||
return false; \
|
||||
\
|
||||
for (size_t i = _deque_->front, j = 0; j < _deque_->count; j++) \
|
||||
{ \
|
||||
new_buffer[j] = _deque_->buffer[i]; \
|
||||
\
|
||||
i = (i + 1) % PFX##_capacity(_deque_); \
|
||||
} \
|
||||
\
|
||||
free(_deque_->buffer); \
|
||||
\
|
||||
_deque_->buffer = new_buffer; \
|
||||
_deque_->capacity = capacity; \
|
||||
_deque_->front = 0; \
|
||||
_deque_->back = _deque_->count; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
SNAME *PFX##_copy_of(SNAME *_deque_, V (*copy_func)(V)) \
|
||||
{ \
|
||||
SNAME *result = PFX##_new(_deque_->capacity); \
|
||||
\
|
||||
if (!result) \
|
||||
return NULL; \
|
||||
\
|
||||
if (copy_func) \
|
||||
{ \
|
||||
for (size_t i = _deque_->front, j = 0; j < _deque_->count; j++) \
|
||||
{ \
|
||||
result->buffer[j] = copy_func(_deque_->buffer[i]); \
|
||||
\
|
||||
i = (i + 1) % _deque_->capacity; \
|
||||
} \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
for (size_t i = _deque_->front, j = 0; j < _deque_->count; j++) \
|
||||
{ \
|
||||
result->buffer[j] = _deque_->buffer[i]; \
|
||||
\
|
||||
i = (i + 1) % _deque_->capacity; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
result->count = _deque_->count; \
|
||||
\
|
||||
return result; \
|
||||
} \
|
||||
\
|
||||
bool PFX##_equals(SNAME *_deque1_, SNAME *_deque2_, int (*comparator)(V, V)) \
|
||||
{ \
|
||||
if (PFX##_count(_deque1_) != PFX##_count(_deque2_)) \
|
||||
return false; \
|
||||
\
|
||||
size_t i, j, k; \
|
||||
for (i = _deque1_->front, j = _deque2_->front, k = 0; k < PFX##_count(_deque1_); k++) \
|
||||
{ \
|
||||
if (comparator(_deque1_->buffer[i], _deque2_->buffer[j]) != 0) \
|
||||
return false; \
|
||||
\
|
||||
i = (i + 1) % _deque1_->capacity; \
|
||||
j = (j + 1) % _deque2_->capacity; \
|
||||
} \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
cmc_string PFX##_to_string(SNAME *_deque_) \
|
||||
{ \
|
||||
cmc_string str; \
|
||||
SNAME *d_ = _deque_; \
|
||||
const char *name = #SNAME; \
|
||||
\
|
||||
snprintf(str.s, cmc_string_len, cmc_string_fmt_deque, \
|
||||
name, d_, d_->buffer, d_->capacity, d_->count, d_->front, d_->back); \
|
||||
\
|
||||
return str; \
|
||||
} \
|
||||
\
|
||||
SNAME##_iter *PFX##_iter_new(SNAME *target) \
|
||||
{ \
|
||||
SNAME##_iter *iter = malloc(sizeof(SNAME##_iter)); \
|
||||
\
|
||||
if (!iter) \
|
||||
return NULL; \
|
||||
\
|
||||
PFX##_iter_init(iter, target); \
|
||||
\
|
||||
return iter; \
|
||||
} \
|
||||
\
|
||||
void PFX##_iter_free(SNAME##_iter *iter) \
|
||||
{ \
|
||||
free(iter); \
|
||||
} \
|
||||
\
|
||||
void PFX##_iter_init(SNAME##_iter *iter, SNAME *target) \
|
||||
{ \
|
||||
iter->target = target; \
|
||||
iter->cursor = target->front; \
|
||||
iter->index = 0; \
|
||||
iter->start = true; \
|
||||
iter->end = PFX##_empty(target); \
|
||||
} \
|
||||
\
|
||||
bool PFX##_iter_start(SNAME##_iter *iter) \
|
||||
{ \
|
||||
return PFX##_empty(iter->target) || iter->start; \
|
||||
} \
|
||||
\
|
||||
bool PFX##_iter_end(SNAME##_iter *iter) \
|
||||
{ \
|
||||
return PFX##_empty(iter->target) || iter->end; \
|
||||
} \
|
||||
\
|
||||
void PFX##_iter_to_start(SNAME##_iter *iter) \
|
||||
{ \
|
||||
iter->cursor = iter->target->front; \
|
||||
iter->index = 0; \
|
||||
iter->start = true; \
|
||||
iter->end = PFX##_empty(iter->target); \
|
||||
} \
|
||||
\
|
||||
void PFX##_iter_to_end(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (PFX##_empty(iter->target)) \
|
||||
{ \
|
||||
iter->cursor = 0; \
|
||||
iter->index = 0; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
if (iter->target->back == 0) \
|
||||
iter->cursor = iter->target->capacity - 1; \
|
||||
else \
|
||||
iter->cursor = iter->target->back - 1; \
|
||||
\
|
||||
iter->index = PFX##_count(iter->target) - 1; \
|
||||
} \
|
||||
\
|
||||
iter->start = PFX##_empty(iter->target); \
|
||||
iter->end = true; \
|
||||
} \
|
||||
\
|
||||
bool PFX##_iter_next(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (iter->end) \
|
||||
return false; \
|
||||
\
|
||||
if (iter->index + 1 == PFX##_count(iter->target)) \
|
||||
{ \
|
||||
iter->end = true; \
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
iter->start = PFX##_empty(iter->target); \
|
||||
\
|
||||
iter->cursor = (iter->cursor + 1) % (iter->target->capacity); \
|
||||
iter->index++; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
bool PFX##_iter_prev(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (iter->start) \
|
||||
return false; \
|
||||
\
|
||||
if (iter->index == 0) \
|
||||
{ \
|
||||
iter->start = true; \
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
iter->end = PFX##_empty(iter->target); \
|
||||
\
|
||||
iter->cursor = (iter->cursor == 0) ? iter->target->capacity - 1 : iter->cursor - 1; \
|
||||
iter->index--; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
/* Returns true only if the iterator moved */ \
|
||||
bool PFX##_iter_advance(SNAME##_iter *iter, size_t steps) \
|
||||
{ \
|
||||
if (iter->end) \
|
||||
return false; \
|
||||
\
|
||||
if (iter->index + 1 == PFX##_count(iter->target)) \
|
||||
{ \
|
||||
iter->end = true; \
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
if (steps == 0 || iter->index + steps >= PFX##_count(iter->target)) \
|
||||
return false; \
|
||||
\
|
||||
iter->start = PFX##_empty(iter->target); \
|
||||
\
|
||||
iter->index += steps; \
|
||||
iter->cursor = (iter->cursor + steps) % iter->target->capacity; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
/* Returns true only if the iterator moved */ \
|
||||
bool PFX##_iter_rewind(SNAME##_iter *iter, size_t steps) \
|
||||
{ \
|
||||
if (iter->start) \
|
||||
return false; \
|
||||
\
|
||||
if (iter->index == 0) \
|
||||
{ \
|
||||
iter->start = true; \
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
if (steps == 0 || iter->index < steps) \
|
||||
return false; \
|
||||
\
|
||||
iter->end = PFX##_empty(iter->target); \
|
||||
\
|
||||
iter->index -= steps; \
|
||||
\
|
||||
/* Prevent underflow */ \
|
||||
if (iter->cursor < steps) \
|
||||
iter->cursor += PFX##_capacity(iter->target); \
|
||||
\
|
||||
iter->cursor -= steps; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
/* Returns true only if the iterator was able to be positioned at the given index */ \
|
||||
bool PFX##_iter_go_to(SNAME##_iter *iter, size_t index) \
|
||||
{ \
|
||||
if (index >= PFX##_count(iter->target)) \
|
||||
return false; \
|
||||
\
|
||||
if (iter->index > index) \
|
||||
return PFX##_iter_rewind(iter, iter->index - index); \
|
||||
else if (iter->index < index) \
|
||||
return PFX##_iter_advance(iter, index - iter->index); \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
V PFX##_iter_value(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (PFX##_empty(iter->target)) \
|
||||
return (V){0}; \
|
||||
\
|
||||
return iter->target->buffer[iter->cursor]; \
|
||||
} \
|
||||
\
|
||||
V *PFX##_iter_rvalue(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (PFX##_empty(iter->target)) \
|
||||
return NULL; \
|
||||
\
|
||||
return &(iter->target->buffer[iter->cursor]); \
|
||||
} \
|
||||
\
|
||||
size_t PFX##_iter_index(SNAME##_iter *iter) \
|
||||
{ \
|
||||
return iter->index; \
|
||||
} \
|
||||
\
|
||||
static SNAME##_iter PFX##_impl_it_start(SNAME *_deque_) \
|
||||
{ \
|
||||
SNAME##_iter iter; \
|
||||
\
|
||||
PFX##_iter_init(&iter, _deque_); \
|
||||
\
|
||||
return iter; \
|
||||
} \
|
||||
\
|
||||
static SNAME##_iter PFX##_impl_it_end(SNAME *_deque_) \
|
||||
{ \
|
||||
SNAME##_iter iter; \
|
||||
\
|
||||
PFX##_iter_init(&iter, _deque_); \
|
||||
PFX##_iter_to_end(&iter); \
|
||||
\
|
||||
return iter; \
|
||||
}
|
||||
|
||||
#endif /* CMC_DEQUE_H */
|
||||
+853
-678
File diff suppressed because it is too large.
Load diff
+960
-798
File diff suppressed because it is too large.
Load diff
+284
-186
@@ -30,136 +30,131 @@
|
||||
#ifndef CMC_HEAP_H
|
||||
#define CMC_HEAP_H
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "../utl/cmc_string.h"
|
||||
|
||||
/* to_string format */
|
||||
static const char *cmc_string_fmt_heap = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", count:%" PRIuMAX ", type:%s, cmp:%p }";
|
||||
|
||||
typedef enum cmc_heap_order_e
|
||||
{
|
||||
cmc_max_heap = 1,
|
||||
cmc_min_heap = -1
|
||||
} cmc_heap_order;
|
||||
|
||||
#define HEAP_GENERATE(PFX, SNAME, FMOD, V) \
|
||||
HEAP_GENERATE_HEADER(PFX, SNAME, FMOD, V) \
|
||||
HEAP_GENERATE_SOURCE(PFX, SNAME, FMOD, V)
|
||||
#define CMC_GENERATE_HEAP(PFX, SNAME, V) \
|
||||
CMC_GENERATE_HEAP_HEADER(PFX, SNAME, V) \
|
||||
CMC_GENERATE_HEAP_SOURCE(PFX, SNAME, V)
|
||||
|
||||
#define HEAP_WRAPGEN_HEADER(PFX, SNAME, FMOD, K, V) \
|
||||
HEAP_GENERATE_HEADER(PFX, SNAME, FMOD, V)
|
||||
#define CMC_WRAPGEN_HEAP_HEADER(PFX, SNAME, K, V) \
|
||||
CMC_GENERATE_HEAP_HEADER(PFX, SNAME, V)
|
||||
|
||||
#define HEAP_WRAPGEN_SOURCE(PFX, SNAME, FMOD, K, V) \
|
||||
HEAP_GENERATE_SOURCE(PFX, SNAME, FMOD, V)
|
||||
#define CMC_WRAPGEN_HEAP_SOURCE(PFX, SNAME, K, V) \
|
||||
CMC_GENERATE_HEAP_SOURCE(PFX, SNAME, V)
|
||||
|
||||
/* HEADER ********************************************************************/
|
||||
#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 cmc_heap_order_e HO; \
|
||||
\
|
||||
/* Element comparison function */ \
|
||||
int (*cmp)(V, V); \
|
||||
\
|
||||
/* Function that returns an iterator to the start of the heap */ \
|
||||
struct SNAME##_iter_s (*it_start)(struct SNAME##_s *); \
|
||||
\
|
||||
/* Function that returns an iterator to the end of the heap */ \
|
||||
struct SNAME##_iter_s (*it_end)(struct SNAME##_s *); \
|
||||
\
|
||||
} SNAME, *SNAME##_ptr; \
|
||||
\
|
||||
/* Heap Iterator */ \
|
||||
typedef struct SNAME##_iter_s \
|
||||
{ \
|
||||
/* Target heap */ \
|
||||
struct SNAME##_s *target; \
|
||||
\
|
||||
/* Cursor's position (index) */ \
|
||||
size_t cursor; \
|
||||
\
|
||||
/* If the iterator has reached the start of the iteration */ \
|
||||
bool start; \
|
||||
\
|
||||
/* If the iterator has reached the end of the iteration */ \
|
||||
bool end; \
|
||||
\
|
||||
} SNAME##_iter, *SNAME##_iter_ptr; \
|
||||
\
|
||||
/* Collection Functions */ \
|
||||
/* Collection Allocation and Deallocation */ \
|
||||
FMOD SNAME *PFX##_new(size_t capacity, cmc_heap_order 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_); \
|
||||
/* Collection Utility */ \
|
||||
FMOD cmc_string PFX##_to_string(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); \
|
||||
\
|
||||
/* Default Value */ \
|
||||
static inline V PFX##_impl_default_value(void) \
|
||||
{ \
|
||||
V _empty_value_; \
|
||||
\
|
||||
memset(&_empty_value_, 0, sizeof(V)); \
|
||||
\
|
||||
return _empty_value_; \
|
||||
} \
|
||||
\
|
||||
#define CMC_GENERATE_HEAP_HEADER(PFX, SNAME, V) \
|
||||
\
|
||||
/* Heap Structure */ \
|
||||
typedef struct SNAME##_s \
|
||||
{ \
|
||||
/* Dynamic array of elements */ \
|
||||
V *buffer; \
|
||||
\
|
||||
/* Current array capacity */ \
|
||||
size_t capacity; \
|
||||
\
|
||||
/* Current amount of elements in the heap */ \
|
||||
size_t count; \
|
||||
\
|
||||
/* Heap order (MaxHeap or MinHeap) */ \
|
||||
enum cmc_heap_order_e HO; \
|
||||
\
|
||||
/* Element comparison function */ \
|
||||
int (*cmp)(V, V); \
|
||||
\
|
||||
/* Function that returns an iterator to the start of the heap */ \
|
||||
struct SNAME##_iter_s (*it_start)(struct SNAME##_s *); \
|
||||
\
|
||||
/* Function that returns an iterator to the end of the heap */ \
|
||||
struct SNAME##_iter_s (*it_end)(struct SNAME##_s *); \
|
||||
\
|
||||
} SNAME, *SNAME##_ptr; \
|
||||
\
|
||||
/* Heap Iterator */ \
|
||||
typedef struct SNAME##_iter_s \
|
||||
{ \
|
||||
/* Target heap */ \
|
||||
struct SNAME##_s *target; \
|
||||
\
|
||||
/* Cursor's position (index) */ \
|
||||
size_t cursor; \
|
||||
\
|
||||
/* If the iterator has reached the start of the iteration */ \
|
||||
bool start; \
|
||||
\
|
||||
/* If the iterator has reached the end of the iteration */ \
|
||||
bool end; \
|
||||
\
|
||||
} SNAME##_iter, *SNAME##_iter_ptr; \
|
||||
\
|
||||
/* Collection Functions */ \
|
||||
/* Collection Allocation and Deallocation */ \
|
||||
SNAME *PFX##_new(size_t capacity, cmc_heap_order HO, int (*compare)(V, V)); \
|
||||
void PFX##_clear(SNAME *_heap_, void (*deallocator)(V)); \
|
||||
void PFX##_free(SNAME *_heap_, void (*deallocator)(V)); \
|
||||
/* Collection Input and Output */ \
|
||||
bool PFX##_insert(SNAME *_heap_, V element); \
|
||||
bool PFX##_remove(SNAME *_heap_, V *result); \
|
||||
/* Element Access */ \
|
||||
V PFX##_peek(SNAME *_heap_); \
|
||||
/* Collection State */ \
|
||||
bool PFX##_contains(SNAME *_heap_, V element); \
|
||||
bool PFX##_empty(SNAME *_heap_); \
|
||||
bool PFX##_full(SNAME *_heap_); \
|
||||
size_t PFX##_count(SNAME *_heap_); \
|
||||
size_t PFX##_capacity(SNAME *_heap_); \
|
||||
/* Collection Utility */ \
|
||||
bool PFX##_resize(SNAME *_heap_, size_t capacity); \
|
||||
SNAME *PFX##_copy_of(SNAME *_heap_, V (*copy_func)(V)); \
|
||||
bool PFX##_equals(SNAME *_heap1_, SNAME *_heap2_); \
|
||||
cmc_string PFX##_to_string(SNAME *_heap_); \
|
||||
\
|
||||
/* Iterator Functions */ \
|
||||
/* Iterator Allocation and Deallocation */ \
|
||||
SNAME##_iter *PFX##_iter_new(SNAME *target); \
|
||||
void PFX##_iter_free(SNAME##_iter *iter); \
|
||||
/* Iterator Initialization */ \
|
||||
void PFX##_iter_init(SNAME##_iter *iter, SNAME *target); \
|
||||
/* Iterator State */ \
|
||||
bool PFX##_iter_start(SNAME##_iter *iter); \
|
||||
bool PFX##_iter_end(SNAME##_iter *iter); \
|
||||
/* Iterator Movement */ \
|
||||
void PFX##_iter_to_start(SNAME##_iter *iter); \
|
||||
void PFX##_iter_to_end(SNAME##_iter *iter); \
|
||||
bool PFX##_iter_next(SNAME##_iter *iter); \
|
||||
bool PFX##_iter_prev(SNAME##_iter *iter); \
|
||||
bool PFX##_iter_advance(SNAME##_iter *iter, size_t steps); \
|
||||
bool PFX##_iter_rewind(SNAME##_iter *iter, size_t steps); \
|
||||
bool PFX##_iter_go_to(SNAME##_iter *iter, size_t index); \
|
||||
/* Iterator Access */ \
|
||||
V PFX##_iter_value(SNAME##_iter *iter); \
|
||||
size_t PFX##_iter_index(SNAME##_iter *iter); \
|
||||
\
|
||||
/* SOURCE ********************************************************************/
|
||||
#define HEAP_GENERATE_SOURCE(PFX, SNAME, FMOD, V) \
|
||||
#define CMC_GENERATE_HEAP_SOURCE(PFX, SNAME, V) \
|
||||
\
|
||||
/* Implementation Detail Functions */ \
|
||||
static bool PFX##_impl_grow(SNAME *_heap_); \
|
||||
static bool PFX##_impl_float_up(SNAME *_heap_, size_t index); \
|
||||
static bool PFX##_impl_float_down(SNAME *_heap_, size_t index); \
|
||||
static SNAME##_iter PFX##_impl_it_start(SNAME *_heap_); \
|
||||
static SNAME##_iter PFX##_impl_it_end(SNAME *_heap_); \
|
||||
\
|
||||
FMOD SNAME *PFX##_new(size_t capacity, cmc_heap_order HO, int (*compare)(V, V)) \
|
||||
SNAME *PFX##_new(size_t capacity, cmc_heap_order HO, int (*compare)(V, V)) \
|
||||
{ \
|
||||
if (capacity < 1) \
|
||||
return NULL; \
|
||||
@@ -193,24 +188,40 @@ typedef enum cmc_heap_order_e
|
||||
return _heap_; \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_clear(SNAME *_heap_) \
|
||||
void PFX##_clear(SNAME *_heap_, void (*deallocator)(V)) \
|
||||
{ \
|
||||
if (deallocator) \
|
||||
{ \
|
||||
for (size_t i = 0; i < _heap_->count; i++) \
|
||||
{ \
|
||||
deallocator(_heap_->buffer[i]); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
memset(_heap_->buffer, 0, sizeof(V) * _heap_->capacity); \
|
||||
\
|
||||
_heap_->count = 0; \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_free(SNAME *_heap_) \
|
||||
void PFX##_free(SNAME *_heap_, void (*deallocator)(V)) \
|
||||
{ \
|
||||
if (deallocator) \
|
||||
{ \
|
||||
for (size_t i = 0; i < _heap_->count; i++) \
|
||||
{ \
|
||||
deallocator(_heap_->buffer[i]); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
free(_heap_->buffer); \
|
||||
free(_heap_); \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_insert(SNAME *_heap_, V element) \
|
||||
bool PFX##_insert(SNAME *_heap_, V element) \
|
||||
{ \
|
||||
if (PFX##_full(_heap_)) \
|
||||
{ \
|
||||
if (!PFX##_impl_grow(_heap_)) \
|
||||
if (!PFX##_resize(_heap_, PFX##_count(_heap_) * 2)) \
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
@@ -228,14 +239,14 @@ typedef enum cmc_heap_order_e
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_remove(SNAME *_heap_, V *result) \
|
||||
bool PFX##_remove(SNAME *_heap_, V *result) \
|
||||
{ \
|
||||
if (PFX##_empty(_heap_)) \
|
||||
return false; \
|
||||
\
|
||||
*result = _heap_->buffer[0]; \
|
||||
_heap_->buffer[0] = _heap_->buffer[_heap_->count - 1]; \
|
||||
_heap_->buffer[_heap_->count - 1] = PFX##_impl_default_value(); \
|
||||
_heap_->buffer[_heap_->count - 1] = (V){0}; \
|
||||
\
|
||||
_heap_->count--; \
|
||||
\
|
||||
@@ -245,39 +256,15 @@ typedef enum cmc_heap_order_e
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_insert_if(SNAME *_heap_, V element, bool condition) \
|
||||
{ \
|
||||
if (condition) \
|
||||
return PFX##_insert(_heap_, element); \
|
||||
\
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_remove_if(SNAME *_heap_, V *result, bool condition) \
|
||||
{ \
|
||||
if (condition) \
|
||||
return PFX##_remove(_heap_, result); \
|
||||
\
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
FMOD V PFX##_peek(SNAME *_heap_) \
|
||||
V PFX##_peek(SNAME *_heap_) \
|
||||
{ \
|
||||
if (PFX##_empty(_heap_)) \
|
||||
return PFX##_impl_default_value(); \
|
||||
return (V){0}; \
|
||||
\
|
||||
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) \
|
||||
bool PFX##_contains(SNAME *_heap_, V element) \
|
||||
{ \
|
||||
for (size_t i = 0; i < _heap_->count; i++) \
|
||||
{ \
|
||||
@@ -288,27 +275,80 @@ typedef enum cmc_heap_order_e
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_empty(SNAME *_heap_) \
|
||||
bool PFX##_empty(SNAME *_heap_) \
|
||||
{ \
|
||||
return _heap_->count == 0; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_full(SNAME *_heap_) \
|
||||
bool PFX##_full(SNAME *_heap_) \
|
||||
{ \
|
||||
return _heap_->count >= _heap_->capacity; \
|
||||
} \
|
||||
\
|
||||
FMOD size_t PFX##_count(SNAME *_heap_) \
|
||||
size_t PFX##_count(SNAME *_heap_) \
|
||||
{ \
|
||||
return _heap_->count; \
|
||||
} \
|
||||
\
|
||||
FMOD size_t PFX##_capacity(SNAME *_heap_) \
|
||||
size_t PFX##_capacity(SNAME *_heap_) \
|
||||
{ \
|
||||
return _heap_->capacity; \
|
||||
} \
|
||||
\
|
||||
FMOD cmc_string PFX##_to_string(SNAME *_heap_) \
|
||||
bool PFX##_resize(SNAME *_heap_, size_t capacity) \
|
||||
{ \
|
||||
if (PFX##_capacity(_heap_) == capacity) \
|
||||
return true; \
|
||||
\
|
||||
if (capacity < PFX##_count(_heap_)) \
|
||||
return false; \
|
||||
\
|
||||
V *new_buffer = realloc(_heap_->buffer, sizeof(V) * capacity); \
|
||||
\
|
||||
if (!new_buffer) \
|
||||
return false; \
|
||||
\
|
||||
_heap_->buffer = new_buffer; \
|
||||
_heap_->capacity = capacity; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
SNAME *PFX##_copy_of(SNAME *_heap_, V (*copy_func)(V)) \
|
||||
{ \
|
||||
SNAME *result = PFX##_new(_heap_->capacity, _heap_->HO, _heap_->cmp); \
|
||||
\
|
||||
if (!result) \
|
||||
return NULL; \
|
||||
\
|
||||
if (copy_func) \
|
||||
{ \
|
||||
for (size_t i = 0; i < _heap_->count; i++) \
|
||||
result->buffer[i] = copy_func(_heap_->buffer[i]); \
|
||||
} \
|
||||
else \
|
||||
memcpy(result->buffer, _heap_->buffer, sizeof(V) * _heap_->count); \
|
||||
\
|
||||
result->count = _heap_->count; \
|
||||
\
|
||||
return result; \
|
||||
} \
|
||||
\
|
||||
bool PFX##_equals(SNAME *_heap1_, SNAME *_heap2_) \
|
||||
{ \
|
||||
if (PFX##_count(_heap1_) != PFX##_count(_heap2_)) \
|
||||
return false; \
|
||||
\
|
||||
for (size_t i = 0; i < PFX##_count(_heap1_); i++) \
|
||||
{ \
|
||||
if (_heap1_->cmp(_heap1_->buffer[i], _heap2_->buffer[i]) != 0) \
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
cmc_string PFX##_to_string(SNAME *_heap_) \
|
||||
{ \
|
||||
cmc_string str; \
|
||||
SNAME *h_ = _heap_; \
|
||||
@@ -321,7 +361,7 @@ typedef enum cmc_heap_order_e
|
||||
return str; \
|
||||
} \
|
||||
\
|
||||
FMOD SNAME##_iter *PFX##_iter_new(SNAME *target) \
|
||||
SNAME##_iter *PFX##_iter_new(SNAME *target) \
|
||||
{ \
|
||||
SNAME##_iter *iter = malloc(sizeof(SNAME##_iter)); \
|
||||
\
|
||||
@@ -333,12 +373,12 @@ typedef enum cmc_heap_order_e
|
||||
return iter; \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_iter_free(SNAME##_iter *iter) \
|
||||
void PFX##_iter_free(SNAME##_iter *iter) \
|
||||
{ \
|
||||
free(iter); \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_iter_init(SNAME##_iter *iter, SNAME *target) \
|
||||
void PFX##_iter_init(SNAME##_iter *iter, SNAME *target) \
|
||||
{ \
|
||||
iter->target = target; \
|
||||
iter->cursor = 0; \
|
||||
@@ -346,88 +386,146 @@ typedef enum cmc_heap_order_e
|
||||
iter->end = PFX##_empty(target); \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_iter_start(SNAME##_iter *iter) \
|
||||
bool PFX##_iter_start(SNAME##_iter *iter) \
|
||||
{ \
|
||||
return PFX##_empty(iter->target) || iter->start; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_iter_end(SNAME##_iter *iter) \
|
||||
bool PFX##_iter_end(SNAME##_iter *iter) \
|
||||
{ \
|
||||
return PFX##_empty(iter->target) || iter->end; \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_iter_to_start(SNAME##_iter *iter) \
|
||||
void PFX##_iter_to_start(SNAME##_iter *iter) \
|
||||
{ \
|
||||
iter->cursor = 0; \
|
||||
iter->start = true; \
|
||||
iter->end = PFX##_empty(iter->target); \
|
||||
if (!PFX##_empty(iter->target)) \
|
||||
{ \
|
||||
iter->cursor = 0; \
|
||||
iter->start = true; \
|
||||
iter->end = PFX##_empty(iter->target); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_iter_to_end(SNAME##_iter *iter) \
|
||||
void PFX##_iter_to_end(SNAME##_iter *iter) \
|
||||
{ \
|
||||
iter->cursor = iter->target->count - 1; \
|
||||
iter->start = PFX##_empty(iter->target); \
|
||||
iter->end = true; \
|
||||
if (!PFX##_empty(iter->target)) \
|
||||
{ \
|
||||
iter->cursor = PFX##_count(iter->target) - 1; \
|
||||
iter->start = PFX##_empty(iter->target); \
|
||||
iter->end = true; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_iter_next(SNAME##_iter *iter) \
|
||||
bool PFX##_iter_next(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (iter->end) \
|
||||
return false; \
|
||||
\
|
||||
iter->start = false; \
|
||||
\
|
||||
if (iter->cursor == iter->target->count - 1) \
|
||||
if (iter->cursor + 1 == PFX##_count(iter->target)) \
|
||||
{ \
|
||||
iter->end = true; \
|
||||
else \
|
||||
iter->cursor++; \
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
iter->start = PFX##_empty(iter->target); \
|
||||
\
|
||||
iter->cursor++; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_iter_prev(SNAME##_iter *iter) \
|
||||
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 false; \
|
||||
} \
|
||||
\
|
||||
iter->end = PFX##_empty(iter->target); \
|
||||
\
|
||||
iter->cursor--; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD V PFX##_iter_value(SNAME##_iter *iter) \
|
||||
/* Returns true only if the iterator moved */ \
|
||||
bool PFX##_iter_advance(SNAME##_iter *iter, size_t steps) \
|
||||
{ \
|
||||
if (iter->start) \
|
||||
return false; \
|
||||
\
|
||||
if (iter->cursor + 1 == PFX##_count(iter->target)) \
|
||||
{ \
|
||||
iter->end = true; \
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
if (steps == 0 || iter->cursor + steps >= PFX##_count(iter->target)) \
|
||||
return false; \
|
||||
\
|
||||
iter->start = PFX##_empty(iter->target); \
|
||||
\
|
||||
if (iter->end) \
|
||||
return false; \
|
||||
\
|
||||
iter->cursor += steps; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
/* Returns true only if the iterator moved */ \
|
||||
bool PFX##_iter_rewind(SNAME##_iter *iter, size_t steps) \
|
||||
{ \
|
||||
if (iter->start) \
|
||||
return false; \
|
||||
\
|
||||
if (iter->cursor == 0) \
|
||||
{ \
|
||||
iter->start = true; \
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
if (steps == 0 || iter->cursor < steps) \
|
||||
return false; \
|
||||
\
|
||||
iter->end = PFX##_empty(iter->target); \
|
||||
\
|
||||
iter->cursor -= steps; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
/* Returns true only if the iterator was able to be positioned at the given index */ \
|
||||
bool PFX##_iter_go_to(SNAME##_iter *iter, size_t index) \
|
||||
{ \
|
||||
if (index >= PFX##_count(iter->target)) \
|
||||
return false; \
|
||||
\
|
||||
if (iter->cursor > index) \
|
||||
return PFX##_iter_rewind(iter, iter->cursor - index); \
|
||||
else if (iter->cursor < index) \
|
||||
return PFX##_iter_advance(iter, index - iter->cursor); \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
V PFX##_iter_value(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (PFX##_empty(iter->target)) \
|
||||
return PFX##_impl_default_value(); \
|
||||
return (V){0}; \
|
||||
\
|
||||
return iter->target->buffer[iter->cursor]; \
|
||||
} \
|
||||
\
|
||||
FMOD size_t PFX##_iter_index(SNAME##_iter *iter) \
|
||||
size_t PFX##_iter_index(SNAME##_iter *iter) \
|
||||
{ \
|
||||
return iter->cursor; \
|
||||
} \
|
||||
\
|
||||
static bool PFX##_impl_grow(SNAME *_heap_) \
|
||||
{ \
|
||||
size_t new_capacity = _heap_->capacity * 2; \
|
||||
\
|
||||
V *new_buffer = realloc(_heap_->buffer, sizeof(V) * new_capacity); \
|
||||
\
|
||||
if (!new_buffer) \
|
||||
return false; \
|
||||
\
|
||||
_heap_->buffer = new_buffer; \
|
||||
_heap_->capacity = new_capacity; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
static bool PFX##_impl_float_up(SNAME *_heap_, size_t index) \
|
||||
{ \
|
||||
/* Current index */ \
|
||||
|
||||
+861
-741
File diff suppressed because it is too large.
Load diff
+729
-646
File diff suppressed because it is too large.
Load diff
+478
-350
@@ -43,24 +43,28 @@
|
||||
#ifndef CMC_QUEUE_H
|
||||
#define CMC_QUEUE_H
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "../utl/cmc_string.h"
|
||||
|
||||
#define QUEUE_GENERATE(PFX, SNAME, FMOD, V) \
|
||||
QUEUE_GENERATE_HEADER(PFX, SNAME, FMOD, V) \
|
||||
QUEUE_GENERATE_SOURCE(PFX, SNAME, FMOD, V)
|
||||
/* to_string format */
|
||||
static const char *cmc_string_fmt_queue = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", count:%" PRIuMAX ", front:%" PRIuMAX ", back:%" PRIuMAX " }";
|
||||
|
||||
#define QUEUE_WRAPGEN_HEADER(PFX, SNAME, FMOD, K, V) \
|
||||
QUEUE_GENERATE_HEADER(PFX, SNAME, FMOD, V)
|
||||
#define CMC_GENERATE_QUEUE(PFX, SNAME, V) \
|
||||
CMC_GENERATE_QUEUE_HEADER(PFX, SNAME, V) \
|
||||
CMC_GENERATE_QUEUE_SOURCE(PFX, SNAME, V)
|
||||
|
||||
#define QUEUE_WRAPGEN_SOURCE(PFX, SNAME, FMOD, K, V) \
|
||||
QUEUE_GENERATE_SOURCE(PFX, SNAME, FMOD, V)
|
||||
#define CMC_WRAPGEN_QUEUE_HEADER(PFX, SNAME, K, V) \
|
||||
CMC_GENERATE_QUEUE_HEADER(PFX, SNAME, V)
|
||||
|
||||
#define CMC_WRAPGEN_QUEUE_SOURCE(PFX, SNAME, K, V) \
|
||||
CMC_GENERATE_QUEUE_SOURCE(PFX, SNAME, V)
|
||||
|
||||
/* HEADER ********************************************************************/
|
||||
#define QUEUE_GENERATE_HEADER(PFX, SNAME, FMOD, V) \
|
||||
#define CMC_GENERATE_QUEUE_HEADER(PFX, SNAME, V) \
|
||||
\
|
||||
/* Queue Structure */ \
|
||||
typedef struct SNAME##_s \
|
||||
@@ -110,361 +114,485 @@
|
||||
\
|
||||
/* Collection Functions */ \
|
||||
/* Collection Allocation and Deallocation */ \
|
||||
FMOD SNAME *PFX##_new(size_t capacity); \
|
||||
FMOD void PFX##_clear(SNAME *_queue_); \
|
||||
FMOD void PFX##_free(SNAME *_queue_); \
|
||||
SNAME *PFX##_new(size_t capacity); \
|
||||
void PFX##_clear(SNAME *_queue_, void (*deallocator)(V)); \
|
||||
void PFX##_free(SNAME *_queue_, void (*deallocator)(V)); \
|
||||
/* Collection Input and Output */ \
|
||||
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); \
|
||||
bool PFX##_enqueue(SNAME *_queue_, V element); \
|
||||
bool PFX##_dequeue(SNAME *_queue_); \
|
||||
/* Element Access */ \
|
||||
FMOD V PFX##_peek(SNAME *_queue_); \
|
||||
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_); \
|
||||
bool PFX##_contains(SNAME *_queue_, V element, int (*comparator)(V, V)); \
|
||||
bool PFX##_empty(SNAME *_queue_); \
|
||||
bool PFX##_full(SNAME *_queue_); \
|
||||
size_t PFX##_count(SNAME *_queue_); \
|
||||
size_t PFX##_capacity(SNAME *_queue_); \
|
||||
/* Collection Utility */ \
|
||||
FMOD cmc_string PFX##_to_string(SNAME *_queue_); \
|
||||
bool PFX##_resize(SNAME *_queue_, size_t capacity); \
|
||||
SNAME *PFX##_copy_of(SNAME *_queue_, V (*copy_func)(V)); \
|
||||
bool PFX##_equals(SNAME *_queue1_, SNAME *_queue2_, int (*comparator)(V, V)); \
|
||||
cmc_string PFX##_to_string(SNAME *_queue_); \
|
||||
\
|
||||
/* Iterator Functions */ \
|
||||
/* Iterator Allocation and Deallocation */ \
|
||||
FMOD SNAME##_iter *PFX##_iter_new(SNAME *target); \
|
||||
FMOD void PFX##_iter_free(SNAME##_iter *iter); \
|
||||
SNAME##_iter *PFX##_iter_new(SNAME *target); \
|
||||
void PFX##_iter_free(SNAME##_iter *iter); \
|
||||
/* Iterator Initialization */ \
|
||||
FMOD void PFX##_iter_init(SNAME##_iter *iter, SNAME *target); \
|
||||
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); \
|
||||
bool PFX##_iter_start(SNAME##_iter *iter); \
|
||||
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); \
|
||||
void PFX##_iter_to_start(SNAME##_iter *iter); \
|
||||
void PFX##_iter_to_end(SNAME##_iter *iter); \
|
||||
bool PFX##_iter_next(SNAME##_iter *iter); \
|
||||
bool PFX##_iter_prev(SNAME##_iter *iter); \
|
||||
bool PFX##_iter_advance(SNAME##_iter *iter, size_t steps); \
|
||||
bool PFX##_iter_rewind(SNAME##_iter *iter, size_t steps); \
|
||||
bool PFX##_iter_go_to(SNAME##_iter *iter, size_t index); \
|
||||
/* Iterator Access */ \
|
||||
FMOD V PFX##_iter_value(SNAME##_iter *iter); \
|
||||
FMOD V *PFX##_iter_rvalue(SNAME##_iter *iter); \
|
||||
FMOD size_t PFX##_iter_index(SNAME##_iter *iter); \
|
||||
\
|
||||
/* Default Value */ \
|
||||
static inline V PFX##_impl_default_value(void) \
|
||||
{ \
|
||||
V _empty_value_; \
|
||||
\
|
||||
memset(&_empty_value_, 0, sizeof(V)); \
|
||||
\
|
||||
return _empty_value_; \
|
||||
} \
|
||||
V PFX##_iter_value(SNAME##_iter *iter); \
|
||||
V *PFX##_iter_rvalue(SNAME##_iter *iter); \
|
||||
size_t PFX##_iter_index(SNAME##_iter *iter); \
|
||||
\
|
||||
/* SOURCE ********************************************************************/
|
||||
#define QUEUE_GENERATE_SOURCE(PFX, SNAME, FMOD, V) \
|
||||
\
|
||||
/* Implementation Detail Functions */ \
|
||||
static bool PFX##_impl_grow(SNAME *_queue_); \
|
||||
static SNAME##_iter PFX##_impl_it_start(SNAME *_queue_); \
|
||||
static SNAME##_iter PFX##_impl_it_end(SNAME *_queue_); \
|
||||
\
|
||||
FMOD SNAME *PFX##_new(size_t capacity) \
|
||||
{ \
|
||||
if (capacity < 1) \
|
||||
return NULL; \
|
||||
\
|
||||
SNAME *_queue_ = malloc(sizeof(SNAME)); \
|
||||
\
|
||||
if (!_queue_) \
|
||||
return NULL; \
|
||||
\
|
||||
_queue_->buffer = malloc(sizeof(V) * capacity); \
|
||||
\
|
||||
if (!_queue_->buffer) \
|
||||
{ \
|
||||
free(_queue_); \
|
||||
return NULL; \
|
||||
} \
|
||||
\
|
||||
memset(_queue_->buffer, 0, sizeof(V) * capacity); \
|
||||
\
|
||||
_queue_->capacity = capacity; \
|
||||
_queue_->count = 0; \
|
||||
_queue_->front = 0; \
|
||||
_queue_->back = 0; \
|
||||
\
|
||||
_queue_->it_start = PFX##_impl_it_start; \
|
||||
_queue_->it_end = PFX##_impl_it_end; \
|
||||
\
|
||||
return _queue_; \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_clear(SNAME *_queue_) \
|
||||
{ \
|
||||
memset(_queue_->buffer, 0, sizeof(V) * _queue_->capacity); \
|
||||
\
|
||||
_queue_->count = 0; \
|
||||
_queue_->front = 0; \
|
||||
_queue_->back = 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##_impl_grow(_queue_)) \
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
_queue_->buffer[_queue_->back] = element; \
|
||||
\
|
||||
_queue_->back = (_queue_->back == _queue_->capacity - 1) ? 0 : _queue_->back + 1; \
|
||||
_queue_->count++; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_dequeue(SNAME *_queue_) \
|
||||
{ \
|
||||
if (PFX##_empty(_queue_)) \
|
||||
return false; \
|
||||
\
|
||||
_queue_->buffer[_queue_->front] = PFX##_impl_default_value(); \
|
||||
\
|
||||
_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 PFX##_impl_default_value(); \
|
||||
\
|
||||
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 cmc_string PFX##_to_string(SNAME *_queue_) \
|
||||
{ \
|
||||
cmc_string str; \
|
||||
SNAME *q_ = _queue_; \
|
||||
const char *name = #SNAME; \
|
||||
\
|
||||
snprintf(str.s, cmc_string_len, cmc_string_fmt_queue, \
|
||||
name, q_, q_->buffer, q_->capacity, q_->count, q_->front, q_->back); \
|
||||
\
|
||||
return str; \
|
||||
} \
|
||||
\
|
||||
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 PFX##_impl_default_value(); \
|
||||
\
|
||||
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; \
|
||||
} \
|
||||
\
|
||||
static bool PFX##_impl_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_->back = _queue_->count; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
static SNAME##_iter PFX##_impl_it_start(SNAME *_queue_) \
|
||||
{ \
|
||||
SNAME##_iter iter; \
|
||||
\
|
||||
PFX##_iter_init(&iter, _queue_); \
|
||||
PFX##_iter_to_start(&iter); \
|
||||
\
|
||||
return iter; \
|
||||
} \
|
||||
\
|
||||
static SNAME##_iter PFX##_impl_it_end(SNAME *_queue_) \
|
||||
{ \
|
||||
SNAME##_iter iter; \
|
||||
\
|
||||
PFX##_iter_init(&iter, _queue_); \
|
||||
PFX##_iter_to_end(&iter); \
|
||||
\
|
||||
return iter; \
|
||||
#define CMC_GENERATE_QUEUE_SOURCE(PFX, SNAME, V) \
|
||||
\
|
||||
/* Implementation Detail Functions */ \
|
||||
static SNAME##_iter PFX##_impl_it_start(SNAME *_queue_); \
|
||||
static SNAME##_iter PFX##_impl_it_end(SNAME *_queue_); \
|
||||
\
|
||||
SNAME *PFX##_new(size_t capacity) \
|
||||
{ \
|
||||
if (capacity < 1) \
|
||||
return NULL; \
|
||||
\
|
||||
SNAME *_queue_ = malloc(sizeof(SNAME)); \
|
||||
\
|
||||
if (!_queue_) \
|
||||
return NULL; \
|
||||
\
|
||||
_queue_->buffer = malloc(sizeof(V) * capacity); \
|
||||
\
|
||||
if (!_queue_->buffer) \
|
||||
{ \
|
||||
free(_queue_); \
|
||||
return NULL; \
|
||||
} \
|
||||
\
|
||||
memset(_queue_->buffer, 0, sizeof(V) * capacity); \
|
||||
\
|
||||
_queue_->capacity = capacity; \
|
||||
_queue_->count = 0; \
|
||||
_queue_->front = 0; \
|
||||
_queue_->back = 0; \
|
||||
\
|
||||
_queue_->it_start = PFX##_impl_it_start; \
|
||||
_queue_->it_end = PFX##_impl_it_end; \
|
||||
\
|
||||
return _queue_; \
|
||||
} \
|
||||
\
|
||||
void PFX##_clear(SNAME *_queue_, void (*deallocator)(V)) \
|
||||
{ \
|
||||
if (deallocator) \
|
||||
{ \
|
||||
for (size_t i = _queue_->front, j = 0; j < _queue_->count; j++) \
|
||||
{ \
|
||||
deallocator(_queue_->buffer[i]); \
|
||||
\
|
||||
i = (i + 1) % _queue_->capacity; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
memset(_queue_->buffer, 0, sizeof(V) * _queue_->capacity); \
|
||||
\
|
||||
_queue_->count = 0; \
|
||||
_queue_->front = 0; \
|
||||
_queue_->back = 0; \
|
||||
} \
|
||||
\
|
||||
void PFX##_free(SNAME *_queue_, void (*deallocator)(V)) \
|
||||
{ \
|
||||
if (deallocator) \
|
||||
{ \
|
||||
for (size_t i = _queue_->front, j = 0; j < _queue_->count; j++) \
|
||||
{ \
|
||||
deallocator(_queue_->buffer[i]); \
|
||||
\
|
||||
i = (i + 1) % _queue_->capacity; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
free(_queue_->buffer); \
|
||||
free(_queue_); \
|
||||
} \
|
||||
\
|
||||
bool PFX##_enqueue(SNAME *_queue_, V element) \
|
||||
{ \
|
||||
if (PFX##_full(_queue_)) \
|
||||
{ \
|
||||
if (!PFX##_resize(_queue_, PFX##_capacity(_queue_) * 2)) \
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
_queue_->buffer[_queue_->back] = element; \
|
||||
\
|
||||
_queue_->back = (_queue_->back == _queue_->capacity - 1) ? 0 : _queue_->back + 1; \
|
||||
_queue_->count++; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
bool PFX##_dequeue(SNAME *_queue_) \
|
||||
{ \
|
||||
if (PFX##_empty(_queue_)) \
|
||||
return false; \
|
||||
\
|
||||
_queue_->buffer[_queue_->front] = (V){0}; \
|
||||
\
|
||||
_queue_->front = (_queue_->front == _queue_->capacity - 1) ? 0 : _queue_->front + 1; \
|
||||
_queue_->count--; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
V PFX##_peek(SNAME *_queue_) \
|
||||
{ \
|
||||
if (PFX##_empty(_queue_)) \
|
||||
return (V){0}; \
|
||||
\
|
||||
return _queue_->buffer[_queue_->front]; \
|
||||
} \
|
||||
\
|
||||
bool PFX##_contains(SNAME *_queue_, V element, int (*comparator)(V, V)) \
|
||||
{ \
|
||||
for (size_t i = _queue_->front, j = 0; j < _queue_->count; j++) \
|
||||
{ \
|
||||
if (comparator(_queue_->buffer[i], element) == 0) \
|
||||
return true; \
|
||||
\
|
||||
i = (i + 1) % _queue_->capacity; \
|
||||
} \
|
||||
\
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
bool PFX##_empty(SNAME *_queue_) \
|
||||
{ \
|
||||
return _queue_->count == 0; \
|
||||
} \
|
||||
\
|
||||
bool PFX##_full(SNAME *_queue_) \
|
||||
{ \
|
||||
return _queue_->count >= _queue_->capacity; \
|
||||
} \
|
||||
\
|
||||
size_t PFX##_count(SNAME *_queue_) \
|
||||
{ \
|
||||
return _queue_->count; \
|
||||
} \
|
||||
\
|
||||
size_t PFX##_capacity(SNAME *_queue_) \
|
||||
{ \
|
||||
return _queue_->capacity; \
|
||||
} \
|
||||
\
|
||||
bool PFX##_resize(SNAME *_queue_, size_t capacity) \
|
||||
{ \
|
||||
if (PFX##_capacity(_queue_) == capacity) \
|
||||
return true; \
|
||||
\
|
||||
if (capacity < PFX##_count(_queue_)) \
|
||||
return false; \
|
||||
\
|
||||
V *new_buffer = malloc(sizeof(V) * capacity); \
|
||||
\
|
||||
if (!new_buffer) \
|
||||
return false; \
|
||||
\
|
||||
for (size_t i = _queue_->front, j = 0; j < _queue_->count; j++) \
|
||||
{ \
|
||||
new_buffer[j] = _queue_->buffer[i]; \
|
||||
\
|
||||
i = (i + 1) % PFX##_capacity(_queue_); \
|
||||
} \
|
||||
\
|
||||
free(_queue_->buffer); \
|
||||
\
|
||||
_queue_->buffer = new_buffer; \
|
||||
_queue_->capacity = capacity; \
|
||||
_queue_->front = 0; \
|
||||
_queue_->back = _queue_->count; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
SNAME *PFX##_copy_of(SNAME *_queue_, V (*copy_func)(V)) \
|
||||
{ \
|
||||
SNAME *result = PFX##_new(_queue_->capacity); \
|
||||
\
|
||||
if (!result) \
|
||||
return NULL; \
|
||||
\
|
||||
if (copy_func) \
|
||||
{ \
|
||||
for (size_t i = _queue_->front, j = 0; j < _queue_->count; j++) \
|
||||
{ \
|
||||
result->buffer[j] = copy_func(_queue_->buffer[i]); \
|
||||
\
|
||||
i = (i + 1) % _queue_->capacity; \
|
||||
} \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
for (size_t i = _queue_->front, j = 0; j < _queue_->count; j++) \
|
||||
{ \
|
||||
result->buffer[j] = _queue_->buffer[i]; \
|
||||
\
|
||||
i = (i + 1) % _queue_->capacity; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
result->count = _queue_->count; \
|
||||
\
|
||||
return result; \
|
||||
} \
|
||||
\
|
||||
bool PFX##_equals(SNAME *_queue1_, SNAME *_queue2_, int (*comparator)(V, V)) \
|
||||
{ \
|
||||
if (PFX##_count(_queue1_) != PFX##_count(_queue2_)) \
|
||||
return false; \
|
||||
\
|
||||
size_t i, j, k; \
|
||||
for (i = _queue1_->front, j = _queue2_->front, k = 0; k < PFX##_count(_queue1_); k++) \
|
||||
{ \
|
||||
if (comparator(_queue1_->buffer[i], _queue2_->buffer[j]) != 0) \
|
||||
return false; \
|
||||
\
|
||||
i = (i + 1) % _queue1_->capacity; \
|
||||
j = (j + 1) % _queue2_->capacity; \
|
||||
} \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
cmc_string PFX##_to_string(SNAME *_queue_) \
|
||||
{ \
|
||||
cmc_string str; \
|
||||
SNAME *q_ = _queue_; \
|
||||
const char *name = #SNAME; \
|
||||
\
|
||||
snprintf(str.s, cmc_string_len, cmc_string_fmt_queue, \
|
||||
name, q_, q_->buffer, q_->capacity, q_->count, q_->front, q_->back); \
|
||||
\
|
||||
return str; \
|
||||
} \
|
||||
\
|
||||
SNAME##_iter *PFX##_iter_new(SNAME *target) \
|
||||
{ \
|
||||
SNAME##_iter *iter = malloc(sizeof(SNAME##_iter)); \
|
||||
\
|
||||
if (!iter) \
|
||||
return NULL; \
|
||||
\
|
||||
PFX##_iter_init(iter, target); \
|
||||
\
|
||||
return iter; \
|
||||
} \
|
||||
\
|
||||
void PFX##_iter_free(SNAME##_iter *iter) \
|
||||
{ \
|
||||
free(iter); \
|
||||
} \
|
||||
\
|
||||
void PFX##_iter_init(SNAME##_iter *iter, SNAME *target) \
|
||||
{ \
|
||||
iter->target = target; \
|
||||
iter->cursor = target->front; \
|
||||
iter->index = 0; \
|
||||
iter->start = true; \
|
||||
iter->end = PFX##_empty(target); \
|
||||
} \
|
||||
\
|
||||
bool PFX##_iter_start(SNAME##_iter *iter) \
|
||||
{ \
|
||||
return PFX##_empty(iter->target) || iter->start; \
|
||||
} \
|
||||
\
|
||||
bool PFX##_iter_end(SNAME##_iter *iter) \
|
||||
{ \
|
||||
return PFX##_empty(iter->target) || iter->end; \
|
||||
} \
|
||||
\
|
||||
void PFX##_iter_to_start(SNAME##_iter *iter) \
|
||||
{ \
|
||||
iter->cursor = iter->target->front; \
|
||||
iter->index = 0; \
|
||||
iter->start = true; \
|
||||
iter->end = PFX##_empty(iter->target); \
|
||||
} \
|
||||
\
|
||||
void PFX##_iter_to_end(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (PFX##_empty(iter->target)) \
|
||||
iter->cursor = 0; \
|
||||
else \
|
||||
{ \
|
||||
if (iter->target->back == 0) \
|
||||
iter->cursor = iter->target->capacity - 1; \
|
||||
else \
|
||||
iter->cursor = iter->target->back - 1; \
|
||||
} \
|
||||
\
|
||||
iter->index = iter->target->count - 1; \
|
||||
iter->start = PFX##_empty(iter->target); \
|
||||
iter->end = true; \
|
||||
} \
|
||||
\
|
||||
bool PFX##_iter_next(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (iter->end) \
|
||||
return false; \
|
||||
\
|
||||
if (iter->index + 1 == PFX##_count(iter->target)) \
|
||||
{ \
|
||||
iter->end = true; \
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
iter->start = PFX##_empty(iter->target); \
|
||||
\
|
||||
iter->cursor = (iter->cursor + 1) % (iter->target->capacity); \
|
||||
iter->index++; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
bool PFX##_iter_prev(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (iter->start) \
|
||||
return false; \
|
||||
\
|
||||
if (iter->index == 0) \
|
||||
{ \
|
||||
iter->start = true; \
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
iter->end = PFX##_empty(iter->target); \
|
||||
\
|
||||
iter->cursor = (iter->cursor == 0) ? iter->target->capacity - 1 : iter->cursor - 1; \
|
||||
iter->index--; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
/* Returns true only if the iterator moved */ \
|
||||
bool PFX##_iter_advance(SNAME##_iter *iter, size_t steps) \
|
||||
{ \
|
||||
if (iter->end) \
|
||||
return false; \
|
||||
\
|
||||
if (iter->index + 1 == PFX##_count(iter->target)) \
|
||||
{ \
|
||||
iter->end = true; \
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
if (steps == 0 || iter->index + steps >= PFX##_count(iter->target)) \
|
||||
return false; \
|
||||
\
|
||||
iter->start = PFX##_empty(iter->target); \
|
||||
\
|
||||
iter->index += steps; \
|
||||
iter->cursor = (iter->cursor + steps) % iter->target->capacity; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
/* Returns true only if the iterator moved */ \
|
||||
bool PFX##_iter_rewind(SNAME##_iter *iter, size_t steps) \
|
||||
{ \
|
||||
if (iter->start) \
|
||||
return false; \
|
||||
\
|
||||
if (iter->index == 0) \
|
||||
{ \
|
||||
iter->start = true; \
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
if (steps == 0 || iter->index < steps) \
|
||||
return false; \
|
||||
\
|
||||
iter->end = PFX##_empty(iter->target); \
|
||||
\
|
||||
iter->index -= steps; \
|
||||
\
|
||||
/* Prevent underflow */ \
|
||||
if (iter->cursor < steps) \
|
||||
iter->cursor += PFX##_capacity(iter->target); \
|
||||
\
|
||||
iter->cursor -= steps; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
/* Returns true only if the iterator was able to be positioned at the given index */ \
|
||||
bool PFX##_iter_go_to(SNAME##_iter *iter, size_t index) \
|
||||
{ \
|
||||
if (index >= PFX##_count(iter->target)) \
|
||||
return false; \
|
||||
\
|
||||
if (iter->index > index) \
|
||||
return PFX##_iter_rewind(iter, iter->index - index); \
|
||||
else if (iter->index < index) \
|
||||
return PFX##_iter_advance(iter, index - iter->index); \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
V PFX##_iter_value(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (PFX##_empty(iter->target)) \
|
||||
return (V){0}; \
|
||||
\
|
||||
return iter->target->buffer[iter->cursor]; \
|
||||
} \
|
||||
\
|
||||
V *PFX##_iter_rvalue(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (PFX##_empty(iter->target)) \
|
||||
return NULL; \
|
||||
\
|
||||
return &(iter->target->buffer[iter->cursor]); \
|
||||
} \
|
||||
\
|
||||
size_t PFX##_iter_index(SNAME##_iter *iter) \
|
||||
{ \
|
||||
return iter->index; \
|
||||
} \
|
||||
\
|
||||
static SNAME##_iter PFX##_impl_it_start(SNAME *_queue_) \
|
||||
{ \
|
||||
SNAME##_iter iter; \
|
||||
\
|
||||
PFX##_iter_init(&iter, _queue_); \
|
||||
PFX##_iter_to_start(&iter); \
|
||||
\
|
||||
return iter; \
|
||||
} \
|
||||
\
|
||||
static SNAME##_iter PFX##_impl_it_end(SNAME *_queue_) \
|
||||
{ \
|
||||
SNAME##_iter iter; \
|
||||
\
|
||||
PFX##_iter_init(&iter, _queue_); \
|
||||
PFX##_iter_to_end(&iter); \
|
||||
\
|
||||
return iter; \
|
||||
}
|
||||
|
||||
#endif /* CMC_QUEUE_H */
|
||||
+217
-129
@@ -28,24 +28,28 @@
|
||||
#ifndef CMC_STACK_H
|
||||
#define CMC_STACK_H
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "../utl/cmc_string.h"
|
||||
|
||||
#define STACK_GENERATE(PFX, SNAME, FMOD, V) \
|
||||
STACK_GENERATE_HEADER(PFX, SNAME, FMOD, V) \
|
||||
STACK_GENERATE_SOURCE(PFX, SNAME, FMOD, V)
|
||||
/* to_string format */
|
||||
static const char *cmc_string_fmt_stack = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", count:%" PRIuMAX " }";
|
||||
|
||||
#define STACK_WRAPGEN_HEADER(PFX, SNAME, FMOD, K, V) \
|
||||
STACK_GENERATE_HEADER(PFX, SNAME, FMOD, V)
|
||||
#define CMC_GENERATE_STACK(PFX, SNAME, V) \
|
||||
CMC_GENERATE_STACK_HEADER(PFX, SNAME, V) \
|
||||
CMC_GENERATE_STACK_SOURCE(PFX, SNAME, V)
|
||||
|
||||
#define STACK_WRAPGEN_SOURCE(PFX, SNAME, FMOD, K, V) \
|
||||
STACK_GENERATE_SOURCE(PFX, SNAME, FMOD, V)
|
||||
#define CMC_WRAPGEN_STACK_HEADER(PFX, SNAME, K, V) \
|
||||
CMC_GENERATE_STACK_HEADER(PFX, SNAME, V)
|
||||
|
||||
#define CMC_WRAPGEN_STACK_SOURCE(PFX, SNAME, K, V) \
|
||||
CMC_GENERATE_STACK_SOURCE(PFX, SNAME, V)
|
||||
|
||||
/* HEADER ********************************************************************/
|
||||
#define STACK_GENERATE_HEADER(PFX, SNAME, FMOD, V) \
|
||||
#define CMC_GENERATE_STACK_HEADER(PFX, SNAME, V) \
|
||||
\
|
||||
/* Stack Structure */ \
|
||||
typedef struct SNAME##_s \
|
||||
@@ -86,64 +90,56 @@
|
||||
\
|
||||
/* Collection Functions */ \
|
||||
/* Collection Allocation and Deallocation */ \
|
||||
FMOD SNAME *PFX##_new(size_t capacity); \
|
||||
FMOD void PFX##_clear(SNAME *_stack_); \
|
||||
FMOD void PFX##_free(SNAME *_stack_); \
|
||||
SNAME *PFX##_new(size_t capacity); \
|
||||
void PFX##_clear(SNAME *_stack_, void (*deallocator)(V)); \
|
||||
void PFX##_free(SNAME *_stack_, void (*deallocator)(V)); \
|
||||
/* Collection Input and Output */ \
|
||||
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); \
|
||||
bool PFX##_push(SNAME *_stack_, V element); \
|
||||
bool PFX##_pop(SNAME *_stack_); \
|
||||
/* Element Access */ \
|
||||
FMOD V PFX##_top(SNAME *_stack_); \
|
||||
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_); \
|
||||
bool PFX##_contains(SNAME *_stack_, V element, int (*comparator)(V, V)); \
|
||||
bool PFX##_empty(SNAME *_stack_); \
|
||||
bool PFX##_full(SNAME *_stack_); \
|
||||
size_t PFX##_count(SNAME *_stack_); \
|
||||
size_t PFX##_capacity(SNAME *_stack_); \
|
||||
/* Collection Utility */ \
|
||||
FMOD cmc_string PFX##_to_string(SNAME *_stack_); \
|
||||
bool PFX##_resize(SNAME *_stack_, size_t capacity); \
|
||||
SNAME *PFX##_copy_of(SNAME *_stack_, V (*copy_func)(V)); \
|
||||
bool PFX##_equals(SNAME *_stack1_, SNAME *_stack2_, int (*comparator)(V, V)); \
|
||||
cmc_string PFX##_to_string(SNAME *_stack_); \
|
||||
\
|
||||
/* Iterator Functions */ \
|
||||
/* Iterator Allocation and Deallocation */ \
|
||||
FMOD SNAME##_iter *PFX##_iter_new(SNAME *target); \
|
||||
FMOD void PFX##_iter_free(SNAME##_iter *iter); \
|
||||
SNAME##_iter *PFX##_iter_new(SNAME *target); \
|
||||
void PFX##_iter_free(SNAME##_iter *iter); \
|
||||
/* Iterator Initialization */ \
|
||||
FMOD void PFX##_iter_init(SNAME##_iter *iter, SNAME *target); \
|
||||
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); \
|
||||
bool PFX##_iter_start(SNAME##_iter *iter); \
|
||||
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); \
|
||||
void PFX##_iter_to_start(SNAME##_iter *iter); \
|
||||
void PFX##_iter_to_end(SNAME##_iter *iter); \
|
||||
bool PFX##_iter_next(SNAME##_iter *iter); \
|
||||
bool PFX##_iter_prev(SNAME##_iter *iter); \
|
||||
bool PFX##_iter_advance(SNAME##_iter *iter, size_t steps); \
|
||||
bool PFX##_iter_rewind(SNAME##_iter *iter, size_t steps); \
|
||||
bool PFX##_iter_go_to(SNAME##_iter *iter, size_t index); \
|
||||
/* Iterator Access */ \
|
||||
FMOD V PFX##_iter_value(SNAME##_iter *iter); \
|
||||
FMOD V *PFX##_iter_rvalue(SNAME##_iter *iter); \
|
||||
FMOD size_t PFX##_iter_index(SNAME##_iter *iter); \
|
||||
\
|
||||
/* Default Value */ \
|
||||
static inline V PFX##_impl_default_value(void) \
|
||||
{ \
|
||||
V _empty_value_; \
|
||||
\
|
||||
memset(&_empty_value_, 0, sizeof(V)); \
|
||||
\
|
||||
return _empty_value_; \
|
||||
} \
|
||||
V PFX##_iter_value(SNAME##_iter *iter); \
|
||||
V *PFX##_iter_rvalue(SNAME##_iter *iter); \
|
||||
size_t PFX##_iter_index(SNAME##_iter *iter); \
|
||||
\
|
||||
/* SOURCE ********************************************************************/
|
||||
#define STACK_GENERATE_SOURCE(PFX, SNAME, FMOD, V) \
|
||||
#define CMC_GENERATE_STACK_SOURCE(PFX, SNAME, V) \
|
||||
\
|
||||
/* Implementation Detail Functions */ \
|
||||
static bool PFX##_impl_grow(SNAME *_stack_); \
|
||||
static SNAME##_iter PFX##_impl_it_start(SNAME *_stack_); \
|
||||
static SNAME##_iter PFX##_impl_it_end(SNAME *_stack_); \
|
||||
\
|
||||
FMOD SNAME *PFX##_new(size_t capacity) \
|
||||
SNAME *PFX##_new(size_t capacity) \
|
||||
{ \
|
||||
if (capacity < 1) \
|
||||
return NULL; \
|
||||
@@ -172,24 +168,36 @@
|
||||
return _stack_; \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_clear(SNAME *_stack_) \
|
||||
void PFX##_clear(SNAME *_stack_, void (*deallocator)(V)) \
|
||||
{ \
|
||||
if (deallocator) \
|
||||
{ \
|
||||
for (size_t i = 0; i < _stack_->count; i++) \
|
||||
deallocator(_stack_->buffer[i]); \
|
||||
} \
|
||||
\
|
||||
memset(_stack_->buffer, 0, sizeof(V) * _stack_->capacity); \
|
||||
\
|
||||
_stack_->count = 0; \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_free(SNAME *_stack_) \
|
||||
void PFX##_free(SNAME *_stack_, void (*deallocator)(V)) \
|
||||
{ \
|
||||
free(_stack_->buffer); \
|
||||
if (deallocator) \
|
||||
{ \
|
||||
for (size_t i = 0; i < _stack_->count; i++) \
|
||||
deallocator(_stack_->buffer[i]); \
|
||||
} \
|
||||
\
|
||||
free(_stack_); \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_push(SNAME *_stack_, V element) \
|
||||
bool PFX##_push(SNAME *_stack_, V element) \
|
||||
{ \
|
||||
if (PFX##_full(_stack_)) \
|
||||
{ \
|
||||
if (!PFX##_impl_grow(_stack_)) \
|
||||
if (!PFX##_resize(_stack_, PFX##_capacity(_stack_) * 2)) \
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
@@ -198,41 +206,25 @@
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_pop(SNAME *_stack_) \
|
||||
bool PFX##_pop(SNAME *_stack_) \
|
||||
{ \
|
||||
if (PFX##_empty(_stack_)) \
|
||||
return false; \
|
||||
\
|
||||
_stack_->buffer[--_stack_->count] = PFX##_impl_default_value(); \
|
||||
_stack_->buffer[--_stack_->count] = (V){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_) \
|
||||
V PFX##_top(SNAME *_stack_) \
|
||||
{ \
|
||||
if (PFX##_empty(_stack_)) \
|
||||
return PFX##_impl_default_value(); \
|
||||
return (V){0}; \
|
||||
\
|
||||
return _stack_->buffer[_stack_->count - 1]; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_contains(SNAME *_stack_, V element, int (*comparator)(V, V)) \
|
||||
bool PFX##_contains(SNAME *_stack_, V element, int (*comparator)(V, V)) \
|
||||
{ \
|
||||
for (size_t i = 0; i < _stack_->count; i++) \
|
||||
{ \
|
||||
@@ -243,27 +235,80 @@
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_empty(SNAME *_stack_) \
|
||||
bool PFX##_empty(SNAME *_stack_) \
|
||||
{ \
|
||||
return _stack_->count == 0; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_full(SNAME *_stack_) \
|
||||
bool PFX##_full(SNAME *_stack_) \
|
||||
{ \
|
||||
return _stack_->count >= _stack_->capacity; \
|
||||
} \
|
||||
\
|
||||
FMOD size_t PFX##_count(SNAME *_stack_) \
|
||||
size_t PFX##_count(SNAME *_stack_) \
|
||||
{ \
|
||||
return _stack_->count; \
|
||||
} \
|
||||
\
|
||||
FMOD size_t PFX##_capacity(SNAME *_stack_) \
|
||||
size_t PFX##_capacity(SNAME *_stack_) \
|
||||
{ \
|
||||
return _stack_->capacity; \
|
||||
} \
|
||||
\
|
||||
FMOD cmc_string PFX##_to_string(SNAME *_stack_) \
|
||||
bool PFX##_resize(SNAME *_stack_, size_t capacity) \
|
||||
{ \
|
||||
if (PFX##_capacity(_stack_) == capacity) \
|
||||
return true; \
|
||||
\
|
||||
if (capacity < PFX##_count(_stack_)) \
|
||||
return false; \
|
||||
\
|
||||
V *new_buffer = realloc(_stack_->buffer, sizeof(V) * capacity); \
|
||||
\
|
||||
if (!new_buffer) \
|
||||
return false; \
|
||||
\
|
||||
_stack_->buffer = new_buffer; \
|
||||
_stack_->capacity = capacity; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
SNAME *PFX##_copy_of(SNAME *_stack_, V (*copy_func)(V)) \
|
||||
{ \
|
||||
SNAME *result = PFX##_new(_stack_->capacity); \
|
||||
\
|
||||
if (!result) \
|
||||
return NULL; \
|
||||
\
|
||||
if (copy_func) \
|
||||
{ \
|
||||
for (size_t i = 0; i < _stack_->count; i++) \
|
||||
result->buffer[i] = copy_func(_stack_->buffer[i]); \
|
||||
} \
|
||||
else \
|
||||
memcpy(result->buffer, _stack_->buffer, sizeof(V) * _stack_->count); \
|
||||
\
|
||||
result->count = _stack_->count; \
|
||||
\
|
||||
return result; \
|
||||
} \
|
||||
\
|
||||
bool PFX##_equals(SNAME *_stack1_, SNAME *_stack2_, int (*comparator)(V, V)) \
|
||||
{ \
|
||||
if (PFX##_count(_stack1_) != PFX##_count(_stack2_)) \
|
||||
return false; \
|
||||
\
|
||||
for (size_t i = 0; i < PFX##_count(_stack1_); i++) \
|
||||
{ \
|
||||
if (comparator(_stack1_->buffer[i], _stack2_->buffer[i]) != 0) \
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
cmc_string PFX##_to_string(SNAME *_stack_) \
|
||||
{ \
|
||||
cmc_string str; \
|
||||
SNAME *s_ = _stack_; \
|
||||
@@ -275,7 +320,7 @@
|
||||
return str; \
|
||||
} \
|
||||
\
|
||||
FMOD SNAME##_iter *PFX##_iter_new(SNAME *target) \
|
||||
SNAME##_iter *PFX##_iter_new(SNAME *target) \
|
||||
{ \
|
||||
SNAME##_iter *iter = malloc(sizeof(SNAME##_iter)); \
|
||||
\
|
||||
@@ -287,95 +332,153 @@
|
||||
return iter; \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_iter_free(SNAME##_iter *iter) \
|
||||
void PFX##_iter_free(SNAME##_iter *iter) \
|
||||
{ \
|
||||
free(iter); \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_iter_init(SNAME##_iter *iter, SNAME *target) \
|
||||
void PFX##_iter_init(SNAME##_iter *iter, SNAME *target) \
|
||||
{ \
|
||||
iter->target = target; \
|
||||
\
|
||||
if (PFX##_empty(target)) \
|
||||
iter->cursor = 0; \
|
||||
else \
|
||||
iter->cursor = iter->target->count - 1; \
|
||||
\
|
||||
iter->cursor = PFX##_empty(target) ? 0 : iter->target->count - 1; \
|
||||
iter->start = true; \
|
||||
iter->end = PFX##_empty(target); \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_iter_start(SNAME##_iter *iter) \
|
||||
bool PFX##_iter_start(SNAME##_iter *iter) \
|
||||
{ \
|
||||
return PFX##_empty(iter->target) || iter->start; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_iter_end(SNAME##_iter *iter) \
|
||||
bool PFX##_iter_end(SNAME##_iter *iter) \
|
||||
{ \
|
||||
return PFX##_empty(iter->target) || iter->end; \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_iter_to_start(SNAME##_iter *iter) \
|
||||
void PFX##_iter_to_start(SNAME##_iter *iter) \
|
||||
{ \
|
||||
iter->cursor = iter->target->count - 1; \
|
||||
iter->start = true; \
|
||||
iter->end = PFX##_empty(iter->target); \
|
||||
if (!PFX##_empty(iter->target)) \
|
||||
{ \
|
||||
iter->cursor = iter->target->count - 1; \
|
||||
iter->start = true; \
|
||||
iter->end = PFX##_empty(iter->target); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_iter_to_end(SNAME##_iter *iter) \
|
||||
void PFX##_iter_to_end(SNAME##_iter *iter) \
|
||||
{ \
|
||||
iter->cursor = 0; \
|
||||
iter->start = PFX##_empty(iter->target); \
|
||||
iter->end = true; \
|
||||
if (!PFX##_empty(iter->target)) \
|
||||
{ \
|
||||
iter->cursor = 0; \
|
||||
iter->start = PFX##_empty(iter->target); \
|
||||
iter->end = true; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_iter_next(SNAME##_iter *iter) \
|
||||
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; \
|
||||
\
|
||||
return false; \
|
||||
} \
|
||||
else \
|
||||
iter->cursor--; \
|
||||
\
|
||||
iter->start = PFX##_empty(iter->target); \
|
||||
\
|
||||
iter->cursor--; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_iter_prev(SNAME##_iter *iter) \
|
||||
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) \
|
||||
if (iter->cursor + 1 == PFX##_count(iter->target)) \
|
||||
{ \
|
||||
iter->start = true; \
|
||||
\
|
||||
return false; \
|
||||
} \
|
||||
else \
|
||||
iter->cursor++; \
|
||||
\
|
||||
iter->end = PFX##_empty(iter->target); \
|
||||
\
|
||||
iter->cursor++; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD V PFX##_iter_value(SNAME##_iter *iter) \
|
||||
/* Returns true only if the iterator moved */ \
|
||||
bool PFX##_iter_advance(SNAME##_iter *iter, size_t steps) \
|
||||
{ \
|
||||
if (iter->end) \
|
||||
return false; \
|
||||
\
|
||||
if (iter->cursor == 0) \
|
||||
{ \
|
||||
iter->end = true; \
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
if (steps == 0 || iter->cursor < steps) \
|
||||
return false; \
|
||||
\
|
||||
iter->start = PFX##_empty(iter->target); \
|
||||
\
|
||||
iter->cursor -= steps; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
/* Returns true only if the iterator moved */ \
|
||||
bool PFX##_iter_rewind(SNAME##_iter *iter, size_t steps) \
|
||||
{ \
|
||||
if (iter->start) \
|
||||
return false; \
|
||||
\
|
||||
if (iter->cursor + 1 == PFX##_count(iter->target)) \
|
||||
{ \
|
||||
iter->start = true; \
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
if (steps == 0 || iter->cursor + steps >= PFX##_count(iter->target)) \
|
||||
return false; \
|
||||
\
|
||||
iter->end = PFX##_empty(iter->target); \
|
||||
\
|
||||
iter->cursor += steps; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
/* Returns true only if the iterator was able to be positioned at the */ \
|
||||
/* given index */ \
|
||||
bool PFX##_iter_go_to(SNAME##_iter *iter, size_t index) \
|
||||
{ \
|
||||
if (index >= PFX##_count(iter->target)) \
|
||||
return false; \
|
||||
\
|
||||
if (iter->cursor > index) \
|
||||
return PFX##_iter_rewind(iter, iter->cursor - index); \
|
||||
else if (iter->cursor < index) \
|
||||
return PFX##_iter_advance(iter, index - iter->cursor); \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
V PFX##_iter_value(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (PFX##_empty(iter->target)) \
|
||||
return PFX##_impl_default_value(); \
|
||||
return (V){0}; \
|
||||
\
|
||||
return iter->target->buffer[iter->cursor]; \
|
||||
} \
|
||||
\
|
||||
FMOD V *PFX##_iter_rvalue(SNAME##_iter *iter) \
|
||||
V *PFX##_iter_rvalue(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (PFX##_empty(iter->target)) \
|
||||
return NULL; \
|
||||
@@ -383,7 +486,7 @@
|
||||
return &(iter->target->buffer[iter->cursor]); \
|
||||
} \
|
||||
\
|
||||
FMOD size_t PFX##_iter_index(SNAME##_iter *iter) \
|
||||
size_t PFX##_iter_index(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (PFX##_empty(iter->target)) \
|
||||
return 0; \
|
||||
@@ -391,21 +494,6 @@
|
||||
return iter->target->count - 1 - iter->cursor; \
|
||||
} \
|
||||
\
|
||||
static 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; \
|
||||
} \
|
||||
\
|
||||
static SNAME##_iter PFX##_impl_it_start(SNAME *_stack_) \
|
||||
{ \
|
||||
SNAME##_iter iter; \
|
||||
|
||||
+985
-881
File diff suppressed because it is too large.
Load diff
+1038
-929
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,873 @@
|
||||
/**
|
||||
* bidimap.h
|
||||
*
|
||||
* Creation Date: 26/09/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CMC_BIDIMAP_H
|
||||
#define CMC_BIDIMAP_H
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "../utl/cmc_string.h"
|
||||
|
||||
/**
|
||||
* THIS IS A PREVIEW ONLY
|
||||
*
|
||||
* BidiMap
|
||||
*
|
||||
* A bidirectional map is a map that allows you to create a bijection in both
|
||||
* directions between two sets of elements (K <-> V).
|
||||
*
|
||||
* This implementation uses two arrays of pointers to an entry containing both
|
||||
* the key and the value.
|
||||
*/
|
||||
|
||||
/* to_string format */
|
||||
static const char *cmc_string_fmt_bidimap = "%s at %p { key_buffer:%p, val_buffer:%p, capacity:%" PRIuMAX ", count:%" PRIuMAX ", load:%lf, key_cmp:%p, val_cmp:%p, key_hash:%p, val_hash:%p }";
|
||||
|
||||
#ifndef CMC_ENTRY_DELETED
|
||||
|
||||
#define CMC_ENTRY_DELETED ((void *)1)
|
||||
|
||||
#endif /* CMC_ENTRY_DELETED */
|
||||
|
||||
#ifndef CMC_IMPL_HASHTABLE_SETUP
|
||||
#define CMC_IMPL_HASHTABLE_SETUP
|
||||
|
||||
static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531,
|
||||
3067, 6143, 12289, 24571, 49157,
|
||||
98299, 196613, 393209, 786431,
|
||||
1572869, 3145721, 6291449,
|
||||
12582917, 25165813, 50331653,
|
||||
100663291, 201326611, 402653189,
|
||||
805306357, 1610612741,
|
||||
3221225473, 6442450939,
|
||||
12884901893, 25769803799,
|
||||
51539607551, 103079215111,
|
||||
206158430209, 412316860441,
|
||||
824633720831, 1649267441651,
|
||||
3298534883309, 6597069766657,
|
||||
13194139533299, 26388279066623,
|
||||
52776558133303, 105553116266489,
|
||||
211106232532969, 422212465066001,
|
||||
844424930131963,
|
||||
1688849860263953,
|
||||
3377699720527861,
|
||||
6755399441055731,
|
||||
13510798882111483,
|
||||
27021597764222939,
|
||||
54043195528445957,
|
||||
108086391056891903,
|
||||
216172782113783773,
|
||||
432345564227567621,
|
||||
864691128455135207,
|
||||
1729382256910270481,
|
||||
3458764513820540933,
|
||||
6917529027641081903,
|
||||
13835058055282163729llu};
|
||||
|
||||
#endif /* CMC_IMPL_HASHTABLE_SETUP */
|
||||
|
||||
#define CMC_GENERATE_BIDIMAP(PFX, SNAME, K, V) \
|
||||
CMC_GENERATE_BIDIMAP_HEADER(PFX, SNAME, K, V) \
|
||||
CMC_GENERATE_BIDIMAP_SOURCE(PFX, SNAME, K, V)
|
||||
|
||||
#define CMC_WRAPGEN_BIDIMAP_HEADER(PFX, SNAME, K, V) \
|
||||
CMC_GENERATE_BIDIMAP_HEADER(PFX, SNAME, K, V)
|
||||
|
||||
#define CMC_WRAPGEN_BIDIMAP_SOURCE(PFX, SNAME, K, V) \
|
||||
CMC_GENERATE_BIDIMAP_SOURCE(PFX, SNAME, K, V)
|
||||
|
||||
/* HEADER ********************************************************************/
|
||||
#define CMC_GENERATE_BIDIMAP_HEADER(PFX, SNAME, K, V) \
|
||||
\
|
||||
/* BidiMap Structure */ \
|
||||
typedef struct SNAME##_s \
|
||||
{ \
|
||||
/* Array of Entries mapping K -> V */ \
|
||||
struct SNAME##_entry_s **key_buffer; \
|
||||
\
|
||||
/* Array of entries mapping V -> K */ \
|
||||
struct SNAME##_entry_s **val_buffer; \
|
||||
\
|
||||
/* Current arrays capacity */ \
|
||||
size_t capacity; \
|
||||
\
|
||||
/* Current amount of keys */ \
|
||||
size_t count; \
|
||||
\
|
||||
/* Load factor in range (0.0, 1.0) */ \
|
||||
double load; \
|
||||
\
|
||||
/* Key comparison function */ \
|
||||
int (*key_cmp)(K, K); \
|
||||
\
|
||||
/* Value comparison function */ \
|
||||
int (*val_cmp)(V, V); \
|
||||
\
|
||||
/* Key hash function */ \
|
||||
size_t (*key_hash)(K); \
|
||||
\
|
||||
/* Value hash function */ \
|
||||
size_t (*val_hash)(V); \
|
||||
\
|
||||
/* Function that returns an iterator to the start of the bidimap */ \
|
||||
struct SNAME##_iter_s (*it_start)(struct SNAME##_s *); \
|
||||
\
|
||||
/* Function that returns an iterator to the end of the bidimap */ \
|
||||
struct SNAME##_iter_s (*it_end)(struct SNAME##_s *); \
|
||||
\
|
||||
} SNAME, *SNAME##_ptr; \
|
||||
\
|
||||
/* BidiMap Entry */ \
|
||||
typedef struct SNAME##_entry_s \
|
||||
{ \
|
||||
/* Entry Key */ \
|
||||
K key; \
|
||||
\
|
||||
/* Entry Value */ \
|
||||
V value; \
|
||||
\
|
||||
/* The distance of this node to its original position, used by */ \
|
||||
/* robin-hood hashing relative to the key_buffer */ \
|
||||
size_t key_dist; \
|
||||
\
|
||||
/* The distance of this node to its original position, used by */ \
|
||||
/* robin-hood hashing relative to the value_buffer */ \
|
||||
size_t val_dist; \
|
||||
\
|
||||
} SNAME##_entry, *SNAME##_entry_ptr; \
|
||||
\
|
||||
/* BidiMap Iterator */ \
|
||||
typedef struct SNAME##_iter_s \
|
||||
{ \
|
||||
/* Target bidimap */ \
|
||||
struct SNAME##_s *target; \
|
||||
\
|
||||
/* Cursor's position (index) */ \
|
||||
size_t cursor; \
|
||||
\
|
||||
/* Keeps track of relative index to the iteration of elements */ \
|
||||
size_t index; \
|
||||
\
|
||||
/* The index of the first element */ \
|
||||
size_t first; \
|
||||
\
|
||||
/* The index of the last element */ \
|
||||
size_t last; \
|
||||
\
|
||||
/* If the iterator has reached the start of the iteration */ \
|
||||
bool start; \
|
||||
\
|
||||
/* If the iterator has reached the end of the iteration */ \
|
||||
bool end; \
|
||||
\
|
||||
} SNAME##_iter, *SNAME##_iter_ptr; \
|
||||
\
|
||||
/* Collection Functions */ \
|
||||
/* Collection Allocation and Deallocation */ \
|
||||
SNAME *PFX##_new(size_t capacity, double load, \
|
||||
int (*key_cmp)(K, K), size_t (*key_hash)(K), \
|
||||
int (*val_cmp)(V, V), size_t (*val_hash)(V)); \
|
||||
void PFX##_clear(SNAME *_map_, void (*deallocator)(K, V)); \
|
||||
void PFX##_free(SNAME *_map_, void (*deallocator)(K, V)); \
|
||||
/* Collection Input and Output */ \
|
||||
bool PFX##_insert(SNAME *_map_, K key, V value); \
|
||||
bool PFX##_update_key(SNAME *_map_, K key, K *old_key); \
|
||||
bool PFX##_update_val(SNAME *_map_, V val, V *old_val); \
|
||||
bool PFX##_remove_by_key(SNAME *_map_, K key, V *out_value); \
|
||||
bool PFX##_remove_by_val(SNAME *_map_, V value, K *out_key); \
|
||||
/* Element Access */ \
|
||||
K PFX##_get_key(SNAME *_map_, V val); \
|
||||
V PFX##_get_val(SNAME *_map_, K key); \
|
||||
/* Collection State */ \
|
||||
bool PFX##_contains_key(SNAME *_map_, K key); \
|
||||
bool PFX##_contains_val(SNAME *_map_, V val); \
|
||||
bool PFX##_empty(SNAME *_map_); \
|
||||
bool PFX##_full(SNAME *_map_); \
|
||||
size_t PFX##_count(SNAME *_map_); \
|
||||
size_t PFX##_capacity(SNAME *_map_); \
|
||||
double PFX##_load(SNAME *_map_); \
|
||||
/* Collection Utility */ \
|
||||
SNAME *PFX##_copy_of(SNAME *_map_, K (*key_copy_func)(K), V (*value_copy_func)(V)); \
|
||||
bool PFX##_equals(SNAME *_map1_, SNAME *_map2_); \
|
||||
cmc_string PFX##_to_string(SNAME *_map_); \
|
||||
\
|
||||
/* Iterator Functions */ \
|
||||
/* Iterator Allocation and Deallocation */ \
|
||||
SNAME##_iter *PFX##_iter_new(SNAME *target); \
|
||||
void PFX##_iter_free(SNAME##_iter *iter); \
|
||||
/* Iterator Initialization */ \
|
||||
void PFX##_iter_init(SNAME##_iter *iter, SNAME *target); \
|
||||
/* Iterator State */ \
|
||||
bool PFX##_iter_start(SNAME##_iter *iter); \
|
||||
bool PFX##_iter_end(SNAME##_iter *iter); \
|
||||
/* Iterator Movement */ \
|
||||
void PFX##_iter_to_start(SNAME##_iter *iter); \
|
||||
void PFX##_iter_to_end(SNAME##_iter *iter); \
|
||||
bool PFX##_iter_next(SNAME##_iter *iter); \
|
||||
bool PFX##_iter_prev(SNAME##_iter *iter); \
|
||||
bool PFX##_iter_advance(SNAME##_iter *iter, size_t steps); \
|
||||
bool PFX##_iter_rewind(SNAME##_iter *iter, size_t steps); \
|
||||
bool PFX##_iter_go_to(SNAME##_iter *iter, size_t index); \
|
||||
/* Iterator Access */ \
|
||||
K PFX##_iter_key(SNAME##_iter *iter); \
|
||||
V PFX##_iter_value(SNAME##_iter *iter); \
|
||||
size_t PFX##_iter_index(SNAME##_iter *iter); \
|
||||
\
|
||||
/* SOURCE ********************************************************************/
|
||||
#define CMC_GENERATE_BIDIMAP_SOURCE(PFX, SNAME, K, V) \
|
||||
\
|
||||
/* Implementation Detail Functions */ \
|
||||
static bool PFX##_impl_grow(SNAME *_map_); \
|
||||
static SNAME##_entry *PFX##_impl_new_entry(K key, V value); \
|
||||
static SNAME##_entry **PFX##_impl_get_entry_by_key(SNAME *_map_, K key); \
|
||||
static SNAME##_entry **PFX##_impl_get_entry_by_val(SNAME *_map_, V val); \
|
||||
static SNAME##_entry **PFX##_impl_add_entry_to_key(SNAME *_map_, SNAME##_entry *entry); \
|
||||
static SNAME##_entry **PFX##_impl_add_entry_to_val(SNAME *_map_, SNAME##_entry *entry); \
|
||||
static size_t PFX##_impl_calculate_size(size_t required); \
|
||||
static SNAME##_iter PFX##_impl_it_start(SNAME *_map_); \
|
||||
static SNAME##_iter PFX##_impl_it_end(SNAME *_map_); \
|
||||
\
|
||||
SNAME *PFX##_new(size_t capacity, double load, \
|
||||
int (*key_cmp)(K, K), size_t (*key_hash)(K), \
|
||||
int (*val_cmp)(V, V), size_t (*val_hash)(V)) \
|
||||
{ \
|
||||
if (capacity == 0 || load <= 0 || load >= 1) \
|
||||
return NULL; \
|
||||
\
|
||||
/* Prevent integer overflow */ \
|
||||
if (capacity >= UINTMAX_MAX * load) \
|
||||
return NULL; \
|
||||
\
|
||||
size_t real_capacity = PFX##_impl_calculate_size(capacity / load); \
|
||||
\
|
||||
SNAME *_map_ = malloc(sizeof(SNAME)); \
|
||||
\
|
||||
if (!_map_) \
|
||||
return NULL; \
|
||||
\
|
||||
_map_->key_buffer = calloc(real_capacity, sizeof(SNAME##_entry *)); \
|
||||
_map_->val_buffer = calloc(real_capacity, sizeof(SNAME##_entry *)); \
|
||||
\
|
||||
if (!_map_->key_buffer || !_map_->val_buffer) \
|
||||
{ \
|
||||
free(_map_->key_buffer); \
|
||||
free(_map_->val_buffer); \
|
||||
free(_map_); \
|
||||
return NULL; \
|
||||
} \
|
||||
\
|
||||
_map_->count = 0; \
|
||||
_map_->capacity = real_capacity; \
|
||||
_map_->load = load; \
|
||||
_map_->key_cmp = key_cmp; \
|
||||
_map_->val_cmp = val_cmp; \
|
||||
_map_->key_hash = key_hash; \
|
||||
_map_->val_hash = val_hash; \
|
||||
\
|
||||
_map_->it_start = PFX##_impl_it_start; \
|
||||
_map_->it_end = PFX##_impl_it_end; \
|
||||
\
|
||||
return _map_; \
|
||||
} \
|
||||
\
|
||||
void PFX##_clear(SNAME *_map_, void (*deallocator)(K, V)) \
|
||||
{ \
|
||||
for (size_t i = 0; i < _map_->capacity; i++) \
|
||||
{ \
|
||||
SNAME##_entry *entry = _map_->key_buffer[i]; \
|
||||
\
|
||||
if (entry != NULL && entry != CMC_ENTRY_DELETED) \
|
||||
{ \
|
||||
if (deallocator) \
|
||||
deallocator(entry->key, entry->value); \
|
||||
\
|
||||
free(entry); \
|
||||
} \
|
||||
\
|
||||
_map_->key_buffer[i] = NULL; \
|
||||
_map_->val_buffer[i] = NULL; \
|
||||
} \
|
||||
\
|
||||
_map_->count = 0; \
|
||||
} \
|
||||
\
|
||||
void PFX##_free(SNAME *_map_, void (*deallocator)(K, V)) \
|
||||
{ \
|
||||
PFX##_clear(_map_, deallocator); \
|
||||
\
|
||||
free(_map_->key_buffer); \
|
||||
free(_map_->val_buffer); \
|
||||
free(_map_); \
|
||||
} \
|
||||
\
|
||||
bool PFX##_insert(SNAME *_map_, K key, V value) \
|
||||
{ \
|
||||
if (PFX##_full(_map_)) \
|
||||
{ \
|
||||
if (!PFX##_impl_grow(_map_)) \
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
if (PFX##_impl_get_entry_by_key(_map_, key) != NULL || \
|
||||
PFX##_impl_get_entry_by_val(_map_, value) != NULL) \
|
||||
return false; \
|
||||
\
|
||||
SNAME##_entry *entry = PFX##_impl_new_entry(key, value); \
|
||||
\
|
||||
SNAME##_entry **key_entry = PFX##_impl_add_entry_to_key(_map_, entry); \
|
||||
SNAME##_entry **val_entry = PFX##_impl_add_entry_to_val(_map_, entry); \
|
||||
\
|
||||
if (!key_entry || !val_entry) \
|
||||
{ \
|
||||
if (key_entry) \
|
||||
*key_entry = CMC_ENTRY_DELETED; \
|
||||
if (val_entry) \
|
||||
*val_entry = CMC_ENTRY_DELETED; \
|
||||
\
|
||||
free(entry); \
|
||||
\
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
_map_->count++; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
bool PFX##_update_key(SNAME *_map_, K key, K *old_key) \
|
||||
{ \
|
||||
if (PFX##_empty(_map_)) \
|
||||
return false; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
bool PFX##_update_val(SNAME *_map_, V val, V *old_val) \
|
||||
{ \
|
||||
if (PFX##_empty(_map_)) \
|
||||
return false; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
bool PFX##_remove_by_key(SNAME *_map_, K key, V *out_value) \
|
||||
{ \
|
||||
if (PFX##_empty(_map_)) \
|
||||
return false; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
bool PFX##_remove_by_val(SNAME *_map_, V value, K *out_key) \
|
||||
{ \
|
||||
if (PFX##_empty(_map_)) \
|
||||
return false; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
K PFX##_get_key(SNAME *_map_, V val) \
|
||||
{ \
|
||||
SNAME##_entry **entry = PFX##_impl_get_entry_by_val(_map_, val); \
|
||||
\
|
||||
if (!entry) \
|
||||
return (V){0}; \
|
||||
\
|
||||
return (*entry)->key; \
|
||||
} \
|
||||
\
|
||||
V PFX##_get_val(SNAME *_map_, K key) \
|
||||
{ \
|
||||
SNAME##_entry **entry = PFX##_impl_get_entry_by_key(_map_, key); \
|
||||
\
|
||||
if (!entry) \
|
||||
return (V){0}; \
|
||||
\
|
||||
return (*entry)->value; \
|
||||
} \
|
||||
\
|
||||
bool PFX##_contains_key(SNAME *_map_, K key) \
|
||||
{ \
|
||||
return PFX##_impl_get_entry_by_key(_map_, key) != NULL; \
|
||||
} \
|
||||
\
|
||||
bool PFX##_contains_val(SNAME *_map_, V val) \
|
||||
{ \
|
||||
return PFX##_impl_get_entry_by_val(_map_, val) != NULL; \
|
||||
} \
|
||||
\
|
||||
bool PFX##_empty(SNAME *_map_) \
|
||||
{ \
|
||||
return _map_->count == 0; \
|
||||
} \
|
||||
\
|
||||
bool PFX##_full(SNAME *_map_) \
|
||||
{ \
|
||||
return (double)PFX##_capacity(_map_) * PFX##_load(_map_) <= (double)PFX##_count(_map_); \
|
||||
} \
|
||||
\
|
||||
size_t PFX##_count(SNAME *_map_) \
|
||||
{ \
|
||||
return _map_->count; \
|
||||
} \
|
||||
\
|
||||
size_t PFX##_capacity(SNAME *_map_) \
|
||||
{ \
|
||||
return _map_->capacity; \
|
||||
} \
|
||||
\
|
||||
double PFX##_load(SNAME *_map_) \
|
||||
{ \
|
||||
return _map_->load; \
|
||||
} \
|
||||
\
|
||||
SNAME *PFX##_copy_of(SNAME *_map_, K (*key_copy_func)(K), V (*value_copy_func)(V)) \
|
||||
{ \
|
||||
return NULL; \
|
||||
} \
|
||||
\
|
||||
bool PFX##_equals(SNAME *_map1_, SNAME *_map2_) \
|
||||
{ \
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
cmc_string PFX##_to_string(SNAME *_map_) \
|
||||
{ \
|
||||
cmc_string str; \
|
||||
SNAME *m_ = _map_; \
|
||||
const char *name = #SNAME; \
|
||||
\
|
||||
snprintf(str.s, cmc_string_len, cmc_string_fmt_bidimap, \
|
||||
name, m_, m_->key_buffer, m_->val_buffer, m_->capacity, m_->count, \
|
||||
m_->load, m_->key_cmp, m_->val_cmp, m_->key_hash, m_->val_hash); \
|
||||
\
|
||||
return str; \
|
||||
} \
|
||||
\
|
||||
SNAME##_iter *PFX##_iter_new(SNAME *target) \
|
||||
{ \
|
||||
SNAME##_iter *iter = malloc(sizeof(SNAME##_iter)); \
|
||||
\
|
||||
if (!iter) \
|
||||
return NULL; \
|
||||
\
|
||||
PFX##_iter_init(iter, target); \
|
||||
\
|
||||
return iter; \
|
||||
} \
|
||||
\
|
||||
void PFX##_iter_free(SNAME##_iter *iter) \
|
||||
{ \
|
||||
free(iter); \
|
||||
} \
|
||||
\
|
||||
void PFX##_iter_init(SNAME##_iter *iter, SNAME *target) \
|
||||
{ \
|
||||
memset(iter, 0, sizeof(SNAME##_iter)); \
|
||||
\
|
||||
iter->target = target; \
|
||||
iter->start = true; \
|
||||
iter->end = PFX##_empty(target); \
|
||||
\
|
||||
if (!PFX##_empty(target)) \
|
||||
{ \
|
||||
for (size_t i = 0; i < target->capacity; i++) \
|
||||
{ \
|
||||
SNAME##_entry *tmp = target->key_buffer[i]; \
|
||||
\
|
||||
if (tmp != NULL && tmp != CMC_ENTRY_DELETED) \
|
||||
{ \
|
||||
iter->first = i; \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
iter->cursor = iter->first; \
|
||||
\
|
||||
for (size_t i = target->capacity; i > 0; i--) \
|
||||
{ \
|
||||
SNAME##_entry *tmp = target->key_buffer[i - 1]; \
|
||||
\
|
||||
if (tmp != NULL && tmp != CMC_ENTRY_DELETED) \
|
||||
{ \
|
||||
iter->last = i - 1; \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
bool PFX##_iter_start(SNAME##_iter *iter) \
|
||||
{ \
|
||||
return PFX##_empty(iter->target) || iter->start; \
|
||||
} \
|
||||
\
|
||||
bool PFX##_iter_end(SNAME##_iter *iter) \
|
||||
{ \
|
||||
return PFX##_empty(iter->target) || iter->end; \
|
||||
} \
|
||||
\
|
||||
void PFX##_iter_to_start(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (!PFX##_empty(iter->target)) \
|
||||
{ \
|
||||
iter->cursor = iter->first; \
|
||||
iter->index = 0; \
|
||||
iter->start = true; \
|
||||
iter->end = false; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
void PFX##_iter_to_end(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (!PFX##_empty(iter->target)) \
|
||||
{ \
|
||||
iter->cursor = iter->last; \
|
||||
iter->index = PFX##_count(iter->target) - 1; \
|
||||
iter->start = false; \
|
||||
iter->end = true; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
bool PFX##_iter_next(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (iter->end) \
|
||||
return false; \
|
||||
\
|
||||
if (iter->index + 1 == PFX##_count(iter->target)) \
|
||||
{ \
|
||||
iter->end = true; \
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
iter->start = PFX##_empty(iter->target); \
|
||||
\
|
||||
SNAME##_entry *scan = iter->target->key_buffer[iter->cursor]; \
|
||||
\
|
||||
iter->index++; \
|
||||
\
|
||||
while (1) \
|
||||
{ \
|
||||
iter->cursor++; \
|
||||
scan = iter->target->key_buffer[iter->cursor]; \
|
||||
\
|
||||
if (scan != NULL && scan != CMC_ENTRY_DELETED) \
|
||||
break; \
|
||||
} \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
bool PFX##_iter_prev(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (iter->start) \
|
||||
return false; \
|
||||
\
|
||||
if (iter->index == 0) \
|
||||
{ \
|
||||
iter->start = true; \
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
iter->end = PFX##_empty(iter->target); \
|
||||
\
|
||||
SNAME##_entry *scan = iter->target->key_buffer[iter->cursor]; \
|
||||
\
|
||||
iter->index--; \
|
||||
\
|
||||
while (1) \
|
||||
{ \
|
||||
iter->cursor--; \
|
||||
scan = iter->target->key_buffer[iter->cursor]; \
|
||||
\
|
||||
if (scan != NULL && scan != CMC_ENTRY_DELETED) \
|
||||
break; \
|
||||
} \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
/* Returns true only if the iterator moved */ \
|
||||
bool PFX##_iter_advance(SNAME##_iter *iter, size_t steps) \
|
||||
{ \
|
||||
if (iter->end) \
|
||||
return false; \
|
||||
\
|
||||
if (iter->index + 1 == PFX##_count(iter->target)) \
|
||||
{ \
|
||||
iter->end = true; \
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
if (steps == 0 || iter->index + steps >= PFX##_count(iter->target)) \
|
||||
return false; \
|
||||
\
|
||||
for (size_t i = 0; i < steps; i++) \
|
||||
PFX##_iter_next(iter); \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
/* Returns true only if the iterator moved */ \
|
||||
bool PFX##_iter_rewind(SNAME##_iter *iter, size_t steps) \
|
||||
{ \
|
||||
if (iter->start) \
|
||||
return false; \
|
||||
\
|
||||
if (iter->index == 0) \
|
||||
{ \
|
||||
iter->start = true; \
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
if (steps == 0 || iter->index < steps) \
|
||||
return false; \
|
||||
\
|
||||
for (size_t i = 0; i < steps; i++) \
|
||||
PFX##_iter_prev(iter); \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
/* Returns true only if the iterator was able to be positioned at the given index */ \
|
||||
bool PFX##_iter_go_to(SNAME##_iter *iter, size_t index) \
|
||||
{ \
|
||||
if (index >= PFX##_count(iter->target)) \
|
||||
return false; \
|
||||
\
|
||||
if (iter->index > index) \
|
||||
return PFX##_iter_rewind(iter, iter->index - index); \
|
||||
else if (iter->index < index) \
|
||||
return PFX##_iter_advance(iter, index - iter->index); \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
K PFX##_iter_key(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (PFX##_empty(iter->target)) \
|
||||
return (K){0}; \
|
||||
\
|
||||
return iter->target->key_buffer[iter->cursor]->key; \
|
||||
} \
|
||||
\
|
||||
V PFX##_iter_value(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (PFX##_empty(iter->target)) \
|
||||
return (V){0}; \
|
||||
\
|
||||
return iter->target->key_buffer[iter->cursor]->value; \
|
||||
} \
|
||||
\
|
||||
size_t PFX##_iter_index(SNAME##_iter *iter) \
|
||||
{ \
|
||||
return iter->index; \
|
||||
} \
|
||||
\
|
||||
static bool PFX##_impl_grow(SNAME *_map_) \
|
||||
{ \
|
||||
/* TODO */ \
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
static SNAME##_entry *PFX##_impl_new_entry(K key, V value) \
|
||||
{ \
|
||||
SNAME##_entry *entry = malloc(sizeof(SNAME##_entry)); \
|
||||
\
|
||||
if (!entry) \
|
||||
return NULL; \
|
||||
\
|
||||
entry->key = key; \
|
||||
entry->value = value; \
|
||||
entry->key_dist = 0; \
|
||||
entry->val_dist = 0; \
|
||||
\
|
||||
return entry; \
|
||||
} \
|
||||
\
|
||||
static SNAME##_entry **PFX##_impl_get_entry_by_key(SNAME *_map_, K key) \
|
||||
{ \
|
||||
size_t hash = _map_->key_hash(key); \
|
||||
size_t pos = hash % _map_->capacity; \
|
||||
\
|
||||
SNAME##_entry *target = _map_->key_buffer[pos]; \
|
||||
\
|
||||
while (target != NULL) \
|
||||
{ \
|
||||
if (target != CMC_ENTRY_DELETED && _map_->key_cmp(target->key, key) == 0) \
|
||||
return &(_map_->key_buffer[pos % _map_->capacity]); \
|
||||
\
|
||||
pos++; \
|
||||
target = _map_->key_buffer[pos % _map_->capacity]; \
|
||||
} \
|
||||
\
|
||||
return NULL; \
|
||||
} \
|
||||
\
|
||||
static SNAME##_entry **PFX##_impl_get_entry_by_val(SNAME *_map_, V val) \
|
||||
{ \
|
||||
size_t hash = _map_->val_hash(val); \
|
||||
size_t pos = hash % _map_->capacity; \
|
||||
\
|
||||
SNAME##_entry *target = _map_->val_buffer[pos]; \
|
||||
\
|
||||
while (target != NULL) \
|
||||
{ \
|
||||
if (target != CMC_ENTRY_DELETED && _map_->val_cmp(target->value, val) == 0) \
|
||||
return &(_map_->val_buffer[pos % _map_->capacity]); \
|
||||
\
|
||||
pos++; \
|
||||
target = _map_->val_buffer[pos % _map_->capacity]; \
|
||||
} \
|
||||
\
|
||||
return NULL; \
|
||||
} \
|
||||
\
|
||||
static SNAME##_entry **PFX##_impl_add_entry_to_key(SNAME *_map_, SNAME##_entry *entry) \
|
||||
{ \
|
||||
SNAME##_entry **to_return = NULL; \
|
||||
\
|
||||
size_t hash = _map_->key_hash(entry->key); \
|
||||
size_t original_pos = hash % _map_->capacity; \
|
||||
size_t pos = original_pos; \
|
||||
\
|
||||
SNAME##_entry **scan = &(_map_->key_buffer[hash % _map_->capacity]); \
|
||||
\
|
||||
if (*scan == NULL) \
|
||||
{ \
|
||||
*scan = entry; \
|
||||
\
|
||||
return scan; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
while (true) \
|
||||
{ \
|
||||
pos++; \
|
||||
scan = &(_map_->key_buffer[pos % _map_->capacity]); \
|
||||
\
|
||||
if (*scan == NULL || *scan == CMC_ENTRY_DELETED) \
|
||||
{ \
|
||||
if (!to_return) \
|
||||
to_return = scan; \
|
||||
\
|
||||
*scan = entry; \
|
||||
entry->key_dist = pos - original_pos; \
|
||||
\
|
||||
return to_return; \
|
||||
} \
|
||||
else if ((*scan)->key_dist < pos - original_pos) \
|
||||
{ \
|
||||
if (!to_return) \
|
||||
to_return = scan; \
|
||||
\
|
||||
size_t tmp_dist = (*scan)->key_dist; \
|
||||
entry->key_dist = pos - original_pos; \
|
||||
original_pos = pos - tmp_dist; \
|
||||
\
|
||||
SNAME##_entry *_tmp_ = *scan; \
|
||||
*scan = entry; \
|
||||
entry = _tmp_; \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
return NULL; \
|
||||
} \
|
||||
\
|
||||
static SNAME##_entry **PFX##_impl_add_entry_to_val(SNAME *_map_, SNAME##_entry *entry) \
|
||||
{ \
|
||||
SNAME##_entry **to_return = NULL; \
|
||||
\
|
||||
size_t hash = _map_->val_hash(entry->value); \
|
||||
size_t original_pos = hash % _map_->capacity; \
|
||||
size_t pos = original_pos; \
|
||||
\
|
||||
SNAME##_entry **scan = &(_map_->val_buffer[hash % _map_->capacity]); \
|
||||
\
|
||||
if (*scan == NULL) \
|
||||
{ \
|
||||
*scan = entry; \
|
||||
\
|
||||
return scan; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
while (true) \
|
||||
{ \
|
||||
pos++; \
|
||||
scan = &(_map_->val_buffer[pos % _map_->capacity]); \
|
||||
\
|
||||
if (*scan == NULL || *scan == CMC_ENTRY_DELETED) \
|
||||
{ \
|
||||
if (!to_return) \
|
||||
to_return = scan; \
|
||||
\
|
||||
*scan = entry; \
|
||||
entry->val_dist = pos - original_pos; \
|
||||
\
|
||||
return to_return; \
|
||||
} \
|
||||
else if ((*scan)->val_dist < pos - original_pos) \
|
||||
{ \
|
||||
if (!to_return) \
|
||||
to_return = scan; \
|
||||
\
|
||||
size_t tmp_dist = (*scan)->val_dist; \
|
||||
entry->val_dist = pos - original_pos; \
|
||||
original_pos = pos - tmp_dist; \
|
||||
\
|
||||
SNAME##_entry *_tmp_ = *scan; \
|
||||
*scan = entry; \
|
||||
entry = _tmp_; \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
return NULL; \
|
||||
} \
|
||||
\
|
||||
static size_t PFX##_impl_calculate_size(size_t required) \
|
||||
{ \
|
||||
const size_t count = sizeof(cmc_hashtable_primes) / sizeof(cmc_hashtable_primes[0]); \
|
||||
\
|
||||
if (cmc_hashtable_primes[count - 1] < required) \
|
||||
return required; \
|
||||
\
|
||||
size_t i = 0; \
|
||||
while (cmc_hashtable_primes[i] < required) \
|
||||
i++; \
|
||||
\
|
||||
return cmc_hashtable_primes[i]; \
|
||||
} \
|
||||
\
|
||||
static SNAME##_iter PFX##_impl_it_start(SNAME *_map_) \
|
||||
{ \
|
||||
SNAME##_iter iter; \
|
||||
\
|
||||
PFX##_iter_init(&iter, _map_); \
|
||||
\
|
||||
return iter; \
|
||||
} \
|
||||
\
|
||||
static SNAME##_iter PFX##_impl_it_end(SNAME *_map_) \
|
||||
{ \
|
||||
SNAME##_iter iter; \
|
||||
\
|
||||
PFX##_iter_init(&iter, _map_); \
|
||||
PFX##_iter_to_end(&iter); \
|
||||
\
|
||||
return iter; \
|
||||
}
|
||||
|
||||
#endif /* CMC_BIDIMAP_H */
|
||||
+915
-804
File diff suppressed because it is too large.
Load diff
@@ -1,384 +0,0 @@
|
||||
/**
|
||||
* linkedqueue.h
|
||||
*
|
||||
* Creation Date: 21/06/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* A node-based Queue using a Singly Linked List
|
||||
*
|
||||
* enqueue : is equivalent to a push_back from a LinkedList
|
||||
* dequeue : is equivalent to a pop_front from a LinkedList
|
||||
*
|
||||
* This Queue has a one-way iterator
|
||||
*/
|
||||
|
||||
#ifndef CMC_LINKEDQUEUE_H
|
||||
#define CMC_LINKEDQUEUE_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#define LINKEDQUEUE_GENERATE(PFX, SNAME, FMOD, V) \
|
||||
LINKEDQUEUE_GENERATE_HEADER(PFX, SNAME, FMOD, V) \
|
||||
LINKEDQUEUE_GENERATE_SOURCE(PFX, SNAME, FMOD, V)
|
||||
|
||||
#define LINKEDQUEUE_WRAPGEN_HEADER(PFX, SNAME, FMOD, K, V) \
|
||||
LINKEDQUEUE_GENERATE_HEADER(PFX, SNAME, FMOD, V)
|
||||
|
||||
#define LINKEDQUEUE_WRAPGEN_SOURCE(PFX, SNAME, FMOD, K, V) \
|
||||
LINKEDQUEUE_GENERATE_SOURCE(PFX, SNAME, FMOD, V)
|
||||
|
||||
/* HEADER ********************************************************************/
|
||||
#define LINKEDQUEUE_GENERATE_HEADER(PFX, SNAME, FMOD, V) \
|
||||
\
|
||||
/* Linked Queue 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 *); \
|
||||
\
|
||||
} SNAME, *SNAME##_ptr; \
|
||||
\
|
||||
/* Singly-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; \
|
||||
\
|
||||
} SNAME##_node, *SNAME##_node_ptr; \
|
||||
\
|
||||
/* Linked Queue Iterator */ \
|
||||
typedef struct SNAME##_iter_s \
|
||||
{ \
|
||||
/* Target Linked Queue */ \
|
||||
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 is at 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 *_lqueue_); \
|
||||
FMOD void PFX##_free(SNAME *_lqueue_); \
|
||||
/* Collection Input and Output */ \
|
||||
FMOD bool PFX##_enqueue(SNAME *_lqueue_, V element); \
|
||||
FMOD bool PFX##_dequeue(SNAME *_lqueue_); \
|
||||
/* Conditional Input and Output */ \
|
||||
FMOD bool PFX##_enqueue_if(SNAME *_lqueue_, V element, bool condition); \
|
||||
FMOD bool PFX##_dequeue_if(SNAME *_lqueue_, bool condition); \
|
||||
/* Element Access */ \
|
||||
FMOD V PFX##_peek(SNAME *_lqueue_); \
|
||||
/* Collection State */ \
|
||||
FMOD bool PFX##_contains(SNAME *_lqueue_, V element, int (*comparator)(V, V)); \
|
||||
FMOD bool PFX##_empty(SNAME *_lqueue_); \
|
||||
FMOD size_t PFX##_count(SNAME *_lqueue_); \
|
||||
\
|
||||
/* 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); \
|
||||
/* Iterator Access */ \
|
||||
FMOD V PFX##_iter_value(SNAME##_iter *iter); \
|
||||
FMOD V *PFX##_iter_rvalue(SNAME##_iter *iter); \
|
||||
FMOD size_t PFX##_iter_index(SNAME##_iter *iter); \
|
||||
\
|
||||
/* Default Value */ \
|
||||
static inline V PFX##_impl_default_value(void) \
|
||||
{ \
|
||||
V _empty_value_; \
|
||||
\
|
||||
memset(&_empty_value_, 0, sizeof(V)); \
|
||||
\
|
||||
return _empty_value_; \
|
||||
} \
|
||||
\
|
||||
/* SOURCE ********************************************************************/
|
||||
#define LINKEDQUEUE_GENERATE_SOURCE(PFX, SNAME, FMOD, V) \
|
||||
\
|
||||
/* Implementation Detail Functions */ \
|
||||
FMOD SNAME##_node *PFX##_impl_new_node(V element); \
|
||||
static SNAME##_iter PFX##_impl_it_start(SNAME *_lqueue_); \
|
||||
\
|
||||
FMOD SNAME *PFX##_new(void) \
|
||||
{ \
|
||||
SNAME *_lqueue_ = malloc(sizeof(SNAME)); \
|
||||
\
|
||||
if (!_lqueue_) \
|
||||
return NULL; \
|
||||
\
|
||||
_lqueue_->count = 0; \
|
||||
_lqueue_->head = NULL; \
|
||||
_lqueue_->tail = NULL; \
|
||||
\
|
||||
_lqueue_->it_start = PFX##_impl_it_start; \
|
||||
\
|
||||
return _lqueue_; \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_clear(SNAME *_lqueue_) \
|
||||
{ \
|
||||
SNAME##_node *scan = _lqueue_->head; \
|
||||
\
|
||||
while (_lqueue_->head != NULL) \
|
||||
{ \
|
||||
_lqueue_->head = _lqueue_->head->next; \
|
||||
free(scan); \
|
||||
scan = _lqueue_->head; \
|
||||
} \
|
||||
\
|
||||
_lqueue_->count = 0; \
|
||||
_lqueue_->head = NULL; \
|
||||
_lqueue_->tail = NULL; \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_free(SNAME *_lqueue_) \
|
||||
{ \
|
||||
PFX##_clear(_lqueue_); \
|
||||
\
|
||||
free(_lqueue_); \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_enqueue(SNAME *_lqueue_, V element) \
|
||||
{ \
|
||||
SNAME##_node *_node_ = PFX##_impl_new_node(element); \
|
||||
\
|
||||
if (!_node_) \
|
||||
return false; \
|
||||
\
|
||||
if (PFX##_empty(_lqueue_)) \
|
||||
{ \
|
||||
_lqueue_->head = _node_; \
|
||||
_lqueue_->tail = _node_; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
_lqueue_->tail->next = _node_; \
|
||||
_lqueue_->tail = _node_; \
|
||||
} \
|
||||
\
|
||||
_lqueue_->count++; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_dequeue(SNAME *_lqueue_) \
|
||||
{ \
|
||||
if (PFX##_empty(_lqueue_)) \
|
||||
return false; \
|
||||
\
|
||||
SNAME##_node *_node_ = _lqueue_->head; \
|
||||
_lqueue_->head = _lqueue_->head->next; \
|
||||
\
|
||||
free(_node_); \
|
||||
\
|
||||
if (_lqueue_->head == NULL) \
|
||||
_lqueue_->tail = NULL; \
|
||||
\
|
||||
_lqueue_->count--; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_enqueue_if(SNAME *_lqueue_, V element, bool condition) \
|
||||
{ \
|
||||
if (condition) \
|
||||
return PFX##_enqueue(_lqueue_, element); \
|
||||
\
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_dequeue_if(SNAME *_lqueue_, bool condition) \
|
||||
{ \
|
||||
if (condition) \
|
||||
return PFX##_dequeue(_lqueue_); \
|
||||
\
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
FMOD V PFX##_peek(SNAME *_lqueue_) \
|
||||
{ \
|
||||
if (PFX##_empty(_lqueue_)) \
|
||||
return PFX##_impl_default_value(); \
|
||||
\
|
||||
return _lqueue_->head->data; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_contains(SNAME *_lqueue_, V element, int (*comparator)(V, V)) \
|
||||
{ \
|
||||
SNAME##_node *scan = _lqueue_->head; \
|
||||
\
|
||||
while (scan != NULL) \
|
||||
{ \
|
||||
if (comparator(scan->data, element) == 0) \
|
||||
return true; \
|
||||
\
|
||||
scan = scan->next; \
|
||||
} \
|
||||
\
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
FMOD bool PFX##_empty(SNAME *_lqueue_) \
|
||||
{ \
|
||||
return _lqueue_->count == 0; \
|
||||
} \
|
||||
\
|
||||
FMOD size_t PFX##_count(SNAME *_lqueue_) \
|
||||
{ \
|
||||
return _lqueue_->count; \
|
||||
} \
|
||||
\
|
||||
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; \
|
||||
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->head; \
|
||||
iter->index = 0; \
|
||||
iter->start = true; \
|
||||
iter->end = PFX##_empty(iter->target); \
|
||||
} \
|
||||
\
|
||||
FMOD void PFX##_iter_to_end(SNAME##_iter *iter) \
|
||||
{ \
|
||||
iter->cursor = iter->target->tail; \
|
||||
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->cursor->next == NULL) \
|
||||
iter->end = true; \
|
||||
else \
|
||||
{ \
|
||||
iter->cursor = iter->cursor->next; \
|
||||
iter->index++; \
|
||||
} \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
FMOD V PFX##_iter_value(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (PFX##_empty(iter->target)) \
|
||||
return PFX##_impl_default_value(); \
|
||||
\
|
||||
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##_impl_new_node(V element) \
|
||||
{ \
|
||||
SNAME##_node *_node_ = malloc(sizeof(SNAME##_node)); \
|
||||
\
|
||||
if (!_node_) \
|
||||
return NULL; \
|
||||
\
|
||||
_node_->data = element; \
|
||||
_node_->next = NULL; \
|
||||
\
|
||||
return _node_; \
|
||||
} \
|
||||
\
|
||||
static SNAME##_iter PFX##_impl_it_start(SNAME *_lqueue_) \
|
||||
{ \
|
||||
SNAME##_iter iter; \
|
||||
\
|
||||
PFX##_iter_init(&iter, _lqueue_); \
|
||||
PFX##_iter_to_start(&iter); \
|
||||
\
|
||||
return iter; \
|
||||
}
|
||||
|
||||
#endif /* CMC_LINKEDQUEUE_H */
|
||||
+1032
-829
File diff suppressed because it is too large.
Load diff
+1154
-983
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,690 @@
|
||||
/**
|
||||
* sortedlist.h
|
||||
*
|
||||
* Creation Date: 17/09/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* THIS IS ONLY A PREVIEW
|
||||
*
|
||||
* SortedList
|
||||
*
|
||||
* A sorted list is a dynamic array, meaning that you can store as many elements
|
||||
* as you like and when its capacity is full, the buffer is reallocated. The
|
||||
* elements are only sorted when a certain action requires that the array is
|
||||
* sorted like accessing min() or max(). This prevents the array from being
|
||||
* sorted after every insertion or removal of elements.
|
||||
*/
|
||||
|
||||
#ifndef CMC_SORTEDLIST_H
|
||||
#define CMC_SORTEDLIST_H
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "../utl/cmc_string.h"
|
||||
|
||||
/* to_string format */
|
||||
static const char *cmc_string_fmt_sortedlist = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", count:%" PRIuMAX ", is_sorted:%s, cmp:%p }";
|
||||
|
||||
#define CMC_GENERATE_SORTEDLIST(PFX, SNAME, V) \
|
||||
CMC_GENERATE_SORTEDLIST_HEADER(PFX, SNAME, V) \
|
||||
CMC_GENERATE_SORTEDLIST_SOURCE(PFX, SNAME, V)
|
||||
|
||||
#define CMC_WRAPGEN_SORTEDLIST_HEADER(PFX, SNAME, K, V) \
|
||||
CMC_GENERATE_SORTEDLIST_HEADER(PFX, SNAME, V)
|
||||
|
||||
#define CMC_WRAPGEN_SORTEDLIST_SOURCE(PFX, SNAME, K, V) \
|
||||
CMC_GENERATE_SORTEDLIST_SOURCE(PFX, SNAME, V)
|
||||
|
||||
/* HEADER ********************************************************************/
|
||||
#define CMC_GENERATE_SORTEDLIST_HEADER(PFX, SNAME, V) \
|
||||
\
|
||||
/* List Structure */ \
|
||||
typedef struct SNAME##_s \
|
||||
{ \
|
||||
/* Dynamic array of elements */ \
|
||||
V *buffer; \
|
||||
\
|
||||
/* Current array capacity */ \
|
||||
size_t capacity; \
|
||||
\
|
||||
/* Current amount of elements */ \
|
||||
size_t count; \
|
||||
\
|
||||
/* Flag if the list is sorted or not, used by lazy evaluation */ \
|
||||
bool is_sorted; \
|
||||
\
|
||||
/* Element comparison function */ \
|
||||
int (*cmp)(V, V); \
|
||||
\
|
||||
/* Function that returns an iterator to the start of the list */ \
|
||||
struct SNAME##_iter_s (*it_start)(struct SNAME##_s *); \
|
||||
\
|
||||
/* Function that returns an iterator to the end of the list */ \
|
||||
struct SNAME##_iter_s (*it_end)(struct SNAME##_s *); \
|
||||
\
|
||||
} SNAME, *SNAME##_ptr; \
|
||||
\
|
||||
/* List Iterator */ \
|
||||
typedef struct SNAME##_iter_s \
|
||||
{ \
|
||||
/* Target list */ \
|
||||
struct SNAME##_s *target; \
|
||||
\
|
||||
/* Cursor's position (index) */ \
|
||||
size_t cursor; \
|
||||
\
|
||||
/* If the iterator has reached the start of the iteration */ \
|
||||
bool start; \
|
||||
\
|
||||
/* If the iterator has reached the end of the iteration */ \
|
||||
bool end; \
|
||||
\
|
||||
} SNAME##_iter, *SNAME##_iter_ptr; \
|
||||
\
|
||||
/* Collection Functions */ \
|
||||
/* Collection Allocation and Deallocation */ \
|
||||
SNAME *PFX##_new(size_t capacity, int (*compare)(V, V)); \
|
||||
void PFX##_clear(SNAME *_list_, void (*deallocator)(V)); \
|
||||
void PFX##_free(SNAME *_list_, void (*deallocator)(V)); \
|
||||
/* Collection Input and Output */ \
|
||||
bool PFX##_insert(SNAME *_list_, V element); \
|
||||
bool PFX##_remove(SNAME *_list_, size_t index); \
|
||||
/* Element Access */ \
|
||||
bool PFX##_max(SNAME *_list_, V *result); \
|
||||
bool PFX##_min(SNAME *_list_, V *result); \
|
||||
V PFX##_get(SNAME *_list_, size_t index); \
|
||||
size_t PFX##_indexof(SNAME *_list_, V element, bool from_start); \
|
||||
/* Collection State */ \
|
||||
bool PFX##_contains(SNAME *_list_, V element); \
|
||||
bool PFX##_empty(SNAME *_list_); \
|
||||
bool PFX##_full(SNAME *_list_); \
|
||||
size_t PFX##_count(SNAME *_list_); \
|
||||
size_t PFX##_capacity(SNAME *_list_); \
|
||||
/* Collection Utility */ \
|
||||
bool PFX##_resize(SNAME *_list_, size_t capacity); \
|
||||
void PFX##_sort(SNAME *_list_); \
|
||||
SNAME *PFX##_copy_of(SNAME *_list_, V (*copy_func)(V)); \
|
||||
bool PFX##_equals(SNAME *_list1_, SNAME *_list2_); \
|
||||
cmc_string PFX##_to_string(SNAME *_list_); \
|
||||
\
|
||||
/* Iterator Functions */ \
|
||||
/* Iterator Allocation and Deallocation */ \
|
||||
SNAME##_iter *PFX##_iter_new(SNAME *target); \
|
||||
void PFX##_iter_free(SNAME##_iter *iter); \
|
||||
/* Iterator Initialization */ \
|
||||
void PFX##_iter_init(SNAME##_iter *iter, SNAME *target); \
|
||||
/* Iterator State */ \
|
||||
bool PFX##_iter_start(SNAME##_iter *iter); \
|
||||
bool PFX##_iter_end(SNAME##_iter *iter); \
|
||||
/* Iterator Movement */ \
|
||||
void PFX##_iter_to_start(SNAME##_iter *iter); \
|
||||
void PFX##_iter_to_end(SNAME##_iter *iter); \
|
||||
bool PFX##_iter_next(SNAME##_iter *iter); \
|
||||
bool PFX##_iter_prev(SNAME##_iter *iter); \
|
||||
bool PFX##_iter_advance(SNAME##_iter *iter, size_t steps); \
|
||||
bool PFX##_iter_rewind(SNAME##_iter *iter, size_t steps); \
|
||||
bool PFX##_iter_go_to(SNAME##_iter *iter, size_t index); \
|
||||
/* Iterator Access */ \
|
||||
V PFX##_iter_value(SNAME##_iter *iter); \
|
||||
size_t PFX##_iter_index(SNAME##_iter *iter); \
|
||||
\
|
||||
/* SOURCE ********************************************************************/
|
||||
#define CMC_GENERATE_SORTEDLIST_SOURCE(PFX, SNAME, V) \
|
||||
\
|
||||
/* Implementation Detail Functions */ \
|
||||
static size_t PFX##_impl_binary_search_first(SNAME *_list_, V value); \
|
||||
static size_t PFX##_impl_binary_search_last(SNAME *_list_, V value); \
|
||||
void PFX##_impl_sort_quicksort(V *array, int (*cmp)(V, V), size_t low, size_t high); \
|
||||
void PFX##_impl_sort_insertion(V *array, int (*cmp)(V, V), size_t low, size_t high); \
|
||||
static SNAME##_iter PFX##_impl_it_start(SNAME *_list_); \
|
||||
static SNAME##_iter PFX##_impl_it_end(SNAME *_list_); \
|
||||
\
|
||||
SNAME *PFX##_new(size_t capacity, int (*compare)(V, V)) \
|
||||
{ \
|
||||
if (capacity < 1) \
|
||||
return NULL; \
|
||||
\
|
||||
SNAME *_list_ = malloc(sizeof(SNAME)); \
|
||||
\
|
||||
if (!_list_) \
|
||||
return NULL; \
|
||||
\
|
||||
_list_->buffer = calloc(capacity, sizeof(V)); \
|
||||
\
|
||||
if (!_list_->buffer) \
|
||||
{ \
|
||||
free(_list_); \
|
||||
return NULL; \
|
||||
} \
|
||||
\
|
||||
_list_->capacity = capacity; \
|
||||
_list_->count = 0; \
|
||||
_list_->cmp = compare; \
|
||||
_list_->is_sorted = false; \
|
||||
\
|
||||
_list_->it_start = PFX##_impl_it_start; \
|
||||
_list_->it_end = PFX##_impl_it_end; \
|
||||
\
|
||||
return _list_; \
|
||||
} \
|
||||
\
|
||||
void PFX##_clear(SNAME *_list_, void (*deallocator)(V)) \
|
||||
{ \
|
||||
if (deallocator) \
|
||||
{ \
|
||||
for (size_t i = 0; i < _list_->count; i++) \
|
||||
deallocator(_list_->buffer[i]); \
|
||||
} \
|
||||
\
|
||||
memset(_list_->buffer, 0, sizeof(V) * _list_->capacity); \
|
||||
\
|
||||
_list_->count = 0; \
|
||||
} \
|
||||
\
|
||||
void PFX##_free(SNAME *_list_, void (*deallocator)(V)) \
|
||||
{ \
|
||||
if (deallocator) \
|
||||
{ \
|
||||
for (size_t i = 0; i < _list_->count; i++) \
|
||||
deallocator(_list_->buffer[i]); \
|
||||
} \
|
||||
\
|
||||
free(_list_->buffer); \
|
||||
free(_list_); \
|
||||
} \
|
||||
\
|
||||
bool PFX##_insert(SNAME *_list_, V element) \
|
||||
{ \
|
||||
if (PFX##_full(_list_)) \
|
||||
{ \
|
||||
if (!PFX##_resize(_list_, PFX##_capacity(_list_) * 2)) \
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
_list_->buffer[_list_->count++] = element; \
|
||||
\
|
||||
_list_->is_sorted = false; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
bool PFX##_remove(SNAME *_list_, size_t index) \
|
||||
{ \
|
||||
if (index >= _list_->count) \
|
||||
return false; \
|
||||
\
|
||||
memmove(_list_->buffer + index, _list_->buffer + index + 1, \
|
||||
(_list_->count - index) * sizeof(V)); \
|
||||
\
|
||||
_list_->buffer[--_list_->count] = (V){0}; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
bool PFX##_min(SNAME *_list_, V *result) \
|
||||
{ \
|
||||
if (PFX##_empty(_list_)) \
|
||||
return false; \
|
||||
\
|
||||
PFX##_sort(_list_); \
|
||||
\
|
||||
*result = _list_->buffer[0]; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
bool PFX##_max(SNAME *_list_, V *result) \
|
||||
{ \
|
||||
if (PFX##_empty(_list_)) \
|
||||
return false; \
|
||||
\
|
||||
PFX##_sort(_list_); \
|
||||
\
|
||||
*result = _list_->buffer[_list_->count - 1]; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
V PFX##_get(SNAME *_list_, size_t index) \
|
||||
{ \
|
||||
if (index >= _list_->count) \
|
||||
return (V){0}; \
|
||||
\
|
||||
PFX##_sort(_list_); \
|
||||
\
|
||||
return _list_->buffer[index]; \
|
||||
} \
|
||||
\
|
||||
size_t PFX##_indexof(SNAME *_list_, V element, bool from_start) \
|
||||
{ \
|
||||
PFX##_sort(_list_); \
|
||||
\
|
||||
if (from_start) \
|
||||
{ \
|
||||
return PFX##_impl_binary_search_first(_list_, element); \
|
||||
} \
|
||||
\
|
||||
return PFX##_impl_binary_search_last(_list_, element); \
|
||||
} \
|
||||
\
|
||||
bool PFX##_contains(SNAME *_list_, V element) \
|
||||
{ \
|
||||
if (PFX##_empty(_list_)) \
|
||||
return false; \
|
||||
\
|
||||
PFX##_sort(_list_); \
|
||||
\
|
||||
return PFX##_impl_binary_search_first(_list_, element) < PFX##_count(_list_); \
|
||||
} \
|
||||
\
|
||||
bool PFX##_empty(SNAME *_list_) \
|
||||
{ \
|
||||
return _list_->count == 0; \
|
||||
} \
|
||||
\
|
||||
bool PFX##_full(SNAME *_list_) \
|
||||
{ \
|
||||
return _list_->count >= _list_->capacity; \
|
||||
} \
|
||||
\
|
||||
size_t PFX##_count(SNAME *_list_) \
|
||||
{ \
|
||||
return _list_->count; \
|
||||
} \
|
||||
\
|
||||
size_t PFX##_capacity(SNAME *_list_) \
|
||||
{ \
|
||||
return _list_->capacity; \
|
||||
} \
|
||||
\
|
||||
bool PFX##_resize(SNAME *_list_, size_t capacity) \
|
||||
{ \
|
||||
if (PFX##_capacity(_list_) == capacity) \
|
||||
return true; \
|
||||
\
|
||||
if (capacity < PFX##_count(_list_)) \
|
||||
return false; \
|
||||
\
|
||||
V *new_buffer = realloc(_list_->buffer, sizeof(V) * capacity); \
|
||||
\
|
||||
if (!new_buffer) \
|
||||
return false; \
|
||||
\
|
||||
_list_->buffer = new_buffer; \
|
||||
_list_->capacity = capacity; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
void PFX##_sort(SNAME *_list_) \
|
||||
{ \
|
||||
if (!_list_->is_sorted && _list_->count > 1) \
|
||||
{ \
|
||||
PFX##_impl_sort_quicksort(_list_->buffer, _list_->cmp, 0, _list_->count - 1); \
|
||||
\
|
||||
_list_->is_sorted = true; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
SNAME *PFX##_copy_of(SNAME *_list_, V (*copy_func)(V)) \
|
||||
{ \
|
||||
SNAME *result = PFX##_new(_list_->capacity, _list_->cmp); \
|
||||
\
|
||||
if (!result) \
|
||||
return NULL; \
|
||||
\
|
||||
if (copy_func) \
|
||||
{ \
|
||||
for (size_t i = 0; i < _list_->count; i++) \
|
||||
result->buffer[i] = copy_func(_list_->buffer[i]); \
|
||||
} \
|
||||
else \
|
||||
memcpy(result->buffer, _list_->buffer, sizeof(V) * _list_->count); \
|
||||
\
|
||||
result->count = _list_->count; \
|
||||
\
|
||||
return result; \
|
||||
} \
|
||||
\
|
||||
bool PFX##_equals(SNAME *_list1_, SNAME *_list2_) \
|
||||
{ \
|
||||
if (PFX##_count(_list1_) != PFX##_count(_list2_)) \
|
||||
return false; \
|
||||
\
|
||||
for (size_t i = 0; i < PFX##_count(_list1_); i++) \
|
||||
{ \
|
||||
if (_list1_->cmp(_list1_->buffer[i], _list2_->buffer[i]) != 0) \
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
cmc_string PFX##_to_string(SNAME *_list_) \
|
||||
{ \
|
||||
cmc_string str; \
|
||||
SNAME *l_ = _list_; \
|
||||
const char *name = #SNAME; \
|
||||
\
|
||||
snprintf(str.s, cmc_string_len, cmc_string_fmt_sortedlist, \
|
||||
name, l_, l_->buffer, l_->capacity, l_->count, \
|
||||
l_->is_sorted ? "true" : "false", l_->cmp); \
|
||||
\
|
||||
return str; \
|
||||
} \
|
||||
\
|
||||
SNAME##_iter *PFX##_iter_new(SNAME *target) \
|
||||
{ \
|
||||
SNAME##_iter *iter = malloc(sizeof(SNAME##_iter)); \
|
||||
\
|
||||
if (!iter) \
|
||||
return NULL; \
|
||||
\
|
||||
PFX##_iter_init(iter, target); \
|
||||
\
|
||||
return iter; \
|
||||
} \
|
||||
\
|
||||
void PFX##_iter_free(SNAME##_iter *iter) \
|
||||
{ \
|
||||
free(iter); \
|
||||
} \
|
||||
\
|
||||
void PFX##_iter_init(SNAME##_iter *iter, SNAME *target) \
|
||||
{ \
|
||||
PFX##_sort(target); \
|
||||
\
|
||||
iter->target = target; \
|
||||
iter->cursor = 0; \
|
||||
iter->start = true; \
|
||||
iter->end = PFX##_empty(target); \
|
||||
} \
|
||||
\
|
||||
bool PFX##_iter_start(SNAME##_iter *iter) \
|
||||
{ \
|
||||
return PFX##_empty(iter->target) || iter->start; \
|
||||
} \
|
||||
\
|
||||
bool PFX##_iter_end(SNAME##_iter *iter) \
|
||||
{ \
|
||||
return PFX##_empty(iter->target) || iter->end; \
|
||||
} \
|
||||
\
|
||||
void PFX##_iter_to_start(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (!PFX##_empty(iter->target)) \
|
||||
{ \
|
||||
iter->cursor = 0; \
|
||||
iter->start = true; \
|
||||
iter->end = PFX##_empty(iter->target); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
void PFX##_iter_to_end(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (!PFX##_empty(iter->target)) \
|
||||
{ \
|
||||
iter->start = PFX##_empty(iter->target); \
|
||||
iter->cursor = PFX##_empty(iter->target) ? 0 : iter->target->count - 1; \
|
||||
iter->end = true; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
bool PFX##_iter_next(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (iter->end) \
|
||||
return false; \
|
||||
\
|
||||
if (iter->cursor + 1 == PFX##_count(iter->target)) \
|
||||
{ \
|
||||
iter->end = true; \
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
iter->start = PFX##_empty(iter->target); \
|
||||
\
|
||||
iter->cursor++; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
bool PFX##_iter_prev(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (iter->start) \
|
||||
return false; \
|
||||
\
|
||||
if (iter->cursor == 0) \
|
||||
{ \
|
||||
iter->start = true; \
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
iter->end = PFX##_empty(iter->target); \
|
||||
\
|
||||
iter->cursor--; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
/* Returns true only if the iterator moved */ \
|
||||
bool PFX##_iter_advance(SNAME##_iter *iter, size_t steps) \
|
||||
{ \
|
||||
if (iter->end) \
|
||||
return false; \
|
||||
\
|
||||
if (iter->cursor + 1 == iter->target->count) \
|
||||
{ \
|
||||
iter->end = true; \
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
if (steps == 0 || iter->cursor + steps >= PFX##_count(iter->target)) \
|
||||
return false; \
|
||||
\
|
||||
iter->start = PFX##_empty(iter->target); \
|
||||
\
|
||||
iter->cursor += steps; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
/* Returns true only if the iterator moved */ \
|
||||
bool PFX##_iter_rewind(SNAME##_iter *iter, size_t steps) \
|
||||
{ \
|
||||
if (iter->start) \
|
||||
return false; \
|
||||
\
|
||||
if (iter->cursor == 0) \
|
||||
{ \
|
||||
iter->start = true; \
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
if (steps == 0 || iter->cursor < steps) \
|
||||
return false; \
|
||||
\
|
||||
iter->end = PFX##_empty(iter->target); \
|
||||
\
|
||||
iter->cursor -= steps; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
/* Returns true only if the iterator was able to be positioned at the given index */ \
|
||||
bool PFX##_iter_go_to(SNAME##_iter *iter, size_t index) \
|
||||
{ \
|
||||
if (index >= PFX##_count(iter->target)) \
|
||||
return false; \
|
||||
\
|
||||
if (iter->cursor > index) \
|
||||
return PFX##_iter_rewind(iter, iter->cursor - index); \
|
||||
else if (iter->cursor < index) \
|
||||
return PFX##_iter_advance(iter, index - iter->cursor); \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
V PFX##_iter_value(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (PFX##_empty(iter->target)) \
|
||||
return (V){0}; \
|
||||
\
|
||||
return iter->target->buffer[iter->cursor]; \
|
||||
} \
|
||||
\
|
||||
size_t PFX##_iter_index(SNAME##_iter *iter) \
|
||||
{ \
|
||||
return iter->cursor; \
|
||||
} \
|
||||
\
|
||||
static size_t PFX##_impl_binary_search_first(SNAME *_list_, V value) \
|
||||
{ \
|
||||
if (PFX##_empty(_list_)) \
|
||||
return 1; \
|
||||
\
|
||||
size_t L = 0; \
|
||||
size_t R = PFX##_count(_list_); \
|
||||
\
|
||||
while (L < R) \
|
||||
{ \
|
||||
size_t M = L + (R - L) / 2; \
|
||||
\
|
||||
if (_list_->cmp(_list_->buffer[M], value) < 0) \
|
||||
L = M + 1; \
|
||||
else \
|
||||
R = M; \
|
||||
} \
|
||||
\
|
||||
if (_list_->cmp(_list_->buffer[L], value) == 0) \
|
||||
return L; \
|
||||
\
|
||||
/* Not found */ \
|
||||
return PFX##_count(_list_); \
|
||||
} \
|
||||
\
|
||||
static size_t PFX##_impl_binary_search_last(SNAME *_list_, V value) \
|
||||
{ \
|
||||
if (PFX##_empty(_list_)) \
|
||||
return 1; \
|
||||
\
|
||||
size_t L = 0; \
|
||||
size_t R = PFX##_count(_list_); \
|
||||
\
|
||||
while (L < R) \
|
||||
{ \
|
||||
size_t M = L + (R - L) / 2; \
|
||||
\
|
||||
if (_list_->cmp(_list_->buffer[M], value) > 0) \
|
||||
R = M; \
|
||||
else \
|
||||
L = M + 1; \
|
||||
} \
|
||||
\
|
||||
if (_list_->cmp(_list_->buffer[L - 1], value) == 0) \
|
||||
return L - 1; \
|
||||
\
|
||||
/* Not found */ \
|
||||
return PFX##_count(_list_); \
|
||||
} \
|
||||
\
|
||||
/* Characteristics of this quicksort implementation: */ \
|
||||
/* - Hybrid: uses insertion sort for small arrays */ \
|
||||
/* - Partition: Lomuto's Method (can be optimized and use Hoare's Method) */ \
|
||||
/* - Tail recursion: minimize recursion depth */ \
|
||||
void PFX##_impl_sort_quicksort(V *array, int (*cmp)(V, V), size_t low, size_t high) \
|
||||
{ \
|
||||
while (low < high) \
|
||||
{ \
|
||||
/* Quicksort performs poorly for smaller arrays so let insertion */ \
|
||||
/* sort do the job */ \
|
||||
if (high - low < 10) \
|
||||
{ \
|
||||
PFX##_impl_sort_insertion(array, cmp, low, high); \
|
||||
break; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
/* Partition */ \
|
||||
V pivot = array[high]; \
|
||||
\
|
||||
size_t pindex = low; \
|
||||
\
|
||||
for (size_t i = low; i < high; i++) \
|
||||
{ \
|
||||
if (cmp(array[i], pivot) <= 0) \
|
||||
{ \
|
||||
V _tmp_ = array[i]; \
|
||||
array[i] = array[pindex]; \
|
||||
array[pindex] = _tmp_; \
|
||||
\
|
||||
pindex++; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
V _tmp_ = array[pindex]; \
|
||||
array[pindex] = array[high]; \
|
||||
array[high] = _tmp_; \
|
||||
\
|
||||
/* Tail recursion */ \
|
||||
if (pindex - low < high - pindex) \
|
||||
{ \
|
||||
PFX##_impl_sort_quicksort(array, cmp, low, pindex - 1); \
|
||||
\
|
||||
low = pindex + 1; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
PFX##_impl_sort_quicksort(array, cmp, pindex + 1, high); \
|
||||
\
|
||||
high = pindex - 1; \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
void PFX##_impl_sort_insertion(V *array, int (*cmp)(V, V), size_t low, size_t high) \
|
||||
{ \
|
||||
for (size_t i = low + 1; i <= high; i++) \
|
||||
{ \
|
||||
V _tmp_ = array[i]; \
|
||||
size_t j = i; \
|
||||
\
|
||||
while (j > low && cmp(array[j - 1], _tmp_) > 0) \
|
||||
{ \
|
||||
array[j] = array[j - 1]; \
|
||||
j--; \
|
||||
} \
|
||||
\
|
||||
array[j] = _tmp_; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
static SNAME##_iter PFX##_impl_it_start(SNAME *_list_) \
|
||||
{ \
|
||||
SNAME##_iter iter; \
|
||||
\
|
||||
PFX##_iter_init(&iter, _list_); \
|
||||
PFX##_iter_to_start(&iter); \
|
||||
\
|
||||
return iter; \
|
||||
} \
|
||||
\
|
||||
static SNAME##_iter PFX##_impl_it_end(SNAME *_list_) \
|
||||
{ \
|
||||
SNAME##_iter iter; \
|
||||
\
|
||||
PFX##_iter_init(&iter, _list_); \
|
||||
PFX##_iter_to_end(&iter); \
|
||||
\
|
||||
return iter; \
|
||||
}
|
||||
|
||||
#endif /* CMC_SORTEDLIST_H */
|
||||
+12
-15
@@ -8,26 +8,24 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CMC_MACRO_COLLECTIONS
|
||||
#define CMC_MACRO_COLLECTIONS
|
||||
#ifndef CMC_MACRO_COLLECTIONS_H
|
||||
#define CMC_MACRO_COLLECTIONS_H
|
||||
|
||||
#define CMC_CONCATH_(C) C##_WRAPGEN_HEADER
|
||||
#define CMC_CONCATC_(C) C##_WRAPGEN_SOURCE
|
||||
#define CMC_CONCATH_(C) CMC_WRAPGEN_##C##_HEADER
|
||||
#define CMC_CONCATC_(C) CMC_WRAPGEN_##C##_SOURCE
|
||||
|
||||
#define CMC_CONCATH(C) CMC_CONCATH_(C)
|
||||
#define CMC_CONCATC(C) CMC_CONCATC_(C)
|
||||
|
||||
#define COLLECTION_GENERATE(C, PFX, SNAME, FMOD, K, V) \
|
||||
COLLECTION_GENERATE_HEADER(C, PFX, SNAME, FMOD, K, V) \
|
||||
COLLECTION_GENERATE_SOURCE(C, PFX, SNAME, FMOD, K, V)
|
||||
#define CMC_COLLECTION_GENERATE(C, PFX, SNAME, K, V) \
|
||||
CMC_COLLECTION_GENERATE_HEADER(C, PFX, SNAME, K, V) \
|
||||
CMC_COLLECTION_GENERATE_SOURCE(C, PFX, SNAME, K, V)
|
||||
|
||||
#define COLLECTION_GENERATE_HEADER(C, PFX, SNAME, FMOD, K, V) \
|
||||
CMC_CONCATH(C) \
|
||||
(PFX, SNAME, FMOD, K, V)
|
||||
#define CMC_COLLECTION_GENERATE_HEADER(C, PFX, SNAME, K, V) \
|
||||
CMC_CONCATH(C)(PFX, SNAME, K, V)
|
||||
|
||||
#define COLLECTION_GENERATE_SOURCE(C, PFX, SNAME, FMOD, K, V) \
|
||||
CMC_CONCATC(C) \
|
||||
(PFX, SNAME, FMOD, K, V)
|
||||
#define CMC_COLLECTION_GENERATE_SOURCE(C, PFX, SNAME, K, V) \
|
||||
CMC_CONCATC(C)(PFX, SNAME, K, V)
|
||||
|
||||
#include "cmc/deque.h"
|
||||
#include "cmc/hashmap.h"
|
||||
@@ -41,7 +39,6 @@
|
||||
#include "cmc/treeset.h"
|
||||
|
||||
#include "ext/intervalheap.h"
|
||||
#include "ext/linkedqueue.h"
|
||||
#include "ext/multimap.h"
|
||||
#include "ext/multiset.h"
|
||||
|
||||
@@ -54,4 +51,4 @@
|
||||
#include "utl/test.h"
|
||||
#include "utl/timer.h"
|
||||
|
||||
#endif /* CMC_MACRO_COLLECTIONS */
|
||||
#endif /* CMC_MACRO_COLLECTIONS_H */
|
||||
+1357
-902
File diff suppressed because it is too large.
Load diff
+1
-17
@@ -13,8 +13,8 @@
|
||||
#ifndef CMC_STRING_H
|
||||
#define CMC_STRING_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <inttypes.h>
|
||||
#include <stddef.h>
|
||||
|
||||
static const size_t cmc_string_len = 200;
|
||||
|
||||
@@ -23,20 +23,4 @@ typedef struct cmc_string_s
|
||||
char s[200];
|
||||
} cmc_string;
|
||||
|
||||
/* to_string formats */
|
||||
static const char *cmc_string_fmt_deque = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", count:%" PRIuMAX ", front:%" PRIuMAX ", back:%" PRIuMAX " }";
|
||||
static const char *cmc_string_fmt_hashmap = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", count:%" PRIuMAX ", load:%lf, cmp:%p, hash:%p }";
|
||||
static const char *cmc_string_fmt_hashset = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", count:%" PRIuMAX ", load:%lf, cmp:%p, hash:%p }";
|
||||
static const char *cmc_string_fmt_heap = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", count:%" PRIuMAX ", type:%s, cmp:%p }";
|
||||
static const char *cmc_string_fmt_linkedlist = "%s at %p { count:%" PRIuMAX ", head:%p, tail:%p }";
|
||||
static const char *cmc_string_fmt_list = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", count:%" PRIuMAX " }";
|
||||
static const char *cmc_string_fmt_queue = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", count:%" PRIuMAX ", front:%" PRIuMAX ", back:%" PRIuMAX " }";
|
||||
static const char *cmc_string_fmt_stack = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", count:%" PRIuMAX " }";
|
||||
static const char *cmc_string_fmt_treemap = "%s at %p { root:%p, count:%" PRIuMAX ", cmp:%p }";
|
||||
static const char *cmc_string_fmt_treeset = "%s at %p { root:%p, count:%" PRIuMAX ", cmp:%p }";
|
||||
|
||||
static const char *cmc_string_fmt_intervalheap = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", size:%" PRIuMAX ", count:%" PRIuMAX ", cmp:%p }";
|
||||
static const char *cmc_string_fmt_multimap = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", count:%" PRIuMAX ", load:%lf, cmp:%p, hash:%p }";
|
||||
static const char *cmc_string_fmt_multiset = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", count:%" PRIuMAX ", cardinality:%" PRIuMAX ", load:%lf, cmp:%p, hash:%p }";;
|
||||
|
||||
#endif /* CMC_STRING_H */
|
||||
+17
-23
@@ -8,31 +8,25 @@
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* ForEach utility
|
||||
*
|
||||
* Read Documentation.md for more information
|
||||
*/
|
||||
#ifndef CMC_FOR_EACH_H
|
||||
#define CMC_FOR_EACH_H
|
||||
|
||||
#ifndef CMC_FOR_EACH
|
||||
#define CMC_FOR_EACH
|
||||
|
||||
#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; \
|
||||
} \
|
||||
#define CMC_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, TARGET, BODY) \
|
||||
do \
|
||||
{ \
|
||||
for (SNAME##_iter iter = TARGET->it_end(TARGET); !PFX##_iter_start(&iter); PFX##_iter_prev(&iter)) \
|
||||
{ \
|
||||
BODY; \
|
||||
} \
|
||||
#define CMC_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)
|
||||
|
||||
#endif /* CMC_FOR_EACH */
|
||||
#endif /* CMC_FOR_EACH_H */
|
||||
+15
-15
@@ -83,25 +83,25 @@ static struct
|
||||
|
||||
} cmc_log_config = {0, 0, true, true, NULL, true};
|
||||
|
||||
typedef enum cmc_log_type_e
|
||||
enum cmc_log_type
|
||||
{
|
||||
LOG_TRACE = 1,
|
||||
LOG_DEBUG = 2,
|
||||
LOG_INFO = 3,
|
||||
LOG_WARN = 4,
|
||||
LOG_ERROR = 5,
|
||||
LOG_FATAL = 6
|
||||
CMC_LOG_TRACE = 1,
|
||||
CMC_LOG_DEBUG = 2,
|
||||
CMC_LOG_INFO = 3,
|
||||
CMC_LOG_WARN = 4,
|
||||
CMC_LOG_ERROR = 5,
|
||||
CMC_LOG_FATAL = 6
|
||||
|
||||
} cmc_log_type;
|
||||
};
|
||||
|
||||
#define log_trace(fmt, ...) cmc_log(LOG_TRACE, __FILE__, __func__, __LINE__, fmt, __VA_ARGS__)
|
||||
#define log_debug(fmt, ...) cmc_log(LOG_DEBUG, __FILE__, __func__, __LINE__, fmt, __VA_ARGS__)
|
||||
#define log_info(fmt, ...) cmc_log(LOG_INFO, __FILE__, __func__, __LINE__, fmt, __VA_ARGS__)
|
||||
#define log_warn(fmt, ...) cmc_log(LOG_WARN, __FILE__, __func__, __LINE__, fmt, __VA_ARGS__)
|
||||
#define log_error(fmt, ...) cmc_log(LOG_ERROR, __FILE__, __func__, __LINE__, fmt, __VA_ARGS__)
|
||||
#define log_fatal(fmt, ...) cmc_log(LOG_FATAL, __FILE__, __func__, __LINE__, fmt, __VA_ARGS__)
|
||||
#define cmc_log_trace(fmt, ...) cmc_log(CMC_LOG_TRACE, __FILE__, __func__, __LINE__, fmt, __VA_ARGS__)
|
||||
#define cmc_log_debug(fmt, ...) cmc_log(CMC_LOG_DEBUG, __FILE__, __func__, __LINE__, fmt, __VA_ARGS__)
|
||||
#define cmc_log_info(fmt, ...) cmc_log(CMC_LOG_INFO, __FILE__, __func__, __LINE__, fmt, __VA_ARGS__)
|
||||
#define cmc_log_warn(fmt, ...) cmc_log(CMC_LOG_WARN, __FILE__, __func__, __LINE__, fmt, __VA_ARGS__)
|
||||
#define cmc_log_error(fmt, ...) cmc_log(CMC_LOG_ERROR, __FILE__, __func__, __LINE__, fmt, __VA_ARGS__)
|
||||
#define cmc_log_fatal(fmt, ...) cmc_log(CMC_LOG_FATAL, __FILE__, __func__, __LINE__, fmt, __VA_ARGS__)
|
||||
|
||||
static void cmc_log(cmc_log_type log, const char *filename, const char *funcname, int line, const char *fmt, ...)
|
||||
static void cmc_log(enum cmc_log_type log, const char *filename, const char *funcname, int line, const char *fmt, ...)
|
||||
{
|
||||
if (!cmc_log_config.enabled)
|
||||
return;
|
||||
|
||||
+44
-47
@@ -11,6 +11,10 @@
|
||||
/**
|
||||
* Simple Unit Test Utility
|
||||
*
|
||||
* Required imports:
|
||||
* - assert.h (to integrate with the cmc_assert_state variable)
|
||||
* - timer.h (to calculate the execution time for the unit test)
|
||||
*
|
||||
* CMC_CREATE_UNIT
|
||||
* Create a UnitTest
|
||||
* Parameters:
|
||||
@@ -42,6 +46,7 @@
|
||||
#ifndef CMC_TEST_H
|
||||
#define CMC_TEST_H
|
||||
|
||||
#include "assert.h"
|
||||
#include "timer.h"
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
@@ -54,14 +59,14 @@
|
||||
static const char *cmc_test_color[] = {"\x1b[32m", "\x1b[31m", "\x1b[35m"};
|
||||
#endif
|
||||
|
||||
typedef struct cmc_test_info_s
|
||||
struct cmc_test_info
|
||||
{
|
||||
uintmax_t total;
|
||||
uintmax_t passed;
|
||||
uintmax_t failed;
|
||||
bool aborted;
|
||||
bool verbose;
|
||||
} cmc_test_info;
|
||||
};
|
||||
|
||||
/* Logging function */
|
||||
static void cmc_test_log(const char *unit_name, const char *current_test, bool aborted, bool passed)
|
||||
@@ -92,23 +97,25 @@ static void cmc_test_log(const char *unit_name, const char *current_test, bool a
|
||||
}
|
||||
|
||||
#define CMC_CREATE_UNIT(UNAME, VERBOSE, BODY) \
|
||||
void UNAME(void) \
|
||||
uintmax_t UNAME(void) \
|
||||
{ \
|
||||
const char *unit_name = #UNAME; \
|
||||
const char *current_test = NULL; \
|
||||
\
|
||||
cmc_test_info tinfo = {0}; \
|
||||
struct cmc_test_info tinfo = {0}; \
|
||||
cmc_timer timer = {0}; \
|
||||
\
|
||||
tinfo.verbose = VERBOSE; \
|
||||
\
|
||||
/* Tests */ \
|
||||
timer_start(timer); \
|
||||
BODY; \
|
||||
timer_stop(timer); \
|
||||
timer_calc(timer); \
|
||||
cmc_timer_start(timer); \
|
||||
\
|
||||
unittest_abort: \
|
||||
BODY; \
|
||||
\
|
||||
cmc_timer_stop(timer); \
|
||||
cmc_timer_calc(timer); \
|
||||
\
|
||||
unittest_abort: \
|
||||
if (tinfo.aborted) \
|
||||
{ \
|
||||
cmc_test_log(unit_name, current_test, true, false); \
|
||||
@@ -122,51 +129,41 @@ static void cmc_test_log(const char *unit_name, const char *current_test, bool a
|
||||
printf("| |\n"); \
|
||||
printf("| Total Unit Test Runtime : %9.0f milliseconds |\n", timer.result); \
|
||||
printf("+--------------------------------------------------+\n"); \
|
||||
\
|
||||
return tinfo.failed; \
|
||||
}
|
||||
|
||||
#define CMC_CREATE_TEST(TNAME, BODY) \
|
||||
do \
|
||||
{ \
|
||||
current_test = #TNAME; \
|
||||
\
|
||||
tinfo.total += 1; \
|
||||
\
|
||||
BODY; \
|
||||
\
|
||||
} while (0)
|
||||
|
||||
#define CMC_TEST_PASS() \
|
||||
do \
|
||||
{ \
|
||||
tinfo.passed += 1; \
|
||||
if (tinfo.verbose) \
|
||||
cmc_test_log(unit_name, current_test, false, true); \
|
||||
\
|
||||
} while (0)
|
||||
|
||||
#define CMC_TEST_FAIL() \
|
||||
do \
|
||||
{ \
|
||||
tinfo.failed += 1; \
|
||||
if (tinfo.verbose) \
|
||||
cmc_test_log(unit_name, current_test, false, false); \
|
||||
\
|
||||
} while (0)
|
||||
|
||||
#define CMC_TEST_PASS_ELSE_FAIL(EXPRESSION) \
|
||||
do \
|
||||
{ \
|
||||
if (EXPRESSION) \
|
||||
CMC_TEST_PASS(); \
|
||||
else \
|
||||
CMC_TEST_FAIL(); \
|
||||
\
|
||||
#define CMC_CREATE_TEST(TNAME, BODY) \
|
||||
do \
|
||||
{ \
|
||||
current_test = #TNAME; \
|
||||
\
|
||||
tinfo.total += 1; \
|
||||
\
|
||||
/* Provided by assert.h */ \
|
||||
cmc_assert_state = true; \
|
||||
\
|
||||
BODY; \
|
||||
\
|
||||
if (tinfo.verbose) \
|
||||
{ \
|
||||
if (!cmc_assert_state) \
|
||||
{ \
|
||||
tinfo.failed += 1; \
|
||||
cmc_test_log(unit_name, current_test, false, false); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
tinfo.passed += 1; \
|
||||
cmc_test_log(unit_name, current_test, false, true); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
} while (0)
|
||||
|
||||
#define CMC_TEST_ABORT() \
|
||||
do \
|
||||
{ \
|
||||
\
|
||||
tinfo.aborted = true; \
|
||||
tinfo.total -= 1; \
|
||||
goto unittest_abort; \
|
||||
|
||||
+8
-8
@@ -22,7 +22,7 @@ typedef struct cmc_timer_s
|
||||
double result;
|
||||
} cmc_timer;
|
||||
|
||||
#define timer_start(timer) \
|
||||
#define cmc_timer_start(timer) \
|
||||
do \
|
||||
{ \
|
||||
cmc_timer *t = &(timer); \
|
||||
@@ -30,15 +30,15 @@ typedef struct cmc_timer_s
|
||||
\
|
||||
} while (0)
|
||||
|
||||
#define timer_stop(timer) \
|
||||
do \
|
||||
{ \
|
||||
cmc_timer *t = &(timer);\
|
||||
t->stop = clock(); \
|
||||
\
|
||||
#define cmc_timer_stop(timer) \
|
||||
do \
|
||||
{ \
|
||||
cmc_timer *t = &(timer); \
|
||||
t->stop = clock(); \
|
||||
\
|
||||
} while (0)
|
||||
|
||||
#define timer_calc(timer) \
|
||||
#define cmc_timer_calc(timer) \
|
||||
do \
|
||||
{ \
|
||||
cmc_timer *t = &(timer); \
|
||||
|
||||
+20
-12
@@ -1,17 +1,25 @@
|
||||
CC = gcc
|
||||
CFLAGS = -std=c11 -Wall -Wextra
|
||||
CFLAGS += -Wno-unused-function -Wno-unused-paramter -Wno-unused-variable -Wno-unused-label
|
||||
CFLAGS += -Wno-unused-function -Wno-unused-parameter -Wno-unused-variable -Wno-unused-label
|
||||
|
||||
main:
|
||||
$(CC) foreach.c -o foreach $(CFLAGS)
|
||||
./foreach
|
||||
$(CC) iterators.c -o iterators $(CFLAGS)
|
||||
./iterators
|
||||
$(CC) contains.c -o contains $(CFLAGS)
|
||||
./contains
|
||||
$(CC) types.c -o types $(CFLAGS)
|
||||
./types
|
||||
main: FORCE
|
||||
$(CC) foreach.c -o foreach.exe $(CFLAGS)
|
||||
./foreach.exe
|
||||
$(CC) iterators.c -o iterators.exe $(CFLAGS)
|
||||
./iterators.exe
|
||||
$(CC) contains.c -o contains.exe $(CFLAGS)
|
||||
./contains.exe
|
||||
$(CC) types.c -o types.exe $(CFLAGS)
|
||||
./types.exe
|
||||
$(CC) -c ./sep/sep.c -o ./sep/sep.o $(CFLAGS)
|
||||
$(CC) -c ./sep/main.c -o ./sep/main.o $(CFLAGS)
|
||||
$(CC) ./sep/sep.o ./sep/main.o -o ./sep/sep
|
||||
./sep/sep
|
||||
$(CC) ./sep/sep.o ./sep/main.o -o ./sep/sep.exe
|
||||
./sep/sep.exe
|
||||
|
||||
dev: main
|
||||
rm *.exe ./sep/*.o ./sep/*.exe
|
||||
|
||||
windev: main
|
||||
del *.exe .\\sep\\*.o .\\sep\\*.exe
|
||||
|
||||
FORCE:
|
||||
+2
-1
@@ -1,6 +1,7 @@
|
||||
# Tests
|
||||
|
||||
* `main` - Unit tests for the main C Macro Collections library with code coverage;
|
||||
* `codecov` - A stalled version for codecov;
|
||||
* `main` - Unit tests for the main C Macro Collections library;
|
||||
* `sep/main.c`, `sep/sep.c` and `sep/sep.h` - Tests separate header and source compilation;
|
||||
* `contains.c` - Tests the `contains` function for all collections;
|
||||
* `foreach.c` - Tests the ForEach macros for all collections;
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
CC = gcc
|
||||
CFLAGS = -std=c11 -Wall -Wextra
|
||||
CFLAGS += -Wno-unused-function -Wno-unused-parameter -Wno-unused-variable -Wno-unused-label
|
||||
CVFLAGS = --coverage -O0
|
||||
INCLUDE = ../../src/
|
||||
|
||||
main: FORCE
|
||||
$(CC) main.c -o main $(CFLAGS) $(CVFLAGS) -I $(INCLUDE)
|
||||
./main
|
||||
gcov ./main.c
|
||||
|
||||
dev: FORCE
|
||||
$(CC) main.c -o main $(CFLAGS) $(CVFLAGS) -I $(INCLUDE)
|
||||
./main
|
||||
gcov ./main.c -n
|
||||
rm *.gcda *.gcno *.exe
|
||||
|
||||
windev: FORCE
|
||||
$(CC) main.c -o main $(CFLAGS) $(CVFLAGS) -I $(INCLUDE)
|
||||
./main
|
||||
gcov ./main.c -n
|
||||
del *.gcda *.gcno *.exe
|
||||
|
||||
FORCE:
|
||||
@@ -0,0 +1,7 @@
|
||||
# codecov
|
||||
|
||||
In order to provide a good code coverage, all macros have been expanded and added to `src/*.c`.
|
||||
|
||||
* `src` - Since gcov fails to detect code that was expanded by macro, all collections where manually expanded and dumped into their respective source files;
|
||||
* `unt` - Unit Tests;
|
||||
* `main.c` - Where all tests are compiled together and called by main().
|
||||
@@ -0,0 +1,35 @@
|
||||
#include "unt/deque.c"
|
||||
#include "unt/hashmap.c"
|
||||
#include "unt/hashset.c"
|
||||
#include "unt/heap.c"
|
||||
#include "unt/linkedlist.c"
|
||||
#include "unt/list.c"
|
||||
#include "unt/queue.c"
|
||||
#include "unt/stack.c"
|
||||
#include "unt/treemap.c"
|
||||
#include "unt/treeset.c"
|
||||
|
||||
#include "unt/multimap.c"
|
||||
#include "unt/multiset.c"
|
||||
|
||||
int main(void)
|
||||
{
|
||||
uintmax_t failed = 0;
|
||||
|
||||
failed += deque_test();
|
||||
failed += hashmap_test();
|
||||
failed += hashset_test();
|
||||
failed += heap_test();
|
||||
failed += linkedlist_test();
|
||||
failed += list_test();
|
||||
failed += queue_test();
|
||||
failed += stack_test();
|
||||
failed += treemap_test();
|
||||
failed += treeset_test();
|
||||
|
||||
/* ext */
|
||||
failed += multimap_test();
|
||||
failed += multiset_test();
|
||||
|
||||
return failed;
|
||||
}
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,61 @@
|
||||
#include "utl/assert.h"
|
||||
#include "utl/test.h"
|
||||
#include "../src/deque.c"
|
||||
|
||||
CMC_CREATE_UNIT(deque_test, false, {
|
||||
CMC_CREATE_TEST(new, {
|
||||
deque *d = d_new(1000000);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, d);
|
||||
cmc_assert_not_equals(ptr, NULL, d->buffer);
|
||||
cmc_assert_equals(size_t, 1000000, d->capacity);
|
||||
cmc_assert_equals(size_t, 0, d_count(d));
|
||||
|
||||
d_free(d);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(new[edge_case:capacity = 0], {
|
||||
deque *d = d_new(0);
|
||||
|
||||
cmc_assert_equals(ptr, NULL, d);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(new[edge_case:capacity = UINT64_MAX], {
|
||||
deque *d = d_new(UINT64_MAX);
|
||||
|
||||
cmc_assert_equals(ptr, NULL, d);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(clear[count capacity], {
|
||||
deque *d = d_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, d);
|
||||
|
||||
for (size_t i = 0; i < 50; i++)
|
||||
d_push_back(d, i);
|
||||
|
||||
cmc_assert_equals(size_t, 50, d_count(d));
|
||||
|
||||
d_clear(d);
|
||||
|
||||
cmc_assert_equals(size_t, 0, d_count(d));
|
||||
cmc_assert_equals(size_t, 100, d_capacity(d));
|
||||
|
||||
d_free(d);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(buffer_growth[edge_case:capacity = 1], {
|
||||
deque *d = d_new(1);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, d);
|
||||
|
||||
for (size_t i = 0; i < 50; i++)
|
||||
d_push_back(d, i);
|
||||
|
||||
cmc_assert_equals(size_t, 50, d_count(d));
|
||||
cmc_assert_lesser_equals(size_t, d_capacity(d), d_count(d));
|
||||
|
||||
d_free(d);
|
||||
});
|
||||
|
||||
});
|
||||
@@ -0,0 +1,48 @@
|
||||
#include "utl/assert.h"
|
||||
#include "utl/test.h"
|
||||
#include "../src/hashmap.c"
|
||||
|
||||
#include "utl.c"
|
||||
|
||||
CMC_CREATE_UNIT(hashmap_test, false, {
|
||||
CMC_CREATE_TEST(new, {
|
||||
hashmap *map = hm_new(943722, 0.6, cmp, hash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
cmc_assert_not_equals(ptr, NULL, map->buffer);
|
||||
cmc_assert_equals(size_t, 0, hm_count(map));
|
||||
cmc_assert_greater_equals(size_t, (943722 / 0.6), hm_capacity(map));
|
||||
|
||||
hm_free(map);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(new[edge_case:capacity = 0], {
|
||||
hashmap *map = hm_new(0, 0.6, cmp, hash);
|
||||
|
||||
cmc_assert_equals(ptr, NULL, map);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(new[edge_case:capacity = UINT64_MAX], {
|
||||
hashmap *map = hm_new(UINT64_MAX, 0.6, cmp, hash);
|
||||
|
||||
cmc_assert_equals(ptr, NULL, map);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(clear[count capacity], {
|
||||
hashmap *map = hm_new(100, 0.6, cmp, hash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
|
||||
for (size_t i = 0; i < 50; i++)
|
||||
hm_insert(map, i, i);
|
||||
|
||||
cmc_assert_equals(size_t, 50, hm_count(map));
|
||||
|
||||
hm_clear(map);
|
||||
|
||||
cmc_assert_equals(size_t, 0, hm_count(map));
|
||||
|
||||
hm_free(map);
|
||||
});
|
||||
|
||||
});
|
||||
@@ -0,0 +1,48 @@
|
||||
#include "utl/assert.h"
|
||||
#include "utl/test.h"
|
||||
#include "../src/hashset.c"
|
||||
|
||||
#include "utl.c"
|
||||
|
||||
CMC_CREATE_UNIT(hashset_test, false, {
|
||||
CMC_CREATE_TEST(new, {
|
||||
hashset *set = hs_new(943722, 0.6, cmp, hash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, set);
|
||||
cmc_assert_not_equals(ptr, NULL, set->buffer);
|
||||
cmc_assert_equals(size_t, 0, hs_count(set));
|
||||
cmc_assert_greater_equals(size_t, (943722 / 0.6), hs_capacity(set));
|
||||
|
||||
hs_free(set);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(new[edge_case:capacity = 0], {
|
||||
hashset *set = hs_new(0, 0.6, cmp, hash);
|
||||
|
||||
cmc_assert_equals(ptr, NULL, set);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(new[edge_case:capacity = UINT64_MAX], {
|
||||
hashset *set = hs_new(UINT64_MAX, 0.6, cmp, hash);
|
||||
|
||||
cmc_assert_equals(ptr, NULL, set);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(clear[count capacity], {
|
||||
hashset *set = hs_new(100, 0.6, cmp, hash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, set);
|
||||
|
||||
for (size_t i = 0; i < 50; i++)
|
||||
hs_insert(set, i);
|
||||
|
||||
cmc_assert_equals(size_t, 50, hs_count(set));
|
||||
|
||||
hs_clear(set);
|
||||
|
||||
cmc_assert_equals(size_t, 0, hs_count(set));
|
||||
|
||||
hs_free(set);
|
||||
});
|
||||
|
||||
});
|
||||
@@ -0,0 +1,62 @@
|
||||
#include "utl/assert.h"
|
||||
#include "utl/test.h"
|
||||
#include "../src/heap.c"
|
||||
|
||||
#include "utl.c"
|
||||
|
||||
CMC_CREATE_UNIT(heap_test, false, {
|
||||
CMC_CREATE_TEST(new, {
|
||||
heap *h = h_new(1000000, cmc_max_heap, cmp);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, h);
|
||||
cmc_assert_not_equals(ptr, NULL, h->buffer);
|
||||
cmc_assert_equals(size_t, 1000000, h_capacity(h));
|
||||
cmc_assert_equals(size_t, 0, h_count(h));
|
||||
|
||||
h_free(h);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(new[edge_case:capacity = 0], {
|
||||
heap *h = h_new(0, cmc_max_heap, cmp);
|
||||
|
||||
cmc_assert_equals(ptr, NULL, h);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(new[edge_case:capacity = UINT64_MAX], {
|
||||
heap *h = h_new(UINT64_MAX, cmc_max_heap, cmp);
|
||||
|
||||
cmc_assert_equals(ptr, NULL, h);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(clear[count capacity], {
|
||||
heap *h = h_new(100, cmc_max_heap, cmp);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, h);
|
||||
|
||||
for (size_t i = 0; i < 50; i++)
|
||||
h_insert(h, i);
|
||||
|
||||
cmc_assert_equals(size_t, 50, h_count(h));
|
||||
|
||||
h_clear(h);
|
||||
|
||||
cmc_assert_equals(size_t, 0, h_count(h));
|
||||
cmc_assert_equals(size_t, 100, h_capacity(h));
|
||||
|
||||
h_free(h);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(buffer_growth[edge_case:capacity = 1], {
|
||||
heap *h = h_new(1, cmc_max_heap, cmp);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, h);
|
||||
|
||||
for (size_t i = 0; i < 50; i++)
|
||||
h_insert(h, i);
|
||||
|
||||
cmc_assert_equals(size_t, 50, h_count(h));
|
||||
|
||||
h_free(h);
|
||||
});
|
||||
|
||||
});
|
||||
@@ -0,0 +1,74 @@
|
||||
#include "utl/assert.h"
|
||||
#include "utl/test.h"
|
||||
#include "../src/linkedlist.c"
|
||||
|
||||
CMC_CREATE_UNIT(linkedlist_test, false, {
|
||||
CMC_CREATE_TEST(new, {
|
||||
linkedlist *ll = ll_new();
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, ll);
|
||||
cmc_assert_equals(size_t, 0, ll_count(ll));
|
||||
cmc_assert_equals(ptr, NULL, ll->head);
|
||||
cmc_assert_equals(ptr, NULL, ll->tail);
|
||||
|
||||
ll_free(ll);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(clear[count capacity], {
|
||||
linkedlist *ll = ll_new();
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, ll);
|
||||
|
||||
for (size_t i = 0; i < 50; i++)
|
||||
ll_push_back(ll, i);
|
||||
|
||||
cmc_assert_equals(size_t, 50, ll_count(ll));
|
||||
|
||||
ll_clear(ll);
|
||||
|
||||
cmc_assert_equals(size_t, 0, ll_count(ll));
|
||||
|
||||
ll_free(ll);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(clear[edge_case:count = 0], {
|
||||
linkedlist *ll = ll_new();
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, ll);
|
||||
|
||||
ll_clear(ll);
|
||||
|
||||
cmc_assert_equals(size_t, 0, ll_count(ll));
|
||||
|
||||
ll_free(ll);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(push_front[count], {
|
||||
linkedlist *ll = ll_new();
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, ll);
|
||||
|
||||
ll_push_front(ll, 1);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, ll->head);
|
||||
cmc_assert_not_equals(ptr, NULL, ll->tail);
|
||||
cmc_assert_equals(size_t, 1, ll_count(ll));
|
||||
|
||||
ll_free(ll);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(push_front[item_preservation], {
|
||||
linkedlist *ll = ll_new();
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, ll);
|
||||
|
||||
for (size_t i = 0; i < 200; i++)
|
||||
ll_push_front(ll, i);
|
||||
|
||||
for (size_t i = 0; i < ll_count(ll); i++)
|
||||
cmc_assert_equals(size_t, ll_get(ll, i), ll_count(ll) - i - 1);
|
||||
|
||||
ll_free(ll);
|
||||
});
|
||||
|
||||
});
|
||||
@@ -0,0 +1,335 @@
|
||||
#include "utl/assert.h"
|
||||
#include "utl/test.h"
|
||||
#include "../src/list.c"
|
||||
|
||||
CMC_CREATE_UNIT(list_test, false, {
|
||||
CMC_CREATE_TEST(new, {
|
||||
list *l = l_new(1000000);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, l);
|
||||
cmc_assert_not_equals(ptr, NULL, l->buffer);
|
||||
cmc_assert_equals(size_t, 1000000, l_capacity(l));
|
||||
cmc_assert_equals(size_t, 0, l_count(l));
|
||||
|
||||
l_free(l);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(new[edge_case:capacity = 0], {
|
||||
list *l = l_new(0);
|
||||
|
||||
cmc_assert_equals(ptr, NULL, l);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(new[edge_case:capacity = UINT64_MAX], {
|
||||
list *l = l_new(UINT64_MAX);
|
||||
|
||||
cmc_assert_equals(ptr, NULL, l);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(new_from[count item_preservation], {
|
||||
size_t v[5];
|
||||
|
||||
for (size_t i = 0; i < 5; i++)
|
||||
{
|
||||
v[i] = i;
|
||||
}
|
||||
|
||||
list *l = l_new_from(v, 5);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, l);
|
||||
|
||||
for (size_t i = 0; i < 5; i++)
|
||||
cmc_assert_equals(size_t, i, l_get(l, i));
|
||||
|
||||
l_free(l);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(new_from[edge_case:size = 1], {
|
||||
size_t a = 10;
|
||||
|
||||
size_t *values = &a;
|
||||
|
||||
list *l = l_new_from(values, 1);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, l);
|
||||
|
||||
l_free(l);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(clear[count capacity], {
|
||||
list *l = l_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, l);
|
||||
|
||||
for (size_t i = 0; i < 50; i++)
|
||||
l_push_back(l, i);
|
||||
|
||||
cmc_assert_equals(size_t, 50, l_count(l));
|
||||
|
||||
l_clear(l);
|
||||
|
||||
cmc_assert_equals(size_t, 0, l_count(l));
|
||||
cmc_assert_equals(size_t, 100, l_capacity(l));
|
||||
|
||||
l_free(l);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(buffer_growth[edge_case:capacity = 1], {
|
||||
list *l = l_new(1);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, l);
|
||||
|
||||
for (size_t i = 0; i < 100; i++)
|
||||
l_push_back(l, i);
|
||||
|
||||
cmc_assert_equals(size_t, 100, l_count(l));
|
||||
|
||||
for (size_t i = 0; i < 100; i++)
|
||||
cmc_assert_equals(size_t, i, l_get(l, i));
|
||||
|
||||
l_free(l);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(push_front[count], {
|
||||
list *l = l_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, l);
|
||||
|
||||
for (size_t i = 0; i < 250; i++)
|
||||
cmc_assert(l_push_front(l, i));
|
||||
|
||||
cmc_assert_equals(size_t, 250, l_count(l));
|
||||
|
||||
l_free(l);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(push_front[capacity], {
|
||||
list *l = l_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, l);
|
||||
|
||||
for (size_t i = 0; i < 250; i++)
|
||||
cmc_assert(l_push_front(l, i));
|
||||
|
||||
cmc_assert_lesser_equals(size_t, l_capacity(l), l_count(l));
|
||||
|
||||
l_free(l);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(push_front[item_preservation], {
|
||||
list *l = l_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, l);
|
||||
|
||||
for (size_t i = 0; i < 250; i++)
|
||||
cmc_assert(l_push_front(l, i));
|
||||
|
||||
for (size_t i = 0; i < l_count(l); i++)
|
||||
cmc_assert_equals(size_t, l_get(l, i), l_count(l) - i - 1);
|
||||
|
||||
l_free(l);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(push[count], {
|
||||
list *l = l_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, l);
|
||||
|
||||
cmc_assert(l_push_back(l, 0));
|
||||
cmc_assert(l_push_back(l, 249));
|
||||
|
||||
for (size_t i = 1; i < 249; i++)
|
||||
cmc_assert(l_push(l, i, l_count(l) - 1));
|
||||
|
||||
cmc_assert_equals(size_t, 250, l_count(l));
|
||||
|
||||
l_free(l);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(push[capacity], {
|
||||
list *l = l_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, l);
|
||||
|
||||
cmc_assert(l_push_back(l, 0));
|
||||
cmc_assert(l_push_back(l, 249));
|
||||
|
||||
for (size_t i = 1; i < 249; i++)
|
||||
cmc_assert(l_push(l, i, l_count(l) - 1));
|
||||
|
||||
cmc_assert_lesser_equals(size_t, l_capacity(l), l_count(l));
|
||||
|
||||
l_free(l);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(push[item_preservation], {
|
||||
list *l = l_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, l);
|
||||
|
||||
cmc_assert(l_push_back(l, 0));
|
||||
cmc_assert(l_push_back(l, 249));
|
||||
|
||||
for (size_t i = 1; i < 249; i++)
|
||||
cmc_assert(l_push(l, i, l_count(l) - 1));
|
||||
|
||||
for (size_t i = 0; i < l_count(l); i++)
|
||||
cmc_assert_equals(size_t, l_get(l, i), i);
|
||||
|
||||
l_free(l);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(push_back[count], {
|
||||
list *l = l_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, l);
|
||||
|
||||
for (size_t i = 0; i < 250; i++)
|
||||
cmc_assert(l_push_back(l, i));
|
||||
|
||||
cmc_assert_equals(size_t, 250, l_count(l));
|
||||
|
||||
l_free(l);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(push_back[capacity], {
|
||||
list *l = l_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, l);
|
||||
|
||||
for (size_t i = 0; i < 250; i++)
|
||||
cmc_assert(l_push_back(l, i));
|
||||
|
||||
cmc_assert_lesser_equals(size_t, l_capacity(l), l_count(l));
|
||||
|
||||
l_free(l);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(push_back[item_preservation], {
|
||||
list *l = l_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, l);
|
||||
|
||||
for (size_t i = 0; i < 250; i++)
|
||||
cmc_assert(l_push_back(l, i));
|
||||
|
||||
for (size_t i = 0; i < l_count(l); i++)
|
||||
cmc_assert_equals(size_t, l_get(l, i), i);
|
||||
|
||||
l_free(l);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(pop_front[count], {
|
||||
list *l = l_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, l);
|
||||
|
||||
for (size_t i = 0; i < 250; i++)
|
||||
l_push_back(l, i);
|
||||
|
||||
cmc_assert(l_pop_front(l));
|
||||
|
||||
l_free(l);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(pop_front[item_preservation], {
|
||||
list *l = l_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, l);
|
||||
|
||||
for (size_t i = 0; i < 250; i++)
|
||||
l_push_back(l, i);
|
||||
|
||||
cmc_assert(l_pop_front(l));
|
||||
|
||||
for (size_t i = 0; i < l_count(l); i++)
|
||||
cmc_assert_equals(size_t, l_get(l, i), i + 1);
|
||||
|
||||
l_free(l);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(pop_front[edge_case:count = 0], {
|
||||
list *l = l_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, l);
|
||||
cmc_assert(!l_pop_front(l));
|
||||
|
||||
l_free(l);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(pop_front[edge_case:count = 1], {
|
||||
list *l = l_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, l);
|
||||
cmc_assert(l_push_back(l, 10));
|
||||
cmc_assert(l_pop_front(l));
|
||||
|
||||
l_free(l);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(pop_front[buffer_clear], {
|
||||
list *l = l_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, l);
|
||||
cmc_assert(l_push_back(l, 1));
|
||||
cmc_assert(l_push_front(l, 2));
|
||||
|
||||
cmc_assert(l_pop_front(l));
|
||||
|
||||
cmc_assert_equals(size_t, 0, l->buffer[1]);
|
||||
|
||||
l_free(l);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(pop[edge_case:count = 0], {
|
||||
list *l = l_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, l);
|
||||
cmc_assert(!l_pop(l, 1));
|
||||
|
||||
l_free(l);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(pop[edge_case:count = 1], {
|
||||
list *l = l_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, l);
|
||||
cmc_assert(l_push_back(l, 1));
|
||||
cmc_assert(l_pop(l, 0));
|
||||
|
||||
cmc_assert_equals(size_t, 0, l->buffer[0]);
|
||||
|
||||
l_free(l);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(pop[buffer_clear], {
|
||||
list *l = l_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, l);
|
||||
cmc_assert(l_push_back(l, 1));
|
||||
cmc_assert(l_push_back(l, 2));
|
||||
cmc_assert(l_push_back(l, 3));
|
||||
cmc_assert(l_pop(l, 1));
|
||||
|
||||
l_free(l);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(pop_back[edge_case:count = 0], {
|
||||
list *l = l_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, l);
|
||||
cmc_assert(!l_pop_back(l));
|
||||
|
||||
l_free(l);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(pop_back[edge_case:count = 1], {
|
||||
list *l = l_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, l);
|
||||
cmc_assert(l_push_back(l, 10));
|
||||
cmc_assert(l_pop_back(l));
|
||||
|
||||
l_free(l);
|
||||
});
|
||||
})
|
||||
@@ -0,0 +1,151 @@
|
||||
#include "utl/assert.h"
|
||||
#include "utl/test.h"
|
||||
#include "../src/multimap.c"
|
||||
|
||||
#include "utl.c"
|
||||
|
||||
CMC_CREATE_UNIT(multimap_test, false, {
|
||||
CMC_CREATE_TEST(new, {
|
||||
multimap *map = mm_new(943722, 0.8, cmp, hash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
cmc_assert_not_equals(ptr, NULL, map->buffer);
|
||||
cmc_assert_equals(size_t, 0, mm_count(map));
|
||||
cmc_assert_greater_equals(size_t, (943722 / 0.8), mm_capacity(map));
|
||||
|
||||
mm_free(map);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(new[edge_case:capacity = 0], {
|
||||
multimap *map = mm_new(0, 0.8, cmp, hash);
|
||||
|
||||
cmc_assert_equals(ptr, NULL, map);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(new[edge_case:capacity = UINT64_MAX], {
|
||||
multimap *map = mm_new(UINT64_MAX, 0.8, cmp, hash);
|
||||
|
||||
cmc_assert_equals(ptr, NULL, map);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(clear[count capacity], {
|
||||
multimap *map = mm_new(100, 0.8, cmp, hash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
|
||||
for (size_t i = 0; i < 50; i++)
|
||||
cmc_assert(mm_insert(map, i, i));
|
||||
|
||||
cmc_assert_equals(size_t, 50, mm_count(map));
|
||||
|
||||
mm_clear(map);
|
||||
|
||||
cmc_assert_equals(size_t, 0, mm_count(map));
|
||||
|
||||
mm_free(map);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(insert[count], {
|
||||
multimap *map = mm_new(100, 0.8, cmp, hash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
|
||||
for (size_t i = 0; i < 200; i++)
|
||||
cmc_assert(mm_insert(map, i % 20, i % 20));
|
||||
|
||||
cmc_assert_equals(size_t, 200, mm_count(map));
|
||||
|
||||
mm_free(map);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(remove[count], {
|
||||
multimap *map = mm_new(100, 0.8, cmp, hash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
|
||||
for (size_t i = 0; i < 200; i++)
|
||||
cmc_assert(mm_insert(map, i % 20, i % 20));
|
||||
|
||||
size_t r;
|
||||
|
||||
for (size_t i = 0; i < 60; i++)
|
||||
cmc_assert(mm_remove(map, i % 20, &r));
|
||||
|
||||
cmc_assert_equals(size_t, 140, mm_count(map));
|
||||
|
||||
mm_free(map);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(remove[edge_case:count = 0], {
|
||||
multimap *map = mm_new(100, 0.8, cmp, hash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
|
||||
size_t r;
|
||||
|
||||
cmc_assert(!mm_remove(map, 10, &r));
|
||||
|
||||
mm_free(map);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(remove[edge_case:count = 1], {
|
||||
multimap *map = mm_new(100, 0.8, cmp, hash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
|
||||
size_t r;
|
||||
|
||||
cmc_assert(mm_insert(map, 10, 11));
|
||||
cmc_assert(mm_remove(map, 10, &r));
|
||||
|
||||
mm_free(map);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(insert_if, {
|
||||
multimap *map = mm_new(100, 0.8, cmp, hash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
|
||||
for (size_t i = 1; i <= 100; i++)
|
||||
cmc_assert(mm_insert_if(map, i % 20, i, i % 2 == 0) || i % 2 != 0);
|
||||
|
||||
cmc_assert_equals(size_t, 50, mm_count(map));
|
||||
|
||||
mm_free(map);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(remove_if, {
|
||||
multimap *map = mm_new(100, 0.8, cmp, hash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
|
||||
for (size_t i = 1; i <= 100; i++)
|
||||
cmc_assert(mm_insert(map, i % 20, i));
|
||||
|
||||
size_t r;
|
||||
|
||||
for (size_t i = 1; i <= 100; i++)
|
||||
cmc_assert(mm_remove_if(map, i % 20, &r, i % 2 == 0) || i % 2 != 0);
|
||||
|
||||
cmc_assert_equals(size_t, 50, mm_count(map));
|
||||
|
||||
mm_free(map);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(get[key_ordering], {
|
||||
multimap *map = mm_new(100, 0.8, cmp, hash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
|
||||
/* Assert that the value 100 is accessed before the value 101 for the
|
||||
* same key */
|
||||
cmc_assert(mm_insert(map, 10, 100));
|
||||
cmc_assert(mm_insert(map, 20, 102));
|
||||
cmc_assert(mm_insert(map, 10, 101));
|
||||
|
||||
cmc_assert_equals(size_t, 100, mm_get(map, 10));
|
||||
|
||||
mm_free(map);
|
||||
});
|
||||
|
||||
});
|
||||
@@ -0,0 +1,86 @@
|
||||
#include "utl/assert.h"
|
||||
#include "utl/test.h"
|
||||
#include "../src/multiset.c"
|
||||
|
||||
#include "utl.c"
|
||||
|
||||
CMC_CREATE_UNIT(multiset_test, false, {
|
||||
CMC_CREATE_TEST(new, {
|
||||
multiset *set = ms_new(943722, 0.6, cmp, hash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, set);
|
||||
cmc_assert_not_equals(ptr, NULL, set->buffer);
|
||||
cmc_assert_equals(size_t, 0, ms_count(set));
|
||||
cmc_assert_greater_equals(size_t, ((size_t)(943722 / 0.6)), ms_capacity(set));
|
||||
|
||||
ms_free(set);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(new[edge_case:capacity = 0], {
|
||||
multiset *set = ms_new(0, 0.6, cmp, hash);
|
||||
|
||||
cmc_assert_equals(ptr, NULL, set);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(new[edge_case:capacity = UINTMAX_MAX], {
|
||||
multiset *set = ms_new(UINTMAX_MAX, 0.99, cmp, hash);
|
||||
|
||||
cmc_assert_equals(ptr, NULL, set);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(clear[count capacity], {
|
||||
multiset *set = ms_new(100, 0.6, cmp, hash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, set);
|
||||
|
||||
for (size_t i = 0; i < 50; i++)
|
||||
cmc_assert(ms_insert(set, i));
|
||||
|
||||
cmc_assert_equals(size_t, 50, ms_count(set));
|
||||
|
||||
ms_clear(set);
|
||||
|
||||
cmc_assert_equals(size_t, 0, ms_count(set));
|
||||
|
||||
ms_free(set);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(insert[count cardinality multiplicity], {
|
||||
multiset *set = ms_new(100, 0.6, cmp, hash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, set);
|
||||
|
||||
cmc_assert(ms_insert(set, 1));
|
||||
cmc_assert(ms_insert(set, 2));
|
||||
cmc_assert(ms_insert(set, 2));
|
||||
cmc_assert(ms_insert(set, 3));
|
||||
cmc_assert(ms_insert(set, 3));
|
||||
cmc_assert(ms_insert(set, 3));
|
||||
|
||||
cmc_assert_equals(size_t, 3, ms_count(set));
|
||||
cmc_assert_equals(size_t, 6, ms_cardinality(set));
|
||||
|
||||
for (size_t i = 0; i <= 3; i++)
|
||||
cmc_assert_equals(size_t, i, ms_multiplicity_of(set, i));
|
||||
|
||||
ms_free(set);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(multiplicity, {
|
||||
multiset *set = ms_new(100, 0.6, cmp, hash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, set);
|
||||
|
||||
for (size_t i = 0; i < 100; i++)
|
||||
cmc_assert(ms_insert(set, i % 20));
|
||||
|
||||
cmc_assert_equals(size_t, 20, ms_count(set));
|
||||
cmc_assert_equals(size_t, 100, ms_cardinality(set));
|
||||
|
||||
for (size_t i = 0; i < 20; i++)
|
||||
cmc_assert_equals(size_t, 5, ms_multiplicity_of(set, i));
|
||||
|
||||
ms_free(set);
|
||||
});
|
||||
|
||||
});
|
||||
@@ -0,0 +1,61 @@
|
||||
#include "utl/assert.h"
|
||||
#include "utl/test.h"
|
||||
#include "../src/queue.c"
|
||||
|
||||
CMC_CREATE_UNIT(queue_test, false, {
|
||||
CMC_CREATE_TEST(new, {
|
||||
queue *q = q_new(1000000);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, q);
|
||||
cmc_assert_not_equals(ptr, NULL, q->buffer);
|
||||
cmc_assert_equals(size_t, 1000000, q_capacity(q));
|
||||
cmc_assert_equals(size_t, 0, q_count(q));
|
||||
cmc_assert_not_equals(ptr, NULL, q->buffer);
|
||||
|
||||
q_free(q);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(new[edge_case:capacity = 0], {
|
||||
queue *q = q_new(0);
|
||||
|
||||
cmc_assert_equals(ptr, NULL, q);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(new[edge_case:capacity = UINT64_MAX], {
|
||||
queue *q = q_new(UINT64_MAX);
|
||||
|
||||
cmc_assert_equals(ptr, NULL, q);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(clear[count capacity], {
|
||||
queue *q = q_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, q);
|
||||
|
||||
for (size_t i = 0; i < 50; i++)
|
||||
cmc_assert(q_enqueue(q, i));
|
||||
|
||||
cmc_assert_equals(size_t, 50, q_count(q));
|
||||
|
||||
q_clear(q);
|
||||
|
||||
cmc_assert_equals(size_t, 0, q_count(q));
|
||||
cmc_assert_equals(size_t, 100, q_capacity(q));
|
||||
|
||||
q_free(q);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(buffer_growth[edge_case:capacity = 1], {
|
||||
queue *q = q_new(1);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, q);
|
||||
|
||||
for (size_t i = 0; i < 50; i++)
|
||||
cmc_assert(q_enqueue(q, i));
|
||||
|
||||
cmc_assert_equals(size_t, 50, q_count(q));
|
||||
|
||||
q_free(q);
|
||||
});
|
||||
|
||||
});
|
||||
@@ -0,0 +1,628 @@
|
||||
#include "utl/assert.h"
|
||||
#include "utl/test.h"
|
||||
#include "../src/stack.c"
|
||||
|
||||
#include "utl.c"
|
||||
|
||||
CMC_CREATE_UNIT(stack_test, false, {
|
||||
CMC_CREATE_TEST(new, {
|
||||
stack *s = s_new(1000000);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, s);
|
||||
cmc_assert_not_equals(ptr, NULL, s->buffer);
|
||||
cmc_assert_equals(size_t, 1000000, s_capacity(s));
|
||||
cmc_assert_equals(size_t, 0, s_count(s));
|
||||
cmc_assert_not_equals(ptr, NULL, s->buffer);
|
||||
|
||||
s_free(s);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(new[edge_case:capacity = 0], {
|
||||
stack *s = s_new(0);
|
||||
|
||||
cmc_assert_equals(ptr, NULL, s);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(new[edge_case:capacity = UINT64_MAX], {
|
||||
stack *s = s_new(UINT64_MAX);
|
||||
|
||||
cmc_assert_equals(ptr, NULL, s);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(clear[count capacity], {
|
||||
stack *s = s_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, s);
|
||||
|
||||
for (size_t i = 0; i < 50; i++)
|
||||
cmc_assert(s_push(s, i));
|
||||
|
||||
cmc_assert_equals(size_t, 50, s_count(s));
|
||||
|
||||
s_clear(s);
|
||||
|
||||
cmc_assert_equals(size_t, 0, s_count(s));
|
||||
cmc_assert_equals(size_t, 100, s_capacity(s));
|
||||
|
||||
s_free(s);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(buffer_growth[edge_case:capacity = 1], {
|
||||
stack *s = s_new(1);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, s);
|
||||
|
||||
for (size_t i = 0; i < 50; i++)
|
||||
cmc_assert(s_push(s, i));
|
||||
|
||||
cmc_assert_equals(size_t, 50, s_count(s));
|
||||
cmc_assert_lesser_equals(size_t, s_capacity(s), s_count(s));
|
||||
|
||||
s_free(s);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(push[count], {
|
||||
stack *s = s_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, s);
|
||||
|
||||
for (size_t i = 0; i < 250; i++)
|
||||
cmc_assert(s_push(s, i));
|
||||
|
||||
cmc_assert_equals(size_t, 250, s_count(s));
|
||||
|
||||
s_free(s);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(push[capacity], {
|
||||
stack *s = s_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, s);
|
||||
|
||||
for (size_t i = 0; i < 250; i++)
|
||||
cmc_assert(s_push(s, i));
|
||||
|
||||
cmc_assert_lesser_equals(size_t, s_capacity(s), s_count(s));
|
||||
|
||||
s_free(s);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(push[item_preservation], {
|
||||
stack *s = s_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, s);
|
||||
|
||||
for (size_t i = 0; i < 250; i++)
|
||||
cmc_assert(s_push(s, i));
|
||||
|
||||
for (size_t i = 0; i < s_count(s); i++)
|
||||
cmc_assert_equals(size_t, i, s->buffer[i]);
|
||||
|
||||
s_free(s);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(pop[count], {
|
||||
stack *s = s_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, s);
|
||||
|
||||
for (size_t i = 0; i < 250; i++)
|
||||
cmc_assert(s_push(s, i));
|
||||
|
||||
cmc_assert(s_pop(s));
|
||||
|
||||
cmc_assert_equals(size_t, 249, s_count(s));
|
||||
|
||||
s_free(s);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(pop[capacity], {
|
||||
stack *s = s_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, s);
|
||||
|
||||
for (size_t i = 0; i < 250; i++)
|
||||
cmc_assert(s_push(s, i));
|
||||
|
||||
cmc_assert(s_pop(s));
|
||||
|
||||
cmc_assert_lesser_equals(size_t, s_capacity(s), s_count(s));
|
||||
|
||||
s_free(s);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(pop[item_preservation], {
|
||||
stack *s = s_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, s);
|
||||
|
||||
for (size_t i = 0; i < 250; i++)
|
||||
cmc_assert(s_push(s, i));
|
||||
|
||||
cmc_assert(s_pop(s));
|
||||
cmc_assert(s_pop(s));
|
||||
|
||||
for (size_t i = 0; i < s_count(s); i++)
|
||||
cmc_assert_equals(size_t, i, s->buffer[i]);
|
||||
|
||||
s_free(s);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(pop[edge_case:count = 0], {
|
||||
stack *s = s_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, s);
|
||||
|
||||
cmc_assert_equals(bool, false, s_pop(s));
|
||||
|
||||
s_free(s);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(push_if, {
|
||||
stack *s = s_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, s);
|
||||
|
||||
for (size_t i = 0; i < 250; i++)
|
||||
s_push_if(s, i, i % 2 == 0);
|
||||
|
||||
for (size_t i = 0; i < s_count(s); i++)
|
||||
cmc_assert(s->buffer[i] % 2 == 0);
|
||||
|
||||
s_free(s);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(pop_if, {
|
||||
stack *s = s_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, s);
|
||||
|
||||
for (size_t i = 0; i < 250; i++)
|
||||
{
|
||||
s_push(s, i);
|
||||
s_pop_if(s, s_top(s) % 2 == 0);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < s_count(s); i++)
|
||||
cmc_assert_not_equals(uint32_t, 0, s->buffer[i] % 2);
|
||||
|
||||
s_free(s);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(top, {
|
||||
stack *s = s_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, s);
|
||||
|
||||
for (size_t i = 0; i < 250; i++)
|
||||
cmc_assert(s_push(s, i));
|
||||
|
||||
cmc_assert(s_pop(s));
|
||||
cmc_assert(s_pop(s));
|
||||
|
||||
cmc_assert_equals(size_t, 247, s_top(s));
|
||||
|
||||
s_free(s);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(top[edge_case:count = 0], {
|
||||
stack *s = s_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, s);
|
||||
|
||||
cmc_assert(s_push(s, 1));
|
||||
|
||||
cmc_assert(s_pop(s));
|
||||
|
||||
cmc_assert_equals(size_t, s_impl_default_value(), s_top(s));
|
||||
|
||||
s_free(s);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(top[edge_case:count = 1], {
|
||||
stack *s = s_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, s);
|
||||
|
||||
cmc_assert(s_push(s, 10));
|
||||
cmc_assert_equals(size_t, 1, s_count(s));
|
||||
cmc_assert_equals(size_t, 10, s_top(s));
|
||||
|
||||
s_free(s);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(contains, {
|
||||
stack *s = s_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, s);
|
||||
|
||||
for (size_t i = 0; i < 150; i++)
|
||||
cmc_assert(s_push(s, i));
|
||||
|
||||
for (size_t i = 0; i < 150; i++)
|
||||
cmc_assert(s_contains(s, i, cmp));
|
||||
|
||||
s_free(s);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(contains[edge_case:count = 0], {
|
||||
stack *s = s_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, s);
|
||||
|
||||
cmc_assert_equals(bool, false, s_contains(s, 10, cmp));
|
||||
|
||||
s_free(s);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(empty, {
|
||||
stack *s = s_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, s);
|
||||
|
||||
cmc_assert(s_empty(s));
|
||||
|
||||
s_free(s);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(empty[after_io], {
|
||||
stack *s = s_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, s);
|
||||
|
||||
cmc_assert(s_push(s, 10));
|
||||
cmc_assert(s_pop(s));
|
||||
cmc_assert(s_empty(s));
|
||||
|
||||
s_free(s);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(full, {
|
||||
stack *s = s_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, s);
|
||||
|
||||
for (size_t i = 0; i < s_capacity(s); i++)
|
||||
cmc_assert(s_push(s, i));
|
||||
|
||||
cmc_assert(s_full(s));
|
||||
|
||||
s_free(s);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(full[edge_case:capacity = 1], {
|
||||
stack *s = s_new(1);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, s);
|
||||
|
||||
cmc_assert(s_push(s, 10));
|
||||
|
||||
cmc_assert(s_full(s));
|
||||
|
||||
s_free(s);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(iter_alloc, {
|
||||
stack *s = s_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, s);
|
||||
|
||||
stack_iter *iter = s_iter_new(s);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, iter);
|
||||
|
||||
s_iter_free(iter);
|
||||
s_free(s);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(iter_init[edge_case:count = 0], {
|
||||
stack *s = s_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, s);
|
||||
|
||||
stack_iter iter;
|
||||
|
||||
s_iter_init(&iter, s);
|
||||
|
||||
cmc_assert_equals(ptr, iter.target, s);
|
||||
cmc_assert_equals(size_t, iter.cursor, 0);
|
||||
cmc_assert(iter.start);
|
||||
cmc_assert(iter.end);
|
||||
|
||||
s_free(s);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(iter_start[edge_case:count = 0], {
|
||||
stack *s = s_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, s);
|
||||
|
||||
stack_iter iter;
|
||||
|
||||
s_iter_init(&iter, s);
|
||||
|
||||
cmc_assert(s_iter_start(&iter));
|
||||
|
||||
s_free(s);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(iter_end[edge_case:count = 0], {
|
||||
stack *s = s_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, s);
|
||||
|
||||
stack_iter iter;
|
||||
|
||||
s_iter_init(&iter, s);
|
||||
|
||||
cmc_assert(s_iter_end(&iter));
|
||||
|
||||
s_free(s);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(iteration, {
|
||||
stack *s = s_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, s);
|
||||
|
||||
for (size_t i = 1; i <= 200; i++)
|
||||
cmc_assert(s_push(s, i));
|
||||
|
||||
size_t total = 0;
|
||||
|
||||
for (stack_iter it = s->it_start(s); !s_iter_end(&it); s_iter_next(&it))
|
||||
{
|
||||
total += s_iter_value(&it);
|
||||
}
|
||||
|
||||
cmc_assert_equals(size_t, 20100, total);
|
||||
|
||||
for (stack_iter it = s->it_end(s); !s_iter_start(&it); s_iter_prev(&it))
|
||||
{
|
||||
total += s_iter_value(&it);
|
||||
}
|
||||
|
||||
cmc_assert_equals(size_t, 40200, total);
|
||||
|
||||
s_free(s);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(iteration[while loop], {
|
||||
stack *s = s_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, s);
|
||||
|
||||
for (size_t i = 1; i <= 200; i++)
|
||||
cmc_assert(s_push(s, i));
|
||||
|
||||
size_t total = 0;
|
||||
stack_iter it = s->it_start(s);
|
||||
|
||||
do
|
||||
{
|
||||
total += s_iter_value(&it);
|
||||
} while (s_iter_next(&it));
|
||||
|
||||
cmc_assert_equals(size_t, 20100, total);
|
||||
|
||||
it = s->it_end(s);
|
||||
|
||||
do
|
||||
{
|
||||
total += s_iter_value(&it);
|
||||
} while (s_iter_prev(&it));
|
||||
|
||||
cmc_assert_equals(size_t, 40200, total);
|
||||
|
||||
s_free(s);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(iteration[edge_case:count = 1], {
|
||||
stack *s = s_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, s);
|
||||
cmc_assert(s_push(s, 10));
|
||||
|
||||
size_t total = 0;
|
||||
|
||||
for (stack_iter it = s->it_start(s); !s_iter_end(&it); s_iter_next(&it))
|
||||
{
|
||||
total += s_iter_value(&it);
|
||||
}
|
||||
|
||||
for (stack_iter it = s->it_end(s); !s_iter_start(&it); s_iter_prev(&it))
|
||||
{
|
||||
total += s_iter_value(&it);
|
||||
}
|
||||
|
||||
cmc_assert_equals(size_t, 20, total);
|
||||
|
||||
s_free(s);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(iteration[edge_case:count = capacity], {
|
||||
stack *s = s_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, s);
|
||||
|
||||
while (!s_full(s))
|
||||
cmc_assert(s_push(s, 10));
|
||||
|
||||
cmc_assert_equals(size_t, s_capacity(s), s_count(s));
|
||||
|
||||
size_t total = 0;
|
||||
|
||||
for (stack_iter it = s->it_start(s); !s_iter_end(&it); s_iter_next(&it))
|
||||
{
|
||||
total += s_iter_value(&it);
|
||||
}
|
||||
|
||||
cmc_assert_equals(size_t, 1000, total);
|
||||
|
||||
for (stack_iter it = s->it_end(s); !s_iter_start(&it); s_iter_prev(&it))
|
||||
{
|
||||
total += *s_iter_rvalue(&it);
|
||||
}
|
||||
|
||||
cmc_assert_equals(size_t, 2000, total);
|
||||
|
||||
s_free(s);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(iteration[to_start = it_start and to_end = it_end], {
|
||||
stack *s = s_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, s);
|
||||
|
||||
for (size_t i = 0; i < 50; i++)
|
||||
cmc_assert(s_push(s, i));
|
||||
|
||||
stack_iter it1;
|
||||
stack_iter it2;
|
||||
|
||||
memset(&it1, 0, sizeof(stack_iter));
|
||||
memset(&it2, 0, sizeof(stack_iter));
|
||||
|
||||
s_iter_init(&it2, s);
|
||||
|
||||
it1 = s->it_start(s);
|
||||
s_iter_to_start(&it2);
|
||||
|
||||
cmc_assert_equals(ptr, it1.target, it2.target);
|
||||
cmc_assert_equals(size_t, it1.cursor, it2.cursor);
|
||||
cmc_assert_equals(bool, it1.start, it2.start);
|
||||
cmc_assert_equals(bool, it1.end, it2.end);
|
||||
|
||||
it1 = s->it_end(s);
|
||||
s_iter_to_end(&it2);
|
||||
|
||||
cmc_assert_equals(ptr, it1.target, it2.target);
|
||||
cmc_assert_equals(size_t, it1.cursor, it2.cursor);
|
||||
cmc_assert_equals(bool, it1.start, it2.start);
|
||||
cmc_assert_equals(bool, it1.end, it2.end);
|
||||
|
||||
s_free(s);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(iteration[boundaries:count = 0], {
|
||||
stack *s = s_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, s);
|
||||
|
||||
stack_iter iter;
|
||||
s_iter_init(&iter, s);
|
||||
|
||||
s_iter_to_end(&iter);
|
||||
|
||||
cmc_assert_equals(bool, false, s_iter_next(&iter));
|
||||
|
||||
s_iter_to_start(&iter);
|
||||
|
||||
cmc_assert_equals(bool, false, s_iter_prev(&iter));
|
||||
|
||||
s_free(s);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(iteration[boundaries:count > 0], {
|
||||
stack *s = s_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, s);
|
||||
|
||||
for (size_t i = 0; i < 200; i++)
|
||||
cmc_assert(s_push(s, i));
|
||||
|
||||
stack_iter iter;
|
||||
s_iter_init(&iter, s);
|
||||
|
||||
s_iter_to_end(&iter);
|
||||
|
||||
cmc_assert_equals(bool, false, s_iter_next(&iter));
|
||||
|
||||
s_iter_to_start(&iter);
|
||||
|
||||
cmc_assert_equals(bool, false, s_iter_prev(&iter));
|
||||
|
||||
s_free(s);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(iter_value[edge_case:count = 0], {
|
||||
stack *s = s_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, s);
|
||||
|
||||
stack_iter iter;
|
||||
|
||||
s_iter_init(&iter, s);
|
||||
|
||||
cmc_assert_equals(size_t, s_impl_default_value(), s_iter_value(&iter));
|
||||
|
||||
s_free(s);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(iter_rvalue[edge_case:count = 0], {
|
||||
stack *s = s_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, s);
|
||||
|
||||
stack_iter iter;
|
||||
|
||||
s_iter_init(&iter, s);
|
||||
|
||||
cmc_assert_equals(ptr, NULL, s_iter_rvalue(&iter));
|
||||
|
||||
s_free(s);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(index, {
|
||||
stack *s = s_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, s);
|
||||
|
||||
for (size_t i = 0; i < 10; i++)
|
||||
cmc_assert(s_push(s, i));
|
||||
|
||||
cmc_assert_equals(size_t, 10, s_count(s));
|
||||
|
||||
size_t total = 0;
|
||||
|
||||
for (stack_iter it = s->it_start(s); false; )
|
||||
{
|
||||
cmc_assert_equals(size_t, 0, s_iter_index(&it));
|
||||
}
|
||||
|
||||
for (stack_iter it = s->it_start(s); false; )
|
||||
{
|
||||
cmc_assert_equals(size_t, s_count(s) - 1, s_iter_index(&it));
|
||||
}
|
||||
|
||||
for (stack_iter it = s->it_start(s); !s_iter_end(&it); s_iter_next(&it))
|
||||
{
|
||||
total += s_iter_index(&it);
|
||||
}
|
||||
|
||||
cmc_assert_equals(size_t, 45, total);
|
||||
|
||||
for (stack_iter it = s->it_end(s); !s_iter_start(&it); s_iter_prev(&it))
|
||||
{
|
||||
total += s_iter_index(&it);
|
||||
}
|
||||
|
||||
cmc_assert_equals(size_t, 90, total);
|
||||
|
||||
s_free(s);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(index[edge_case:count = 0], {
|
||||
stack *s = s_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, s);
|
||||
|
||||
stack_iter iter;
|
||||
s_iter_init(&iter, s);
|
||||
|
||||
cmc_assert_equals(size_t, 0, s_iter_index(&iter));
|
||||
|
||||
s_free(s);
|
||||
});
|
||||
|
||||
});
|
||||
@@ -0,0 +1,34 @@
|
||||
#include "utl/assert.h"
|
||||
#include "utl/test.h"
|
||||
#include "../src/treemap.c"
|
||||
|
||||
#include "utl.c"
|
||||
|
||||
CMC_CREATE_UNIT(treemap_test, false, {
|
||||
CMC_CREATE_TEST(new, {
|
||||
treemap *map = tm_new(cmp);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
|
||||
tm_free(map);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(clear[count], {
|
||||
treemap *map = tm_new(cmp);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
|
||||
for (size_t i = 0; i < 50; i++)
|
||||
tm_insert(map, i, i);
|
||||
|
||||
cmc_assert_equals(size_t, 50, tm_count(map));
|
||||
|
||||
tm_clear(map);
|
||||
|
||||
cmc_assert_equals(size_t, 0, tm_count(map));
|
||||
cmc_assert_equals(ptr, NULL, map->root);
|
||||
|
||||
tm_free(map);
|
||||
});
|
||||
|
||||
});
|
||||
@@ -0,0 +1,34 @@
|
||||
#include "utl/assert.h"
|
||||
#include "utl/test.h"
|
||||
#include "../src/treeset.c"
|
||||
|
||||
#include "utl.c"
|
||||
|
||||
CMC_CREATE_UNIT(treeset_test, false, {
|
||||
CMC_CREATE_TEST(new, {
|
||||
treeset *set = ts_new(cmp);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, set);
|
||||
|
||||
ts_free(set);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(clear[count], {
|
||||
treeset *set = ts_new(cmp);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, set);
|
||||
|
||||
for (size_t i = 0; i < 50; i++)
|
||||
ts_insert(set, i);
|
||||
|
||||
cmc_assert_equals(size_t, 50, ts_count(set));
|
||||
|
||||
ts_clear(set);
|
||||
|
||||
cmc_assert_equals(size_t, 0, ts_count(set));
|
||||
cmc_assert_equals(ptr, NULL, set->root);
|
||||
|
||||
ts_free(set);
|
||||
});
|
||||
|
||||
});
|
||||
@@ -0,0 +1,23 @@
|
||||
/* Utility file to be included in the unit tests */
|
||||
#ifndef CMC_UNIT_TEST_UTL__
|
||||
#define CMC_UNIT_TEST_UTL__
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
int cmp(size_t a, size_t b)
|
||||
{
|
||||
return (a > b) - (a < b);
|
||||
}
|
||||
|
||||
size_t hash(size_t a)
|
||||
{
|
||||
a += ~(a << 15);
|
||||
a ^= (a >> 10);
|
||||
a += (a << 3);
|
||||
a ^= (a >> 6);
|
||||
a += ~(a << 11);
|
||||
a ^= (a >> 16);
|
||||
return a;
|
||||
}
|
||||
|
||||
#endif /* CMC_UNIT_TEST_UTL__ */
|
||||
+109
-55
@@ -20,16 +20,20 @@ size_t inthash(int t)
|
||||
return a;
|
||||
}
|
||||
|
||||
COLLECTION_GENERATE(LIST, l, list, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE(STACK, s, stack, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE(QUEUE, q, queue, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE(DEQUE, d, deque, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE(LINKEDLIST, ll, linked, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE(HEAP, h, heap, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE(TREESET, ts, tset, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE(TREEMAP, tm, tmap, /* FMOD */, int, int)
|
||||
COLLECTION_GENERATE(HASHSET, hs, hset, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE(HASHMAP, hm, hmap, /* FMOD */, int, int)
|
||||
CMC_COLLECTION_GENERATE(LIST, l, list, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE(STACK, s, stack, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE(QUEUE, q, queue, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE(DEQUE, d, deque, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE(LINKEDLIST, ll, linked, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE(HEAP, h, heap, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE(TREESET, ts, tset, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE(TREEMAP, tm, tmap, int, int)
|
||||
CMC_COLLECTION_GENERATE(HASHSET, hs, hset, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE(HASHMAP, hm, hmap, int, int)
|
||||
|
||||
CMC_COLLECTION_GENERATE(INTERVALHEAP, ih, iheap, , int)
|
||||
CMC_COLLECTION_GENERATE(MULTIMAP, mm, mmap, int, int)
|
||||
CMC_COLLECTION_GENERATE(MULTISET, ms, mset, , int)
|
||||
|
||||
int main(void)
|
||||
{
|
||||
@@ -41,12 +45,16 @@ int main(void)
|
||||
heap *h = h_new(1000, cmc_max_heap, 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);
|
||||
hset *hs = hs_new(1000, 0.6, intcmp, inthash);
|
||||
hmap *hm = hm_new(1000, 0.6, 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};
|
||||
iheap *ih = ih_new(1000, intcmp);
|
||||
mmap *mm = mm_new(1000, 0.8, intcmp, inthash);
|
||||
mset *ms = ms_new(1000, 0.6, intcmp, inthash);
|
||||
|
||||
bool a[13] = {false, false, false, false, false, false, false, false, false, false, false, false, false},
|
||||
b[13] = {false, false, false, false, false, false, false, false, false, false, false, false, false},
|
||||
c[13] = {true, true, true, true, true, true, true, true, true, true, true, true, true};
|
||||
|
||||
b[0] = d_contains(d, 1, intcmp);
|
||||
b[1] = hm_contains(hm, 1);
|
||||
@@ -59,6 +67,10 @@ int main(void)
|
||||
b[8] = tm_contains(tm, 1);
|
||||
b[9] = ts_contains(ts, 1);
|
||||
|
||||
b[10] = ih_contains(ih, 1);
|
||||
b[11] = mm_contains(mm, 1);
|
||||
b[12] = ms_contains(ms, 1);
|
||||
|
||||
for (int i = 1; i < 1001; i++)
|
||||
{
|
||||
if (i % 2 == 0)
|
||||
@@ -81,6 +93,10 @@ int main(void)
|
||||
tm_insert(tm, i, i);
|
||||
hs_insert(hs, i);
|
||||
hm_insert(hm, i, i);
|
||||
|
||||
ih_insert(ih, i);
|
||||
mm_insert(mm, i, i);
|
||||
ms_insert(ms, i);
|
||||
}
|
||||
|
||||
for (int i = 1; i < 1001; i++)
|
||||
@@ -95,6 +111,10 @@ int main(void)
|
||||
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);
|
||||
|
||||
c[10] = c[10] && ih_contains(ih, i);
|
||||
c[11] = c[11] && mm_contains(mm, i);
|
||||
c[12] = c[12] && ms_contains(ms, i);
|
||||
}
|
||||
|
||||
for (int i = -500; i < 1; i++)
|
||||
@@ -109,6 +129,10 @@ int main(void)
|
||||
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);
|
||||
|
||||
a[10] = a[10] || ih_contains(ih, i);
|
||||
a[11] = a[11] || mm_contains(mm, i);
|
||||
a[12] = a[12] || ms_contains(ms, i);
|
||||
}
|
||||
|
||||
for (int i = 1001; i < 1500; i++)
|
||||
@@ -123,18 +147,26 @@ int main(void)
|
||||
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);
|
||||
|
||||
a[10] = a[10] || ih_contains(ih, i);
|
||||
a[11] = a[11] || mm_contains(mm, i);
|
||||
a[12] = a[12] || ms_contains(ms, 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);
|
||||
d_clear(d, NULL);
|
||||
hm_clear(hm, NULL);
|
||||
hs_clear(hs, NULL);
|
||||
h_clear(h, NULL);
|
||||
ll_clear(ll, NULL);
|
||||
l_clear(l, NULL);
|
||||
q_clear(q, NULL);
|
||||
s_clear(s, NULL);
|
||||
tm_clear(tm, NULL);
|
||||
ts_clear(ts, NULL);
|
||||
|
||||
ih_clear(ih, NULL);
|
||||
mm_clear(mm, NULL);
|
||||
ms_clear(ms, NULL);
|
||||
|
||||
b[0] = b[0] || d_contains(d, 1, intcmp);
|
||||
b[1] = b[1] || hm_contains(hm, 1);
|
||||
@@ -147,58 +179,80 @@ int main(void)
|
||||
b[8] = b[8] || tm_contains(tm, 1);
|
||||
b[9] = b[9] || ts_contains(ts, 1);
|
||||
|
||||
b[10] = b[10] || ih_contains(ih, 1);
|
||||
b[11] = b[11] || mm_contains(mm, 1);
|
||||
b[12] = b[12] || ms_contains(ms, 1);
|
||||
|
||||
printf("-------------------- CONTAINS --------------------\n");
|
||||
if (c[0] && !a[0] && !b[0])
|
||||
printf("%10s PASSED\n", "DEQUE");
|
||||
printf("%12s PASSED\n", "DEQUE");
|
||||
else
|
||||
printf("%10s FAILED\n", "DEQUE");
|
||||
printf("%12s FAILED\n", "DEQUE");
|
||||
if (c[1] && !a[1] && !b[1])
|
||||
printf("%10s PASSED\n", "HASHMAP");
|
||||
printf("%12s PASSED\n", "HASHMAP");
|
||||
else
|
||||
printf("%10s FAILED\n", "HASHMAP");
|
||||
printf("%12s FAILED\n", "HASHMAP");
|
||||
if (c[2] && !a[2] && !b[2])
|
||||
printf("%10s PASSED\n", "HASHSET");
|
||||
printf("%12s PASSED\n", "HASHSET");
|
||||
else
|
||||
printf("%10s FAILED\n", "HASHSET");
|
||||
printf("%12s FAILED\n", "HASHSET");
|
||||
if (c[3] && !a[3] && !b[3])
|
||||
printf("%10s PASSED\n", "HEAP");
|
||||
printf("%12s PASSED\n", "HEAP");
|
||||
else
|
||||
printf("%10s FAILED\n", "HEAP");
|
||||
printf("%12s FAILED\n", "HEAP");
|
||||
if (c[4] && !a[4] && !b[4])
|
||||
printf("%10s PASSED\n", "LINKEDLIST");
|
||||
printf("%12s PASSED\n", "LINKEDLIST");
|
||||
else
|
||||
printf("%10s FAILED\n", "LINKEDLIST");
|
||||
printf("%12s FAILED\n", "LINKEDLIST");
|
||||
if (c[5] && !a[5] && !b[5])
|
||||
printf("%10s PASSED\n", "LIST");
|
||||
printf("%12s PASSED\n", "LIST");
|
||||
else
|
||||
printf("%10s FAILED\n", "LIST");
|
||||
printf("%12s FAILED\n", "LIST");
|
||||
if (c[6] && !a[6] && !b[6])
|
||||
printf("%10s PASSED\n", "QUEUE");
|
||||
printf("%12s PASSED\n", "QUEUE");
|
||||
else
|
||||
printf("%10s FAILED\n", "QUEUE");
|
||||
printf("%12s FAILED\n", "QUEUE");
|
||||
if (c[7] && !a[7] && !b[7])
|
||||
printf("%10s PASSED\n", "STACK");
|
||||
printf("%12s PASSED\n", "STACK");
|
||||
else
|
||||
printf("%10s FAILED\n", "STACK");
|
||||
printf("%12s FAILED\n", "STACK");
|
||||
if (c[8] && !a[8] && !b[8])
|
||||
printf("%10s PASSED\n", "TREEMAP");
|
||||
printf("%12s PASSED\n", "TREEMAP");
|
||||
else
|
||||
printf("%10s FAILED\n", "TREEMAP");
|
||||
printf("%12s FAILED\n", "TREEMAP");
|
||||
if (c[9] && !a[9] && !b[9])
|
||||
printf("%10s PASSED\n", "TREESET");
|
||||
printf("%12s PASSED\n", "TREESET");
|
||||
else
|
||||
printf("%10s FAILED\n", "TREESET");
|
||||
printf("%12s FAILED\n", "TREESET");
|
||||
if (c[10] && !a[10] && !b[10])
|
||||
printf("%12s PASSED\n", "INTERVALHEAP");
|
||||
else
|
||||
printf("%12s FAILED\n", "INTERVALHEAP");
|
||||
if (c[11] && !a[11] && !b[11])
|
||||
printf("%12s PASSED\n", "MULTIMAP");
|
||||
else
|
||||
printf("%12s FAILED\n", "MULTIMAP");
|
||||
if (c[12] && !a[12] && !b[12])
|
||||
printf("%12s PASSED\n", "MULTISET");
|
||||
else
|
||||
printf("%12s FAILED\n", "MULTISET");
|
||||
|
||||
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);
|
||||
printf("\n\n");
|
||||
|
||||
l_free(l, NULL);
|
||||
ll_free(ll, NULL);
|
||||
s_free(s, NULL);
|
||||
q_free(q, NULL);
|
||||
d_free(d, NULL);
|
||||
h_free(h, NULL);
|
||||
ts_free(ts, NULL);
|
||||
tm_free(tm, NULL);
|
||||
hs_free(hs, NULL);
|
||||
hm_free(hm, NULL);
|
||||
|
||||
ih_free(ih, NULL);
|
||||
mm_free(mm, NULL);
|
||||
ms_free(ms, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
+224
-155
@@ -1,5 +1,6 @@
|
||||
#include "../src/macro_collections.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
int intcmp(int a, int b)
|
||||
@@ -19,16 +20,20 @@ size_t inthash(int t)
|
||||
return a;
|
||||
}
|
||||
|
||||
COLLECTION_GENERATE(LIST, l, list, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE(STACK, s, stack, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE(QUEUE, q, queue, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE(DEQUE, d, deque, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE(LINKEDLIST, ll, linked, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE(HEAP, h, heap, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE(TREESET, ts, tset, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE(TREEMAP, tm, tmap, /* FMOD */, int, int)
|
||||
COLLECTION_GENERATE(HASHSET, hs, hset, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE(HASHMAP, hm, hmap, /* FMOD */, int, int)
|
||||
CMC_COLLECTION_GENERATE(LIST, l, list, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE(STACK, s, stack, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE(QUEUE, q, queue, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE(DEQUE, d, deque, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE(LINKEDLIST, ll, linked, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE(HEAP, h, heap, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE(TREESET, ts, tset, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE(TREEMAP, tm, tmap, int, int)
|
||||
CMC_COLLECTION_GENERATE(HASHSET, hs, hset, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE(HASHMAP, hm, hmap, int, int)
|
||||
|
||||
CMC_COLLECTION_GENERATE(INTERVALHEAP, ih, iheap, , int)
|
||||
CMC_COLLECTION_GENERATE(MULTIMAP, mm, mmap, int, int)
|
||||
CMC_COLLECTION_GENERATE(MULTISET, ms, mset, , int)
|
||||
|
||||
int main(void)
|
||||
{
|
||||
@@ -40,219 +45,283 @@ int main(void)
|
||||
heap *h = h_new(1000, cmc_max_heap, 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);
|
||||
hset *hs = hs_new(1000, 0.6, intcmp, inthash);
|
||||
hmap *hm = hm_new(1000, 0.6, intcmp, inthash);
|
||||
|
||||
iheap *ih = ih_new(1000, intcmp);
|
||||
mmap *mm = mm_new(1000, 0.8, intcmp, inthash);
|
||||
mset *ms = ms_new(1000, 0.6, intcmp, inthash);
|
||||
|
||||
bool p = true;
|
||||
|
||||
for (int i = 1; i < 10001; i++)
|
||||
{
|
||||
if (i % 2 == 0)
|
||||
{
|
||||
d_push_front(d, i);
|
||||
l_push_front(l, i);
|
||||
ll_push_front(ll, i);
|
||||
assert(d_push_front(d, i));
|
||||
assert(l_push_front(l, i));
|
||||
assert(ll_push_front(ll, i));
|
||||
}
|
||||
else
|
||||
{
|
||||
d_push_back(d, i);
|
||||
l_push_back(l, i);
|
||||
ll_push_back(ll, i);
|
||||
assert(d_push_back(d, i));
|
||||
assert(l_push_back(l, i));
|
||||
assert(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);
|
||||
assert(s_push(s, i));
|
||||
assert(q_enqueue(q, i));
|
||||
assert(h_insert(h, i));
|
||||
assert(ts_insert(ts, i));
|
||||
assert(tm_insert(tm, i, i));
|
||||
assert(hs_insert(hs, i));
|
||||
assert(hm_insert(hm, i, i));
|
||||
|
||||
assert(ih_insert(ih, i));
|
||||
assert(mm_insert(mm, i, i));
|
||||
assert(ms_insert(ms, i));
|
||||
}
|
||||
|
||||
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;
|
||||
int sums[16] = {0};
|
||||
|
||||
FOR_EACH(d, deque, d, {
|
||||
sum3 += d_iter_value(&iter);
|
||||
CMC_FOR_EACH(d, deque, d, {
|
||||
sums[0] += d_iter_value(&iter);
|
||||
});
|
||||
|
||||
FOR_EACH(hm, hmap, hm, {
|
||||
sum10 += hm_iter_key(&iter);
|
||||
sum11 += hm_iter_value(&iter);
|
||||
CMC_FOR_EACH(hm, hmap, hm, {
|
||||
sums[1] += hm_iter_key(&iter);
|
||||
sums[2] += hm_iter_value(&iter);
|
||||
});
|
||||
|
||||
FOR_EACH(hs, hset, hs, {
|
||||
sum9 += hs_iter_value(&iter);
|
||||
CMC_FOR_EACH(hs, hset, hs, {
|
||||
sums[3] += hs_iter_value(&iter);
|
||||
});
|
||||
|
||||
FOR_EACH(h, heap, h, {
|
||||
sum5 += h_iter_value(&iter);
|
||||
CMC_FOR_EACH(h, heap, h, {
|
||||
sums[4] += h_iter_value(&iter);
|
||||
});
|
||||
|
||||
FOR_EACH(ll, linked, ll, {
|
||||
sum4 += ll_iter_value(&iter);
|
||||
CMC_FOR_EACH(ll, linked, ll, {
|
||||
sums[5] += ll_iter_value(&iter);
|
||||
});
|
||||
|
||||
FOR_EACH(l, list, l, {
|
||||
sum0 += l_iter_value(&iter);
|
||||
CMC_FOR_EACH(l, list, l, {
|
||||
sums[6] += l_iter_value(&iter);
|
||||
});
|
||||
|
||||
FOR_EACH(q, queue, q, {
|
||||
sum2 += q_iter_value(&iter);
|
||||
CMC_FOR_EACH(q, queue, q, {
|
||||
sums[7] += q_iter_value(&iter);
|
||||
});
|
||||
|
||||
FOR_EACH(s, stack, s, {
|
||||
sum1 += s_iter_value(&iter);
|
||||
CMC_FOR_EACH(s, stack, s, {
|
||||
sums[8] += s_iter_value(&iter);
|
||||
});
|
||||
|
||||
FOR_EACH(tm, tmap, tm, {
|
||||
sum7 += tm_iter_key(&iter);
|
||||
sum8 += tm_iter_value(&iter);
|
||||
CMC_FOR_EACH(tm, tmap, tm, {
|
||||
sums[9] += tm_iter_key(&iter);
|
||||
sums[10] += tm_iter_value(&iter);
|
||||
});
|
||||
|
||||
FOR_EACH(ts, tset, ts, {
|
||||
sum6 += ts_iter_value(&iter);
|
||||
CMC_FOR_EACH(ts, tset, ts, {
|
||||
sums[11] += ts_iter_value(&iter);
|
||||
});
|
||||
|
||||
printf("\n-------------------- FOR_EACH --------------------\n");
|
||||
if (sum3 == 50005000)
|
||||
printf("%10s PASSED\n", "DEQUE");
|
||||
CMC_FOR_EACH(ih, iheap, ih, {
|
||||
sums[12] += ih_iter_value(&iter);
|
||||
});
|
||||
|
||||
CMC_FOR_EACH(mm, mmap, mm, {
|
||||
sums[13] += mm_iter_key(&iter);
|
||||
sums[14] += mm_iter_value(&iter);
|
||||
});
|
||||
|
||||
CMC_FOR_EACH(ms, mset, ms, {
|
||||
sums[15] += ms_iter_value(&iter);
|
||||
});
|
||||
|
||||
printf("\n-------------------- CMC_FOR_EACH --------------------\n");
|
||||
if (sums[0] == 50005000)
|
||||
printf("%12s PASSED\n", "DEQUE");
|
||||
else
|
||||
printf("%10s FAILED\n", "DEQUE");
|
||||
if (sum9 == 50005000)
|
||||
printf("%10s PASSED\n", "HASHSET");
|
||||
printf("%12s FAILED\n", "DEQUE");
|
||||
if (sums[1] == 50005000 && sums[2] == 50005000)
|
||||
printf("%12s PASSED\n", "HASHMAP");
|
||||
else
|
||||
printf("%10s FAILED\n", "HASHSET");
|
||||
if (sum10 == 50005000 && sum11 == 50005000)
|
||||
printf("%10s PASSED\n", "HASHMAP");
|
||||
printf("%12s FAILED\n", "HASHMAP");
|
||||
if (sums[3] == 50005000)
|
||||
printf("%12s PASSED\n", "HASHSET");
|
||||
else
|
||||
printf("%10s FAILED\n", "HASHMAP");
|
||||
if (sum5 == 50005000)
|
||||
printf("%10s PASSED\n", "HEAP");
|
||||
printf("%12s FAILED\n", "HASHSET");
|
||||
if (sums[4] == 50005000)
|
||||
printf("%12s PASSED\n", "HEAP");
|
||||
else
|
||||
printf("%10s FAILED\n", "HEAP");
|
||||
if (sum4 == 50005000)
|
||||
printf("%10s PASSED\n", "LINKEDLIST");
|
||||
printf("%12s FAILED\n", "HEAP");
|
||||
if (sums[5] == 50005000)
|
||||
printf("%12s PASSED\n", "LINKEDLIST");
|
||||
else
|
||||
printf("%10s FAILED\n", "LINKEDLIST");
|
||||
if (sum0 == 50005000)
|
||||
printf("%10s PASSED\n", "LIST");
|
||||
printf("%12s FAILED\n", "LINKEDLIST");
|
||||
if (sums[6] == 50005000)
|
||||
printf("%12s PASSED\n", "LIST");
|
||||
else
|
||||
printf("%10s FAILED\n", "LIST");
|
||||
if (sum2 == 50005000)
|
||||
printf("%10s PASSED\n", "QUEUE");
|
||||
printf("%12s FAILED\n", "LIST");
|
||||
if (sums[7] == 50005000)
|
||||
printf("%12s PASSED\n", "QUEUE");
|
||||
else
|
||||
printf("%10s FAILED\n", "QUEUE");
|
||||
if (sum1 == 50005000)
|
||||
printf("%10s PASSED\n", "STACK");
|
||||
printf("%12s FAILED\n", "QUEUE");
|
||||
if (sums[8] == 50005000)
|
||||
printf("%12s PASSED\n", "STACK");
|
||||
else
|
||||
printf("%10s FAILED\n", "STACK");
|
||||
if (sum7 == 50005000 && sum8 == 50005000)
|
||||
printf("%10s PASSED\n", "TREEMAP");
|
||||
printf("%12s FAILED\n", "STACK");
|
||||
if (sums[9] == 50005000 && sums[10] == 50005000)
|
||||
printf("%12s PASSED\n", "TREEMAP");
|
||||
else
|
||||
printf("%10s FAILED\n", "TREEMAP");
|
||||
if (sum6 == 50005000)
|
||||
printf("%10s PASSED\n", "TREESET");
|
||||
printf("%12s FAILED\n", "TREEMAP");
|
||||
if (sums[11] == 50005000)
|
||||
printf("%12s PASSED\n", "TREESET");
|
||||
else
|
||||
printf("%10s FAILED\n", "TREESET");
|
||||
printf("%12s FAILED\n", "TREESET");
|
||||
if (sums[12] == 50005000)
|
||||
printf("%12s PASSED\n", "INTERVALHEAP");
|
||||
else
|
||||
printf("%12s FAILED\n", "INTERVALHEAP");
|
||||
if (sums[13] == 50005000 && sums[14] == 50005000)
|
||||
printf("%12s PASSED\n", "MULTIMAP");
|
||||
else
|
||||
printf("%12s FAILED\n", "MULTIMAP");
|
||||
if (sums[15] == 50005000)
|
||||
printf("%12s PASSED\n", "MULTISET");
|
||||
else
|
||||
printf("%12s FAILED\n", "MULTISET");
|
||||
|
||||
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;
|
||||
memset(sums, 0, sizeof sums);
|
||||
|
||||
FOR_EACH_REV(d, deque, d, {
|
||||
sum3 += d_iter_value(&iter);
|
||||
CMC_FOR_EACH_REV(d, deque, d, {
|
||||
sums[0] += d_iter_value(&iter);
|
||||
});
|
||||
|
||||
FOR_EACH_REV(hm, hmap, hm, {
|
||||
sum10 += hm_iter_key(&iter);
|
||||
sum11 += hm_iter_value(&iter);
|
||||
CMC_FOR_EACH_REV(hm, hmap, hm, {
|
||||
sums[1] += hm_iter_key(&iter);
|
||||
sums[2] += hm_iter_value(&iter);
|
||||
});
|
||||
|
||||
FOR_EACH_REV(hs, hset, hs, {
|
||||
sum9 += hs_iter_value(&iter);
|
||||
CMC_FOR_EACH_REV(hs, hset, hs, {
|
||||
sums[3] += hs_iter_value(&iter);
|
||||
});
|
||||
|
||||
FOR_EACH_REV(h, heap, h, {
|
||||
sum5 += h_iter_value(&iter);
|
||||
CMC_FOR_EACH_REV(h, heap, h, {
|
||||
sums[4] += h_iter_value(&iter);
|
||||
});
|
||||
|
||||
FOR_EACH_REV(ll, linked, ll, {
|
||||
sum4 += ll_iter_value(&iter);
|
||||
CMC_FOR_EACH_REV(ll, linked, ll, {
|
||||
sums[5] += ll_iter_value(&iter);
|
||||
});
|
||||
|
||||
FOR_EACH_REV(l, list, l, {
|
||||
sum0 += l_iter_value(&iter);
|
||||
CMC_FOR_EACH_REV(l, list, l, {
|
||||
sums[6] += l_iter_value(&iter);
|
||||
});
|
||||
|
||||
FOR_EACH_REV(q, queue, q, {
|
||||
sum2 += q_iter_value(&iter);
|
||||
CMC_FOR_EACH_REV(q, queue, q, {
|
||||
sums[7] += q_iter_value(&iter);
|
||||
});
|
||||
|
||||
FOR_EACH_REV(s, stack, s, {
|
||||
sum1 += s_iter_value(&iter);
|
||||
CMC_FOR_EACH_REV(s, stack, s, {
|
||||
sums[8] += s_iter_value(&iter);
|
||||
});
|
||||
|
||||
FOR_EACH_REV(tm, tmap, tm, {
|
||||
sum7 += tm_iter_key(&iter);
|
||||
sum8 += tm_iter_value(&iter);
|
||||
CMC_FOR_EACH_REV(tm, tmap, tm, {
|
||||
sums[9] += tm_iter_key(&iter);
|
||||
sums[10] += tm_iter_value(&iter);
|
||||
});
|
||||
|
||||
FOR_EACH_REV(ts, tset, ts, {
|
||||
sum6 += ts_iter_value(&iter);
|
||||
CMC_FOR_EACH_REV(ts, tset, ts, {
|
||||
sums[11] += ts_iter_value(&iter);
|
||||
});
|
||||
|
||||
printf("-------------------- FOR_EACH_REV --------------------\n");
|
||||
if (sum3 == 50005000)
|
||||
printf("%10s PASSED\n", "DEQUE");
|
||||
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");
|
||||
CMC_FOR_EACH_REV(ih, iheap, ih, {
|
||||
sums[12] += ih_iter_value(&iter);
|
||||
});
|
||||
|
||||
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);
|
||||
CMC_FOR_EACH_REV(mm, mmap, mm, {
|
||||
sums[13] += mm_iter_key(&iter);
|
||||
sums[14] += mm_iter_value(&iter);
|
||||
});
|
||||
|
||||
CMC_FOR_EACH_REV(ms, mset, ms, {
|
||||
sums[15] += ms_iter_value(&iter);
|
||||
});
|
||||
|
||||
printf("-------------------- CMC_FOR_EACH_REV --------------------\n");
|
||||
if (sums[0] == 50005000)
|
||||
printf("%12s PASSED\n", "DEQUE");
|
||||
else
|
||||
printf("%12s FAILED\n", "DEQUE");
|
||||
if (sums[1] == 50005000 && sums[2] == 50005000)
|
||||
printf("%12s PASSED\n", "HASHMAP");
|
||||
else
|
||||
printf("%12s FAILED\n", "HASHMAP");
|
||||
if (sums[3] == 50005000)
|
||||
printf("%12s PASSED\n", "HASHSET");
|
||||
else
|
||||
printf("%12s FAILED\n", "HASHSET");
|
||||
if (sums[4] == 50005000)
|
||||
printf("%12s PASSED\n", "HEAP");
|
||||
else
|
||||
printf("%12s FAILED\n", "HEAP");
|
||||
if (sums[5] == 50005000)
|
||||
printf("%12s PASSED\n", "LINKEDLIST");
|
||||
else
|
||||
printf("%12s FAILED\n", "LINKEDLIST");
|
||||
if (sums[6] == 50005000)
|
||||
printf("%12s PASSED\n", "LIST");
|
||||
else
|
||||
printf("%12s FAILED\n", "LIST");
|
||||
if (sums[7] == 50005000)
|
||||
printf("%12s PASSED\n", "QUEUE");
|
||||
else
|
||||
printf("%12s FAILED\n", "QUEUE");
|
||||
if (sums[8] == 50005000)
|
||||
printf("%12s PASSED\n", "STACK");
|
||||
else
|
||||
printf("%12s FAILED\n", "STACK");
|
||||
if (sums[9] == 50005000 && sums[10] == 50005000)
|
||||
printf("%12s PASSED\n", "TREEMAP");
|
||||
else
|
||||
printf("%12s FAILED\n", "TREEMAP");
|
||||
if (sums[11] == 50005000)
|
||||
printf("%12s PASSED\n", "TREESET");
|
||||
else
|
||||
printf("%12s FAILED\n", "TREESET");
|
||||
if (sums[12] == 50005000)
|
||||
printf("%12s PASSED\n", "INTERVALHEAP");
|
||||
else
|
||||
printf("%12s FAILED\n", "INTERVALHEAP");
|
||||
if (sums[13] == 50005000 && sums[14] == 50005000)
|
||||
printf("%12s PASSED\n", "MULTIMAP");
|
||||
else
|
||||
printf("%12s FAILED\n", "MULTIMAP");
|
||||
if (sums[15] == 50005000)
|
||||
printf("%12s PASSED\n", "MULTISET");
|
||||
else
|
||||
printf("%12s FAILED\n", "MULTISET");
|
||||
|
||||
printf("\n\n");
|
||||
|
||||
l_free(l, NULL);
|
||||
ll_free(ll, NULL);
|
||||
s_free(s, NULL);
|
||||
q_free(q, NULL);
|
||||
d_free(d, NULL);
|
||||
h_free(h, NULL);
|
||||
ts_free(ts, NULL);
|
||||
tm_free(tm, NULL);
|
||||
hs_free(hs, NULL);
|
||||
hm_free(hm, NULL);
|
||||
|
||||
ih_free(ih, NULL);
|
||||
mm_free(mm, NULL);
|
||||
ms_free(ms, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
+29
-17
@@ -1,6 +1,5 @@
|
||||
#include "../src/macro_collections.h"
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
|
||||
int intcmp(int a, int b)
|
||||
{
|
||||
@@ -19,16 +18,20 @@ size_t inthash(int t)
|
||||
return a;
|
||||
}
|
||||
|
||||
COLLECTION_GENERATE(LIST, l, list, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE(STACK, s, stack, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE(QUEUE, q, queue, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE(DEQUE, d, deque, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE(LINKEDLIST, ll, linked, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE(HEAP, h, heap, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE(TREESET, ts, tset, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE(TREEMAP, tm, tmap, /* FMOD */, int, double)
|
||||
COLLECTION_GENERATE(HASHSET, hs, hset, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE(HASHMAP, hm, hmap, /* FMOD */, int, double)
|
||||
CMC_COLLECTION_GENERATE(LIST, l, list, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE(STACK, s, stack, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE(QUEUE, q, queue, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE(DEQUE, d, deque, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE(LINKEDLIST, ll, linked, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE(HEAP, h, heap, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE(TREESET, ts, tset, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE(TREEMAP, tm, tmap, int, double)
|
||||
CMC_COLLECTION_GENERATE(HASHSET, hs, hset, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE(HASHMAP, hm, hmap, int, double)
|
||||
|
||||
CMC_COLLECTION_GENERATE(INTERVALHEAP, ih, iheap, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE(MULTIMAP, mm, mmap, int, double)
|
||||
CMC_COLLECTION_GENERATE(MULTISET, ms, mset, /* K */, int)
|
||||
|
||||
#define ITERATOR_TEST(NAME, PFX, sname, initfunc, insertbody, sumbody, validation1, validation2) \
|
||||
void NAME##_iterator_test(void) \
|
||||
@@ -69,24 +72,27 @@ COLLECTION_GENERATE(HASHMAP, hm, hmap, /* FMOD */, int, double)
|
||||
sumbody; \
|
||||
} \
|
||||
\
|
||||
PFX##_free(coll); \
|
||||
PFX##_free(coll, NULL); \
|
||||
\
|
||||
if (validation1 && validation2) \
|
||||
printf("%10s PASSED\n", #NAME); \
|
||||
if ((validation1) && (validation2)) \
|
||||
printf("%12s PASSED\n", #NAME); \
|
||||
else \
|
||||
printf("%10s FAILED\n", #NAME); \
|
||||
printf("%12s 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(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, (int)sum2 == (int)45)
|
||||
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, cmc_max_heap, 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(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, (int)sum2 == (int)45)
|
||||
ITERATOR_TEST(TREESET, ts, tset, ts_new(intcmp), ts_insert(coll, i), sum1 += ts_iter_value(&iter), sum1 == 450, 1)
|
||||
ITERATOR_TEST(INTERVALHEAP, ih, iheap, ih_new(20, intcmp), ih_insert(coll, i), sum1 += ih_iter_value(&iter), sum1 == 450, 1)
|
||||
ITERATOR_TEST(MULTIMAP, mm, mmap, mm_new(50, 0.8, intcmp, inthash), mm_insert(coll, i, (double)i / 10.0), sum1 += mm_iter_key(&iter); sum2 += mm_iter_value(&iter), sum1 == 450, (int)sum2 == (int)45)
|
||||
ITERATOR_TEST(MULTISET, ms, mset, ms_new(50, 0.6, intcmp, inthash), ms_insert(coll, i), sum1 += ms_iter_value(&iter); sum2 += ms_iter_multiplicity(&iter), sum1 == 450, (size_t)sum2 == 100)
|
||||
|
||||
int main(void)
|
||||
{
|
||||
@@ -102,5 +108,11 @@ int main(void)
|
||||
TREEMAP_iterator_test();
|
||||
TREESET_iterator_test();
|
||||
|
||||
INTERVALHEAP_iterator_test();
|
||||
MULTIMAP_iterator_test();
|
||||
MULTISET_iterator_test();
|
||||
|
||||
printf("\n\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
+13
-8
@@ -1,16 +1,21 @@
|
||||
CC = gcc
|
||||
CFLAGS = -std=c11 -Wall -Wextra
|
||||
CFLAGS += -Wno-unused-function -Wno-unused-parameter -Wno-unused-variable -Wno-unused-label
|
||||
CVFLAGS = --coverage -O0
|
||||
CFLAGS += -DCMC_TEST_COLOR
|
||||
INCLUDE = ../../src/
|
||||
|
||||
main:
|
||||
$(CC) main.c -o main $(CFLAGS) $(CVFLAGS) -I $(INCLUDE)
|
||||
main: FORCE
|
||||
$(CC) main.c -o main $(CFLAGS) -I $(INCLUDE)
|
||||
./main
|
||||
gcov ./main.c
|
||||
|
||||
dev:
|
||||
$(CC) main.c -o main $(CFLAGS) $(CVFLAGS) -I $(INCLUDE)
|
||||
dev: FORCE
|
||||
$(CC) main.c -o main.exe $(CFLAGS) -I $(INCLUDE)
|
||||
./main.exe
|
||||
rm *.exe
|
||||
|
||||
windev: FORCE
|
||||
$(CC) main.c -o main $(CFLAGS) -I $(INCLUDE)
|
||||
./main
|
||||
gcov ./main.c -n
|
||||
rm *.gcda *.gcno *.exe
|
||||
del *.exe
|
||||
|
||||
FORCE:
|
||||
@@ -1,7 +1,5 @@
|
||||
# main
|
||||
|
||||
Tests for the main C Macro Collections library. In order to provide a good code coverage, all macros have been expanded and added to `src/*.c`.
|
||||
This folder hosts the main tests for the C Macro Collections Library. While this library is under development with breaking changes the old unit tests were moved to codecov to keep track of code coverage without breaking the test.
|
||||
|
||||
* `src` - Since gcov fails to detect code that was expanded by macro, all collections where manually expanded and dumped into their respective source files;
|
||||
* `unt` - Unit Tests;
|
||||
* `main.c` - Where all tests are compiled together and called by main().
|
||||
This new folder however will contain up-to-date changes and tests in order to have any modifications done to the library tracked and where they were broken.
|
||||
+33
-15
@@ -1,3 +1,5 @@
|
||||
#include <utl/timer.h>
|
||||
|
||||
#include "unt/deque.c"
|
||||
#include "unt/hashmap.c"
|
||||
#include "unt/hashset.c"
|
||||
@@ -9,27 +11,43 @@
|
||||
#include "unt/treemap.c"
|
||||
#include "unt/treeset.c"
|
||||
|
||||
#include "unt/linkedqueue.c"
|
||||
#include "unt/bidimap.c"
|
||||
#include "unt/intervalheap.c"
|
||||
#include "unt/multimap.c"
|
||||
#include "unt/multiset.c"
|
||||
#include "unt/sortedlist.c"
|
||||
|
||||
int main(void)
|
||||
{
|
||||
deque_test();
|
||||
hashmap_test();
|
||||
hashset_test();
|
||||
heap_test();
|
||||
linkedlist_test();
|
||||
list_test();
|
||||
queue_test();
|
||||
stack_test();
|
||||
treemap_test();
|
||||
treeset_test();
|
||||
cmc_timer timer;
|
||||
|
||||
cmc_timer_start(timer);
|
||||
uintmax_t failed = 0;
|
||||
|
||||
failed += deque_test();
|
||||
failed += hashmap_test();
|
||||
failed += hashset_test();
|
||||
failed += heap_test();
|
||||
failed += linkedlist_test();
|
||||
failed += list_test();
|
||||
failed += queue_test();
|
||||
failed += stack_test();
|
||||
failed += treemap_test();
|
||||
failed += treeset_test();
|
||||
|
||||
/* ext */
|
||||
linkedqueue_test();
|
||||
multimap_test();
|
||||
multiset_test();
|
||||
failed += bidimap_test();
|
||||
failed += intervalheap_test();
|
||||
failed += multimap_test();
|
||||
failed += multiset_test();
|
||||
failed += sortedlist_test();
|
||||
|
||||
return 0;
|
||||
cmc_timer_stop(timer);
|
||||
cmc_timer_calc(timer);
|
||||
|
||||
printf("+--------------------------------------------------+\n");
|
||||
printf("| Total running time : %14.0lf milliseconds |\n", timer.result);
|
||||
printf("+--------------------------------------------------+\n");
|
||||
|
||||
return failed;
|
||||
}
|
||||
@@ -1,220 +0,0 @@
|
||||
#include "ext/linkedqueue.h"
|
||||
|
||||
//LINKEDQUEUE_GENERATE(lq, linkedqueue, , size_t)
|
||||
|
||||
typedef struct linkedqueue_s
|
||||
{
|
||||
struct linkedqueue_node_s *head;
|
||||
struct linkedqueue_node_s *tail;
|
||||
size_t count;
|
||||
struct linkedqueue_iter_s (*it_start)(struct linkedqueue_s *);
|
||||
} linkedqueue, *linkedqueue_ptr;
|
||||
typedef struct linkedqueue_node_s
|
||||
{
|
||||
size_t data;
|
||||
struct linkedqueue_node_s *next;
|
||||
} linkedqueue_node, *linkedqueue_node_ptr;
|
||||
typedef struct linkedqueue_iter_s
|
||||
{
|
||||
struct linkedqueue_s *target;
|
||||
struct linkedqueue_node_s *cursor;
|
||||
size_t index;
|
||||
bool start;
|
||||
bool end;
|
||||
} linkedqueue_iter, *linkedqueue_iter_ptr;
|
||||
linkedqueue *lq_new(void);
|
||||
void lq_clear(linkedqueue *_lqueue_);
|
||||
void lq_free(linkedqueue *_lqueue_);
|
||||
bool lq_enqueue(linkedqueue *_lqueue_, size_t element);
|
||||
bool lq_dequeue(linkedqueue *_lqueue_);
|
||||
bool lq_enqueue_if(linkedqueue *_lqueue_, size_t element, bool condition);
|
||||
bool lq_dequeue_if(linkedqueue *_lqueue_, bool condition);
|
||||
size_t lq_peek(linkedqueue *_lqueue_);
|
||||
bool lq_contains(linkedqueue *_lqueue_, size_t element, int (*comparator)(size_t, size_t));
|
||||
bool lq_empty(linkedqueue *_lqueue_);
|
||||
size_t lq_count(linkedqueue *_lqueue_);
|
||||
linkedqueue_iter *lq_iter_new(linkedqueue *target);
|
||||
void lq_iter_free(linkedqueue_iter *iter);
|
||||
void lq_iter_init(linkedqueue_iter *iter, linkedqueue *target);
|
||||
bool lq_iter_start(linkedqueue_iter *iter);
|
||||
bool lq_iter_end(linkedqueue_iter *iter);
|
||||
void lq_iter_to_start(linkedqueue_iter *iter);
|
||||
void lq_iter_to_end(linkedqueue_iter *iter);
|
||||
bool lq_iter_next(linkedqueue_iter *iter);
|
||||
size_t lq_iter_value(linkedqueue_iter *iter);
|
||||
size_t *lq_iter_rvalue(linkedqueue_iter *iter);
|
||||
size_t lq_iter_index(linkedqueue_iter *iter);
|
||||
static inline size_t lq_impl_default_value(void)
|
||||
{
|
||||
size_t _empty_value_;
|
||||
memset(&_empty_value_, 0, sizeof(size_t));
|
||||
return _empty_value_;
|
||||
}
|
||||
linkedqueue_node *lq_impl_new_node(size_t element);
|
||||
static linkedqueue_iter lq_impl_it_start(linkedqueue *_lqueue_);
|
||||
linkedqueue *lq_new(void)
|
||||
{
|
||||
linkedqueue *_lqueue_ = malloc(sizeof(linkedqueue));
|
||||
if (!_lqueue_)
|
||||
return NULL;
|
||||
_lqueue_->count = 0;
|
||||
_lqueue_->head = NULL;
|
||||
_lqueue_->tail = NULL;
|
||||
_lqueue_->it_start = lq_impl_it_start;
|
||||
return _lqueue_;
|
||||
}
|
||||
void lq_clear(linkedqueue *_lqueue_)
|
||||
{
|
||||
linkedqueue_node *scan = _lqueue_->head;
|
||||
while (_lqueue_->head != NULL)
|
||||
{
|
||||
_lqueue_->head = _lqueue_->head->next;
|
||||
free(scan);
|
||||
scan = _lqueue_->head;
|
||||
}
|
||||
_lqueue_->count = 0;
|
||||
_lqueue_->head = NULL;
|
||||
_lqueue_->tail = NULL;
|
||||
}
|
||||
void lq_free(linkedqueue *_lqueue_)
|
||||
{
|
||||
lq_clear(_lqueue_);
|
||||
free(_lqueue_);
|
||||
}
|
||||
bool lq_enqueue(linkedqueue *_lqueue_, size_t element)
|
||||
{
|
||||
linkedqueue_node *_node_ = lq_impl_new_node(element);
|
||||
if (!_node_)
|
||||
return false;
|
||||
if (lq_empty(_lqueue_))
|
||||
{
|
||||
_lqueue_->head = _node_;
|
||||
_lqueue_->tail = _node_;
|
||||
}
|
||||
else
|
||||
{
|
||||
_lqueue_->tail->next = _node_;
|
||||
_lqueue_->tail = _node_;
|
||||
}
|
||||
_lqueue_->count++;
|
||||
return true;
|
||||
}
|
||||
bool lq_dequeue(linkedqueue *_lqueue_)
|
||||
{
|
||||
if (lq_empty(_lqueue_))
|
||||
return false;
|
||||
linkedqueue_node *_node_ = _lqueue_->head;
|
||||
_lqueue_->head = _lqueue_->head->next;
|
||||
free(_node_);
|
||||
if (_lqueue_->head == NULL)
|
||||
_lqueue_->tail = NULL;
|
||||
_lqueue_->count--;
|
||||
return true;
|
||||
}
|
||||
bool lq_enqueue_if(linkedqueue *_lqueue_, size_t element, bool condition)
|
||||
{
|
||||
if (condition)
|
||||
return lq_enqueue(_lqueue_, element);
|
||||
return false;
|
||||
}
|
||||
bool lq_dequeue_if(linkedqueue *_lqueue_, bool condition)
|
||||
{
|
||||
if (condition)
|
||||
return lq_dequeue(_lqueue_);
|
||||
return false;
|
||||
}
|
||||
size_t lq_peek(linkedqueue *_lqueue_)
|
||||
{
|
||||
if (lq_empty(_lqueue_))
|
||||
return lq_impl_default_value();
|
||||
return _lqueue_->head->data;
|
||||
}
|
||||
bool lq_contains(linkedqueue *_lqueue_, size_t element, int (*comparator)(size_t, size_t))
|
||||
{
|
||||
linkedqueue_node *scan = _lqueue_->head;
|
||||
while (scan != NULL)
|
||||
{
|
||||
if (comparator(scan->data, element) == 0)
|
||||
return true;
|
||||
scan = scan->next;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool lq_empty(linkedqueue *_lqueue_) { return _lqueue_->count == 0; }
|
||||
size_t lq_count(linkedqueue *_lqueue_) { return _lqueue_->count; }
|
||||
linkedqueue_iter *lq_iter_new(linkedqueue *target)
|
||||
{
|
||||
linkedqueue_iter *iter = malloc(sizeof(linkedqueue_iter));
|
||||
if (!iter)
|
||||
return NULL;
|
||||
lq_iter_init(iter, target);
|
||||
return iter;
|
||||
}
|
||||
void lq_iter_free(linkedqueue_iter *iter) { free(iter); }
|
||||
void lq_iter_init(linkedqueue_iter *iter, linkedqueue *target)
|
||||
{
|
||||
iter->target = target;
|
||||
iter->cursor = target->head;
|
||||
iter->index = 0;
|
||||
iter->start = true;
|
||||
iter->end = lq_empty(target);
|
||||
}
|
||||
bool lq_iter_start(linkedqueue_iter *iter) { return lq_empty(iter->target) || iter->start; }
|
||||
bool lq_iter_end(linkedqueue_iter *iter) { return lq_empty(iter->target) || iter->end; }
|
||||
void lq_iter_to_start(linkedqueue_iter *iter)
|
||||
{
|
||||
iter->cursor = iter->target->head;
|
||||
iter->index = 0;
|
||||
iter->start = true;
|
||||
iter->end = lq_empty(iter->target);
|
||||
}
|
||||
void lq_iter_to_end(linkedqueue_iter *iter)
|
||||
{
|
||||
iter->cursor = iter->target->tail;
|
||||
iter->index = iter->target->count - 1;
|
||||
iter->start = lq_empty(iter->target);
|
||||
iter->end = true;
|
||||
}
|
||||
bool lq_iter_next(linkedqueue_iter *iter)
|
||||
{
|
||||
if (iter->end)
|
||||
return false;
|
||||
iter->start = lq_empty(iter->target);
|
||||
if (iter->cursor->next == NULL)
|
||||
iter->end = true;
|
||||
else
|
||||
{
|
||||
iter->cursor = iter->cursor->next;
|
||||
iter->index++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
size_t lq_iter_value(linkedqueue_iter *iter)
|
||||
{
|
||||
if (lq_empty(iter->target))
|
||||
return lq_impl_default_value();
|
||||
return iter->cursor->data;
|
||||
}
|
||||
size_t *lq_iter_rvalue(linkedqueue_iter *iter)
|
||||
{
|
||||
if (lq_empty(iter->target))
|
||||
return NULL;
|
||||
return &(iter->cursor->data);
|
||||
}
|
||||
size_t lq_iter_index(linkedqueue_iter *iter) { return iter->index; }
|
||||
linkedqueue_node *lq_impl_new_node(size_t element)
|
||||
{
|
||||
linkedqueue_node *_node_ = malloc(sizeof(linkedqueue_node));
|
||||
if (!_node_)
|
||||
return NULL;
|
||||
_node_->data = element;
|
||||
_node_->next = NULL;
|
||||
return _node_;
|
||||
}
|
||||
static linkedqueue_iter lq_impl_it_start(linkedqueue *_lqueue_)
|
||||
{
|
||||
linkedqueue_iter iter;
|
||||
lq_iter_init(&iter, _lqueue_);
|
||||
lq_iter_to_start(&iter);
|
||||
return iter;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
#include "utl.c"
|
||||
#include <utl/assert.h>
|
||||
#include <utl/log.h>
|
||||
#include <utl/test.h>
|
||||
|
||||
#include <ext/bidimap.h>
|
||||
|
||||
CMC_GENERATE_BIDIMAP(bm, bidimap, size_t, size_t)
|
||||
|
||||
CMC_CREATE_UNIT(bidimap_test, true, {
|
||||
CMC_CREATE_TEST(new, {
|
||||
bidimap *map = bm_new(100, 0.6, cmp, hash, cmp, hash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
|
||||
bm_free(map, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(clear[count], {
|
||||
bidimap *map = bm_new(100, 0.6, cmp, hash, cmp, hash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
|
||||
for (size_t i = 0; i < 50; i++)
|
||||
cmc_assert(bm_insert(map, i, i));
|
||||
|
||||
cmc_assert_equals(size_t, 50, bm_count(map));
|
||||
|
||||
bm_clear(map, NULL);
|
||||
|
||||
cmc_assert_equals(size_t, 0, bm_count(map));
|
||||
|
||||
bm_free(map, NULL);
|
||||
});
|
||||
});
|
||||
+583
-24
@@ -1,38 +1,34 @@
|
||||
#include "utl/assert.h"
|
||||
#include "utl/test.h"
|
||||
#include "../src/deque.c"
|
||||
#include "utl.c"
|
||||
#include <utl/assert.h>
|
||||
#include <utl/log.h>
|
||||
#include <utl/test.h>
|
||||
|
||||
#include <cmc/deque.h>
|
||||
|
||||
CMC_GENERATE_DEQUE(d, deque, size_t)
|
||||
|
||||
CMC_CREATE_UNIT(deque_test, true, {
|
||||
CMC_CREATE_TEST(new, {
|
||||
deque *d = d_new(1000000);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, d);
|
||||
|
||||
bool passed = d->capacity == 1000000 && d->count == 0 && d->buffer;
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, d->buffer);
|
||||
cmc_assert_equals(size_t, 1000000, d->capacity);
|
||||
cmc_assert_equals(size_t, 0, d_count(d));
|
||||
cmc_assert_not_equals(ptr, NULL, d->buffer);
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(passed);
|
||||
|
||||
d_free(d);
|
||||
d_free(d, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(new[edge_case:capacity = 0], {
|
||||
CMC_CREATE_TEST(new[capacity = 0], {
|
||||
deque *d = d_new(0);
|
||||
|
||||
cmc_assert_equals(ptr, NULL, d);
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(d == NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(new[edge_case:capacity = UINT64_MAX], {
|
||||
CMC_CREATE_TEST(new[capacity = UINT64_MAX], {
|
||||
deque *d = d_new(UINT64_MAX);
|
||||
|
||||
cmc_assert_equals(ptr, NULL, d);
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(d == NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(clear[count capacity], {
|
||||
@@ -45,17 +41,15 @@ CMC_CREATE_UNIT(deque_test, true, {
|
||||
|
||||
cmc_assert_equals(size_t, 50, d_count(d));
|
||||
|
||||
d_clear(d);
|
||||
d_clear(d, NULL);
|
||||
|
||||
cmc_assert_equals(size_t, 0, d_count(d));
|
||||
cmc_assert_equals(size_t, 100, d_capacity(d));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(d_count(d) == 0 && d_capacity(d) == 100);
|
||||
|
||||
d_free(d);
|
||||
d_free(d, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(buffer_growth[edge_case:capacity = 1], {
|
||||
CMC_CREATE_TEST(buffer_growth[capacity = 1], {
|
||||
deque *d = d_new(1);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, d);
|
||||
@@ -66,9 +60,574 @@ CMC_CREATE_UNIT(deque_test, true, {
|
||||
cmc_assert_equals(size_t, 50, d_count(d));
|
||||
cmc_assert_lesser_equals(size_t, d_capacity(d), d_count(d));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(d_count(d) == 50 && d_count(d) <= d_capacity(d));
|
||||
|
||||
d_free(d);
|
||||
d_free(d, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(buffer_growth[item preservation], {
|
||||
deque *d = d_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, d);
|
||||
|
||||
for (size_t i = 1; i <= 1200; i++)
|
||||
{
|
||||
if (i % 2 == 0)
|
||||
d_push_front(d, i);
|
||||
else
|
||||
d_push_back(d, i);
|
||||
}
|
||||
|
||||
size_t sum = 0;
|
||||
for (size_t i = d->front, j = 0; j < d->count; i = (i + 1) % d->capacity, j++)
|
||||
sum += d->buffer[i];
|
||||
|
||||
cmc_assert_equals(size_t, 1200, d_count(d));
|
||||
cmc_assert_equals(size_t, 720600, sum);
|
||||
|
||||
d_free(d, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(push_front[count capacity], {
|
||||
deque *d = d_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, d);
|
||||
|
||||
for (size_t i = 0; i < 150; i++)
|
||||
cmc_assert(d_push_front(d, i));
|
||||
|
||||
cmc_assert_equals(size_t, 150, d_count(d));
|
||||
cmc_assert_greater(size_t, 100, d_capacity(d));
|
||||
|
||||
d_free(d, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(push_front[item preservation], {
|
||||
deque *d = d_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, d);
|
||||
|
||||
for (size_t i = 1; i <= 100; i++)
|
||||
cmc_assert(d_push_front(d, i));
|
||||
|
||||
size_t sum = 0;
|
||||
|
||||
for (size_t i = d->front, j = 0; j < d->count; i = (i + 1) % d->capacity, j++)
|
||||
{
|
||||
sum += d->buffer[i];
|
||||
}
|
||||
|
||||
cmc_assert_equals(size_t, 5050, sum);
|
||||
|
||||
d_free(d, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(push_back[count capacity], {
|
||||
deque *d = d_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, d);
|
||||
|
||||
for (size_t i = 0; i < 150; i++)
|
||||
cmc_assert(d_push_back(d, i));
|
||||
|
||||
cmc_assert_equals(size_t, 150, d_count(d));
|
||||
cmc_assert_greater(size_t, 100, d_capacity(d));
|
||||
|
||||
d_free(d, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(push_back[item preservation], {
|
||||
deque *d = d_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, d);
|
||||
|
||||
for (size_t i = 1; i <= 100; i++)
|
||||
cmc_assert(d_push_back(d, i));
|
||||
|
||||
size_t sum = 0;
|
||||
|
||||
for (size_t i = d->front, j = 0; j < d->count; i = (i + 1) % d->capacity, j++)
|
||||
{
|
||||
sum += d->buffer[i];
|
||||
}
|
||||
|
||||
cmc_assert_equals(size_t, 5050, sum);
|
||||
|
||||
d_free(d, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(pop_front[count capacity], {
|
||||
deque *d = d_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, d);
|
||||
|
||||
cmc_assert(d_push_front(d, 10));
|
||||
cmc_assert(d_pop_front(d));
|
||||
|
||||
cmc_assert_equals(size_t, 0, d_count(d));
|
||||
|
||||
cmc_assert(d_push_back(d, 10));
|
||||
cmc_assert(d_pop_front(d));
|
||||
|
||||
cmc_assert_equals(size_t, 0, d_count(d));
|
||||
|
||||
d_free(d, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(pop_front[item preservation], {
|
||||
deque *d = d_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, d);
|
||||
|
||||
for (size_t i = 1; i <= 200; i++)
|
||||
cmc_assert(d_push_front(d, i));
|
||||
|
||||
for (size_t i = 0; i < 100; i++)
|
||||
cmc_assert(d_pop_front(d));
|
||||
|
||||
size_t sum = 0;
|
||||
|
||||
for (size_t i = d->front, j = 0; j < d->count; i = (i + 1) % d->capacity, j++)
|
||||
{
|
||||
sum += d->buffer[i];
|
||||
}
|
||||
|
||||
cmc_assert_equals(size_t, 5050, sum);
|
||||
|
||||
d_free(d, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(pop_back[count capacity], {
|
||||
deque *d = d_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, d);
|
||||
|
||||
cmc_assert(d_push_front(d, 10));
|
||||
cmc_assert(d_pop_back(d));
|
||||
|
||||
cmc_assert_equals(size_t, 0, d_count(d));
|
||||
|
||||
cmc_assert(d_push_back(d, 10));
|
||||
cmc_assert(d_pop_back(d));
|
||||
|
||||
cmc_assert_equals(size_t, 0, d_count(d));
|
||||
|
||||
d_free(d, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(pop_back[item preservation], {
|
||||
deque *d = d_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, d);
|
||||
|
||||
for (size_t i = 1; i <= 200; i++)
|
||||
cmc_assert(d_push_back(d, i));
|
||||
|
||||
for (size_t i = 0; i < 100; i++)
|
||||
cmc_assert(d_pop_back(d));
|
||||
|
||||
size_t sum = 0;
|
||||
|
||||
for (size_t i = d->front, j = 0; j < d->count; i = (i + 1) % d->capacity, j++)
|
||||
{
|
||||
sum += d->buffer[i];
|
||||
}
|
||||
|
||||
cmc_assert_equals(size_t, 5050, sum);
|
||||
|
||||
d_free(d, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(Mixed IO, {
|
||||
deque *d = d_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, d);
|
||||
|
||||
cmc_assert(d_push_front(d, 10));
|
||||
cmc_assert(d_push_front(d, 10));
|
||||
cmc_assert(d_pop_back(d));
|
||||
cmc_assert(d_pop_back(d));
|
||||
|
||||
cmc_assert_equals(size_t, 0, d_count(d));
|
||||
|
||||
cmc_assert(d_push_back(d, 10));
|
||||
cmc_assert(d_push_back(d, 10));
|
||||
cmc_assert(d_pop_back(d));
|
||||
cmc_assert(d_pop_back(d));
|
||||
|
||||
cmc_assert_equals(size_t, 0, d_count(d));
|
||||
|
||||
cmc_assert(d_push_front(d, 10));
|
||||
cmc_assert(d_push_front(d, 10));
|
||||
cmc_assert(d_pop_front(d));
|
||||
cmc_assert(d_pop_front(d));
|
||||
|
||||
cmc_assert_equals(size_t, 0, d_count(d));
|
||||
|
||||
cmc_assert(d_push_back(d, 10));
|
||||
cmc_assert(d_push_back(d, 10));
|
||||
cmc_assert(d_pop_front(d));
|
||||
cmc_assert(d_pop_front(d));
|
||||
|
||||
cmc_assert_equals(size_t, 0, d_count(d));
|
||||
// ----------
|
||||
cmc_assert(d_push_back(d, 10));
|
||||
cmc_assert(d_push_front(d, 10));
|
||||
cmc_assert(d_pop_back(d));
|
||||
cmc_assert(d_pop_front(d));
|
||||
|
||||
cmc_assert_equals(size_t, 0, d_count(d));
|
||||
|
||||
cmc_assert(d_push_back(d, 10));
|
||||
cmc_assert(d_push_front(d, 10));
|
||||
cmc_assert(d_pop_front(d));
|
||||
cmc_assert(d_pop_back(d));
|
||||
|
||||
cmc_assert_equals(size_t, 0, d_count(d));
|
||||
|
||||
cmc_assert(d_push_front(d, 10));
|
||||
cmc_assert(d_push_back(d, 10));
|
||||
cmc_assert(d_pop_back(d));
|
||||
cmc_assert(d_pop_front(d));
|
||||
|
||||
cmc_assert_equals(size_t, 0, d_count(d));
|
||||
|
||||
cmc_assert(d_push_front(d, 10));
|
||||
cmc_assert(d_push_back(d, 10));
|
||||
cmc_assert(d_pop_front(d));
|
||||
cmc_assert(d_pop_back(d));
|
||||
|
||||
cmc_assert_equals(size_t, 0, d_count(d));
|
||||
|
||||
d_free(d, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(front[count = 0], {
|
||||
deque *d = d_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, d);
|
||||
|
||||
size_t r = d_front(d);
|
||||
|
||||
cmc_assert_equals(size_t, (size_t){0}, r);
|
||||
|
||||
d_free(d, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(front[sum], {
|
||||
deque *d = d_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, d);
|
||||
|
||||
size_t sum = 0;
|
||||
|
||||
for (size_t i = 0; i <= 100; i++)
|
||||
{
|
||||
if (i % 2 == 0)
|
||||
cmc_assert(d_push_back(d, i));
|
||||
else
|
||||
cmc_assert(d_push_front(d, i));
|
||||
}
|
||||
|
||||
while (!d_empty(d))
|
||||
{
|
||||
size_t r = d_front(d);
|
||||
|
||||
sum += r;
|
||||
|
||||
cmc_assert(d_pop_front(d));
|
||||
}
|
||||
|
||||
cmc_assert_equals(size_t, 5050, sum);
|
||||
|
||||
d_free(d, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(back[count = 0], {
|
||||
deque *d = d_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, d);
|
||||
|
||||
size_t r = d_back(d);
|
||||
|
||||
cmc_assert_equals(size_t, (size_t){0}, r);
|
||||
|
||||
d_free(d, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(back[sum], {
|
||||
deque *d = d_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, d);
|
||||
|
||||
size_t sum = 0;
|
||||
|
||||
for (size_t i = 0; i <= 100; i++)
|
||||
{
|
||||
if (i % 2 == 0)
|
||||
cmc_assert(d_push_back(d, i));
|
||||
else
|
||||
cmc_assert(d_push_front(d, i));
|
||||
}
|
||||
|
||||
while (!d_empty(d))
|
||||
{
|
||||
size_t r = d_back(d);
|
||||
|
||||
sum += r;
|
||||
|
||||
cmc_assert(d_pop_back(d));
|
||||
}
|
||||
|
||||
cmc_assert_equals(size_t, 5050, sum);
|
||||
|
||||
d_free(d, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(contains, {
|
||||
deque *d = d_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, d);
|
||||
|
||||
for (size_t i = 1; i <= 20; i++)
|
||||
cmc_assert(d_push_back(d, i));
|
||||
|
||||
for (size_t i = 1; i <= 20; i++)
|
||||
cmc_assert(d_contains(d, i, cmp));
|
||||
|
||||
d_clear(d, NULL);
|
||||
|
||||
for (size_t i = 1; i <= 20; i++)
|
||||
cmc_assert(d_push_front(d, i));
|
||||
|
||||
for (size_t i = 1; i <= 20; i++)
|
||||
cmc_assert(d_contains(d, i, cmp));
|
||||
|
||||
d_free(d, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(contains[count = 0], {
|
||||
deque *d = d_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, d);
|
||||
|
||||
cmc_assert(!d_contains(d, 10, cmp));
|
||||
|
||||
d_free(d, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(contains[count = 1], {
|
||||
deque *d = d_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, d);
|
||||
|
||||
cmc_assert(!d_contains(d, 10, cmp));
|
||||
|
||||
cmc_assert(d_push_back(d, 100));
|
||||
|
||||
cmc_assert(d_contains(d, 100, cmp));
|
||||
cmc_assert(!d_contains(d, 101, cmp));
|
||||
|
||||
cmc_assert(d_pop_front(d));
|
||||
cmc_assert(d_push_front(d, 100));
|
||||
|
||||
cmc_assert(d_contains(d, 100, cmp));
|
||||
cmc_assert(!d_contains(d, 101, cmp));
|
||||
|
||||
d_free(d, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(empty, {
|
||||
deque *d = d_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, d);
|
||||
|
||||
cmc_assert(d_empty(d));
|
||||
|
||||
cmc_assert(d_push_front(d, 1));
|
||||
|
||||
cmc_assert(!d_empty(d));
|
||||
|
||||
d_free(d, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(full, {
|
||||
deque *d = d_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, d);
|
||||
|
||||
cmc_assert(!d_full(d));
|
||||
|
||||
for (size_t i = 0; i != d_capacity(d); i++)
|
||||
cmc_assert(d_push_front(d, i));
|
||||
|
||||
cmc_assert(d_full(d));
|
||||
|
||||
d_free(d, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(count, {
|
||||
deque *d = d_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, d);
|
||||
|
||||
cmc_assert_equals(size_t, 0, d_count(d));
|
||||
|
||||
for (size_t i = 0; i < 100; i++)
|
||||
cmc_assert(d_push_back(d, i));
|
||||
|
||||
cmc_assert_equals(size_t, 100, d_count(d));
|
||||
|
||||
d_free(d, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(capacity, {
|
||||
deque *d = d_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, d);
|
||||
|
||||
cmc_assert_equals(size_t, 100, d_capacity(d));
|
||||
|
||||
d_free(d, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(resize, {
|
||||
deque *d = d_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, d);
|
||||
|
||||
for (size_t i = 0; i < 150; i++)
|
||||
{
|
||||
if (i % 2 == 0)
|
||||
cmc_assert(d_push_back(d, i));
|
||||
else
|
||||
cmc_assert(d_push_front(d, i));
|
||||
}
|
||||
|
||||
cmc_assert_equals(size_t, 150, d_count(d));
|
||||
cmc_assert(d_resize(d, d_count(d)));
|
||||
cmc_assert_equals(size_t, 150, d_capacity(d));
|
||||
|
||||
d_free(d, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(resize[item preservation], {
|
||||
deque *d = d_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, d);
|
||||
|
||||
for (size_t i = 1; i <= 150; i++)
|
||||
{
|
||||
if (i % 2 != 0)
|
||||
cmc_assert(d_push_back(d, i));
|
||||
else
|
||||
cmc_assert(d_push_front(d, i));
|
||||
}
|
||||
|
||||
cmc_assert(d_resize(d, d_count(d)));
|
||||
|
||||
size_t sum = 0;
|
||||
|
||||
for (size_t i = d->front, j = 0; j < d->count; i = (i + 1) % d->capacity, j++)
|
||||
{
|
||||
sum += d->buffer[i];
|
||||
}
|
||||
|
||||
cmc_assert_equals(size_t, 11325, sum);
|
||||
|
||||
d_free(d, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(copy_of, {
|
||||
deque *d1 = d_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, d1);
|
||||
|
||||
for (size_t i = 1; i <= 150; i++)
|
||||
{
|
||||
if (i % 2 != 0)
|
||||
cmc_assert(d_push_back(d1, i));
|
||||
else
|
||||
cmc_assert(d_push_front(d1, i));
|
||||
}
|
||||
|
||||
deque *d2 = d_copy_of(d1, NULL);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, d2);
|
||||
cmc_assert_equals(size_t, d_count(d1), d_count(d2));
|
||||
|
||||
for (size_t i1 = d1->front, i2 = d2->front, j = 0; j < d1->count; j++)
|
||||
{
|
||||
cmc_assert_equals(size_t, d1->buffer[i1], d2->buffer[i2]);
|
||||
|
||||
i1 = (i1 + 1) % d1->capacity;
|
||||
i2 = (i2 + 1) % d2->capacity;
|
||||
}
|
||||
|
||||
d_free(d1, NULL);
|
||||
d_free(d2, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(equals, {
|
||||
deque *d1 = d_new(100);
|
||||
deque *d2 = d_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, d1);
|
||||
cmc_assert_not_equals(ptr, NULL, d2);
|
||||
|
||||
for (size_t i = 1; i <= 150; i++)
|
||||
{
|
||||
if (i % 2 != 0)
|
||||
{
|
||||
cmc_assert(d_push_back(d1, i));
|
||||
cmc_assert(d_push_back(d2, i));
|
||||
}
|
||||
else
|
||||
{
|
||||
cmc_assert(d_push_front(d1, i));
|
||||
cmc_assert(d_push_front(d2, i));
|
||||
}
|
||||
}
|
||||
|
||||
cmc_assert(d_equals(d1, d2, cmp));
|
||||
|
||||
d_free(d1, NULL);
|
||||
d_free(d2, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(equals[from copy], {
|
||||
deque *d1 = d_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, d1);
|
||||
|
||||
for (size_t i = 1; i <= 150; i++)
|
||||
{
|
||||
if (i % 2 != 0)
|
||||
cmc_assert(d_push_back(d1, i));
|
||||
else
|
||||
cmc_assert(d_push_front(d1, i));
|
||||
}
|
||||
|
||||
deque *d2 = d_copy_of(d1, NULL);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, d2);
|
||||
|
||||
cmc_assert(d_equals(d1, d2, cmp));
|
||||
|
||||
d_free(d1, NULL);
|
||||
d_free(d2, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(equals[count = 0], {
|
||||
deque *d1 = d_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, d1);
|
||||
|
||||
deque *d2 = d_copy_of(d1, NULL);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, d2);
|
||||
|
||||
cmc_assert(d_equals(d1, d2, cmp));
|
||||
|
||||
d_free(d1, NULL);
|
||||
d_free(d2, NULL);
|
||||
});
|
||||
});
|
||||
+419
-20
@@ -1,37 +1,34 @@
|
||||
#include "utl/assert.h"
|
||||
#include "utl/test.h"
|
||||
#include "../src/hashmap.c"
|
||||
|
||||
#include "utl.c"
|
||||
#include <utl/assert.h>
|
||||
#include <utl/log.h>
|
||||
#include <utl/test.h>
|
||||
|
||||
#include <cmc/hashmap.h>
|
||||
|
||||
CMC_GENERATE_HASHMAP(hm, hashmap, size_t, size_t)
|
||||
|
||||
CMC_CREATE_UNIT(hashmap_test, true, {
|
||||
CMC_CREATE_TEST(new, {
|
||||
hashmap *map = hm_new(943722, 0.6, cmp, hash);
|
||||
|
||||
bool passed = (map->capacity >= (943722 / 0.6)) && map->count == 0 && map->buffer;
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
cmc_assert_not_equals(ptr, NULL, map->buffer);
|
||||
cmc_assert_equals(size_t, 0, hm_count(map));
|
||||
cmc_assert_greater_equals(size_t, (943722 / 0.6), hm_capacity(map));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(passed);
|
||||
|
||||
hm_free(map);
|
||||
hm_free(map, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(new[edge_case:capacity = 0], {
|
||||
CMC_CREATE_TEST(new[capacity = 0], {
|
||||
hashmap *map = hm_new(0, 0.6, cmp, hash);
|
||||
|
||||
cmc_assert_equals(ptr, NULL, map);
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(map == NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(new[edge_case:capacity = UINT64_MAX], {
|
||||
hashmap *map = hm_new(UINT64_MAX, 0.6, cmp, hash);
|
||||
CMC_CREATE_TEST(new[capacity = UINT64_MAX], {
|
||||
hashmap *map = hm_new(UINT64_MAX, 0.99, cmp, hash);
|
||||
|
||||
cmc_assert_equals(ptr, NULL, map);
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(map == NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(clear[count capacity], {
|
||||
@@ -44,13 +41,415 @@ CMC_CREATE_UNIT(hashmap_test, true, {
|
||||
|
||||
cmc_assert_equals(size_t, 50, hm_count(map));
|
||||
|
||||
hm_clear(map);
|
||||
hm_clear(map, NULL);
|
||||
|
||||
cmc_assert_equals(size_t, 0, hm_count(map));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(hm_count(map) == 0);
|
||||
|
||||
hm_free(map);
|
||||
hm_free(map, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(insert, {
|
||||
hashmap *map = hm_new(100, 0.6, cmp, hash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
|
||||
cmc_assert(hm_insert(map, 1, 1));
|
||||
cmc_assert_equals(size_t, 1, hm_count(map));
|
||||
|
||||
hm_free(map, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(insert[smallest capacity], {
|
||||
hashmap *map = hm_new(1, 0.99, cmp, hash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
|
||||
cmc_assert_equals(size_t, cmc_hashtable_primes[0], hm_capacity(map));
|
||||
cmc_assert(hm_insert(map, 1, 1));
|
||||
|
||||
hm_free(map, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(insert[element position], {
|
||||
// Using the numhash the key is the hash itself
|
||||
hashmap *map = hm_new(1, 0.99, cmp, numhash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
|
||||
size_t capacity = hm_capacity(map);
|
||||
|
||||
cmc_assert_greater(size_t, 0, capacity);
|
||||
|
||||
cmc_assert(hm_insert(map, capacity - 1, capacity - 1));
|
||||
cmc_assert(hm_insert(map, capacity, capacity));
|
||||
|
||||
cmc_assert_equals(size_t, capacity - 1, map->buffer[capacity - 1].key);
|
||||
cmc_assert_equals(size_t, capacity, map->buffer[0].key);
|
||||
|
||||
hm_free(map, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(insert[distance], {
|
||||
hashmap *map = hm_new(500, 0.6, cmp, hash0);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
|
||||
for (size_t i = 0; i < 200; i++)
|
||||
cmc_assert(hm_insert(map, i, i));
|
||||
|
||||
// Everything is hashed to 0 so key 0 should have dist 0, key 1 dist 1, etc
|
||||
for (size_t i = 0; i < 200; i++)
|
||||
cmc_assert_equals(size_t, i, map->buffer[i].dist);
|
||||
|
||||
hm_free(map, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(insert[distance wrap], {
|
||||
hashmap *map = hm_new(1, 0.99, cmp, hashcapminus1);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
|
||||
size_t capacity = hm_capacity(map);
|
||||
|
||||
// Just to be sure, not part of the test
|
||||
cmc_assert_equals(size_t, cmc_hashtable_primes[0] - 1, hashcapminus1(0));
|
||||
cmc_assert_equals(size_t, capacity - 1, hashcapminus1(0));
|
||||
|
||||
cmc_assert(hm_insert(map, 0, 0));
|
||||
cmc_assert(hm_insert(map, 1, 1));
|
||||
|
||||
cmc_assert_equals(size_t, 0, map->buffer[capacity - 1].dist);
|
||||
cmc_assert_equals(size_t, 1, map->buffer[0].dist);
|
||||
|
||||
hm_free(map, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(insert[distances], {
|
||||
hashmap *map = hm_new(1, 0.99, cmp, hashcapminus4);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
|
||||
cmc_assert_equals(size_t, cmc_hashtable_primes[0], hm_capacity(map));
|
||||
|
||||
for (size_t i = 0; i < 6; i++)
|
||||
cmc_assert(hm_insert(map, i, i));
|
||||
|
||||
for (size_t i = 0; i < 6; i++)
|
||||
cmc_assert_equals(size_t, i, hm_impl_get_entry(map, i)->dist);
|
||||
|
||||
hm_free(map, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(insert[buffer growth and item preservation], {
|
||||
hashmap *map = hm_new(1, 0.99, cmp, hash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
|
||||
cmc_assert_equals(size_t, cmc_hashtable_primes[0], hm_capacity(map));
|
||||
|
||||
size_t p = 0;
|
||||
for (size_t i = 0; i < 100000; i++)
|
||||
{
|
||||
if (hm_full(map))
|
||||
p++;
|
||||
|
||||
cmc_assert(hm_insert(map, i, i));
|
||||
}
|
||||
|
||||
cmc_assert_equals(size_t, cmc_hashtable_primes[p], hm_capacity(map));
|
||||
|
||||
for (size_t i = 0; i < 100000; i++)
|
||||
cmc_assert(hm_contains(map, i));
|
||||
|
||||
hm_free(map, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(update, {
|
||||
hashmap *map = hm_new(100, 0.6, cmp, hash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
|
||||
cmc_assert(hm_insert(map, 1, 1));
|
||||
|
||||
size_t old;
|
||||
cmc_assert(hm_update(map, 1, 2, &old));
|
||||
|
||||
cmc_assert_equals(size_t, 1, old);
|
||||
|
||||
hm_free(map, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(update[key not found], {
|
||||
hashmap *map = hm_new(100, 0.6, cmp, hash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
|
||||
for (size_t i = 0; i < 100; i++)
|
||||
cmc_assert(hm_insert(map, i, i));
|
||||
|
||||
cmc_assert(!hm_update(map, 120, 120, NULL));
|
||||
|
||||
hm_free(map, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(remove, {
|
||||
hashmap *map = hm_new(100, 0.6, cmp, hash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
|
||||
for (size_t i = 0; i < 100; i++)
|
||||
cmc_assert(hm_insert(map, i, i));
|
||||
|
||||
for (size_t i = 0; i < 100; i++)
|
||||
cmc_assert(hm_remove(map, i, NULL));
|
||||
|
||||
hm_free(map, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(remove[count = 0], {
|
||||
hashmap *map = hm_new(100, 0.6, cmp, hash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
|
||||
for (size_t i = 100; i < 200; i++)
|
||||
cmc_assert(!hm_remove(map, i, NULL));
|
||||
|
||||
hm_free(map, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(remove[key not found], {
|
||||
hashmap *map = hm_new(100, 0.6, cmp, hash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
|
||||
for (size_t i = 0; i < 100; i++)
|
||||
cmc_assert(hm_insert(map, i, i));
|
||||
|
||||
for (size_t i = 100; i < 200; i++)
|
||||
cmc_assert(!hm_remove(map, i, NULL));
|
||||
|
||||
hm_free(map, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(max, {
|
||||
hashmap *map = hm_new(100, 0.6, cmp, hash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
|
||||
for (size_t i = 1; i <= 100; i++)
|
||||
cmc_assert(hm_insert(map, i, i));
|
||||
|
||||
size_t key;
|
||||
size_t val;
|
||||
cmc_assert(hm_max(map, &key, &val));
|
||||
|
||||
cmc_assert_equals(size_t, 100, key);
|
||||
cmc_assert_equals(size_t, 100, val);
|
||||
|
||||
hm_free(map, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(max[count = 0], {
|
||||
hashmap *map = hm_new(100, 0.6, cmp, hash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
|
||||
cmc_assert(!hm_min(map, NULL, NULL));
|
||||
|
||||
hm_free(map, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(min, {
|
||||
hashmap *map = hm_new(100, 0.6, cmp, hash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
|
||||
for (size_t i = 1; i <= 100; i++)
|
||||
cmc_assert(hm_insert(map, i, i));
|
||||
|
||||
size_t key;
|
||||
size_t val;
|
||||
cmc_assert(hm_min(map, &key, &val));
|
||||
|
||||
cmc_assert_equals(size_t, 1, key);
|
||||
cmc_assert_equals(size_t, 1, val);
|
||||
|
||||
hm_free(map, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(min[count = 0], {
|
||||
hashmap *map = hm_new(100, 0.6, cmp, hash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
|
||||
cmc_assert(!hm_min(map, NULL, NULL));
|
||||
|
||||
hm_free(map, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(get, {
|
||||
hashmap *map = hm_new(100, 0.6, cmp, hash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
|
||||
cmc_assert(hm_insert(map, 4321, 1234));
|
||||
|
||||
cmc_assert_equals(size_t, 1234, hm_get(map, 4321));
|
||||
|
||||
hm_free(map, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(get[count = 0], {
|
||||
hashmap *map = hm_new(100, 0.6, cmp, hash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
|
||||
cmc_assert_equals(size_t, (size_t){0}, hm_get(map, 4321));
|
||||
|
||||
hm_free(map, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(get_ref, {
|
||||
hashmap *map = hm_new(100, 0.6, cmp, hash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
|
||||
cmc_assert(hm_insert(map, 4321, 1234));
|
||||
|
||||
size_t *result = hm_get_ref(map, 4321);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, result);
|
||||
cmc_assert_equals(size_t, 1234, *result);
|
||||
|
||||
hm_free(map, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(get_ref[count = 0], {
|
||||
hashmap *map = hm_new(100, 0.6, cmp, hash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
|
||||
cmc_assert_equals(ptr, NULL, hm_get_ref(map, 4321));
|
||||
|
||||
hm_free(map, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(contains, {
|
||||
hashmap *map = hm_new(100, 0.6, cmp, hash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
|
||||
cmc_assert(hm_insert(map, 987654321, 1));
|
||||
|
||||
cmc_assert(hm_contains(map, 987654321));
|
||||
|
||||
hm_free(map, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(contains[count = 0], {
|
||||
hashmap *map = hm_new(100, 0.6, cmp, hash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
|
||||
cmc_assert(!hm_contains(map, 987654321));
|
||||
|
||||
hm_free(map, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(contains[sum], {
|
||||
hashmap *map = hm_new(100, 0.6, cmp, hash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
|
||||
for (size_t i = 101; i <= 200; i++)
|
||||
cmc_assert(hm_insert(map, i, i));
|
||||
|
||||
size_t sum = 0;
|
||||
for (size_t i = 1; i <= 300; i++)
|
||||
if (hm_contains(map, i))
|
||||
sum += i;
|
||||
|
||||
cmc_assert_equals(size_t, 15050, sum);
|
||||
|
||||
hm_free(map, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(empty, {
|
||||
hashmap *map = hm_new(100, 0.6, cmp, hash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
|
||||
cmc_assert(hm_empty(map));
|
||||
|
||||
cmc_assert(hm_insert(map, 1, 1));
|
||||
|
||||
cmc_assert(!hm_empty(map));
|
||||
|
||||
hm_free(map, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(full, {
|
||||
hashmap *map = hm_new(cmc_hashtable_primes[0], 0.99999, cmp, hash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
|
||||
cmc_assert_equals(size_t, cmc_hashtable_primes[0], hm_capacity(map));
|
||||
|
||||
for (size_t i = 0; i < hm_capacity(map); i++)
|
||||
cmc_assert(hm_insert(map, i, i));
|
||||
|
||||
cmc_assert(hm_full(map));
|
||||
|
||||
cmc_assert(hm_insert(map, 10000, 10000));
|
||||
|
||||
cmc_assert_equals(size_t, cmc_hashtable_primes[1], hm_capacity(map));
|
||||
|
||||
cmc_assert(!hm_full(map));
|
||||
|
||||
hm_free(map, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(count, {
|
||||
hashmap *map = hm_new(100, 0.6, cmp, hash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
|
||||
for (size_t i = 1; i < 100; i++)
|
||||
{
|
||||
cmc_assert(hm_insert(map, i, i));
|
||||
cmc_assert_equals(size_t, i, hm_count(map));
|
||||
}
|
||||
|
||||
hm_free(map, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(capacity, {
|
||||
hashmap *map = hm_new(2500, 0.6, cmp, hash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
|
||||
cmc_assert_greater_equals(size_t, (size_t)(2500 / 0.6), hm_capacity(map));
|
||||
|
||||
hm_free(map, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(capacity[small], {
|
||||
hashmap *map = hm_new(1, 0.99, cmp, hash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
|
||||
cmc_assert_equals(size_t, cmc_hashtable_primes[0], hm_capacity(map));
|
||||
|
||||
hm_free(map, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(load, {
|
||||
hashmap *map = hm_new(1, 0.99, cmp, hash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
|
||||
cmc_assert_in_range(double, 0.99 - 0.0001, 0.99 + 0.0001, hm_load(map));
|
||||
|
||||
hm_free(map, NULL);
|
||||
});
|
||||
});
|
||||
+325
-21
@@ -1,37 +1,34 @@
|
||||
#include "utl/assert.h"
|
||||
#include "utl/test.h"
|
||||
#include "../src/hashset.c"
|
||||
|
||||
#include "utl.c"
|
||||
#include <utl/assert.h>
|
||||
#include <utl/log.h>
|
||||
#include <utl/test.h>
|
||||
|
||||
#include <cmc/hashset.h>
|
||||
|
||||
CMC_GENERATE_HASHSET(hs, hashset, size_t)
|
||||
|
||||
CMC_CREATE_UNIT(hashset_test, true, {
|
||||
CMC_CREATE_TEST(new, {
|
||||
hashset *set = hs_new(943722, 0.6, cmp, hash);
|
||||
|
||||
bool passed = (set->capacity >= (943722 / 0.6)) && set->count == 0 && set->buffer;
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, set);
|
||||
cmc_assert(hs_capacity(set) > (943722 / 0.6));
|
||||
cmc_assert_not_equals(ptr, NULL, set->buffer);
|
||||
cmc_assert_equals(size_t, 0, hs_count(set));
|
||||
cmc_assert_greater_equals(size_t, (943722 / 0.6), hs_capacity(set));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(passed);
|
||||
|
||||
hs_free(set);
|
||||
hs_free(set, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(new[edge_case:capacity = 0], {
|
||||
CMC_CREATE_TEST(new[capacity = 0], {
|
||||
hashset *set = hs_new(0, 0.6, cmp, hash);
|
||||
|
||||
cmc_assert_equals(ptr, NULL, set);
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(set == NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(new[edge_case:capacity = UINT64_MAX], {
|
||||
hashset *set = hs_new(UINT64_MAX, 0.6, cmp, hash);
|
||||
CMC_CREATE_TEST(new[capacity = UINT64_MAX], {
|
||||
hashset *set = hs_new(UINT64_MAX, 0.99, cmp, hash);
|
||||
|
||||
cmc_assert_equals(ptr, NULL, set);
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(set == NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(clear[count capacity], {
|
||||
@@ -44,13 +41,320 @@ CMC_CREATE_UNIT(hashset_test, true, {
|
||||
|
||||
cmc_assert_equals(size_t, 50, hs_count(set));
|
||||
|
||||
hs_clear(set);
|
||||
hs_clear(set, NULL);
|
||||
|
||||
cmc_assert_equals(size_t, 0, hs_count(set));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(hs_count(set) == 0);
|
||||
|
||||
hs_free(set);
|
||||
hs_free(set, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(insert, {
|
||||
hashset *set = hs_new(100, 0.6, cmp, hash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, set);
|
||||
|
||||
cmc_assert(hs_insert(set, 1));
|
||||
cmc_assert_equals(size_t, 1, hs_count(set));
|
||||
|
||||
hs_free(set, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(insert[smallest capacity], {
|
||||
hashset *set = hs_new(1, 0.99, cmp, hash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, set);
|
||||
|
||||
cmc_assert_equals(size_t, cmc_hashtable_primes[0], hs_capacity(set));
|
||||
cmc_assert(hs_insert(set, 1));
|
||||
|
||||
hs_free(set, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(insert[element position], {
|
||||
// Using the numhash the key is the hash itself
|
||||
hashset *set = hs_new(1, 0.99, cmp, numhash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, set);
|
||||
|
||||
size_t capacity = hs_capacity(set);
|
||||
|
||||
cmc_assert_greater(size_t, 0, capacity);
|
||||
|
||||
cmc_assert(hs_insert(set, capacity - 1));
|
||||
cmc_assert(hs_insert(set, capacity));
|
||||
|
||||
cmc_assert_equals(size_t, capacity - 1, set->buffer[capacity - 1].value);
|
||||
cmc_assert_equals(size_t, capacity, set->buffer[0].value);
|
||||
|
||||
hs_free(set, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(insert[distance], {
|
||||
hashset *set = hs_new(500, 0.6, cmp, hash0);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, set);
|
||||
|
||||
for (size_t i = 0; i < 200; i++)
|
||||
cmc_assert(hs_insert(set, i));
|
||||
|
||||
// Everything is hashed to 0 so key 0 should have dist 0, key 1 dist 1, etc
|
||||
for (size_t i = 0; i < 200; i++)
|
||||
cmc_assert_equals(size_t, i, set->buffer[i].dist);
|
||||
|
||||
hs_free(set, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(insert[distance wrap], {
|
||||
hashset *set = hs_new(1, 0.99, cmp, hashcapminus1);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, set);
|
||||
|
||||
size_t capacity = hs_capacity(set);
|
||||
|
||||
// Just to be sure, not part of the test
|
||||
cmc_assert_equals(size_t, cmc_hashtable_primes[0] - 1, hashcapminus1(0));
|
||||
cmc_assert_equals(size_t, capacity - 1, hashcapminus1(0));
|
||||
|
||||
cmc_assert(hs_insert(set, 0));
|
||||
cmc_assert(hs_insert(set, 1));
|
||||
|
||||
cmc_assert_equals(size_t, 0, set->buffer[capacity - 1].dist);
|
||||
cmc_assert_equals(size_t, 1, set->buffer[0].dist);
|
||||
|
||||
hs_free(set, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(insert[buffer growth and item preservation], {
|
||||
hashset *set = hs_new(1, 0.99, cmp, hash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, set);
|
||||
|
||||
cmc_assert_equals(size_t, cmc_hashtable_primes[0], hs_capacity(set));
|
||||
|
||||
size_t p = 0;
|
||||
for (size_t i = 0; i < 100000; i++)
|
||||
{
|
||||
if (hs_full(set))
|
||||
p++;
|
||||
|
||||
cmc_assert(hs_insert(set, i));
|
||||
}
|
||||
|
||||
cmc_assert_equals(size_t, cmc_hashtable_primes[p], hs_capacity(set));
|
||||
|
||||
for (size_t i = 0; i < 100000; i++)
|
||||
cmc_assert(hs_contains(set, i));
|
||||
|
||||
hs_free(set, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(remove, {
|
||||
hashset *set = hs_new(100, 0.6, cmp, hash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, set);
|
||||
|
||||
for (size_t i = 0; i < 100; i++)
|
||||
cmc_assert(hs_insert(set, i));
|
||||
|
||||
for (size_t i = 0; i < 100; i++)
|
||||
cmc_assert(hs_remove(set, i));
|
||||
|
||||
hs_free(set, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(remove[count = 0], {
|
||||
hashset *set = hs_new(100, 0.6, cmp, hash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, set);
|
||||
|
||||
for (size_t i = 100; i < 200; i++)
|
||||
cmc_assert(!hs_remove(set, i));
|
||||
|
||||
hs_free(set, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(remove[key not found], {
|
||||
hashset *set = hs_new(100, 0.6, cmp, hash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, set);
|
||||
|
||||
for (size_t i = 0; i < 100; i++)
|
||||
cmc_assert(hs_insert(set, i));
|
||||
|
||||
for (size_t i = 100; i < 200; i++)
|
||||
cmc_assert(!hs_remove(set, i));
|
||||
|
||||
hs_free(set, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(max, {
|
||||
hashset *set = hs_new(100, 0.6, cmp, hash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, set);
|
||||
|
||||
for (size_t i = 1; i <= 100; i++)
|
||||
cmc_assert(hs_insert(set, i));
|
||||
|
||||
size_t val;
|
||||
cmc_assert(hs_max(set, &val));
|
||||
|
||||
cmc_assert_equals(size_t, 100, val);
|
||||
|
||||
hs_free(set, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(max[count = 0], {
|
||||
hashset *set = hs_new(100, 0.6, cmp, hash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, set);
|
||||
|
||||
cmc_assert(!hs_min(set, NULL));
|
||||
|
||||
hs_free(set, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(min, {
|
||||
hashset *set = hs_new(100, 0.6, cmp, hash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, set);
|
||||
|
||||
for (size_t i = 1; i <= 100; i++)
|
||||
cmc_assert(hs_insert(set, i));
|
||||
|
||||
size_t val;
|
||||
cmc_assert(hs_min(set, &val));
|
||||
|
||||
cmc_assert_equals(size_t, 1, val);
|
||||
|
||||
hs_free(set, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(min[count = 0], {
|
||||
hashset *set = hs_new(100, 0.6, cmp, hash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, set);
|
||||
|
||||
cmc_assert(!hs_min(set, NULL));
|
||||
|
||||
hs_free(set, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(contains, {
|
||||
hashset *set = hs_new(100, 0.6, cmp, hash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, set);
|
||||
|
||||
cmc_assert(hs_insert(set, 987654321));
|
||||
|
||||
cmc_assert(hs_contains(set, 987654321));
|
||||
|
||||
hs_free(set, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(contains[count = 0], {
|
||||
hashset *set = hs_new(100, 0.6, cmp, hash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, set);
|
||||
|
||||
cmc_assert(!hs_contains(set, 987654321));
|
||||
|
||||
hs_free(set, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(contains[sum], {
|
||||
hashset *set = hs_new(100, 0.6, cmp, hash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, set);
|
||||
|
||||
for (size_t i = 101; i <= 200; i++)
|
||||
cmc_assert(hs_insert(set, i));
|
||||
|
||||
size_t sum = 0;
|
||||
for (size_t i = 1; i <= 300; i++)
|
||||
if (hs_contains(set, i))
|
||||
sum += i;
|
||||
|
||||
cmc_assert_equals(size_t, 15050, sum);
|
||||
|
||||
hs_free(set, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(empty, {
|
||||
hashset *set = hs_new(100, 0.6, cmp, hash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, set);
|
||||
|
||||
cmc_assert(hs_empty(set));
|
||||
|
||||
cmc_assert(hs_insert(set, 1));
|
||||
|
||||
cmc_assert(!hs_empty(set));
|
||||
|
||||
hs_free(set, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(full, {
|
||||
hashset *set = hs_new(cmc_hashtable_primes[0], 0.99999, cmp, hash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, set);
|
||||
|
||||
cmc_assert_equals(size_t, cmc_hashtable_primes[0], hs_capacity(set));
|
||||
|
||||
for (size_t i = 0; i < hs_capacity(set); i++)
|
||||
cmc_assert(hs_insert(set, i));
|
||||
|
||||
cmc_assert(hs_full(set));
|
||||
|
||||
cmc_assert(hs_insert(set, 10000));
|
||||
|
||||
cmc_assert_equals(size_t, cmc_hashtable_primes[1], hs_capacity(set));
|
||||
|
||||
cmc_assert(!hs_full(set));
|
||||
|
||||
hs_free(set, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(count, {
|
||||
hashset *set = hs_new(100, 0.6, cmp, hash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, set);
|
||||
|
||||
for (size_t i = 1; i < 100; i++)
|
||||
{
|
||||
cmc_assert(hs_insert(set, i));
|
||||
cmc_assert_equals(size_t, i, hs_count(set));
|
||||
}
|
||||
|
||||
hs_free(set, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(capacity, {
|
||||
hashset *set = hs_new(2500, 0.6, cmp, hash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, set);
|
||||
|
||||
cmc_assert_greater_equals(size_t, (size_t)(2500 / 0.6), hs_capacity(set));
|
||||
|
||||
hs_free(set, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(capacity[small], {
|
||||
hashset *set = hs_new(1, 0.99, cmp, hash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, set);
|
||||
|
||||
cmc_assert_equals(size_t, cmc_hashtable_primes[0], hs_capacity(set));
|
||||
|
||||
hs_free(set, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(load, {
|
||||
hashset *set = hs_new(1, 0.99, cmp, hash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, set);
|
||||
|
||||
cmc_assert_in_range(double, 0.99 - 0.0001, 0.99 + 0.0001, hs_load(set));
|
||||
|
||||
hs_free(set, NULL);
|
||||
});
|
||||
});
|
||||
+116
-27
@@ -1,40 +1,34 @@
|
||||
#include "utl/assert.h"
|
||||
#include "utl/test.h"
|
||||
#include "../src/heap.c"
|
||||
|
||||
#include "utl.c"
|
||||
#include <utl/assert.h>
|
||||
#include <utl/log.h>
|
||||
#include <utl/test.h>
|
||||
|
||||
#include <cmc/heap.h>
|
||||
|
||||
CMC_GENERATE_HEAP(h, heap, size_t)
|
||||
|
||||
CMC_CREATE_UNIT(heap_test, true, {
|
||||
CMC_CREATE_TEST(new, {
|
||||
heap *h = h_new(1000000, cmc_max_heap, cmp);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, h);
|
||||
|
||||
bool passed = h->capacity == 1000000 && h->count == 0 && h->buffer;
|
||||
|
||||
cmc_assert_equals(size_t, 1000000, h->capacity);
|
||||
cmc_assert_equals(size_t, 0, h_count(h));
|
||||
cmc_assert_not_equals(ptr, NULL, h->buffer);
|
||||
cmc_assert_equals(size_t, 1000000, h_capacity(h));
|
||||
cmc_assert_equals(size_t, 0, h_count(h));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(passed);
|
||||
|
||||
h_free(h);
|
||||
h_free(h, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(new[edge_case:capacity = 0], {
|
||||
CMC_CREATE_TEST(new[edge_case capacity = 0], {
|
||||
heap *h = h_new(0, cmc_max_heap, cmp);
|
||||
|
||||
cmc_assert_equals(ptr, NULL, h);
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(h == NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(new[edge_case:capacity = UINT64_MAX], {
|
||||
CMC_CREATE_TEST(new[edge_case capacity = UINT64_MAX], {
|
||||
heap *h = h_new(UINT64_MAX, cmc_max_heap, cmp);
|
||||
|
||||
cmc_assert_equals(ptr, NULL, h);
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(h == NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(clear[count capacity], {
|
||||
@@ -47,29 +41,124 @@ CMC_CREATE_UNIT(heap_test, true, {
|
||||
|
||||
cmc_assert_equals(size_t, 50, h_count(h));
|
||||
|
||||
h_clear(h);
|
||||
h_clear(h, NULL);
|
||||
|
||||
cmc_assert_equals(size_t, 0, h_count(h));
|
||||
cmc_assert_equals(size_t, 100, h_capacity(h));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(h_count(h) == 0 && h_capacity(h) == 100);
|
||||
|
||||
h_free(h);
|
||||
h_free(h, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(buffer_growth[edge_case:capacity = 1], {
|
||||
CMC_CREATE_TEST(buffer_growth[edge_case capacity = 1], {
|
||||
heap *h = h_new(1, cmc_max_heap, cmp);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, h);
|
||||
|
||||
for (size_t i = 0; i < 50; i++)
|
||||
h_insert(h, i);
|
||||
cmc_assert(h_insert(h, i));
|
||||
|
||||
cmc_assert_equals(size_t, 50, h_count(h));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(h_count(h) == 50);
|
||||
|
||||
h_free(h);
|
||||
h_free(h, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(insert, {
|
||||
heap *h = h_new(100, cmc_max_heap, cmp);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, h);
|
||||
|
||||
cmc_assert(h_insert(h, 10));
|
||||
|
||||
h_free(h, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(insert[item preservation], {
|
||||
heap *h = h_new(50, cmc_max_heap, cmp);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, h);
|
||||
|
||||
for (size_t i = 0; i <= 100; i++)
|
||||
cmc_assert(h_insert(h, i));
|
||||
|
||||
size_t sum = 0;
|
||||
for (size_t i = 0; i < h_count(h); i++)
|
||||
sum += h->buffer[i];
|
||||
|
||||
cmc_assert_equals(size_t, 5050, sum);
|
||||
|
||||
h_free(h, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(remove, {
|
||||
heap *h = h_new(50, cmc_max_heap, cmp);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, h);
|
||||
|
||||
for (size_t i = 0; i <= 100; i++)
|
||||
cmc_assert(h_insert(h, i));
|
||||
|
||||
size_t r;
|
||||
cmc_assert(h_remove(h, &r));
|
||||
|
||||
cmc_assert_equals(size_t, 100, r);
|
||||
|
||||
h_free(h, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(remove[count = 0], {
|
||||
heap *h = h_new(100, cmc_max_heap, cmp);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, h);
|
||||
|
||||
size_t _;
|
||||
cmc_assert(!h_remove(h, &_));
|
||||
|
||||
h_free(h, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(remove[sorted], {
|
||||
heap *h = h_new(100, cmc_min_heap, cmp);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, h);
|
||||
|
||||
for (size_t i = 1; i <= 100; i++)
|
||||
cmc_assert(h_insert(h, i));
|
||||
|
||||
size_t r;
|
||||
size_t i = 0;
|
||||
size_t arr[100];
|
||||
while (!h_empty(h))
|
||||
{
|
||||
cmc_assert(h_remove(h, &r));
|
||||
|
||||
arr[i++] = r;
|
||||
}
|
||||
|
||||
cmc_assert_array_sorted_any(size_t, arr, cmp, 0, 99);
|
||||
|
||||
h_free(h, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(peek, {
|
||||
heap *h = h_new(100, cmc_max_heap, cmp);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, h);
|
||||
|
||||
for (size_t i = 1; i <= 100; i++)
|
||||
cmc_assert(h_insert(h, i));
|
||||
|
||||
cmc_assert_equals(size_t, 100, h_peek(h));
|
||||
|
||||
h_free(h, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(peek[count = 0], {
|
||||
heap *h = h_new(100, cmc_max_heap, cmp);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, h);
|
||||
|
||||
cmc_assert_equals(size_t, (size_t){0}, h_peek(h));
|
||||
|
||||
h_free(h, NULL);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,134 @@
|
||||
#include "utl.c"
|
||||
#include <utl/assert.h>
|
||||
#include <utl/log.h>
|
||||
#include <utl/test.h>
|
||||
|
||||
#include <ext/intervalheap.h>
|
||||
|
||||
CMC_GENERATE_INTERVALHEAP(ih, intervalheap, size_t)
|
||||
|
||||
CMC_CREATE_UNIT(intervalheap_test, true, {
|
||||
CMC_CREATE_TEST(new, {
|
||||
intervalheap *ih = ih_new(1000000, cmp);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, ih);
|
||||
cmc_assert_not_equals(ptr, NULL, ih->buffer);
|
||||
cmc_assert_equals(size_t, 500000, ih_capacity(ih));
|
||||
cmc_assert_equals(size_t, 0, ih_count(ih));
|
||||
|
||||
ih_free(ih, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(new[capacity = 0], {
|
||||
intervalheap *ih = ih_new(0, cmp);
|
||||
|
||||
cmc_assert_equals(ptr, NULL, ih);
|
||||
|
||||
if (ih)
|
||||
ih_free(ih, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(new[capacity], {
|
||||
intervalheap *ih = ih_new(1, cmp);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, ih);
|
||||
cmc_assert_equals(size_t, 1, ih_capacity(ih));
|
||||
|
||||
ih_free(ih, NULL);
|
||||
|
||||
ih = ih_new(2, cmp);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, ih);
|
||||
cmc_assert_equals(size_t, 1, ih_capacity(ih));
|
||||
|
||||
ih_free(ih, NULL);
|
||||
|
||||
ih = ih_new(3, cmp);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, ih);
|
||||
cmc_assert_equals(size_t, 2, ih_capacity(ih));
|
||||
|
||||
ih_free(ih, NULL);
|
||||
|
||||
ih = ih_new(4, cmp);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, ih);
|
||||
cmc_assert_equals(size_t, 2, ih_capacity(ih));
|
||||
|
||||
ih_free(ih, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(new[capacity = UINT64_MAX], {
|
||||
intervalheap *ih = ih_new(UINT64_MAX, cmp);
|
||||
|
||||
cmc_assert_equals(ptr, NULL, ih);
|
||||
|
||||
if (ih)
|
||||
ih_free(ih, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(clear[count capacity], {
|
||||
intervalheap *ih = ih_new(100, cmp);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, ih);
|
||||
|
||||
for (size_t i = 0; i < 50; i++)
|
||||
cmc_assert(ih_insert(ih, i));
|
||||
|
||||
cmc_assert_equals(size_t, 50, ih_count(ih));
|
||||
|
||||
ih_clear(ih, NULL);
|
||||
|
||||
cmc_assert_equals(size_t, 0, ih_count(ih));
|
||||
cmc_assert_equals(size_t, 50, ih_capacity(ih));
|
||||
|
||||
ih_free(ih, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(buffer_growth[capacity = 1], {
|
||||
intervalheap *ih = ih_new(1, cmp);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, ih);
|
||||
|
||||
for (size_t i = 0; i < 50; i++)
|
||||
cmc_assert(ih_insert(ih, i));
|
||||
|
||||
cmc_assert_equals(size_t, 50, ih_count(ih));
|
||||
cmc_assert_greater(size_t, 50, ih_capacity(ih) * 2);
|
||||
|
||||
ih_free(ih, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(insert[count], {
|
||||
intervalheap *ih = ih_new(100, cmp);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, ih);
|
||||
|
||||
cmc_assert(ih_insert(ih, 1));
|
||||
cmc_assert(ih_insert(ih, 0));
|
||||
|
||||
cmc_assert_equals(size_t, 2, ih_count(ih));
|
||||
|
||||
ih_free(ih, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(insert[max min], {
|
||||
intervalheap *ih = ih_new(1, cmp);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, ih);
|
||||
|
||||
cmc_assert(ih_insert(ih, 1));
|
||||
cmc_assert(ih_insert(ih, 0));
|
||||
|
||||
size_t min;
|
||||
size_t max;
|
||||
|
||||
cmc_assert(ih_min(ih, &min));
|
||||
cmc_assert(ih_max(ih, &max));
|
||||
|
||||
cmc_assert_equals(size_t, 0, min);
|
||||
cmc_assert_equals(size_t, 1, max);
|
||||
|
||||
ih_free(ih, NULL);
|
||||
});
|
||||
});
|
||||
+17
-32
@@ -1,22 +1,22 @@
|
||||
#include "utl/assert.h"
|
||||
#include "utl/test.h"
|
||||
#include "../src/linkedlist.c"
|
||||
#include "utl.c"
|
||||
#include <utl/assert.h>
|
||||
#include <utl/log.h>
|
||||
#include <utl/test.h>
|
||||
|
||||
#include <cmc/linkedlist.h>
|
||||
|
||||
CMC_GENERATE_LINKEDLIST(ll, linkedlist, size_t)
|
||||
|
||||
CMC_CREATE_UNIT(linkedlist_test, true, {
|
||||
CMC_CREATE_TEST(new, {
|
||||
linkedlist *ll = ll_new();
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, ll);
|
||||
|
||||
bool passed = ll->count == 0 && ll->head == NULL && ll->tail == NULL;
|
||||
|
||||
cmc_assert_equals(size_t, 0, ll_count(ll));
|
||||
cmc_assert_equals(ptr, NULL, ll->head);
|
||||
cmc_assert_equals(ptr, NULL, ll->tail);
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(passed);
|
||||
|
||||
ll_free(ll);
|
||||
ll_free(ll, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(clear[count capacity], {
|
||||
@@ -29,27 +29,23 @@ CMC_CREATE_UNIT(linkedlist_test, true, {
|
||||
|
||||
cmc_assert_equals(size_t, 50, ll_count(ll));
|
||||
|
||||
ll_clear(ll);
|
||||
ll_clear(ll, NULL);
|
||||
|
||||
cmc_assert_equals(size_t, 0, ll_count(ll));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(ll_count(ll) == 0);
|
||||
|
||||
ll_free(ll);
|
||||
ll_free(ll, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(clear[edge_case:count = 0], {
|
||||
CMC_CREATE_TEST(clear[count = 0], {
|
||||
linkedlist *ll = ll_new();
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, ll);
|
||||
|
||||
ll_clear(ll);
|
||||
ll_clear(ll, NULL);
|
||||
|
||||
cmc_assert_equals(size_t, 0, ll_count(ll));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(ll_count(ll) == 0);
|
||||
|
||||
ll_free(ll);
|
||||
ll_free(ll, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(push_front[count], {
|
||||
@@ -63,12 +59,10 @@ CMC_CREATE_UNIT(linkedlist_test, true, {
|
||||
cmc_assert_not_equals(ptr, NULL, ll->tail);
|
||||
cmc_assert_equals(size_t, 1, ll_count(ll));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(ll->head && ll->tail && ll_count(ll) == 1);
|
||||
|
||||
ll_free(ll);
|
||||
ll_free(ll, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(push_front[item_preservation], {
|
||||
CMC_CREATE_TEST(push_front[item preservation], {
|
||||
linkedlist *ll = ll_new();
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, ll);
|
||||
@@ -76,18 +70,9 @@ CMC_CREATE_UNIT(linkedlist_test, true, {
|
||||
for (size_t i = 0; i < 200; i++)
|
||||
ll_push_front(ll, i);
|
||||
|
||||
bool passed = true;
|
||||
|
||||
for (size_t i = 0; i < ll_count(ll); i++)
|
||||
{
|
||||
passed = passed && ll_get(ll, i) == (ll_count(ll) - i - 1);
|
||||
|
||||
cmc_assert_equals(size_t, ll_get(ll, i), ll_count(ll) - i - 1);
|
||||
}
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(passed && ll_count(ll) == 200);
|
||||
|
||||
ll_free(ll);
|
||||
ll_free(ll, NULL);
|
||||
});
|
||||
|
||||
});
|
||||
@@ -1,41 +0,0 @@
|
||||
#include "utl/assert.h"
|
||||
#include "utl/test.h"
|
||||
#include "../src/linkedqueue.c"
|
||||
|
||||
CMC_CREATE_UNIT(linkedqueue_test, true, {
|
||||
CMC_CREATE_TEST(new, {
|
||||
linkedqueue *q = lq_new();
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, q);
|
||||
|
||||
bool passed = q->count == 0 && !q->head && !q->tail;
|
||||
|
||||
cmc_assert_equals(size_t, 0, lq_count(q));
|
||||
cmc_assert_equals(ptr, NULL, q->head);
|
||||
cmc_assert_equals(ptr, NULL, q->tail);
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(passed);
|
||||
|
||||
lq_free(q);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(clear[count], {
|
||||
linkedqueue *q = lq_new();
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, q);
|
||||
|
||||
for (size_t i = 0; i < 50; i++)
|
||||
lq_enqueue(q, i);
|
||||
|
||||
cmc_assert_equals(size_t, 50, lq_count(q));
|
||||
|
||||
lq_clear(q);
|
||||
|
||||
cmc_assert_equals(size_t, 0, lq_count(q));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(lq_count(q) == 0);
|
||||
|
||||
lq_free(q);
|
||||
});
|
||||
|
||||
});
|
||||
+61
-141
@@ -1,41 +1,37 @@
|
||||
#include "utl/assert.h"
|
||||
#include "utl/test.h"
|
||||
#include "../src/list.c"
|
||||
#include "utl.c"
|
||||
#include <utl/assert.h>
|
||||
#include <utl/log.h>
|
||||
#include <utl/test.h>
|
||||
|
||||
#include <cmc/list.h>
|
||||
|
||||
CMC_GENERATE_LIST(l, list, size_t)
|
||||
|
||||
CMC_CREATE_UNIT(list_test, true, {
|
||||
CMC_CREATE_TEST(new, {
|
||||
list *l = l_new(1000000);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, l);
|
||||
|
||||
bool passed = l->capacity == 1000000 && l->count == 0 && l->buffer;
|
||||
|
||||
cmc_assert_equals(size_t, 1000000, l->capacity);
|
||||
cmc_assert_equals(size_t, 0, l_count(l));
|
||||
cmc_assert_not_equals(ptr, NULL, l->buffer);
|
||||
cmc_assert_equals(size_t, 1000000, l_capacity(l));
|
||||
cmc_assert_equals(size_t, 0, l_count(l));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(passed);
|
||||
|
||||
l_free(l);
|
||||
l_free(l, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(new[edge_case:capacity = 0], {
|
||||
CMC_CREATE_TEST(new[capacity = 0], {
|
||||
list *l = l_new(0);
|
||||
|
||||
cmc_assert_equals(ptr, NULL, l);
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(l == NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(new[edge_case:capacity = UINT64_MAX], {
|
||||
CMC_CREATE_TEST(new[capacity = UINT64_MAX], {
|
||||
list *l = l_new(UINT64_MAX);
|
||||
|
||||
cmc_assert_equals(ptr, NULL, l);
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(l == NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(new_from[count item_preservation], {
|
||||
CMC_CREATE_TEST(new_from[count and item preservation], {
|
||||
size_t v[5];
|
||||
|
||||
for (size_t i = 0; i < 5; i++)
|
||||
@@ -47,21 +43,13 @@ CMC_CREATE_UNIT(list_test, true, {
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, l);
|
||||
|
||||
bool passed = true;
|
||||
|
||||
for (size_t i = 0; i < 5; i++)
|
||||
{
|
||||
cmc_assert_equals(size_t, i, l_get(l, i));
|
||||
|
||||
passed = passed && l_get(l, i) == i;
|
||||
}
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(passed && l_count(l) == 5);
|
||||
|
||||
l_free(l);
|
||||
l_free(l, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(new_from[edge_case:size = 1], {
|
||||
CMC_CREATE_TEST(new_from[size = 1], {
|
||||
size_t a = 10;
|
||||
|
||||
size_t *values = &a;
|
||||
@@ -70,9 +58,7 @@ CMC_CREATE_UNIT(list_test, true, {
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, l);
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(l_count(l) == 1);
|
||||
|
||||
l_free(l);
|
||||
l_free(l, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(clear[count capacity], {
|
||||
@@ -85,17 +71,15 @@ CMC_CREATE_UNIT(list_test, true, {
|
||||
|
||||
cmc_assert_equals(size_t, 50, l_count(l));
|
||||
|
||||
l_clear(l);
|
||||
l_clear(l, NULL);
|
||||
|
||||
cmc_assert_equals(size_t, 0, l_count(l));
|
||||
cmc_assert_equals(size_t, 100, l_capacity(l));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(l_count(l) == 0 && l_capacity(l) == 100);
|
||||
|
||||
l_free(l);
|
||||
l_free(l, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(buffer_growth[edge_case:capacity = 1], {
|
||||
CMC_CREATE_TEST(buffer_growth[capacity = 1], {
|
||||
list *l = l_new(1);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, l);
|
||||
@@ -105,17 +89,10 @@ CMC_CREATE_UNIT(list_test, true, {
|
||||
|
||||
cmc_assert_equals(size_t, 100, l_count(l));
|
||||
|
||||
bool passed = true;
|
||||
|
||||
for (size_t i = 0; i < 100; i++)
|
||||
{
|
||||
passed = passed && l_get(l, i) == i;
|
||||
cmc_assert_equals(size_t, i, l_get(l, i));
|
||||
}
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(passed);
|
||||
|
||||
l_free(l);
|
||||
l_free(l, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(push_front[count], {
|
||||
@@ -128,9 +105,7 @@ CMC_CREATE_UNIT(list_test, true, {
|
||||
|
||||
cmc_assert_equals(size_t, 250, l_count(l));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(l_count(l) == 250);
|
||||
|
||||
l_free(l);
|
||||
l_free(l, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(push_front[capacity], {
|
||||
@@ -143,12 +118,10 @@ CMC_CREATE_UNIT(list_test, true, {
|
||||
|
||||
cmc_assert_lesser_equals(size_t, l_capacity(l), l_count(l));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(l_count(l) <= l_capacity(l));
|
||||
|
||||
l_free(l);
|
||||
l_free(l, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(push_front[item_preservation], {
|
||||
CMC_CREATE_TEST(push_front[item preservation], {
|
||||
list *l = l_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, l);
|
||||
@@ -156,21 +129,13 @@ CMC_CREATE_UNIT(list_test, true, {
|
||||
for (size_t i = 0; i < 250; i++)
|
||||
cmc_assert(l_push_front(l, i));
|
||||
|
||||
bool passed = true;
|
||||
|
||||
for (size_t i = 0; i < l_count(l); i++)
|
||||
{
|
||||
passed = passed && l_get(l, i) == (l_count(l) - i - 1);
|
||||
|
||||
cmc_assert_equals(size_t, l_get(l, i), l_count(l) - i - 1);
|
||||
}
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(passed);
|
||||
|
||||
l_free(l);
|
||||
l_free(l, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(push[count], {
|
||||
CMC_CREATE_TEST(push_at[count], {
|
||||
list *l = l_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, l);
|
||||
@@ -179,16 +144,14 @@ CMC_CREATE_UNIT(list_test, true, {
|
||||
cmc_assert(l_push_back(l, 249));
|
||||
|
||||
for (size_t i = 1; i < 249; i++)
|
||||
cmc_assert(l_push(l, i, l_count(l) - 1));
|
||||
cmc_assert(l_push_at(l, i, l_count(l) - 1));
|
||||
|
||||
cmc_assert_equals(size_t, 250, l_count(l));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(l_count(l) == 250);
|
||||
|
||||
l_free(l);
|
||||
l_free(l, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(push[capacity], {
|
||||
CMC_CREATE_TEST(push_at[capacity], {
|
||||
list *l = l_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, l);
|
||||
@@ -197,16 +160,14 @@ CMC_CREATE_UNIT(list_test, true, {
|
||||
cmc_assert(l_push_back(l, 249));
|
||||
|
||||
for (size_t i = 1; i < 249; i++)
|
||||
cmc_assert(l_push(l, i, l_count(l) - 1));
|
||||
cmc_assert(l_push_at(l, i, l_count(l) - 1));
|
||||
|
||||
cmc_assert_lesser_equals(size_t, l_capacity(l), l_count(l));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(l_count(l) <= l_capacity(l));
|
||||
|
||||
l_free(l);
|
||||
l_free(l, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(push[item_preservation], {
|
||||
CMC_CREATE_TEST(push_at[item preservation], {
|
||||
list *l = l_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, l);
|
||||
@@ -215,20 +176,12 @@ CMC_CREATE_UNIT(list_test, true, {
|
||||
cmc_assert(l_push_back(l, 249));
|
||||
|
||||
for (size_t i = 1; i < 249; i++)
|
||||
cmc_assert(l_push(l, i, l_count(l) - 1));
|
||||
|
||||
bool passed = true;
|
||||
cmc_assert(l_push_at(l, i, l_count(l) - 1));
|
||||
|
||||
for (size_t i = 0; i < l_count(l); i++)
|
||||
{
|
||||
passed = passed && l_get(l, i) == i;
|
||||
|
||||
cmc_assert_equals(size_t, l_get(l, i), i);
|
||||
}
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(passed);
|
||||
|
||||
l_free(l);
|
||||
l_free(l, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(push_back[count], {
|
||||
@@ -241,9 +194,7 @@ CMC_CREATE_UNIT(list_test, true, {
|
||||
|
||||
cmc_assert_equals(size_t, 250, l_count(l));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(l_count(l) == 250);
|
||||
|
||||
l_free(l);
|
||||
l_free(l, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(push_back[capacity], {
|
||||
@@ -256,12 +207,10 @@ CMC_CREATE_UNIT(list_test, true, {
|
||||
|
||||
cmc_assert_lesser_equals(size_t, l_capacity(l), l_count(l));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(l_count(l) <= l_capacity(l));
|
||||
|
||||
l_free(l);
|
||||
l_free(l, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(push_back[item_preservation], {
|
||||
CMC_CREATE_TEST(push_back[item preservation], {
|
||||
list *l = l_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, l);
|
||||
@@ -269,18 +218,10 @@ CMC_CREATE_UNIT(list_test, true, {
|
||||
for (size_t i = 0; i < 250; i++)
|
||||
cmc_assert(l_push_back(l, i));
|
||||
|
||||
bool passed = true;
|
||||
|
||||
for (size_t i = 0; i < l_count(l); i++)
|
||||
{
|
||||
passed = passed && l_get(l, i) == i;
|
||||
|
||||
cmc_assert_equals(size_t, l_get(l, i), i);
|
||||
}
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(passed);
|
||||
|
||||
l_free(l);
|
||||
l_free(l, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(pop_front[count], {
|
||||
@@ -293,12 +234,10 @@ CMC_CREATE_UNIT(list_test, true, {
|
||||
|
||||
cmc_assert(l_pop_front(l));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(l_count(l) == 250 - 1);
|
||||
|
||||
l_free(l);
|
||||
l_free(l, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(pop_front[item_preservation], {
|
||||
CMC_CREATE_TEST(pop_front[item preservation], {
|
||||
list *l = l_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, l);
|
||||
@@ -306,40 +245,31 @@ CMC_CREATE_UNIT(list_test, true, {
|
||||
for (size_t i = 0; i < 250; i++)
|
||||
l_push_back(l, i);
|
||||
|
||||
bool passed = l_pop_front(l);
|
||||
cmc_assert(l_pop_front(l));
|
||||
|
||||
for (size_t i = 0; i < l_count(l); i++)
|
||||
{
|
||||
passed = passed && l_get(l, i) == i + 1;
|
||||
|
||||
cmc_assert_equals(size_t, l_get(l, i), i + 1);
|
||||
}
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(passed);
|
||||
|
||||
l_free(l);
|
||||
l_free(l, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(pop_front[edge_case:count = 0], {
|
||||
CMC_CREATE_TEST(pop_front[count = 0], {
|
||||
list *l = l_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, l);
|
||||
cmc_assert(!l_pop_front(l));
|
||||
CMC_TEST_PASS_ELSE_FAIL(l_count(l) == 0);
|
||||
|
||||
l_free(l);
|
||||
l_free(l, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(pop_front[edge_case:count = 1], {
|
||||
CMC_CREATE_TEST(pop_front[count = 1], {
|
||||
list *l = l_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, l);
|
||||
cmc_assert(l_push_back(l, 10));
|
||||
cmc_assert(l_pop_front(l));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(l_count(l) == 0);
|
||||
|
||||
l_free(l);
|
||||
l_free(l, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(pop_front[buffer_clear], {
|
||||
@@ -349,72 +279,62 @@ CMC_CREATE_UNIT(list_test, true, {
|
||||
cmc_assert(l_push_back(l, 1));
|
||||
cmc_assert(l_push_front(l, 2));
|
||||
|
||||
bool passed = l_pop_front(l) && l->buffer[1] == 0;
|
||||
cmc_assert(l_pop_front(l));
|
||||
|
||||
cmc_assert_equals(size_t, 0, l->buffer[1]);
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(passed && l_count(l) == 1);
|
||||
|
||||
l_free(l);
|
||||
l_free(l, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(pop[edge_case:count = 0], {
|
||||
CMC_CREATE_TEST(pop_at[count = 0], {
|
||||
list *l = l_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, l);
|
||||
cmc_assert(!l_pop(l, 1));
|
||||
cmc_assert(!l_pop_at(l, 1));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(!l_pop(l, 1));
|
||||
|
||||
l_free(l);
|
||||
l_free(l, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(pop[edge_case:count = 1], {
|
||||
CMC_CREATE_TEST(pop_at[count = 1], {
|
||||
list *l = l_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, l);
|
||||
cmc_assert(l_push_back(l, 1));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(l_pop(l, 0));
|
||||
cmc_assert(l_pop_at(l, 0));
|
||||
|
||||
cmc_assert_equals(size_t, 0, l->buffer[0]);
|
||||
|
||||
l_free(l);
|
||||
l_free(l, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(pop[buffer_clear], {
|
||||
CMC_CREATE_TEST(pop_at[buffer_clear], {
|
||||
list *l = l_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, l);
|
||||
cmc_assert(l_push_back(l, 1));
|
||||
cmc_assert(l_push_back(l, 2));
|
||||
cmc_assert(l_push_back(l, 3));
|
||||
cmc_assert(l_pop(l, 1));
|
||||
cmc_assert(l_pop_at(l, 1));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(0 == l->buffer[2]);
|
||||
|
||||
l_free(l);
|
||||
l_free(l, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(pop_back[edge_case:count = 0], {
|
||||
CMC_CREATE_TEST(pop_back[count = 0], {
|
||||
list *l = l_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, l);
|
||||
cmc_assert(!l_pop_back(l));
|
||||
CMC_TEST_PASS_ELSE_FAIL(l_count(l) == 0);
|
||||
|
||||
l_free(l);
|
||||
l_free(l, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(pop_back[edge_case:count = 1], {
|
||||
CMC_CREATE_TEST(pop_back[count = 1], {
|
||||
list *l = l_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, l);
|
||||
cmc_assert(l_push_back(l, 10));
|
||||
cmc_assert(l_pop_back(l));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(l_count(l) == 0);
|
||||
|
||||
l_free(l);
|
||||
l_free(l, NULL);
|
||||
});
|
||||
})
|
||||
+40
-75
@@ -1,37 +1,34 @@
|
||||
#include "utl/assert.h"
|
||||
#include "utl/test.h"
|
||||
#include "../src/multimap.c"
|
||||
|
||||
#include "utl.c"
|
||||
#include <utl/assert.h>
|
||||
#include <utl/log.h>
|
||||
#include <utl/test.h>
|
||||
|
||||
#include <ext/multimap.h>
|
||||
|
||||
CMC_GENERATE_MULTIMAP(mm, multimap, size_t, size_t)
|
||||
|
||||
CMC_CREATE_UNIT(multimap_test, true, {
|
||||
CMC_CREATE_TEST(new, {
|
||||
multimap *map = mm_new(943722, 0.8, cmp, hash);
|
||||
|
||||
bool passed = (map->capacity >= (943722 / 0.8)) && map->count == 0 && map->buffer;
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
cmc_assert_not_equals(ptr, NULL, map->buffer);
|
||||
cmc_assert_equals(size_t, 0, mm_count(map));
|
||||
cmc_assert_greater_equals(size_t, (943722 / 0.8), mm_capacity(map));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(passed);
|
||||
|
||||
mm_free(map);
|
||||
mm_free(map, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(new[edge_case:capacity = 0], {
|
||||
CMC_CREATE_TEST(new[capacity = 0], {
|
||||
multimap *map = mm_new(0, 0.8, cmp, hash);
|
||||
|
||||
cmc_assert_equals(ptr, NULL, map);
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(map == NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(new[edge_case:capacity = UINT64_MAX], {
|
||||
multimap *map = mm_new(UINT64_MAX, 0.8, cmp, hash);
|
||||
CMC_CREATE_TEST(new[capacity = UINT64_MAX], {
|
||||
multimap *map = mm_new(UINT64_MAX, 0.99, cmp, hash);
|
||||
|
||||
cmc_assert_equals(ptr, NULL, map);
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(map == NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(clear[count capacity], {
|
||||
@@ -44,13 +41,11 @@ CMC_CREATE_UNIT(multimap_test, true, {
|
||||
|
||||
cmc_assert_equals(size_t, 50, mm_count(map));
|
||||
|
||||
mm_clear(map);
|
||||
mm_clear(map, NULL);
|
||||
|
||||
cmc_assert_equals(size_t, 0, mm_count(map));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(mm_count(map) == 0);
|
||||
|
||||
mm_free(map);
|
||||
mm_free(map, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(insert[count], {
|
||||
@@ -58,14 +53,12 @@ CMC_CREATE_UNIT(multimap_test, true, {
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
|
||||
for (size_t i = 0; i < 200; i++)
|
||||
for (size_t i = 0; i < 100; i++)
|
||||
cmc_assert(mm_insert(map, i % 20, i % 20));
|
||||
|
||||
cmc_assert_equals(size_t, 200, mm_count(map));
|
||||
cmc_assert_equals(size_t, 100, mm_count(map));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(mm_count(map) == 200);
|
||||
|
||||
mm_free(map);
|
||||
mm_free(map, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(remove[count], {
|
||||
@@ -83,12 +76,10 @@ CMC_CREATE_UNIT(multimap_test, true, {
|
||||
|
||||
cmc_assert_equals(size_t, 140, mm_count(map));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(mm_count(map) == 140);
|
||||
|
||||
mm_free(map);
|
||||
mm_free(map, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(remove[edge_case:count = 0], {
|
||||
CMC_CREATE_TEST(remove[count = 0], {
|
||||
multimap *map = mm_new(100, 0.8, cmp, hash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
@@ -97,12 +88,10 @@ CMC_CREATE_UNIT(multimap_test, true, {
|
||||
|
||||
cmc_assert(!mm_remove(map, 10, &r));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(!mm_remove(map, 10, &r));
|
||||
|
||||
mm_free(map);
|
||||
mm_free(map, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(remove[edge_case:count = 1], {
|
||||
CMC_CREATE_TEST(remove[count = 1], {
|
||||
multimap *map = mm_new(100, 0.8, cmp, hash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
@@ -112,47 +101,10 @@ CMC_CREATE_UNIT(multimap_test, true, {
|
||||
cmc_assert(mm_insert(map, 10, 11));
|
||||
cmc_assert(mm_remove(map, 10, &r));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(mm_count(map) == 0);
|
||||
|
||||
mm_free(map);
|
||||
mm_free(map, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(insert_if, {
|
||||
multimap *map = mm_new(100, 0.8, cmp, hash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
|
||||
for (size_t i = 1; i <= 100; i++)
|
||||
cmc_assert(mm_insert_if(map, i % 20, i, i % 2 == 0) || i % 2 != 0);
|
||||
|
||||
cmc_assert_equals(size_t, 50, mm_count(map));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(mm_count(map) == 50);
|
||||
|
||||
mm_free(map);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(remove_if, {
|
||||
multimap *map = mm_new(100, 0.8, cmp, hash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
|
||||
for (size_t i = 1; i <= 100; i++)
|
||||
cmc_assert(mm_insert(map, i % 20, i));
|
||||
|
||||
size_t r;
|
||||
|
||||
for (size_t i = 1; i <= 100; i++)
|
||||
cmc_assert(mm_remove_if(map, i % 20, &r, i % 2 == 0) || i % 2 != 0);
|
||||
|
||||
cmc_assert_equals(size_t, 50, mm_count(map));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(mm_count(map) == 50);
|
||||
|
||||
mm_free(map);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(get[key_ordering], {
|
||||
CMC_CREATE_TEST(get[key ordering], {
|
||||
multimap *map = mm_new(100, 0.8, cmp, hash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
@@ -165,9 +117,22 @@ CMC_CREATE_UNIT(multimap_test, true, {
|
||||
|
||||
cmc_assert_equals(size_t, 100, mm_get(map, 10));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(mm_get(map, 10) == 100);
|
||||
|
||||
mm_free(map);
|
||||
mm_free(map, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(key_count, {
|
||||
multimap *map = mm_new(50, 0.8, cmp, hash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
|
||||
for (size_t i = 0; i < 1000; i++)
|
||||
cmc_assert(mm_insert(map, i % 20, i % 20));
|
||||
|
||||
cmc_assert_equals(size_t, 1000, mm_count(map));
|
||||
|
||||
for (size_t i = 0; i < 20; i++)
|
||||
cmc_assert_equals(size_t, 50, mm_key_count(map, i));
|
||||
|
||||
mm_free(map, NULL);
|
||||
});
|
||||
});
|
||||
+88
-37
@@ -1,37 +1,34 @@
|
||||
#include "utl/assert.h"
|
||||
#include "utl/test.h"
|
||||
#include "../src/multiset.c"
|
||||
|
||||
#include "utl.c"
|
||||
#include <utl/assert.h>
|
||||
#include <utl/log.h>
|
||||
#include <utl/test.h>
|
||||
|
||||
#include <ext/multiset.h>
|
||||
|
||||
CMC_GENERATE_MULTISET(ms, multiset, size_t)
|
||||
|
||||
CMC_CREATE_UNIT(multiset_test, true, {
|
||||
CMC_CREATE_TEST(new, {
|
||||
multiset *set = ms_new(943722, 0.6, cmp, hash);
|
||||
|
||||
bool passed = (set->capacity >= (943722 / 0.6)) && set->count == 0 && set->buffer;
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, set);
|
||||
cmc_assert(ms_capacity(set) > (943722 / 0.6));
|
||||
cmc_assert_not_equals(ptr, NULL, set->buffer);
|
||||
cmc_assert_equals(size_t, 0, ms_count(set));
|
||||
cmc_assert_greater_equals(size_t, ((size_t)(943722 / 0.6)), ms_capacity(set));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(passed);
|
||||
|
||||
ms_free(set);
|
||||
ms_free(set, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(new[edge_case:capacity = 0], {
|
||||
CMC_CREATE_TEST(new[capacity = 0], {
|
||||
multiset *set = ms_new(0, 0.6, cmp, hash);
|
||||
|
||||
cmc_assert_equals(ptr, NULL, set);
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(set == NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(new[edge_case:capacity = UINTMAX_MAX], {
|
||||
multiset *set = ms_new(UINTMAX_MAX, 0.99, cmp, hash);
|
||||
CMC_CREATE_TEST(new[capacity = UINT64_MAX], {
|
||||
multiset *set = ms_new(UINT64_MAX, 0.99, cmp, hash);
|
||||
|
||||
cmc_assert_equals(ptr, NULL, set);
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(set == NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(clear[count capacity], {
|
||||
@@ -44,13 +41,11 @@ CMC_CREATE_UNIT(multiset_test, true, {
|
||||
|
||||
cmc_assert_equals(size_t, 50, ms_count(set));
|
||||
|
||||
ms_clear(set);
|
||||
ms_clear(set, NULL);
|
||||
|
||||
cmc_assert_equals(size_t, 0, ms_count(set));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(ms_count(set) == 0);
|
||||
|
||||
ms_free(set);
|
||||
ms_free(set, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(insert[count cardinality multiplicity], {
|
||||
@@ -68,35 +63,91 @@ CMC_CREATE_UNIT(multiset_test, true, {
|
||||
cmc_assert_equals(size_t, 3, ms_count(set));
|
||||
cmc_assert_equals(size_t, 6, ms_cardinality(set));
|
||||
|
||||
bool passed = ms_count(set) == 3 && ms_cardinality(set) == 6;
|
||||
|
||||
for (size_t i = 0; i <= 3; i++)
|
||||
passed = passed && ms_multiplicity_of(set, i) == i;
|
||||
cmc_assert_equals(size_t, i, ms_multiplicity_of(set, i));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(passed);
|
||||
|
||||
ms_free(set);
|
||||
ms_free(set, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(multiplicity, {
|
||||
CMC_CREATE_TEST(remove[count cardinality multiplicity], {
|
||||
multiset *set = ms_new(100, 0.6, cmp, hash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, set);
|
||||
|
||||
for (size_t i = 0; i < 100; i++)
|
||||
cmc_assert(ms_insert(set, 1));
|
||||
cmc_assert(ms_insert(set, 2));
|
||||
cmc_assert(ms_insert(set, 2));
|
||||
cmc_assert(ms_insert(set, 3));
|
||||
cmc_assert(ms_insert(set, 3));
|
||||
cmc_assert(ms_insert(set, 3));
|
||||
|
||||
cmc_assert_equals(size_t, 3, ms_count(set));
|
||||
cmc_assert_equals(size_t, 6, ms_cardinality(set));
|
||||
|
||||
for (size_t i = 0; i <= 3; i++)
|
||||
cmc_assert_equals(size_t, i, ms_multiplicity_of(set, i));
|
||||
|
||||
cmc_assert(ms_remove(set, 1));
|
||||
cmc_assert(ms_remove(set, 2));
|
||||
cmc_assert(ms_remove(set, 3));
|
||||
|
||||
cmc_assert_equals(size_t, 2, ms_count(set));
|
||||
cmc_assert_equals(size_t, 3, ms_cardinality(set));
|
||||
|
||||
cmc_assert_equals(size_t, 0, ms_multiplicity_of(set, 0));
|
||||
cmc_assert_equals(size_t, 0, ms_multiplicity_of(set, 1));
|
||||
cmc_assert_equals(size_t, 1, ms_multiplicity_of(set, 2));
|
||||
cmc_assert_equals(size_t, 2, ms_multiplicity_of(set, 3));
|
||||
|
||||
ms_free(set, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(remove_all[count cardinality multiplicity], {
|
||||
multiset *set = ms_new(100, 0.6, cmp, hash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, set);
|
||||
|
||||
cmc_assert(ms_insert(set, 1));
|
||||
cmc_assert(ms_insert(set, 2));
|
||||
cmc_assert(ms_insert(set, 2));
|
||||
cmc_assert(ms_insert(set, 3));
|
||||
cmc_assert(ms_insert(set, 3));
|
||||
cmc_assert(ms_insert(set, 3));
|
||||
|
||||
cmc_assert_equals(size_t, 3, ms_count(set));
|
||||
cmc_assert_equals(size_t, 6, ms_cardinality(set));
|
||||
|
||||
for (size_t i = 0; i <= 3; i++)
|
||||
cmc_assert_equals(size_t, i, ms_multiplicity_of(set, i));
|
||||
|
||||
cmc_assert(ms_remove_all(set, 1));
|
||||
cmc_assert(ms_remove_all(set, 3));
|
||||
|
||||
cmc_assert_equals(size_t, 1, ms_count(set));
|
||||
cmc_assert_equals(size_t, 2, ms_cardinality(set));
|
||||
|
||||
cmc_assert_equals(size_t, 0, ms_multiplicity_of(set, 0));
|
||||
cmc_assert_equals(size_t, 0, ms_multiplicity_of(set, 1));
|
||||
cmc_assert_equals(size_t, 2, ms_multiplicity_of(set, 2));
|
||||
cmc_assert_equals(size_t, 0, ms_multiplicity_of(set, 3));
|
||||
|
||||
ms_free(set, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(multiplicity, {
|
||||
multiset *set = ms_new(50, 0.6, cmp, hash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, set);
|
||||
|
||||
for (size_t i = 0; i < 1000; i++)
|
||||
cmc_assert(ms_insert(set, i % 20));
|
||||
|
||||
cmc_assert_equals(size_t, 20, ms_count(set));
|
||||
cmc_assert_equals(size_t, 100, ms_cardinality(set));
|
||||
|
||||
bool passed = ms_count(set) == 20 && ms_cardinality(set) == 100;
|
||||
cmc_assert_equals(size_t, 1000, ms_cardinality(set));
|
||||
|
||||
for (size_t i = 0; i < 20; i++)
|
||||
passed = passed && ms_multiplicity_of(set, i) == 5;
|
||||
cmc_assert_equals(size_t, 50, ms_multiplicity_of(set, i));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(passed);
|
||||
|
||||
ms_free(set);
|
||||
ms_free(set, NULL);
|
||||
});
|
||||
|
||||
});
|
||||
+363
-26
@@ -1,38 +1,35 @@
|
||||
#include "utl/assert.h"
|
||||
#include "utl/test.h"
|
||||
#include "../src/queue.c"
|
||||
#include "utl.c"
|
||||
#include <utl/assert.h>
|
||||
#include <utl/log.h>
|
||||
#include <utl/test.h>
|
||||
|
||||
#include <cmc/queue.h>
|
||||
|
||||
CMC_GENERATE_QUEUE(q, queue, size_t)
|
||||
|
||||
CMC_CREATE_UNIT(queue_test, true, {
|
||||
CMC_CREATE_TEST(new, {
|
||||
queue *q = q_new(1000000);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, q);
|
||||
|
||||
bool passed = q->capacity == 1000000 && q->count == 0 && q->buffer;
|
||||
|
||||
cmc_assert_equals(size_t, 1000000, q->capacity);
|
||||
cmc_assert_not_equals(ptr, NULL, q->buffer);
|
||||
cmc_assert_equals(size_t, 1000000, q_capacity(q));
|
||||
cmc_assert_equals(size_t, 0, q_count(q));
|
||||
cmc_assert_not_equals(ptr, NULL, q->buffer);
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(passed);
|
||||
|
||||
q_free(q);
|
||||
q_free(q, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(new[edge_case:capacity = 0], {
|
||||
CMC_CREATE_TEST(new[capacity = 0], {
|
||||
queue *q = q_new(0);
|
||||
|
||||
cmc_assert_equals(ptr, NULL, q);
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(q == NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(new[edge_case:capacity = UINT64_MAX], {
|
||||
CMC_CREATE_TEST(new[capacity = UINT64_MAX], {
|
||||
queue *q = q_new(UINT64_MAX);
|
||||
|
||||
cmc_assert_equals(ptr, NULL, q);
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(q == NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(clear[count capacity], {
|
||||
@@ -41,33 +38,373 @@ CMC_CREATE_UNIT(queue_test, true, {
|
||||
cmc_assert_not_equals(ptr, NULL, q);
|
||||
|
||||
for (size_t i = 0; i < 50; i++)
|
||||
q_enqueue(q, i);
|
||||
cmc_assert(q_enqueue(q, i));
|
||||
|
||||
cmc_assert_equals(size_t, 50, q_count(q));
|
||||
|
||||
q_clear(q);
|
||||
q_clear(q, NULL);
|
||||
|
||||
cmc_assert_equals(size_t, 0, q_count(q));
|
||||
cmc_assert_equals(size_t, 100, q_capacity(q));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(q_count(q) == 0 && q_capacity(q) == 100);
|
||||
|
||||
q_free(q);
|
||||
q_free(q, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(buffer_growth[edge_case:capacity = 1], {
|
||||
CMC_CREATE_TEST(buffer_growth[capacity = 1], {
|
||||
queue *q = q_new(1);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, q);
|
||||
|
||||
for (size_t i = 0; i < 50; i++)
|
||||
q_enqueue(q, i);
|
||||
cmc_assert(q_enqueue(q, i));
|
||||
|
||||
cmc_assert_equals(size_t, 50, q_count(q));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(q_count(q) == 50);
|
||||
|
||||
q_free(q);
|
||||
q_free(q, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(buffer_growth[item preservation], {
|
||||
queue *q = q_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, q);
|
||||
|
||||
for (size_t i = 1; i <= 1200; i++)
|
||||
{
|
||||
q_enqueue(q, i);
|
||||
}
|
||||
|
||||
size_t sum = 0;
|
||||
for (size_t i = q->front, j = 0; j < q->count; i = (i + 1) % q->capacity, j++)
|
||||
sum += q->buffer[i];
|
||||
|
||||
cmc_assert_equals(size_t, 1200, q_count(q));
|
||||
cmc_assert_equals(size_t, 720600, sum);
|
||||
|
||||
q_free(q, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(enqueue[count capacity], {
|
||||
queue *q = q_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, q);
|
||||
|
||||
for (size_t i = 0; i < 150; i++)
|
||||
cmc_assert(q_enqueue(q, i));
|
||||
|
||||
cmc_assert_equals(size_t, 150, q_count(q));
|
||||
cmc_assert_greater(size_t, 100, q_capacity(q));
|
||||
|
||||
q_free(q, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(enqueue[item preservation], {
|
||||
queue *q = q_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, q);
|
||||
|
||||
for (size_t i = 1; i <= 100; i++)
|
||||
cmc_assert(q_enqueue(q, i));
|
||||
|
||||
size_t sum = 0;
|
||||
|
||||
for (size_t i = q->front, j = 0; j < q->count; i = (i + 1) % q->capacity, j++)
|
||||
{
|
||||
sum += q->buffer[i];
|
||||
}
|
||||
|
||||
cmc_assert_equals(size_t, 5050, sum);
|
||||
|
||||
q_free(q, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(dequeue[count capacity], {
|
||||
queue *q = q_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, q);
|
||||
|
||||
cmc_assert(q_enqueue(q, 10));
|
||||
cmc_assert(q_dequeue(q));
|
||||
|
||||
cmc_assert_equals(size_t, 0, q_count(q));
|
||||
|
||||
cmc_assert(q_enqueue(q, 10));
|
||||
cmc_assert(q_dequeue(q));
|
||||
|
||||
cmc_assert_equals(size_t, 0, q_count(q));
|
||||
|
||||
q_free(q, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(dequeue[item preservation], {
|
||||
queue *q = q_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, q);
|
||||
|
||||
for (size_t i = 200; i > 0; i--)
|
||||
cmc_assert(q_enqueue(q, i));
|
||||
|
||||
for (size_t i = 0; i < 100; i++)
|
||||
cmc_assert(q_dequeue(q));
|
||||
|
||||
size_t sum = 0;
|
||||
|
||||
for (size_t i = q->front, j = 0; j < q->count; i = (i + 1) % q->capacity, j++)
|
||||
{
|
||||
sum += q->buffer[i];
|
||||
}
|
||||
|
||||
cmc_assert_equals(size_t, 5050, sum);
|
||||
|
||||
q_free(q, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(peek[count = 0], {
|
||||
queue *q = q_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, q);
|
||||
|
||||
size_t r = q_peek(q);
|
||||
|
||||
cmc_assert_equals(size_t, (size_t){0}, r);
|
||||
|
||||
q_free(q, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(peek[sum], {
|
||||
queue *q = q_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, q);
|
||||
|
||||
size_t sum = 0;
|
||||
|
||||
for (size_t i = 0; i <= 100; i++)
|
||||
cmc_assert(q_enqueue(q, i));
|
||||
|
||||
while (!q_empty(q))
|
||||
{
|
||||
size_t r = q_peek(q);
|
||||
|
||||
sum += r;
|
||||
|
||||
cmc_assert(q_dequeue(q));
|
||||
}
|
||||
|
||||
cmc_assert_equals(size_t, 5050, sum);
|
||||
|
||||
q_free(q, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(contains, {
|
||||
queue *q = q_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, q);
|
||||
|
||||
for (size_t i = 1; i <= 20; i++)
|
||||
cmc_assert(q_enqueue(q, i));
|
||||
|
||||
for (size_t i = 1; i <= 20; i++)
|
||||
cmc_assert(q_contains(q, i, cmp));
|
||||
|
||||
q_clear(q, NULL);
|
||||
|
||||
for (size_t i = 1; i <= 20; i++)
|
||||
cmc_assert(!q_contains(q, i, cmp));
|
||||
|
||||
q_free(q, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(contains[count = 0], {
|
||||
queue *q = q_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, q);
|
||||
|
||||
cmc_assert(!q_contains(q, 10, cmp));
|
||||
|
||||
q_free(q, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(contains[count = 1], {
|
||||
queue *q = q_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, q);
|
||||
|
||||
cmc_assert(!q_contains(q, 10, cmp));
|
||||
|
||||
cmc_assert(q_enqueue(q, 100));
|
||||
|
||||
cmc_assert(q_contains(q, 100, cmp));
|
||||
cmc_assert(!q_contains(q, 101, cmp));
|
||||
|
||||
q_free(q, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(empty, {
|
||||
queue *q = q_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, q);
|
||||
|
||||
cmc_assert(q_empty(q));
|
||||
|
||||
cmc_assert(q_enqueue(q, 1));
|
||||
|
||||
cmc_assert(!q_empty(q));
|
||||
|
||||
q_free(q, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(full, {
|
||||
queue *q = q_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, q);
|
||||
|
||||
cmc_assert(!q_full(q));
|
||||
|
||||
for (size_t i = 0; i != q_capacity(q); i++)
|
||||
cmc_assert(q_enqueue(q, i));
|
||||
|
||||
cmc_assert(q_full(q));
|
||||
|
||||
q_free(q, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(count, {
|
||||
queue *q = q_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, q);
|
||||
|
||||
cmc_assert_equals(size_t, 0, q_count(q));
|
||||
|
||||
for (size_t i = 0; i < 100; i++)
|
||||
cmc_assert(q_enqueue(q, i));
|
||||
|
||||
cmc_assert_equals(size_t, 100, q_count(q));
|
||||
|
||||
q_free(q, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(capacity, {
|
||||
queue *q = q_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, q);
|
||||
|
||||
cmc_assert_equals(size_t, 100, q_capacity(q));
|
||||
|
||||
q_free(q, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(resize, {
|
||||
queue *q = q_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, q);
|
||||
|
||||
for (size_t i = 0; i < 150; i++)
|
||||
cmc_assert(q_enqueue(q, i));
|
||||
|
||||
cmc_assert_equals(size_t, 150, q_count(q));
|
||||
cmc_assert(q_resize(q, q_count(q)));
|
||||
cmc_assert_equals(size_t, 150, q_capacity(q));
|
||||
|
||||
q_free(q, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(resize[item preservation], {
|
||||
queue *q = q_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, q);
|
||||
|
||||
for (size_t i = 1; i <= 150; i++)
|
||||
cmc_assert(q_enqueue(q, i));
|
||||
|
||||
cmc_assert(q_resize(q, q_count(q)));
|
||||
|
||||
size_t sum = 0;
|
||||
|
||||
for (size_t i = q->front, j = 0; j < q->count; i = (i + 1) % q->capacity, j++)
|
||||
{
|
||||
sum += q->buffer[i];
|
||||
}
|
||||
|
||||
cmc_assert_equals(size_t, 11325, sum);
|
||||
|
||||
q_free(q, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(copy_of, {
|
||||
queue *d1 = q_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, d1);
|
||||
|
||||
for (size_t i = 1; i <= 150; i++)
|
||||
cmc_assert(q_enqueue(d1, i));
|
||||
|
||||
queue *d2 = q_copy_of(d1, NULL);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, d2);
|
||||
cmc_assert_equals(size_t, q_count(d1), q_count(d2));
|
||||
|
||||
for (size_t i1 = d1->front, i2 = d2->front, j = 0; j < d1->count; j++)
|
||||
{
|
||||
cmc_assert_equals(size_t, d1->buffer[i1], d2->buffer[i2]);
|
||||
|
||||
i1 = (i1 + 1) % d1->capacity;
|
||||
i2 = (i2 + 1) % d2->capacity;
|
||||
}
|
||||
|
||||
q_free(d1, NULL);
|
||||
q_free(d2, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(equals, {
|
||||
queue *d1 = q_new(100);
|
||||
queue *d2 = q_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, d1);
|
||||
cmc_assert_not_equals(ptr, NULL, d2);
|
||||
|
||||
for (size_t i = 1; i <= 150; i++)
|
||||
{
|
||||
cmc_assert(q_enqueue(d1, i));
|
||||
cmc_assert(q_enqueue(d2, i));
|
||||
}
|
||||
|
||||
cmc_assert(q_equals(d1, d2, cmp));
|
||||
|
||||
q_free(d1, NULL);
|
||||
q_free(d2, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(equals[from copy], {
|
||||
queue *d1 = q_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, d1);
|
||||
|
||||
for (size_t i = 1; i <= 150; i++)
|
||||
{
|
||||
cmc_assert(q_enqueue(d1, i));
|
||||
}
|
||||
|
||||
queue *d2 = q_copy_of(d1, NULL);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, d2);
|
||||
|
||||
cmc_assert(q_equals(d1, d2, cmp));
|
||||
|
||||
q_free(d1, NULL);
|
||||
q_free(d2, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(equals[count = 0], {
|
||||
queue *d1 = q_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, d1);
|
||||
|
||||
queue *d2 = q_copy_of(d1, NULL);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, d2);
|
||||
|
||||
cmc_assert(q_equals(d1, d2, cmp));
|
||||
|
||||
q_free(d1, NULL);
|
||||
q_free(d2, NULL);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,140 @@
|
||||
#include "utl.c"
|
||||
#include <utl/assert.h>
|
||||
#include <utl/log.h>
|
||||
#include <utl/test.h>
|
||||
|
||||
#include <ext/sortedlist.h>
|
||||
|
||||
CMC_GENERATE_SORTEDLIST(sl, sortedlist, size_t)
|
||||
|
||||
CMC_CREATE_UNIT(sortedlist_test, true, {
|
||||
CMC_CREATE_TEST(new, {
|
||||
sortedlist *sl = sl_new(1000000, cmp);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, sl);
|
||||
cmc_assert_not_equals(ptr, NULL, sl->buffer);
|
||||
cmc_assert_equals(size_t, 1000000, sl_capacity(sl));
|
||||
cmc_assert_equals(size_t, 0, sl_count(sl));
|
||||
cmc_assert_not_equals(ptr, NULL, sl->buffer);
|
||||
|
||||
sl_free(sl, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(new[capacity = 0], {
|
||||
sortedlist *sl = sl_new(0, cmp);
|
||||
|
||||
cmc_assert_equals(ptr, NULL, sl);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(new[capacity = UINT64_MAX], {
|
||||
sortedlist *sl = sl_new(UINT64_MAX, cmp);
|
||||
|
||||
cmc_assert_equals(ptr, NULL, sl);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(clear[count capacity], {
|
||||
sortedlist *sl = sl_new(100, cmp);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, sl);
|
||||
|
||||
for (size_t i = 0; i < 50; i++)
|
||||
cmc_assert(sl_insert(sl, i));
|
||||
|
||||
cmc_assert_equals(size_t, 50, sl_count(sl));
|
||||
|
||||
sl_clear(sl, NULL);
|
||||
|
||||
cmc_assert_equals(size_t, 0, sl_count(sl));
|
||||
cmc_assert_equals(size_t, 100, sl_capacity(sl));
|
||||
|
||||
sl_free(sl, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(buffer_growth[capacity = 1], {
|
||||
sortedlist *sl = sl_new(1, cmp);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, sl);
|
||||
|
||||
for (size_t i = 0; i < 50; i++)
|
||||
cmc_assert(sl_insert(sl, i));
|
||||
|
||||
sl_sort(sl);
|
||||
|
||||
cmc_assert_equals(size_t, 50, sl_count(sl));
|
||||
cmc_assert_array_sorted_any(size_t, sl->buffer, cmp, 0, sl->count - 1);
|
||||
|
||||
sl_free(sl, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(insert, {
|
||||
sortedlist *sl = sl_new(100, cmp);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, sl);
|
||||
|
||||
cmc_assert(sl_insert(sl, 1));
|
||||
|
||||
sl_free(sl, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(remove, {
|
||||
sortedlist *sl = sl_new(100, cmp);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, sl);
|
||||
|
||||
cmc_assert(sl_insert(sl, 32));
|
||||
|
||||
cmc_assert(sl_remove(sl, 0));
|
||||
|
||||
sl_free(sl, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(remove[count = 0], {
|
||||
sortedlist *sl = sl_new(100, cmp);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, sl);
|
||||
|
||||
cmc_assert(!sl_remove(sl, 0));
|
||||
|
||||
sl_free(sl, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(remove[out of range], {
|
||||
sortedlist *sl = sl_new(100, cmp);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, sl);
|
||||
|
||||
cmc_assert(sl_insert(sl, 32));
|
||||
|
||||
cmc_assert(!sl_remove(sl, 2));
|
||||
|
||||
sl_free(sl, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(indexof, {
|
||||
sortedlist *sl = sl_new(1, cmp);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, sl);
|
||||
|
||||
for (size_t i = 0; i < 20; i++)
|
||||
cmc_assert(sl_insert(sl, i % 10));
|
||||
|
||||
/* 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9 */
|
||||
cmc_assert_equals(size_t, 4, sl_indexof(sl, 2, true));
|
||||
cmc_assert_equals(size_t, 5, sl_indexof(sl, 2, false));
|
||||
|
||||
cmc_assert_equals(size_t, 0, sl_indexof(sl, 0, true));
|
||||
cmc_assert_equals(size_t, 1, sl_indexof(sl, 0, false));
|
||||
|
||||
cmc_assert(sl_remove(sl, 0));
|
||||
|
||||
cmc_assert_equals(size_t, 0, sl_indexof(sl, 0, true));
|
||||
cmc_assert_equals(size_t, 0, sl_indexof(sl, 0, false));
|
||||
|
||||
cmc_assert(sl_remove(sl, 0));
|
||||
|
||||
cmc_assert_equals(size_t, sl_count(sl), sl_indexof(sl, 0, true));
|
||||
cmc_assert_equals(size_t, sl_count(sl), sl_indexof(sl, 0, false));
|
||||
|
||||
sl_free(sl, NULL);
|
||||
});
|
||||
});
|
||||
+71
-212
@@ -1,40 +1,35 @@
|
||||
#include "utl/assert.h"
|
||||
#include "utl/test.h"
|
||||
#include "../src/stack.c"
|
||||
|
||||
#include "utl.c"
|
||||
#include <utl/assert.h>
|
||||
#include <utl/log.h>
|
||||
#include <utl/test.h>
|
||||
|
||||
#include <cmc/stack.h>
|
||||
|
||||
CMC_GENERATE_STACK(s, stack, size_t)
|
||||
|
||||
CMC_CREATE_UNIT(stack_test, true, {
|
||||
CMC_CREATE_TEST(new, {
|
||||
stack *s = s_new(1000000);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, s);
|
||||
|
||||
bool passed = s->capacity == 1000000 && s->count == 0 && s->buffer;
|
||||
|
||||
cmc_assert_equals(size_t, 1000000, s->capacity);
|
||||
cmc_assert_not_equals(ptr, NULL, s->buffer);
|
||||
cmc_assert_equals(size_t, 1000000, s_capacity(s));
|
||||
cmc_assert_equals(size_t, 0, s_count(s));
|
||||
cmc_assert_not_equals(ptr, NULL, s->buffer);
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(passed);
|
||||
|
||||
s_free(s);
|
||||
s_free(s, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(new[edge_case:capacity = 0], {
|
||||
CMC_CREATE_TEST(new[capacity = 0], {
|
||||
stack *s = s_new(0);
|
||||
|
||||
cmc_assert_equals(ptr, NULL, s);
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(s == NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(new[edge_case:capacity = UINT64_MAX], {
|
||||
CMC_CREATE_TEST(new[capacity = UINT64_MAX], {
|
||||
stack *s = s_new(UINT64_MAX);
|
||||
|
||||
cmc_assert_equals(ptr, NULL, s);
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(s == NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(clear[count capacity], {
|
||||
@@ -47,17 +42,15 @@ CMC_CREATE_UNIT(stack_test, true, {
|
||||
|
||||
cmc_assert_equals(size_t, 50, s_count(s));
|
||||
|
||||
s_clear(s);
|
||||
s_clear(s, NULL);
|
||||
|
||||
cmc_assert_equals(size_t, 0, s_count(s));
|
||||
cmc_assert_equals(size_t, 100, s_capacity(s));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(s_count(s) == 0 && s_capacity(s) == 100);
|
||||
|
||||
s_free(s);
|
||||
s_free(s, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(buffer_growth[edge_case:capacity = 1], {
|
||||
CMC_CREATE_TEST(buffer_growth[capacity = 1], {
|
||||
stack *s = s_new(1);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, s);
|
||||
@@ -68,9 +61,7 @@ CMC_CREATE_UNIT(stack_test, true, {
|
||||
cmc_assert_equals(size_t, 50, s_count(s));
|
||||
cmc_assert_lesser_equals(size_t, s_capacity(s), s_count(s));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(s_count(s) == 50 && s_count(s) <= s_capacity(s));
|
||||
|
||||
s_free(s);
|
||||
s_free(s, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(push[count], {
|
||||
@@ -83,9 +74,7 @@ CMC_CREATE_UNIT(stack_test, true, {
|
||||
|
||||
cmc_assert_equals(size_t, 250, s_count(s));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(s_count(s) == 250);
|
||||
|
||||
s_free(s);
|
||||
s_free(s, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(push[capacity], {
|
||||
@@ -98,12 +87,10 @@ CMC_CREATE_UNIT(stack_test, true, {
|
||||
|
||||
cmc_assert_lesser_equals(size_t, s_capacity(s), s_count(s));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(s_count(s) <= s_capacity(s));
|
||||
|
||||
s_free(s);
|
||||
s_free(s, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(push[item_preservation], {
|
||||
CMC_CREATE_TEST(push[item preservation], {
|
||||
stack *s = s_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, s);
|
||||
@@ -111,18 +98,10 @@ CMC_CREATE_UNIT(stack_test, true, {
|
||||
for (size_t i = 0; i < 250; i++)
|
||||
cmc_assert(s_push(s, i));
|
||||
|
||||
bool passed = true;
|
||||
|
||||
for (size_t i = 0; i < s_count(s); i++)
|
||||
{
|
||||
passed = s->buffer[i] == i;
|
||||
|
||||
cmc_assert_equals(size_t, i, s->buffer[i]);
|
||||
}
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(passed);
|
||||
|
||||
s_free(s);
|
||||
s_free(s, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(pop[count], {
|
||||
@@ -137,9 +116,7 @@ CMC_CREATE_UNIT(stack_test, true, {
|
||||
|
||||
cmc_assert_equals(size_t, 249, s_count(s));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(s_count(s) == 249);
|
||||
|
||||
s_free(s);
|
||||
s_free(s, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(pop[capacity], {
|
||||
@@ -154,12 +131,10 @@ CMC_CREATE_UNIT(stack_test, true, {
|
||||
|
||||
cmc_assert_lesser_equals(size_t, s_capacity(s), s_count(s));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(s_count(s) <= s_capacity(s));
|
||||
|
||||
s_free(s);
|
||||
s_free(s, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(pop[item_preservation], {
|
||||
CMC_CREATE_TEST(pop[item preservation], {
|
||||
stack *s = s_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, s);
|
||||
@@ -170,77 +145,20 @@ CMC_CREATE_UNIT(stack_test, true, {
|
||||
cmc_assert(s_pop(s));
|
||||
cmc_assert(s_pop(s));
|
||||
|
||||
bool passed = true;
|
||||
|
||||
for (size_t i = 0; i < s_count(s); i++)
|
||||
{
|
||||
passed = s->buffer[i] == i;
|
||||
|
||||
cmc_assert_equals(size_t, i, s->buffer[i]);
|
||||
}
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(passed);
|
||||
|
||||
s_free(s);
|
||||
s_free(s, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(pop[edge_case:count = 0], {
|
||||
CMC_CREATE_TEST(pop[count = 0], {
|
||||
stack *s = s_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, s);
|
||||
|
||||
cmc_assert_equals(bool, false, s_pop(s));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(!s_pop(s));
|
||||
|
||||
s_free(s);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(push_if, {
|
||||
stack *s = s_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, s);
|
||||
|
||||
for (size_t i = 0; i < 250; i++)
|
||||
s_push_if(s, i, i % 2 == 0);
|
||||
|
||||
bool passed = true;
|
||||
|
||||
for (size_t i = 0; i < s_count(s); i++)
|
||||
{
|
||||
passed = passed && s->buffer[i] % 2 == 0;
|
||||
|
||||
cmc_assert(s->buffer[i] % 2 == 0);
|
||||
}
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(passed);
|
||||
|
||||
s_free(s);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(pop_if, {
|
||||
stack *s = s_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, s);
|
||||
|
||||
for (size_t i = 0; i < 250; i++)
|
||||
{
|
||||
s_push(s, i);
|
||||
s_pop_if(s, s_top(s) % 2 == 0);
|
||||
}
|
||||
|
||||
bool passed = true;
|
||||
|
||||
for (size_t i = 0; i < s_count(s); i++)
|
||||
{
|
||||
passed = passed && !(s->buffer[i] % 2 == 0);
|
||||
|
||||
cmc_assert(!(s->buffer[i] % 2 == 0));
|
||||
}
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(passed);
|
||||
|
||||
s_free(s);
|
||||
s_free(s, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(top, {
|
||||
@@ -256,12 +174,10 @@ CMC_CREATE_UNIT(stack_test, true, {
|
||||
|
||||
cmc_assert_equals(size_t, 247, s_top(s));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(247 == s_top(s));
|
||||
|
||||
s_free(s);
|
||||
s_free(s, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(top[edge_case:count = 0], {
|
||||
CMC_CREATE_TEST(top[count = 0], {
|
||||
stack *s = s_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, s);
|
||||
@@ -270,14 +186,12 @@ CMC_CREATE_UNIT(stack_test, true, {
|
||||
|
||||
cmc_assert(s_pop(s));
|
||||
|
||||
cmc_assert_equals(size_t, s_impl_default_value(), s_top(s));
|
||||
cmc_assert_equals(size_t, (size_t){0}, s_top(s));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(s_impl_default_value() == s_top(s));
|
||||
|
||||
s_free(s);
|
||||
s_free(s, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(top[edge_case:count = 1], {
|
||||
CMC_CREATE_TEST(top[count = 1], {
|
||||
stack *s = s_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, s);
|
||||
@@ -286,9 +200,7 @@ CMC_CREATE_UNIT(stack_test, true, {
|
||||
cmc_assert_equals(size_t, 1, s_count(s));
|
||||
cmc_assert_equals(size_t, 10, s_top(s));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(10 == s_top(s));
|
||||
|
||||
s_free(s);
|
||||
s_free(s, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(contains, {
|
||||
@@ -299,26 +211,20 @@ CMC_CREATE_UNIT(stack_test, true, {
|
||||
for (size_t i = 0; i < 150; i++)
|
||||
cmc_assert(s_push(s, i));
|
||||
|
||||
bool passed = true;
|
||||
|
||||
for (size_t i = 0; i < 150; i++)
|
||||
passed = passed && s_contains(s, i, cmp);
|
||||
cmc_assert(s_contains(s, i, cmp));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(passed);
|
||||
|
||||
s_free(s);
|
||||
s_free(s, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(contains[edge_case:count = 0], {
|
||||
CMC_CREATE_TEST(contains[count = 0], {
|
||||
stack *s = s_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, s);
|
||||
|
||||
cmc_assert_equals(bool, false, s_contains(s, 10, cmp));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(!s_contains(s, 10, cmp));
|
||||
|
||||
s_free(s);
|
||||
s_free(s, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(empty, {
|
||||
@@ -328,9 +234,7 @@ CMC_CREATE_UNIT(stack_test, true, {
|
||||
|
||||
cmc_assert(s_empty(s));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(s_empty(s));
|
||||
|
||||
s_free(s);
|
||||
s_free(s, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(empty[after_io], {
|
||||
@@ -342,9 +246,7 @@ CMC_CREATE_UNIT(stack_test, true, {
|
||||
cmc_assert(s_pop(s));
|
||||
cmc_assert(s_empty(s));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(s_empty(s));
|
||||
|
||||
s_free(s);
|
||||
s_free(s, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(full, {
|
||||
@@ -357,12 +259,10 @@ CMC_CREATE_UNIT(stack_test, true, {
|
||||
|
||||
cmc_assert(s_full(s));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(s_full(s));
|
||||
|
||||
s_free(s);
|
||||
s_free(s, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(full[edge_case:capacity = 1], {
|
||||
CMC_CREATE_TEST(full[capacity = 1], {
|
||||
stack *s = s_new(1);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, s);
|
||||
@@ -371,9 +271,7 @@ CMC_CREATE_UNIT(stack_test, true, {
|
||||
|
||||
cmc_assert(s_full(s));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(s_full(s));
|
||||
|
||||
s_free(s);
|
||||
s_free(s, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(iter_alloc, {
|
||||
@@ -385,13 +283,11 @@ CMC_CREATE_UNIT(stack_test, true, {
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, iter);
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(s && iter);
|
||||
|
||||
s_iter_free(iter);
|
||||
s_free(s);
|
||||
s_free(s, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(iter_init[edge_case:count = 0], {
|
||||
CMC_CREATE_TEST(iter_init[count = 0], {
|
||||
stack *s = s_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, s);
|
||||
@@ -405,14 +301,10 @@ CMC_CREATE_UNIT(stack_test, true, {
|
||||
cmc_assert(iter.start);
|
||||
cmc_assert(iter.end);
|
||||
|
||||
bool passed = iter.target == s && iter.cursor == 0 && iter.start && iter.end;
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(passed);
|
||||
|
||||
s_free(s);
|
||||
s_free(s, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(iter_start[edge_case:count = 0], {
|
||||
CMC_CREATE_TEST(iter_start[count = 0], {
|
||||
stack *s = s_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, s);
|
||||
@@ -421,12 +313,12 @@ CMC_CREATE_UNIT(stack_test, true, {
|
||||
|
||||
s_iter_init(&iter, s);
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(s_iter_start(&iter));
|
||||
cmc_assert(s_iter_start(&iter));
|
||||
|
||||
s_free(s);
|
||||
s_free(s, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(iter_end[edge_case:count = 0], {
|
||||
CMC_CREATE_TEST(iter_end[count = 0], {
|
||||
stack *s = s_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, s);
|
||||
@@ -435,9 +327,9 @@ CMC_CREATE_UNIT(stack_test, true, {
|
||||
|
||||
s_iter_init(&iter, s);
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(s_iter_end(&iter));
|
||||
cmc_assert(s_iter_end(&iter));
|
||||
|
||||
s_free(s);
|
||||
s_free(s, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(iteration, {
|
||||
@@ -464,9 +356,7 @@ CMC_CREATE_UNIT(stack_test, true, {
|
||||
|
||||
cmc_assert_equals(size_t, 40200, total);
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(total == 40200);
|
||||
|
||||
s_free(s);
|
||||
s_free(s, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(iteration[while loop], {
|
||||
@@ -496,12 +386,10 @@ CMC_CREATE_UNIT(stack_test, true, {
|
||||
|
||||
cmc_assert_equals(size_t, 40200, total);
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(total == 40200);
|
||||
|
||||
s_free(s);
|
||||
s_free(s, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(iteration[edge_case:count = 1], {
|
||||
CMC_CREATE_TEST(iteration[count = 1], {
|
||||
stack *s = s_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, s);
|
||||
@@ -521,12 +409,10 @@ CMC_CREATE_UNIT(stack_test, true, {
|
||||
|
||||
cmc_assert_equals(size_t, 20, total);
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(total == 20);
|
||||
|
||||
s_free(s);
|
||||
s_free(s, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(iteration[edge_case:count = capacity], {
|
||||
CMC_CREATE_TEST(iteration[count = capacity], {
|
||||
stack *s = s_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, s);
|
||||
@@ -552,9 +438,7 @@ CMC_CREATE_UNIT(stack_test, true, {
|
||||
|
||||
cmc_assert_equals(size_t, 2000, total);
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(total == 2000);
|
||||
|
||||
s_free(s);
|
||||
s_free(s, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(iteration[to_start = it_start and to_end = it_end], {
|
||||
@@ -565,7 +449,6 @@ CMC_CREATE_UNIT(stack_test, true, {
|
||||
for (size_t i = 0; i < 50; i++)
|
||||
cmc_assert(s_push(s, i));
|
||||
|
||||
bool passed = true;
|
||||
stack_iter it1;
|
||||
stack_iter it2;
|
||||
|
||||
@@ -581,7 +464,6 @@ CMC_CREATE_UNIT(stack_test, true, {
|
||||
cmc_assert_equals(size_t, it1.cursor, it2.cursor);
|
||||
cmc_assert_equals(bool, it1.start, it2.start);
|
||||
cmc_assert_equals(bool, it1.end, it2.end);
|
||||
passed = passed && it1.target == it2.target && it1.cursor == it2.cursor && it1.start == it2.start && it1.end == it2.end;
|
||||
|
||||
it1 = s->it_end(s);
|
||||
s_iter_to_end(&it2);
|
||||
@@ -590,14 +472,11 @@ CMC_CREATE_UNIT(stack_test, true, {
|
||||
cmc_assert_equals(size_t, it1.cursor, it2.cursor);
|
||||
cmc_assert_equals(bool, it1.start, it2.start);
|
||||
cmc_assert_equals(bool, it1.end, it2.end);
|
||||
passed = passed && it1.target == it2.target && it1.cursor == it2.cursor && it1.start == it2.start && it1.end == it2.end;
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(passed);
|
||||
|
||||
s_free(s);
|
||||
s_free(s, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(iteration[boundaries:count = 0], {
|
||||
CMC_CREATE_TEST(iteration[boundaries count = 0], {
|
||||
stack *s = s_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, s);
|
||||
@@ -608,19 +487,15 @@ CMC_CREATE_UNIT(stack_test, true, {
|
||||
s_iter_to_end(&iter);
|
||||
|
||||
cmc_assert_equals(bool, false, s_iter_next(&iter));
|
||||
bool passed = !s_iter_next(&iter);
|
||||
|
||||
s_iter_to_start(&iter);
|
||||
|
||||
cmc_assert_equals(bool, false, s_iter_prev(&iter));
|
||||
passed = !s_iter_prev(&iter);
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(passed);
|
||||
|
||||
s_free(s);
|
||||
s_free(s, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(iteration[boundaries:count > 0], {
|
||||
CMC_CREATE_TEST(iteration[boundaries count > 0], {
|
||||
stack *s = s_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, s);
|
||||
@@ -634,19 +509,15 @@ CMC_CREATE_UNIT(stack_test, true, {
|
||||
s_iter_to_end(&iter);
|
||||
|
||||
cmc_assert_equals(bool, false, s_iter_next(&iter));
|
||||
bool passed = !s_iter_next(&iter);
|
||||
|
||||
s_iter_to_start(&iter);
|
||||
|
||||
cmc_assert_equals(bool, false, s_iter_prev(&iter));
|
||||
passed = !s_iter_prev(&iter);
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(passed);
|
||||
|
||||
s_free(s);
|
||||
s_free(s, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(iter_value[edge_case:count = 0], {
|
||||
CMC_CREATE_TEST(iter_value[count = 0], {
|
||||
stack *s = s_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, s);
|
||||
@@ -655,14 +526,12 @@ CMC_CREATE_UNIT(stack_test, true, {
|
||||
|
||||
s_iter_init(&iter, s);
|
||||
|
||||
cmc_assert_equals(size_t, s_impl_default_value(), s_iter_value(&iter));
|
||||
cmc_assert_equals(size_t, (size_t){0}, s_iter_value(&iter));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(s_impl_default_value() == s_iter_value(&iter));
|
||||
|
||||
s_free(s);
|
||||
s_free(s, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(iter_rvalue[edge_case:count = 0], {
|
||||
CMC_CREATE_TEST(iter_rvalue[count = 0], {
|
||||
stack *s = s_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, s);
|
||||
@@ -673,9 +542,7 @@ CMC_CREATE_UNIT(stack_test, true, {
|
||||
|
||||
cmc_assert_equals(ptr, NULL, s_iter_rvalue(&iter));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(NULL == s_iter_rvalue(&iter));
|
||||
|
||||
s_free(s);
|
||||
s_free(s, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(index, {
|
||||
@@ -688,18 +555,15 @@ CMC_CREATE_UNIT(stack_test, true, {
|
||||
|
||||
cmc_assert_equals(size_t, 10, s_count(s));
|
||||
|
||||
bool passed = true;
|
||||
size_t total = 0;
|
||||
|
||||
for (stack_iter it = s->it_start(s); false; )
|
||||
for (stack_iter it = s->it_start(s); false;)
|
||||
{
|
||||
passed = passed && s_iter_index(&it) == 0;
|
||||
cmc_assert_equals(size_t, 0, s_iter_index(&it));
|
||||
}
|
||||
|
||||
for (stack_iter it = s->it_start(s); false; )
|
||||
for (stack_iter it = s->it_start(s); false;)
|
||||
{
|
||||
passed = passed && s_iter_index(&it) == s_count(s) - 1;
|
||||
cmc_assert_equals(size_t, s_count(s) - 1, s_iter_index(&it));
|
||||
}
|
||||
|
||||
@@ -717,12 +581,10 @@ CMC_CREATE_UNIT(stack_test, true, {
|
||||
|
||||
cmc_assert_equals(size_t, 90, total);
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(passed && total == 90);
|
||||
|
||||
s_free(s);
|
||||
s_free(s, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(index[edge_case:count = 0], {
|
||||
CMC_CREATE_TEST(index[count = 0], {
|
||||
stack *s = s_new(100);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, s);
|
||||
@@ -732,9 +594,6 @@ CMC_CREATE_UNIT(stack_test, true, {
|
||||
|
||||
cmc_assert_equals(size_t, 0, s_iter_index(&iter));
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(0 == s_iter_index(&iter));
|
||||
|
||||
s_free(s);
|
||||
s_free(s, NULL);
|
||||
});
|
||||
|
||||
});
|
||||
+10
-12
@@ -1,8 +1,11 @@
|
||||
#include "utl/assert.h"
|
||||
#include "utl/test.h"
|
||||
#include "../src/treemap.c"
|
||||
|
||||
#include "utl.c"
|
||||
#include <utl/assert.h>
|
||||
#include <utl/log.h>
|
||||
#include <utl/test.h>
|
||||
|
||||
#include <cmc/treemap.h>
|
||||
|
||||
CMC_GENERATE_TREEMAP(tm, treemap, size_t, size_t)
|
||||
|
||||
CMC_CREATE_UNIT(treemap_test, true, {
|
||||
CMC_CREATE_TEST(new, {
|
||||
@@ -10,9 +13,7 @@ CMC_CREATE_UNIT(treemap_test, true, {
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(map);
|
||||
|
||||
tm_free(map);
|
||||
tm_free(map, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(clear[count], {
|
||||
@@ -25,14 +26,11 @@ CMC_CREATE_UNIT(treemap_test, true, {
|
||||
|
||||
cmc_assert_equals(size_t, 50, tm_count(map));
|
||||
|
||||
tm_clear(map);
|
||||
tm_clear(map, NULL);
|
||||
|
||||
cmc_assert_equals(size_t, 0, tm_count(map));
|
||||
cmc_assert_equals(ptr, NULL, map->root);
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(tm_count(map) == 0);
|
||||
|
||||
tm_free(map);
|
||||
tm_free(map, NULL);
|
||||
});
|
||||
|
||||
});
|
||||
+10
-13
@@ -1,8 +1,11 @@
|
||||
#include "utl/assert.h"
|
||||
#include "utl/test.h"
|
||||
#include "../src/treeset.c"
|
||||
|
||||
#include "utl.c"
|
||||
#include <utl/assert.h>
|
||||
#include <utl/log.h>
|
||||
#include <utl/test.h>
|
||||
|
||||
#include <cmc/treeset.h>
|
||||
|
||||
CMC_GENERATE_TREESET(ts, treeset, size_t)
|
||||
|
||||
CMC_CREATE_UNIT(treeset_test, true, {
|
||||
CMC_CREATE_TEST(new, {
|
||||
@@ -10,9 +13,7 @@ CMC_CREATE_UNIT(treeset_test, true, {
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, set);
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(set);
|
||||
|
||||
ts_free(set);
|
||||
ts_free(set, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(clear[count], {
|
||||
@@ -25,15 +26,11 @@ CMC_CREATE_UNIT(treeset_test, true, {
|
||||
|
||||
cmc_assert_equals(size_t, 50, ts_count(set));
|
||||
|
||||
ts_clear(set);
|
||||
ts_clear(set, NULL);
|
||||
|
||||
cmc_assert_equals(size_t, 0, ts_count(set));
|
||||
cmc_assert_equals(ptr, NULL, set->root);
|
||||
|
||||
|
||||
CMC_TEST_PASS_ELSE_FAIL(ts_count(set) == 0);
|
||||
|
||||
ts_free(set);
|
||||
ts_free(set, NULL);
|
||||
});
|
||||
|
||||
});
|
||||
@@ -3,6 +3,7 @@
|
||||
#define CMC_UNIT_TEST_UTL__
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <cmc/hashmap.h>
|
||||
|
||||
int cmp(size_t a, size_t b)
|
||||
{
|
||||
@@ -20,4 +21,24 @@ size_t hash(size_t a)
|
||||
return a;
|
||||
}
|
||||
|
||||
size_t numhash(size_t a)
|
||||
{
|
||||
return a;
|
||||
}
|
||||
|
||||
size_t hashcapminus1(size_t a)
|
||||
{
|
||||
return cmc_hashtable_primes[0] - 1;
|
||||
}
|
||||
|
||||
size_t hashcapminus4(size_t a)
|
||||
{
|
||||
return cmc_hashtable_primes[0] - 1;
|
||||
}
|
||||
|
||||
size_t hash0(size_t a)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* CMC_UNIT_TEST_UTL__ */
|
||||
+21
-13
@@ -28,23 +28,31 @@ int main(void)
|
||||
heap *h = h_new(1000, cmc_max_heap, 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);
|
||||
hset *hs = hs_new(1000, 0.6, intcmp, inthash);
|
||||
hmap *hm = hm_new(1000, 0.6, intcmp, inthash);
|
||||
|
||||
iheap *ih = ih_new(1000, intcmp);
|
||||
mmap *mm = mm_new(1000, 0.8, intcmp, inthash);
|
||||
mset *ms = ms_new(1000, 0.6, intcmp, inthash);
|
||||
|
||||
printf("+--------------------------------------------------+\n");
|
||||
printf("| Separate Header and Source is Working |\n");
|
||||
printf("+--------------------------------------------------+\n");
|
||||
|
||||
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);
|
||||
l_free(l, NULL);
|
||||
ll_free(ll, NULL);
|
||||
s_free(s, NULL);
|
||||
q_free(q, NULL);
|
||||
d_free(d, NULL);
|
||||
h_free(h, NULL);
|
||||
ts_free(ts, NULL);
|
||||
tm_free(tm, NULL);
|
||||
hs_free(hs, NULL);
|
||||
hm_free(hm, NULL);
|
||||
|
||||
ih_free(ih, NULL);
|
||||
mm_free(mm, NULL);
|
||||
ms_free(ms, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
+14
-10
@@ -1,12 +1,16 @@
|
||||
#include "sep.h"
|
||||
|
||||
COLLECTION_GENERATE_SOURCE(LIST, l, list, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE_SOURCE(STACK, s, stack, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE_SOURCE(QUEUE, q, queue, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE_SOURCE(DEQUE, d, deque, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE_SOURCE(LINKEDLIST, ll, linked, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE_SOURCE(HEAP, h, heap, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE_SOURCE(TREESET, ts, tset, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE_SOURCE(TREEMAP, tm, tmap, /* FMOD */, int, int)
|
||||
COLLECTION_GENERATE_SOURCE(HASHSET, hs, hset, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE_SOURCE(HASHMAP, hm, hmap, /* FMOD */, int, int)
|
||||
CMC_COLLECTION_GENERATE_SOURCE(LIST, l, list, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE_SOURCE(STACK, s, stack, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE_SOURCE(QUEUE, q, queue, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE_SOURCE(DEQUE, d, deque, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE_SOURCE(LINKEDLIST, ll, linked, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE_SOURCE(HEAP, h, heap, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE_SOURCE(TREESET, ts, tset, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE_SOURCE(TREEMAP, tm, tmap, int, int)
|
||||
CMC_COLLECTION_GENERATE_SOURCE(HASHSET, hs, hset, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE_SOURCE(HASHMAP, hm, hmap, int, int)
|
||||
|
||||
CMC_COLLECTION_GENERATE_SOURCE(INTERVALHEAP, ih, iheap, , int)
|
||||
CMC_COLLECTION_GENERATE_SOURCE(MULTIMAP, mm, mmap, int, int)
|
||||
CMC_COLLECTION_GENERATE_SOURCE(MULTISET, ms, mset, , int)
|
||||
+14
-10
@@ -1,12 +1,16 @@
|
||||
#include "../../src/macro_collections.h"
|
||||
|
||||
COLLECTION_GENERATE_HEADER(LIST, l, list, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE_HEADER(STACK, s, stack, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE_HEADER(QUEUE, q, queue, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE_HEADER(DEQUE, d, deque, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE_HEADER(LINKEDLIST, ll, linked, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE_HEADER(HEAP, h, heap, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE_HEADER(TREESET, ts, tset, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE_HEADER(TREEMAP, tm, tmap, /* FMOD */, int, int)
|
||||
COLLECTION_GENERATE_HEADER(HASHSET, hs, hset, /* FMOD */, /* K */, int)
|
||||
COLLECTION_GENERATE_HEADER(HASHMAP, hm, hmap, /* FMOD */, int, int)
|
||||
CMC_COLLECTION_GENERATE_HEADER(LIST, l, list, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE_HEADER(STACK, s, stack, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE_HEADER(QUEUE, q, queue, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE_HEADER(DEQUE, d, deque, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE_HEADER(LINKEDLIST, ll, linked, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE_HEADER(HEAP, h, heap, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE_HEADER(TREESET, ts, tset, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE_HEADER(TREEMAP, tm, tmap, int, int)
|
||||
CMC_COLLECTION_GENERATE_HEADER(HASHSET, hs, hset, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE_HEADER(HASHMAP, hm, hmap, int, int)
|
||||
|
||||
CMC_COLLECTION_GENERATE_HEADER(INTERVALHEAP, ih, iheap, , int)
|
||||
CMC_COLLECTION_GENERATE_HEADER(MULTIMAP, mm, mmap, int, int)
|
||||
CMC_COLLECTION_GENERATE_HEADER(MULTISET, ms, mset, , int)
|
||||
+127
-100
@@ -26,115 +26,142 @@ typedef union union_u {
|
||||
|
||||
typedef int (*func_t)(int, double, char *);
|
||||
|
||||
COLLECTION_GENERATE(LIST, l0, list0, static, /* K */, struct_t *)
|
||||
COLLECTION_GENERATE(STACK, s0, stack0, static, /* K */, struct_t *)
|
||||
COLLECTION_GENERATE(QUEUE, q0, queue0, static, /* K */, struct_t *)
|
||||
COLLECTION_GENERATE(DEQUE, d0, deque0, static, /* K */, struct_t *)
|
||||
COLLECTION_GENERATE(LINKEDLIST, ll0, linked0, static, /* K */, struct_t *)
|
||||
COLLECTION_GENERATE(HEAP, h0, heap0, static, /* K */, struct_t *)
|
||||
COLLECTION_GENERATE(TREESET, ts0, tset0, static, /* K */, struct_t *)
|
||||
COLLECTION_GENERATE(TREEMAP, tm0, tmap0, static, struct_t *, struct_t *)
|
||||
COLLECTION_GENERATE(HASHSET, hs0, hset0, static, /* K */, struct_t *)
|
||||
COLLECTION_GENERATE(HASHMAP, hm0, hmap0, static, struct_t *, struct_t *)
|
||||
CMC_COLLECTION_GENERATE(LIST, l0, list0, /* K */, struct_t *)
|
||||
CMC_COLLECTION_GENERATE(STACK, s0, stack0, /* K */, struct_t *)
|
||||
CMC_COLLECTION_GENERATE(QUEUE, q0, queue0, /* K */, struct_t *)
|
||||
CMC_COLLECTION_GENERATE(DEQUE, d0, deque0, /* K */, struct_t *)
|
||||
CMC_COLLECTION_GENERATE(LINKEDLIST, ll0, linked0, /* K */, struct_t *)
|
||||
CMC_COLLECTION_GENERATE(HEAP, h0, heap0, /* K */, struct_t *)
|
||||
CMC_COLLECTION_GENERATE(TREESET, ts0, tset0, /* K */, struct_t *)
|
||||
CMC_COLLECTION_GENERATE(TREEMAP, tm0, tmap0, struct_t *, struct_t *)
|
||||
CMC_COLLECTION_GENERATE(HASHSET, hs0, hset0, /* K */, struct_t *)
|
||||
CMC_COLLECTION_GENERATE(HASHMAP, hm0, hmap0, struct_t *, struct_t *)
|
||||
CMC_COLLECTION_GENERATE(INTERVALHEAP, ih0, iheap0, struct_t *, struct_t *)
|
||||
CMC_COLLECTION_GENERATE(MULTIMAP, mm0, mmap0, struct_t *, struct_t *)
|
||||
CMC_COLLECTION_GENERATE(MULTISET, ms0, mset0, struct_t *, struct_t *)
|
||||
|
||||
COLLECTION_GENERATE(LIST, l1, list1, static, /* K */, struct_t)
|
||||
COLLECTION_GENERATE(STACK, s1, stack1, static, /* K */, struct_t)
|
||||
COLLECTION_GENERATE(QUEUE, q1, queue1, static, /* K */, struct_t)
|
||||
COLLECTION_GENERATE(DEQUE, d1, deque1, static, /* K */, struct_t)
|
||||
COLLECTION_GENERATE(LINKEDLIST, ll1, linked1, static, /* K */, struct_t)
|
||||
COLLECTION_GENERATE(HEAP, h1, heap1, static, /* K */, struct_t)
|
||||
COLLECTION_GENERATE(TREESET, ts1, tset1, static, /* K */, struct_t)
|
||||
COLLECTION_GENERATE(TREEMAP, tm1, tmap1, static, struct_t, struct_t)
|
||||
COLLECTION_GENERATE(HASHSET, hs1, hset1, static, /* K */, struct_t)
|
||||
COLLECTION_GENERATE(HASHMAP, hm1, hmap1, static, struct_t, struct_t)
|
||||
CMC_COLLECTION_GENERATE(LIST, l1, list1, /* K */, struct_t)
|
||||
CMC_COLLECTION_GENERATE(STACK, s1, stack1, /* K */, struct_t)
|
||||
CMC_COLLECTION_GENERATE(QUEUE, q1, queue1, /* K */, struct_t)
|
||||
CMC_COLLECTION_GENERATE(DEQUE, d1, deque1, /* K */, struct_t)
|
||||
CMC_COLLECTION_GENERATE(LINKEDLIST, ll1, linked1, /* K */, struct_t)
|
||||
CMC_COLLECTION_GENERATE(HEAP, h1, heap1, /* K */, struct_t)
|
||||
CMC_COLLECTION_GENERATE(TREESET, ts1, tset1, /* K */, struct_t)
|
||||
CMC_COLLECTION_GENERATE(TREEMAP, tm1, tmap1, struct_t, struct_t)
|
||||
CMC_COLLECTION_GENERATE(HASHSET, hs1, hset1, /* K */, struct_t)
|
||||
CMC_COLLECTION_GENERATE(HASHMAP, hm1, hmap1, struct_t, struct_t)
|
||||
CMC_COLLECTION_GENERATE(INTERVALHEAP, ih1, iheap1, struct_t, struct_t)
|
||||
CMC_COLLECTION_GENERATE(MULTIMAP, mm1, mmap1, struct_t, struct_t)
|
||||
CMC_COLLECTION_GENERATE(MULTISET, ms1, mset1, struct_t, struct_t)
|
||||
|
||||
COLLECTION_GENERATE(LIST, l2, list2, static, /* K */, int)
|
||||
COLLECTION_GENERATE(STACK, s2, stack2, static, /* K */, int)
|
||||
COLLECTION_GENERATE(QUEUE, q2, queue2, static, /* K */, int)
|
||||
COLLECTION_GENERATE(DEQUE, d2, deque2, static, /* K */, int)
|
||||
COLLECTION_GENERATE(LINKEDLIST, ll2, linked2, static, /* K */, int)
|
||||
COLLECTION_GENERATE(HEAP, h2, heap2, static, /* K */, int)
|
||||
COLLECTION_GENERATE(TREESET, ts2, tset2, static, /* K */, int)
|
||||
COLLECTION_GENERATE(TREEMAP, tm2, tmap2, static, int, int)
|
||||
COLLECTION_GENERATE(HASHSET, hs2, hset2, static, /* K */, int)
|
||||
COLLECTION_GENERATE(HASHMAP, hm2, hmap2, static, int, int)
|
||||
CMC_COLLECTION_GENERATE(LIST, l2, list2, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE(STACK, s2, stack2, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE(QUEUE, q2, queue2, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE(DEQUE, d2, deque2, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE(LINKEDLIST, ll2, linked2, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE(HEAP, h2, heap2, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE(TREESET, ts2, tset2, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE(TREEMAP, tm2, tmap2, int, int)
|
||||
CMC_COLLECTION_GENERATE(HASHSET, hs2, hset2, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE(HASHMAP, hm2, hmap2, int, int)
|
||||
CMC_COLLECTION_GENERATE(INTERVALHEAP, ih2, iheap2, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE(MULTIMAP, mm2, mmap2, int, int)
|
||||
CMC_COLLECTION_GENERATE(MULTISET, ms2, mset2, /* K */, int)
|
||||
|
||||
COLLECTION_GENERATE(LIST, l3, list3, static, /* K */, int *)
|
||||
COLLECTION_GENERATE(STACK, s3, stack3, static, /* K */, int *)
|
||||
COLLECTION_GENERATE(QUEUE, q3, queue3, static, /* K */, int *)
|
||||
COLLECTION_GENERATE(DEQUE, d3, deque3, static, /* K */, int *)
|
||||
COLLECTION_GENERATE(LINKEDLIST, ll3, linked3, static, /* K */, int *)
|
||||
COLLECTION_GENERATE(HEAP, h3, heap3, static, /* K */, int *)
|
||||
COLLECTION_GENERATE(TREESET, ts3, tset3, static, /* K */, int *)
|
||||
COLLECTION_GENERATE(TREEMAP, tm3, tmap3, static, int *, int *)
|
||||
COLLECTION_GENERATE(HASHSET, hs3, hset3, static, /* K */, int *)
|
||||
COLLECTION_GENERATE(HASHMAP, hm3, hmap3, static, int *, int *)
|
||||
CMC_COLLECTION_GENERATE(LIST, l3, list3, /* K */, int *)
|
||||
CMC_COLLECTION_GENERATE(STACK, s3, stack3, /* K */, int *)
|
||||
CMC_COLLECTION_GENERATE(QUEUE, q3, queue3, /* K */, int *)
|
||||
CMC_COLLECTION_GENERATE(DEQUE, d3, deque3, /* K */, int *)
|
||||
CMC_COLLECTION_GENERATE(LINKEDLIST, ll3, linked3, /* K */, int *)
|
||||
CMC_COLLECTION_GENERATE(HEAP, h3, heap3, /* K */, int *)
|
||||
CMC_COLLECTION_GENERATE(TREESET, ts3, tset3, /* K */, int *)
|
||||
CMC_COLLECTION_GENERATE(TREEMAP, tm3, tmap3, int *, int *)
|
||||
CMC_COLLECTION_GENERATE(HASHSET, hs3, hset3, /* K */, int *)
|
||||
CMC_COLLECTION_GENERATE(HASHMAP, hm3, hmap3, int *, int *)
|
||||
CMC_COLLECTION_GENERATE(INTERVALHEAP, ih3, iheap3, /* K */, int *)
|
||||
CMC_COLLECTION_GENERATE(MULTIMAP, mm3, mmap3, int *, int *)
|
||||
CMC_COLLECTION_GENERATE(MULTISET, ms3, mset3, /* K */, int *)
|
||||
|
||||
COLLECTION_GENERATE(LIST, l4, list4, static, /* K */, enum_t *)
|
||||
COLLECTION_GENERATE(STACK, s4, stack4, static, /* K */, enum_t *)
|
||||
COLLECTION_GENERATE(QUEUE, q4, queue4, static, /* K */, enum_t *)
|
||||
COLLECTION_GENERATE(DEQUE, d4, deque4, static, /* K */, enum_t *)
|
||||
COLLECTION_GENERATE(LINKEDLIST, ll4, linked4, static, /* K */, enum_t *)
|
||||
COLLECTION_GENERATE(HEAP, h4, heap4, static, /* K */, enum_t *)
|
||||
COLLECTION_GENERATE(TREESET, ts4, tset4, static, /* K */, enum_t *)
|
||||
COLLECTION_GENERATE(TREEMAP, tm4, tmap4, static, enum_t *, enum_t *)
|
||||
COLLECTION_GENERATE(HASHSET, hs4, hset4, static, /* K */, enum_t *)
|
||||
COLLECTION_GENERATE(HASHMAP, hm4, hmap4, static, enum_t *, enum_t *)
|
||||
CMC_COLLECTION_GENERATE(LIST, l4, list4, /* K */, enum_t *)
|
||||
CMC_COLLECTION_GENERATE(STACK, s4, stack4, /* K */, enum_t *)
|
||||
CMC_COLLECTION_GENERATE(QUEUE, q4, queue4, /* K */, enum_t *)
|
||||
CMC_COLLECTION_GENERATE(DEQUE, d4, deque4, /* K */, enum_t *)
|
||||
CMC_COLLECTION_GENERATE(LINKEDLIST, ll4, linked4, /* K */, enum_t *)
|
||||
CMC_COLLECTION_GENERATE(HEAP, h4, heap4, /* K */, enum_t *)
|
||||
CMC_COLLECTION_GENERATE(TREESET, ts4, tset4, /* K */, enum_t *)
|
||||
CMC_COLLECTION_GENERATE(TREEMAP, tm4, tmap4, enum_t *, enum_t *)
|
||||
CMC_COLLECTION_GENERATE(HASHSET, hs4, hset4, /* K */, enum_t *)
|
||||
CMC_COLLECTION_GENERATE(HASHMAP, hm4, hmap4, enum_t *, enum_t *)
|
||||
CMC_COLLECTION_GENERATE(INTERVALHEAP, ih4, iheap4, /* K */, enum_t *)
|
||||
CMC_COLLECTION_GENERATE(MULTIMAP, mm4, mmap4, enum_t *, enum_t *)
|
||||
CMC_COLLECTION_GENERATE(MULTISET, ms4, mset4, /* K */, enum_t *)
|
||||
|
||||
COLLECTION_GENERATE(LIST, l5, list5, static, /* K */, enum_t)
|
||||
COLLECTION_GENERATE(STACK, s5, stack5, static, /* K */, enum_t)
|
||||
COLLECTION_GENERATE(QUEUE, q5, queue5, static, /* K */, enum_t)
|
||||
COLLECTION_GENERATE(DEQUE, d5, deque5, static, /* K */, enum_t)
|
||||
COLLECTION_GENERATE(LINKEDLIST, ll5, linked5, static, /* K */, enum_t)
|
||||
COLLECTION_GENERATE(HEAP, h5, heap5, static, /* K */, enum_t)
|
||||
COLLECTION_GENERATE(TREESET, ts5, tset5, static, /* K */, enum_t)
|
||||
COLLECTION_GENERATE(TREEMAP, tm5, tmap5, static, enum_t, enum_t)
|
||||
COLLECTION_GENERATE(HASHSET, hs5, hset5, static, /* K */, enum_t)
|
||||
COLLECTION_GENERATE(HASHMAP, hm5, hmap5, static, enum_t, enum_t)
|
||||
CMC_COLLECTION_GENERATE(LIST, l5, list5, /* K */, enum_t)
|
||||
CMC_COLLECTION_GENERATE(STACK, s5, stack5, /* K */, enum_t)
|
||||
CMC_COLLECTION_GENERATE(QUEUE, q5, queue5, /* K */, enum_t)
|
||||
CMC_COLLECTION_GENERATE(DEQUE, d5, deque5, /* K */, enum_t)
|
||||
CMC_COLLECTION_GENERATE(LINKEDLIST, ll5, linked5, /* K */, enum_t)
|
||||
CMC_COLLECTION_GENERATE(HEAP, h5, heap5, /* K */, enum_t)
|
||||
CMC_COLLECTION_GENERATE(TREESET, ts5, tset5, /* K */, enum_t)
|
||||
CMC_COLLECTION_GENERATE(TREEMAP, tm5, tmap5, enum_t, enum_t)
|
||||
CMC_COLLECTION_GENERATE(HASHSET, hs5, hset5, /* K */, enum_t)
|
||||
CMC_COLLECTION_GENERATE(HASHMAP, hm5, hmap5, enum_t, enum_t)
|
||||
CMC_COLLECTION_GENERATE(INTERVALHEAP, ih5, iheap5, /* K */, enum_t)
|
||||
CMC_COLLECTION_GENERATE(MULTIMAP, mm5, mmap5, enum_t, enum_t)
|
||||
CMC_COLLECTION_GENERATE(MULTISET, ms5, mset5, /* K */, enum_t)
|
||||
|
||||
COLLECTION_GENERATE(LIST, l6, list6, static, /* K */, union_t *)
|
||||
COLLECTION_GENERATE(STACK, s6, stack6, static, /* K */, union_t *)
|
||||
COLLECTION_GENERATE(QUEUE, q6, queue6, static, /* K */, union_t *)
|
||||
COLLECTION_GENERATE(DEQUE, d6, deque6, static, /* K */, union_t *)
|
||||
COLLECTION_GENERATE(LINKEDLIST, ll6, linked6, static, /* K */, union_t *)
|
||||
COLLECTION_GENERATE(HEAP, h6, heap6, static, /* K */, union_t *)
|
||||
COLLECTION_GENERATE(TREESET, ts6, tset6, static, /* K */, union_t *)
|
||||
COLLECTION_GENERATE(TREEMAP, tm6, tmap6, static, union_t *, union_t *)
|
||||
COLLECTION_GENERATE(HASHSET, hs6, hset6, static, /* K */, union_t *)
|
||||
COLLECTION_GENERATE(HASHMAP, hm6, hmap6, static, union_t *, union_t *)
|
||||
CMC_COLLECTION_GENERATE(LIST, l6, list6, /* K */, union_t *)
|
||||
CMC_COLLECTION_GENERATE(STACK, s6, stack6, /* K */, union_t *)
|
||||
CMC_COLLECTION_GENERATE(QUEUE, q6, queue6, /* K */, union_t *)
|
||||
CMC_COLLECTION_GENERATE(DEQUE, d6, deque6, /* K */, union_t *)
|
||||
CMC_COLLECTION_GENERATE(LINKEDLIST, ll6, linked6, /* K */, union_t *)
|
||||
CMC_COLLECTION_GENERATE(HEAP, h6, heap6, /* K */, union_t *)
|
||||
CMC_COLLECTION_GENERATE(TREESET, ts6, tset6, /* K */, union_t *)
|
||||
CMC_COLLECTION_GENERATE(TREEMAP, tm6, tmap6, union_t *, union_t *)
|
||||
CMC_COLLECTION_GENERATE(HASHSET, hs6, hset6, /* K */, union_t *)
|
||||
CMC_COLLECTION_GENERATE(HASHMAP, hm6, hmap6, union_t *, union_t *)
|
||||
CMC_COLLECTION_GENERATE(INTERVALHEAP, ih6, iheap6, /* K */, union_t *)
|
||||
CMC_COLLECTION_GENERATE(MULTIMAP, mm6, mmap6, union_t *, union_t *)
|
||||
CMC_COLLECTION_GENERATE(MULTISET, ms6, mset6, /* K */, union_t *)
|
||||
|
||||
COLLECTION_GENERATE(LIST, l7, list7, static, /* K */, union_t)
|
||||
COLLECTION_GENERATE(STACK, s7, stack7, static, /* K */, union_t)
|
||||
COLLECTION_GENERATE(QUEUE, q7, queue7, static, /* K */, union_t)
|
||||
COLLECTION_GENERATE(DEQUE, d7, deque7, static, /* K */, union_t)
|
||||
COLLECTION_GENERATE(LINKEDLIST, ll7, linked7, static, /* K */, union_t)
|
||||
COLLECTION_GENERATE(HEAP, h7, heap7, static, /* K */, union_t)
|
||||
COLLECTION_GENERATE(TREESET, ts7, tset7, static, /* K */, union_t)
|
||||
COLLECTION_GENERATE(TREEMAP, tm7, tmap7, static, union_t, union_t)
|
||||
COLLECTION_GENERATE(HASHSET, hs7, hset7, static, /* K */, union_t)
|
||||
COLLECTION_GENERATE(HASHMAP, hm7, hmap7, static, union_t, union_t)
|
||||
CMC_COLLECTION_GENERATE(LIST, l7, list7, /* K */, union_t)
|
||||
CMC_COLLECTION_GENERATE(STACK, s7, stack7, /* K */, union_t)
|
||||
CMC_COLLECTION_GENERATE(QUEUE, q7, queue7, /* K */, union_t)
|
||||
CMC_COLLECTION_GENERATE(DEQUE, d7, deque7, /* K */, union_t)
|
||||
CMC_COLLECTION_GENERATE(LINKEDLIST, ll7, linked7, /* K */, union_t)
|
||||
CMC_COLLECTION_GENERATE(HEAP, h7, heap7, /* K */, union_t)
|
||||
CMC_COLLECTION_GENERATE(TREESET, ts7, tset7, /* K */, union_t)
|
||||
CMC_COLLECTION_GENERATE(TREEMAP, tm7, tmap7, union_t, union_t)
|
||||
CMC_COLLECTION_GENERATE(HASHSET, hs7, hset7, /* K */, union_t)
|
||||
CMC_COLLECTION_GENERATE(HASHMAP, hm7, hmap7, union_t, union_t)
|
||||
CMC_COLLECTION_GENERATE(INTERVALHEAP, ih7, iheap7, /* K */, union_t)
|
||||
CMC_COLLECTION_GENERATE(MULTIMAP, mm7, mmap7, union_t, union_t)
|
||||
CMC_COLLECTION_GENERATE(MULTISET, ms7, mset7, /* K */, union_t)
|
||||
|
||||
COLLECTION_GENERATE(LIST, l8, list8, static, /* K */, func_t)
|
||||
COLLECTION_GENERATE(STACK, s8, stack8, static, /* K */, func_t)
|
||||
COLLECTION_GENERATE(QUEUE, q8, queue8, static, /* K */, func_t)
|
||||
COLLECTION_GENERATE(DEQUE, d8, deque8, static, /* K */, func_t)
|
||||
COLLECTION_GENERATE(LINKEDLIST, ll8, linked8, static, /* K */, func_t)
|
||||
COLLECTION_GENERATE(HEAP, h8, heap8, static, /* K */, func_t)
|
||||
COLLECTION_GENERATE(TREESET, ts8, tset8, static, /* K */, func_t)
|
||||
COLLECTION_GENERATE(TREEMAP, tm8, tmap8, static, func_t, func_t)
|
||||
COLLECTION_GENERATE(HASHSET, hs8, hset8, static, /* K */, func_t)
|
||||
COLLECTION_GENERATE(HASHMAP, hm8, hmap8, static, func_t, func_t)
|
||||
CMC_COLLECTION_GENERATE(LIST, l8, list8, /* K */, func_t)
|
||||
CMC_COLLECTION_GENERATE(STACK, s8, stack8, /* K */, func_t)
|
||||
CMC_COLLECTION_GENERATE(QUEUE, q8, queue8, /* K */, func_t)
|
||||
CMC_COLLECTION_GENERATE(DEQUE, d8, deque8, /* K */, func_t)
|
||||
CMC_COLLECTION_GENERATE(LINKEDLIST, ll8, linked8, /* K */, func_t)
|
||||
CMC_COLLECTION_GENERATE(HEAP, h8, heap8, /* K */, func_t)
|
||||
CMC_COLLECTION_GENERATE(TREESET, ts8, tset8, /* K */, func_t)
|
||||
CMC_COLLECTION_GENERATE(TREEMAP, tm8, tmap8, func_t, func_t)
|
||||
CMC_COLLECTION_GENERATE(HASHSET, hs8, hset8, /* K */, func_t)
|
||||
CMC_COLLECTION_GENERATE(HASHMAP, hm8, hmap8, func_t, func_t)
|
||||
CMC_COLLECTION_GENERATE(INTERVALHEAP, ih8, iheap8, /* K */, func_t)
|
||||
CMC_COLLECTION_GENERATE(MULTIMAP, mm8, mmap8, func_t, func_t)
|
||||
CMC_COLLECTION_GENERATE(MULTISET, ms8, mset8, /* K */, func_t)
|
||||
|
||||
COLLECTION_GENERATE(LIST, l9, list9, static, /* K */, func_t)
|
||||
COLLECTION_GENERATE(STACK, s9, stack9, static, /* K */, func_t)
|
||||
COLLECTION_GENERATE(QUEUE, q9, queue9, static, /* K */, func_t)
|
||||
COLLECTION_GENERATE(DEQUE, d9, deque9, static, /* K */, func_t)
|
||||
COLLECTION_GENERATE(LINKEDLIST, ll9, linked9, static, /* K */, func_t)
|
||||
COLLECTION_GENERATE(HEAP, h9, heap9, static, /* K */, func_t)
|
||||
COLLECTION_GENERATE(TREESET, ts9, tset9, static, /* K */, func_t)
|
||||
COLLECTION_GENERATE(TREEMAP, tm9, tmap9, static, func_t, func_t)
|
||||
COLLECTION_GENERATE(HASHSET, hs9, hset9, static, /* K */, func_t)
|
||||
COLLECTION_GENERATE(HASHMAP, hm9, hmap9, static, func_t, func_t)
|
||||
CMC_COLLECTION_GENERATE(LIST, l9, list9, /* K */, func_t)
|
||||
CMC_COLLECTION_GENERATE(STACK, s9, stack9, /* K */, func_t)
|
||||
CMC_COLLECTION_GENERATE(QUEUE, q9, queue9, /* K */, func_t)
|
||||
CMC_COLLECTION_GENERATE(DEQUE, d9, deque9, /* K */, func_t)
|
||||
CMC_COLLECTION_GENERATE(LINKEDLIST, ll9, linked9, /* K */, func_t)
|
||||
CMC_COLLECTION_GENERATE(HEAP, h9, heap9, /* K */, func_t)
|
||||
CMC_COLLECTION_GENERATE(TREESET, ts9, tset9, /* K */, func_t)
|
||||
CMC_COLLECTION_GENERATE(TREEMAP, tm9, tmap9, func_t, func_t)
|
||||
CMC_COLLECTION_GENERATE(HASHSET, hs9, hset9, /* K */, func_t)
|
||||
CMC_COLLECTION_GENERATE(HASHMAP, hm9, hmap9, func_t, func_t)
|
||||
|
||||
int main(void)
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user