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 |
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
|
||||
- cd ./main
|
||||
- make
|
||||
- make -C ./tests/
|
||||
- make -C ./tests/main/
|
||||
- make -C ./tests/codecov/
|
||||
after_success:
|
||||
- bash <(curl -s https://codecov.io/bash)
|
||||
@@ -1,5 +1,23 @@
|
||||
# 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,11 +1,22 @@
|
||||
# C-Macro-Collections
|
||||
# C Macro Collections
|
||||
|
||||
Header only, macro generated, generic and type-safe Collections in C.
|
||||
<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
|
||||
|
||||
@@ -13,8 +24,8 @@ Header only, macro generated, generic and type-safe Collections in C.
|
||||
* Available Collections
|
||||
* Overall To-Do
|
||||
* Design Decisions
|
||||
* What to Use
|
||||
* How to Use
|
||||
* What to use
|
||||
* How to use
|
||||
|
||||
## Project Structure
|
||||
|
||||
@@ -31,28 +42,34 @@ Header only, macro generated, generic and type-safe Collections in C.
|
||||
|
||||
## Available Collections
|
||||
|
||||
* Main C Macro Collections Library
|
||||
* Deque
|
||||
* HashMap
|
||||
* HashSet
|
||||
* Heap
|
||||
* LinkedList
|
||||
* List
|
||||
* Queue
|
||||
* Stack
|
||||
* TreeMap
|
||||
* TreeSet
|
||||
* Extra Collections Library
|
||||
* IntervalHeap
|
||||
* MultiMap
|
||||
* MultiSet
|
||||
* Statically 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. The documentation is still being written.
|
||||
| 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
|
||||
|
||||
@@ -117,35 +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`).
|
||||
* \*__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:
|
||||
|
||||
@@ -154,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>
|
||||
|
||||
|
||||
@@ -4,19 +4,16 @@ TODO
|
||||
[X] - Finished
|
||||
[~] - Needs to be reviewed
|
||||
|
||||
[ ] Future possible Collections
|
||||
[ ] Add TreeHashMap
|
||||
[ ] Add SortedList
|
||||
[ ] Add BiDiMap
|
||||
[ ] Add Trie (or any variant)
|
||||
|
||||
[/] Documentation
|
||||
[/] Tests
|
||||
[X] Remove PUBLIC and PRIVATE
|
||||
[X] Extra Collections
|
||||
[X] Add MultiSet
|
||||
[X] Add MultiMap
|
||||
[X] Add IntervalHeap
|
||||
[ ] Add functions
|
||||
[/] Add SortedList
|
||||
[/] Add BiDiMap
|
||||
[/] Add functions
|
||||
[X] update {hashmap, treemap, multimap}
|
||||
[X] set {hashmap, treemap, multimap}
|
||||
[X] to_string {all}
|
||||
@@ -27,15 +24,15 @@ TODO
|
||||
[ ] to_array {all}
|
||||
[X] equals {all}
|
||||
[X] copy_of {all}
|
||||
[ ] resize {dynamic arrays and circular buffers}
|
||||
[X] resize {array based collections}
|
||||
[ ] Serialization
|
||||
[ ] save {all}
|
||||
[ ] load {all}
|
||||
[ ] serialize {all}
|
||||
[ ] deserialize {all}
|
||||
[ ] Add callback utility
|
||||
[ ] Callback utility
|
||||
[ ] Zip Iterators
|
||||
[ ] Stack Allocated Collections
|
||||
[ ] Statically Allocated Collections
|
||||
[ ] Deque
|
||||
[ ] HashMap
|
||||
[ ] HashSet
|
||||
@@ -57,9 +54,14 @@ TODO
|
||||
[ ] Stack
|
||||
[ ] TreeMap
|
||||
[ ] TreeSet
|
||||
[~] Utility
|
||||
[~] assert.h
|
||||
[X] Utility
|
||||
[X] assert.h
|
||||
[X] foreach.h
|
||||
[~] log.h
|
||||
[~] test.h
|
||||
[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
|
||||
|
||||
+38
-28
@@ -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,8 +151,8 @@ 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, NULL); \
|
||||
\
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
+485
-508
File diff suppressed because it is too large.
Load diff
+724
-718
File diff suppressed because it is too large.
Load diff
+830
-822
File diff suppressed because it is too large.
Load diff
+28
-58
@@ -30,12 +30,16 @@
|
||||
#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,
|
||||
@@ -106,12 +110,8 @@ typedef enum cmc_heap_order_e
|
||||
/* Collection Input and Output */ \
|
||||
bool PFX##_insert(SNAME *_heap_, V element); \
|
||||
bool PFX##_remove(SNAME *_heap_, V *result); \
|
||||
/* Conditional Input and Output */ \
|
||||
bool PFX##_insert_if(SNAME *_heap_, V element, bool condition); \
|
||||
bool PFX##_remove_if(SNAME *_heap_, V *result, bool condition); \
|
||||
/* Element Access */ \
|
||||
V PFX##_peek(SNAME *_heap_); \
|
||||
V *PFX##_peek_ref(SNAME *_heap_); \
|
||||
/* Collection State */ \
|
||||
bool PFX##_contains(SNAME *_heap_, V element); \
|
||||
bool PFX##_empty(SNAME *_heap_); \
|
||||
@@ -119,6 +119,7 @@ typedef enum cmc_heap_order_e
|
||||
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_); \
|
||||
@@ -144,21 +145,10 @@ typedef enum cmc_heap_order_e
|
||||
V PFX##_iter_value(SNAME##_iter *iter); \
|
||||
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 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_); \
|
||||
@@ -231,7 +221,7 @@ typedef enum cmc_heap_order_e
|
||||
{ \
|
||||
if (PFX##_full(_heap_)) \
|
||||
{ \
|
||||
if (!PFX##_impl_grow(_heap_)) \
|
||||
if (!PFX##_resize(_heap_, PFX##_count(_heap_) * 2)) \
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
@@ -256,7 +246,7 @@ typedef enum cmc_heap_order_e
|
||||
\
|
||||
*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--; \
|
||||
\
|
||||
@@ -266,38 +256,14 @@ typedef enum cmc_heap_order_e
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
bool PFX##_insert_if(SNAME *_heap_, V element, bool condition) \
|
||||
{ \
|
||||
if (condition) \
|
||||
return PFX##_insert(_heap_, element); \
|
||||
\
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
bool PFX##_remove_if(SNAME *_heap_, V *result, bool condition) \
|
||||
{ \
|
||||
if (condition) \
|
||||
return PFX##_remove(_heap_, result); \
|
||||
\
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
V PFX##_peek(SNAME *_heap_) \
|
||||
{ \
|
||||
if (PFX##_empty(_heap_)) \
|
||||
return PFX##_impl_default_value(); \
|
||||
return (V){0}; \
|
||||
\
|
||||
return _heap_->buffer[0]; \
|
||||
} \
|
||||
\
|
||||
V *PFX##_peek_ref(SNAME *_heap_) \
|
||||
{ \
|
||||
if (PFX##_empty(_heap_)) \
|
||||
return NULL; \
|
||||
\
|
||||
return &(_heap_->buffer[0]); \
|
||||
} \
|
||||
\
|
||||
bool PFX##_contains(SNAME *_heap_, V element) \
|
||||
{ \
|
||||
for (size_t i = 0; i < _heap_->count; i++) \
|
||||
@@ -329,6 +295,25 @@ typedef enum cmc_heap_order_e
|
||||
return _heap_->capacity; \
|
||||
} \
|
||||
\
|
||||
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); \
|
||||
@@ -531,7 +516,7 @@ typedef enum cmc_heap_order_e
|
||||
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]; \
|
||||
} \
|
||||
@@ -541,21 +526,6 @@ typedef enum cmc_heap_order_e
|
||||
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 */ \
|
||||
|
||||
+13
-38
@@ -28,12 +28,16 @@
|
||||
#ifndef CMC_LINKEDLIST_H
|
||||
#define CMC_LINKEDLIST_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_linkedlist = "%s at %p { count:%" PRIuMAX ", head:%p, tail:%p }";
|
||||
|
||||
#define CMC_GENERATE_LINKEDLIST(PFX, SNAME, V) \
|
||||
CMC_GENERATE_LINKEDLIST_HEADER(PFX, SNAME, V) \
|
||||
CMC_GENERATE_LINKEDLIST_SOURCE(PFX, SNAME, V)
|
||||
@@ -108,14 +112,11 @@
|
||||
void PFX##_free(SNAME *_list_, void (*deallocator)(V)); \
|
||||
/* Collection Input and Output */ \
|
||||
bool PFX##_push_front(SNAME *_list_, V element); \
|
||||
bool PFX##_push(SNAME *_list_, V element, size_t index); \
|
||||
bool PFX##_push_at(SNAME *_list_, V element, size_t index); \
|
||||
bool PFX##_push_back(SNAME *_list_, V element); \
|
||||
bool PFX##_pop_front(SNAME *_list_); \
|
||||
bool PFX##_pop(SNAME *_list_, size_t index); \
|
||||
bool PFX##_pop_at(SNAME *_list_, size_t index); \
|
||||
bool PFX##_pop_back(SNAME *_list_); \
|
||||
/* Conditional Input and Output */ \
|
||||
bool PFX##_push_if(SNAME *_list_, V element, size_t index, bool condition); \
|
||||
bool PFX##_pop_if(SNAME *_list_, size_t index, bool condition); \
|
||||
/* Element Access */ \
|
||||
V PFX##_front(SNAME *_list_); \
|
||||
V PFX##_get(SNAME *_list_, size_t index); \
|
||||
@@ -171,16 +172,6 @@
|
||||
size_t PFX##_iter_index(SNAME##_iter *iter); \
|
||||
SNAME##_node *PFX##_iter_node(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 CMC_GENERATE_LINKEDLIST_SOURCE(PFX, SNAME, V) \
|
||||
\
|
||||
@@ -259,7 +250,7 @@
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
bool PFX##_push(SNAME *_list_, V element, size_t index) \
|
||||
bool PFX##_push_at(SNAME *_list_, V element, size_t index) \
|
||||
{ \
|
||||
if (index > _list_->count) \
|
||||
return false; \
|
||||
@@ -334,7 +325,7 @@
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
bool PFX##_pop(SNAME *_list_, size_t index) \
|
||||
bool PFX##_pop_at(SNAME *_list_, size_t index) \
|
||||
{ \
|
||||
if (PFX##_empty(_list_)) \
|
||||
return false; \
|
||||
@@ -386,26 +377,10 @@
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
bool PFX##_push_if(SNAME *_list_, V element, size_t index, bool condition) \
|
||||
{ \
|
||||
if (condition) \
|
||||
return PFX##_push(_list_, element, index); \
|
||||
\
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
bool PFX##_pop_if(SNAME *_list_, size_t index, bool condition) \
|
||||
{ \
|
||||
if (condition) \
|
||||
return PFX##_pop(_list_, index); \
|
||||
\
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
V PFX##_front(SNAME *_list_) \
|
||||
{ \
|
||||
if (PFX##_empty(_list_)) \
|
||||
return PFX##_impl_default_value(); \
|
||||
return (V){0}; \
|
||||
\
|
||||
return _list_->head->data; \
|
||||
} \
|
||||
@@ -413,12 +388,12 @@
|
||||
V PFX##_get(SNAME *_list_, size_t index) \
|
||||
{ \
|
||||
if (index >= _list_->count || PFX##_empty(_list_)) \
|
||||
return PFX##_impl_default_value(); \
|
||||
return (V){0}; \
|
||||
\
|
||||
SNAME##_node *scan = PFX##_get_node(_list_, index); \
|
||||
\
|
||||
if (scan == NULL) \
|
||||
return PFX##_impl_default_value(); \
|
||||
return (V){0}; \
|
||||
\
|
||||
return scan->data; \
|
||||
} \
|
||||
@@ -442,7 +417,7 @@
|
||||
V PFX##_back(SNAME *_list_) \
|
||||
{ \
|
||||
if (PFX##_empty(_list_)) \
|
||||
return PFX##_impl_default_value(); \
|
||||
return (V){0}; \
|
||||
\
|
||||
return _list_->tail->data; \
|
||||
} \
|
||||
@@ -884,7 +859,7 @@
|
||||
V PFX##_iter_value(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (PFX##_empty(iter->target)) \
|
||||
return PFX##_impl_default_value(); \
|
||||
return (V){0}; \
|
||||
\
|
||||
return iter->cursor->data; \
|
||||
} \
|
||||
|
||||
+632
-670
File diff suppressed because it is too large.
Load diff
+441
-446
@@ -43,12 +43,16 @@
|
||||
#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"
|
||||
|
||||
/* to_string format */
|
||||
static const char *cmc_string_fmt_queue = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", count:%" PRIuMAX ", front:%" PRIuMAX ", back:%" PRIuMAX " }";
|
||||
|
||||
#define CMC_GENERATE_QUEUE(PFX, SNAME, V) \
|
||||
CMC_GENERATE_QUEUE_HEADER(PFX, SNAME, V) \
|
||||
CMC_GENERATE_QUEUE_SOURCE(PFX, SNAME, V)
|
||||
@@ -116,9 +120,6 @@
|
||||
/* Collection Input and Output */ \
|
||||
bool PFX##_enqueue(SNAME *_queue_, V element); \
|
||||
bool PFX##_dequeue(SNAME *_queue_); \
|
||||
/* Conditional Input and Output */ \
|
||||
bool PFX##_enqueue_if(SNAME *_queue_, V element, bool condition); \
|
||||
bool PFX##_dequeue_if(SNAME *_queue_, bool condition); \
|
||||
/* Element Access */ \
|
||||
V PFX##_peek(SNAME *_queue_); \
|
||||
/* Collection State */ \
|
||||
@@ -128,6 +129,7 @@
|
||||
size_t PFX##_count(SNAME *_queue_); \
|
||||
size_t PFX##_capacity(SNAME *_queue_); \
|
||||
/* Collection Utility */ \
|
||||
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_); \
|
||||
@@ -154,450 +156,443 @@
|
||||
V *PFX##_iter_rvalue(SNAME##_iter *iter); \
|
||||
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 CMC_GENERATE_QUEUE_SOURCE(PFX, SNAME, 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_); \
|
||||
\
|
||||
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; i = (i + 1) % _queue_->capacity, j++) \
|
||||
{ \
|
||||
deallocator(_queue_->buffer[i]); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
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; i = (i + 1) % _queue_->capacity, j++) \
|
||||
{ \
|
||||
deallocator(_queue_->buffer[i]); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
free(_queue_->buffer); \
|
||||
free(_queue_); \
|
||||
} \
|
||||
\
|
||||
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; \
|
||||
} \
|
||||
\
|
||||
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; \
|
||||
} \
|
||||
\
|
||||
bool PFX##_enqueue_if(SNAME *_queue_, V element, bool condition) \
|
||||
{ \
|
||||
if (condition) \
|
||||
return PFX##_enqueue(_queue_, element); \
|
||||
\
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
bool PFX##_dequeue_if(SNAME *_queue_, bool condition) \
|
||||
{ \
|
||||
if (condition) \
|
||||
return PFX##_dequeue(_queue_); \
|
||||
\
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
V PFX##_peek(SNAME *_queue_) \
|
||||
{ \
|
||||
if (PFX##_empty(_queue_)) \
|
||||
return PFX##_impl_default_value(); \
|
||||
\
|
||||
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; i = (i + 1) % _queue_->count, j++) \
|
||||
{ \
|
||||
if (comparator(_queue_->buffer[i], element) == 0) \
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
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; \
|
||||
} \
|
||||
\
|
||||
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; i = (i + 1) % _queue_->capacity, j++) \
|
||||
{ \
|
||||
result->buffer[j] = copy_func(_queue_->buffer[i]); \
|
||||
} \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
for (size_t i = _queue_->front, j = 0; j < _queue_->count; i = (i + 1) % _queue_->capacity, j++) \
|
||||
{ \
|
||||
result->buffer[j] = _queue_->buffer[i]; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
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 \
|
||||
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; \
|
||||
} \
|
||||
\
|
||||
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 PFX##_impl_default_value(); \
|
||||
\
|
||||
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 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 */
|
||||
+384
-405
@@ -28,12 +28,16 @@
|
||||
#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"
|
||||
|
||||
/* to_string format */
|
||||
static const char *cmc_string_fmt_stack = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", count:%" PRIuMAX " }";
|
||||
|
||||
#define CMC_GENERATE_STACK(PFX, SNAME, V) \
|
||||
CMC_GENERATE_STACK_HEADER(PFX, SNAME, V) \
|
||||
CMC_GENERATE_STACK_SOURCE(PFX, SNAME, V)
|
||||
@@ -92,9 +96,6 @@
|
||||
/* Collection Input and Output */ \
|
||||
bool PFX##_push(SNAME *_stack_, V element); \
|
||||
bool PFX##_pop(SNAME *_stack_); \
|
||||
/* Conditional Input and Output */ \
|
||||
bool PFX##_push_if(SNAME *_stack_, V element, bool condition); \
|
||||
bool PFX##_pop_if(SNAME *_stack_, bool condition); \
|
||||
/* Element Access */ \
|
||||
V PFX##_top(SNAME *_stack_); \
|
||||
/* Collection State */ \
|
||||
@@ -104,6 +105,7 @@
|
||||
size_t PFX##_count(SNAME *_stack_); \
|
||||
size_t PFX##_capacity(SNAME *_stack_); \
|
||||
/* Collection Utility */ \
|
||||
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_); \
|
||||
@@ -130,409 +132,386 @@
|
||||
V *PFX##_iter_rvalue(SNAME##_iter *iter); \
|
||||
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 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_); \
|
||||
\
|
||||
SNAME *PFX##_new(size_t capacity) \
|
||||
{ \
|
||||
if (capacity < 1) \
|
||||
return NULL; \
|
||||
\
|
||||
SNAME *_stack_ = malloc(sizeof(SNAME)); \
|
||||
\
|
||||
if (!_stack_) \
|
||||
return NULL; \
|
||||
\
|
||||
_stack_->buffer = malloc(sizeof(V) * capacity); \
|
||||
\
|
||||
if (!_stack_->buffer) \
|
||||
{ \
|
||||
free(_stack_); \
|
||||
return NULL; \
|
||||
} \
|
||||
\
|
||||
memset(_stack_->buffer, 0, sizeof(V) * capacity); \
|
||||
\
|
||||
_stack_->capacity = capacity; \
|
||||
_stack_->count = 0; \
|
||||
\
|
||||
_stack_->it_start = PFX##_impl_it_start; \
|
||||
_stack_->it_end = PFX##_impl_it_end; \
|
||||
\
|
||||
return _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; \
|
||||
} \
|
||||
\
|
||||
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_); \
|
||||
} \
|
||||
\
|
||||
bool PFX##_push(SNAME *_stack_, V element) \
|
||||
{ \
|
||||
if (PFX##_full(_stack_)) \
|
||||
{ \
|
||||
if (!PFX##_impl_grow(_stack_)) \
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
_stack_->buffer[_stack_->count++] = element; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
bool PFX##_pop(SNAME *_stack_) \
|
||||
{ \
|
||||
if (PFX##_empty(_stack_)) \
|
||||
return false; \
|
||||
\
|
||||
_stack_->buffer[--_stack_->count] = PFX##_impl_default_value(); \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
bool PFX##_push_if(SNAME *_stack_, V element, bool condition) \
|
||||
{ \
|
||||
if (condition) \
|
||||
return PFX##_push(_stack_, element); \
|
||||
\
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
bool PFX##_pop_if(SNAME *_stack_, bool condition) \
|
||||
{ \
|
||||
if (condition) \
|
||||
return PFX##_pop(_stack_); \
|
||||
\
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
V PFX##_top(SNAME *_stack_) \
|
||||
{ \
|
||||
if (PFX##_empty(_stack_)) \
|
||||
return PFX##_impl_default_value(); \
|
||||
\
|
||||
return _stack_->buffer[_stack_->count - 1]; \
|
||||
} \
|
||||
\
|
||||
bool PFX##_contains(SNAME *_stack_, V element, int (*comparator)(V, V)) \
|
||||
{ \
|
||||
for (size_t i = 0; i < _stack_->count; i++) \
|
||||
{ \
|
||||
if (comparator(_stack_->buffer[i], element) == 0) \
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
bool PFX##_empty(SNAME *_stack_) \
|
||||
{ \
|
||||
return _stack_->count == 0; \
|
||||
} \
|
||||
\
|
||||
bool PFX##_full(SNAME *_stack_) \
|
||||
{ \
|
||||
return _stack_->count >= _stack_->capacity; \
|
||||
} \
|
||||
\
|
||||
size_t PFX##_count(SNAME *_stack_) \
|
||||
{ \
|
||||
return _stack_->count; \
|
||||
} \
|
||||
\
|
||||
size_t PFX##_capacity(SNAME *_stack_) \
|
||||
{ \
|
||||
return _stack_->capacity; \
|
||||
} \
|
||||
\
|
||||
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_; \
|
||||
const char *name = #SNAME; \
|
||||
\
|
||||
snprintf(str.s, cmc_string_len, cmc_string_fmt_stack, \
|
||||
name, s_, s_->buffer, s_->capacity, s_->count); \
|
||||
\
|
||||
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 = PFX##_empty(target) ? 0 : iter->target->count - 1; \
|
||||
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 = iter->target->count - 1; \
|
||||
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->start = PFX##_empty(iter->target); \
|
||||
iter->end = true; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
bool PFX##_iter_next(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (iter->end) \
|
||||
return false; \
|
||||
\
|
||||
if (iter->cursor == 0) \
|
||||
{ \
|
||||
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 + 1 == PFX##_count(iter->target)) \
|
||||
{ \
|
||||
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 == 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 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) \
|
||||
{ \
|
||||
if (PFX##_empty(iter->target)) \
|
||||
return 0; \
|
||||
\
|
||||
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; \
|
||||
\
|
||||
PFX##_iter_init(&iter, _stack_); \
|
||||
PFX##_iter_to_start(&iter); \
|
||||
\
|
||||
return iter; \
|
||||
} \
|
||||
\
|
||||
static SNAME##_iter PFX##_impl_it_end(SNAME *_stack_) \
|
||||
{ \
|
||||
SNAME##_iter iter; \
|
||||
\
|
||||
PFX##_iter_init(&iter, _stack_); \
|
||||
PFX##_iter_to_end(&iter); \
|
||||
\
|
||||
return iter; \
|
||||
#define CMC_GENERATE_STACK_SOURCE(PFX, SNAME, V) \
|
||||
\
|
||||
/* Implementation Detail Functions */ \
|
||||
static SNAME##_iter PFX##_impl_it_start(SNAME *_stack_); \
|
||||
static SNAME##_iter PFX##_impl_it_end(SNAME *_stack_); \
|
||||
\
|
||||
SNAME *PFX##_new(size_t capacity) \
|
||||
{ \
|
||||
if (capacity < 1) \
|
||||
return NULL; \
|
||||
\
|
||||
SNAME *_stack_ = malloc(sizeof(SNAME)); \
|
||||
\
|
||||
if (!_stack_) \
|
||||
return NULL; \
|
||||
\
|
||||
_stack_->buffer = malloc(sizeof(V) * capacity); \
|
||||
\
|
||||
if (!_stack_->buffer) \
|
||||
{ \
|
||||
free(_stack_); \
|
||||
return NULL; \
|
||||
} \
|
||||
\
|
||||
memset(_stack_->buffer, 0, sizeof(V) * capacity); \
|
||||
\
|
||||
_stack_->capacity = capacity; \
|
||||
_stack_->count = 0; \
|
||||
\
|
||||
_stack_->it_start = PFX##_impl_it_start; \
|
||||
_stack_->it_end = PFX##_impl_it_end; \
|
||||
\
|
||||
return _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; \
|
||||
} \
|
||||
\
|
||||
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_); \
|
||||
} \
|
||||
\
|
||||
bool PFX##_push(SNAME *_stack_, V element) \
|
||||
{ \
|
||||
if (PFX##_full(_stack_)) \
|
||||
{ \
|
||||
if (!PFX##_resize(_stack_, PFX##_capacity(_stack_) * 2)) \
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
_stack_->buffer[_stack_->count++] = element; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
bool PFX##_pop(SNAME *_stack_) \
|
||||
{ \
|
||||
if (PFX##_empty(_stack_)) \
|
||||
return false; \
|
||||
\
|
||||
_stack_->buffer[--_stack_->count] = (V){0}; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
V PFX##_top(SNAME *_stack_) \
|
||||
{ \
|
||||
if (PFX##_empty(_stack_)) \
|
||||
return (V){0}; \
|
||||
\
|
||||
return _stack_->buffer[_stack_->count - 1]; \
|
||||
} \
|
||||
\
|
||||
bool PFX##_contains(SNAME *_stack_, V element, int (*comparator)(V, V)) \
|
||||
{ \
|
||||
for (size_t i = 0; i < _stack_->count; i++) \
|
||||
{ \
|
||||
if (comparator(_stack_->buffer[i], element) == 0) \
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
bool PFX##_empty(SNAME *_stack_) \
|
||||
{ \
|
||||
return _stack_->count == 0; \
|
||||
} \
|
||||
\
|
||||
bool PFX##_full(SNAME *_stack_) \
|
||||
{ \
|
||||
return _stack_->count >= _stack_->capacity; \
|
||||
} \
|
||||
\
|
||||
size_t PFX##_count(SNAME *_stack_) \
|
||||
{ \
|
||||
return _stack_->count; \
|
||||
} \
|
||||
\
|
||||
size_t PFX##_capacity(SNAME *_stack_) \
|
||||
{ \
|
||||
return _stack_->capacity; \
|
||||
} \
|
||||
\
|
||||
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_; \
|
||||
const char *name = #SNAME; \
|
||||
\
|
||||
snprintf(str.s, cmc_string_len, cmc_string_fmt_stack, \
|
||||
name, s_, s_->buffer, s_->capacity, s_->count); \
|
||||
\
|
||||
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 = PFX##_empty(target) ? 0 : iter->target->count - 1; \
|
||||
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 = iter->target->count - 1; \
|
||||
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->start = PFX##_empty(iter->target); \
|
||||
iter->end = true; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
bool PFX##_iter_next(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (iter->end) \
|
||||
return false; \
|
||||
\
|
||||
if (iter->cursor == 0) \
|
||||
{ \
|
||||
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 + 1 == PFX##_count(iter->target)) \
|
||||
{ \
|
||||
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 == 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 (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) \
|
||||
{ \
|
||||
if (PFX##_empty(iter->target)) \
|
||||
return 0; \
|
||||
\
|
||||
return iter->target->count - 1 - iter->cursor; \
|
||||
} \
|
||||
\
|
||||
static SNAME##_iter PFX##_impl_it_start(SNAME *_stack_) \
|
||||
{ \
|
||||
SNAME##_iter iter; \
|
||||
\
|
||||
PFX##_iter_init(&iter, _stack_); \
|
||||
PFX##_iter_to_start(&iter); \
|
||||
\
|
||||
return iter; \
|
||||
} \
|
||||
\
|
||||
static SNAME##_iter PFX##_impl_it_end(SNAME *_stack_) \
|
||||
{ \
|
||||
SNAME##_iter iter; \
|
||||
\
|
||||
PFX##_iter_init(&iter, _stack_); \
|
||||
PFX##_iter_to_end(&iter); \
|
||||
\
|
||||
return iter; \
|
||||
}
|
||||
|
||||
#endif /* CMC_STACK_H */
|
||||
+7
-42
@@ -19,12 +19,16 @@
|
||||
#ifndef CMC_TREEMAP_H
|
||||
#define CMC_TREEMAP_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_treemap = "%s at %p { root:%p, count:%" PRIuMAX ", cmp:%p }";
|
||||
|
||||
#define CMC_GENERATE_TREEMAP(PFX, SNAME, K, V) \
|
||||
CMC_GENERATE_TREEMAP_HEADER(PFX, SNAME, K, V) \
|
||||
CMC_GENERATE_TREEMAP_SOURCE(PFX, SNAME, K, V)
|
||||
@@ -116,9 +120,6 @@
|
||||
bool PFX##_insert(SNAME *_map_, K key, V value); \
|
||||
bool PFX##_update(SNAME *_map_, K key, V new_value, V *old_value); \
|
||||
bool PFX##_remove(SNAME *_map_, K key, V *out_value); \
|
||||
/* Conditional Input and Output */ \
|
||||
bool PFX##_insert_if(SNAME *_map_, K key, V value, bool condition); \
|
||||
bool PFX##_remove_if(SNAME *_map_, K key, V *out_value, bool condition); \
|
||||
/* Element Access */ \
|
||||
bool PFX##_max(SNAME *_map_, K *key, V *value); \
|
||||
bool PFX##_min(SNAME *_map_, K *key, V *value); \
|
||||
@@ -156,26 +157,6 @@
|
||||
V *PFX##_iter_rvalue(SNAME##_iter *iter); \
|
||||
size_t PFX##_iter_index(SNAME##_iter *iter); \
|
||||
\
|
||||
/* Default Key */ \
|
||||
static inline K PFX##_impl_default_key(void) \
|
||||
{ \
|
||||
K _empty_key_; \
|
||||
\
|
||||
memset(&_empty_key_, 0, sizeof(K)); \
|
||||
\
|
||||
return _empty_key_; \
|
||||
} \
|
||||
\
|
||||
/* Default Value */ \
|
||||
static inline V PFX##_impl_default_value(void) \
|
||||
{ \
|
||||
V _empty_value_; \
|
||||
\
|
||||
memset(&_empty_value_, 0, sizeof(V)); \
|
||||
\
|
||||
return _empty_value_; \
|
||||
} \
|
||||
\
|
||||
/* SOURCE ********************************************************************/
|
||||
#define CMC_GENERATE_TREEMAP_SOURCE(PFX, SNAME, K, V) \
|
||||
\
|
||||
@@ -473,22 +454,6 @@
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
bool PFX##_insert_if(SNAME *_map_, K key, V value, bool condition) \
|
||||
{ \
|
||||
if (condition) \
|
||||
return PFX##_insert(_map_, key, value); \
|
||||
\
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
bool PFX##_remove_if(SNAME *_map_, K key, V *out_value, bool condition) \
|
||||
{ \
|
||||
if (condition) \
|
||||
return PFX##_remove(_map_, key, out_value); \
|
||||
\
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
bool PFX##_max(SNAME *_map_, K *key, V *value) \
|
||||
{ \
|
||||
if (PFX##_empty(_map_)) \
|
||||
@@ -526,7 +491,7 @@
|
||||
SNAME##_node *node = PFX##_impl_get_node(_map_, key); \
|
||||
\
|
||||
if (!node) \
|
||||
return PFX##_impl_default_value(); \
|
||||
return (V){0}; \
|
||||
\
|
||||
return node->value; \
|
||||
} \
|
||||
@@ -849,7 +814,7 @@
|
||||
K PFX##_iter_key(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (PFX##_empty(iter->target)) \
|
||||
return PFX##_impl_default_key(); \
|
||||
return (K){0}; \
|
||||
\
|
||||
return iter->cursor->key; \
|
||||
} \
|
||||
@@ -857,7 +822,7 @@
|
||||
V PFX##_iter_value(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (PFX##_empty(iter->target)) \
|
||||
return PFX##_impl_default_value(); \
|
||||
return (V){0}; \
|
||||
\
|
||||
return iter->cursor->value; \
|
||||
} \
|
||||
|
||||
+5
-20
@@ -19,12 +19,16 @@
|
||||
#ifndef CMC_TREESET_H
|
||||
#define CMC_TREESET_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_treeset = "%s at %p { root:%p, count:%" PRIuMAX ", cmp:%p }";
|
||||
|
||||
#define CMC_GENERATE_TREESET(PFX, SNAME, V) \
|
||||
CMC_GENERATE_TREESET_HEADER(PFX, SNAME, V) \
|
||||
CMC_GENERATE_TREESET_SOURCE(PFX, SNAME, V)
|
||||
@@ -112,9 +116,6 @@
|
||||
/* Collection Input and Output */ \
|
||||
bool PFX##_insert(SNAME *_set_, V element); \
|
||||
bool PFX##_remove(SNAME *_set_, V element); \
|
||||
/* Conditional Input and Output */ \
|
||||
bool PFX##_insert_if(SNAME *_set_, V element, bool condition); \
|
||||
bool PFX##_remove_if(SNAME *_set_, V element, bool condition); \
|
||||
/* Element Access */ \
|
||||
bool PFX##_max(SNAME *_set_, V *value); \
|
||||
bool PFX##_min(SNAME *_set_, V *value); \
|
||||
@@ -446,22 +447,6 @@
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
bool PFX##_insert_if(SNAME *_set_, V element, bool condition) \
|
||||
{ \
|
||||
if (condition) \
|
||||
return PFX##_insert(_set_, element); \
|
||||
\
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
bool PFX##_remove_if(SNAME *_set_, V element, bool condition) \
|
||||
{ \
|
||||
if (condition) \
|
||||
return PFX##_remove(_set_, element); \
|
||||
\
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
bool PFX##_max(SNAME *_set_, V *value) \
|
||||
{ \
|
||||
if (PFX##_empty(_set_)) \
|
||||
@@ -992,7 +977,7 @@
|
||||
V PFX##_iter_value(SNAME##_iter *iter) \
|
||||
{ \
|
||||
if (PFX##_empty(iter->target)) \
|
||||
return PFX##_impl_default_value(); \
|
||||
return (V){0}; \
|
||||
\
|
||||
return iter->cursor->value; \
|
||||
} \
|
||||
|
||||
@@ -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 */
|
||||
+40
-65
@@ -21,12 +21,16 @@
|
||||
#ifndef CMC_INTERVALHEAP_H
|
||||
#define CMC_INTERVALHEAP_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_intervalheap = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", size:%" PRIuMAX ", count:%" PRIuMAX ", cmp:%p }";
|
||||
|
||||
#define CMC_GENERATE_INTERVALHEAP(PFX, SNAME, V) \
|
||||
CMC_GENERATE_INTERVALHEAP_HEADER(PFX, SNAME, V) \
|
||||
CMC_GENERATE_INTERVALHEAP_SOURCE(PFX, SNAME, V)
|
||||
@@ -101,10 +105,6 @@
|
||||
bool PFX##_insert(SNAME *_heap_, V element); \
|
||||
bool PFX##_remove_max(SNAME *_heap_, V *result); \
|
||||
bool PFX##_remove_min(SNAME *_heap_, V *result); \
|
||||
/* Conditional Input and Output */ \
|
||||
bool PFX##_insert_if(SNAME *_heap_, V element, bool condition); \
|
||||
bool PFX##_remove_max_if(SNAME *_heap_, V *result, bool condition); \
|
||||
bool PFX##_remove_min_if(SNAME *_heap_, V *result, bool condition); \
|
||||
/* Collection Update */ \
|
||||
bool PFX##_update_max(SNAME *_heap_, V element); \
|
||||
bool PFX##_update_min(SNAME *_heap_, V element); \
|
||||
@@ -118,6 +118,7 @@
|
||||
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 *_set_, V (*copy_func)(V)); \
|
||||
bool PFX##_equals(SNAME *_heap1_, SNAME *_heap2_); \
|
||||
cmc_string PFX##_to_string(SNAME *_heap_); \
|
||||
@@ -143,21 +144,10 @@
|
||||
V PFX##_iter_value(SNAME##_iter *iter); \
|
||||
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 CMC_GENERATE_INTERVALHEAP_SOURCE(PFX, SNAME, V) \
|
||||
\
|
||||
/* Implementation Detail Functions */ \
|
||||
static bool PFX##_impl_grow(SNAME *_heap_); \
|
||||
static void PFX##_impl_float_up_max(SNAME *_heap_); \
|
||||
static void PFX##_impl_float_up_min(SNAME *_heap_); \
|
||||
static void PFX##_impl_float_down_max(SNAME *_heap_); \
|
||||
@@ -167,6 +157,9 @@
|
||||
\
|
||||
SNAME *PFX##_new(size_t capacity, int (*compare)(V, V)) \
|
||||
{ \
|
||||
if (capacity == 0 || capacity == UINT64_MAX) \
|
||||
return NULL; \
|
||||
\
|
||||
SNAME *_heap_ = malloc(sizeof(SNAME)); \
|
||||
\
|
||||
if (!_heap_) \
|
||||
@@ -232,7 +225,7 @@
|
||||
{ \
|
||||
if (PFX##_full(_heap_)) \
|
||||
{ \
|
||||
if (!PFX##_impl_grow(_heap_)) \
|
||||
if (!PFX##_resize(_heap_, PFX##_capacity(_heap_) * 4)) \
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
@@ -240,7 +233,7 @@
|
||||
{ \
|
||||
/* Occupying a new node */ \
|
||||
_heap_->buffer[_heap_->size].data[0] = element; \
|
||||
_heap_->buffer[_heap_->size].data[1] = PFX##_impl_default_value(); \
|
||||
_heap_->buffer[_heap_->size].data[1] = (V){0}; \
|
||||
\
|
||||
_heap_->size++; \
|
||||
} \
|
||||
@@ -288,7 +281,7 @@
|
||||
{ \
|
||||
*result = _heap_->buffer[0].data[0]; \
|
||||
\
|
||||
_heap_->buffer[0].data[0] = PFX##_impl_default_value(); \
|
||||
_heap_->buffer[0].data[0] = (V){0}; \
|
||||
\
|
||||
_heap_->count--; \
|
||||
\
|
||||
@@ -305,7 +298,7 @@
|
||||
/* Grab from MinHeap and discard last node */ \
|
||||
_heap_->buffer[0].data[1] = last_node->data[0]; \
|
||||
\
|
||||
last_node->data[0] = PFX##_impl_default_value(); \
|
||||
last_node->data[0] = (V){0}; \
|
||||
\
|
||||
_heap_->size--; \
|
||||
} \
|
||||
@@ -313,7 +306,7 @@
|
||||
{ \
|
||||
_heap_->buffer[0].data[1] = last_node->data[1]; \
|
||||
\
|
||||
last_node->data[1] = PFX##_impl_default_value(); \
|
||||
last_node->data[1] = (V){0}; \
|
||||
} \
|
||||
\
|
||||
_heap_->count--; \
|
||||
@@ -333,7 +326,7 @@
|
||||
\
|
||||
if (PFX##_count(_heap_) == 1) \
|
||||
{ \
|
||||
_heap_->buffer[0].data[0] = PFX##_impl_default_value(); \
|
||||
_heap_->buffer[0].data[0] = (V){0}; \
|
||||
\
|
||||
_heap_->count--; \
|
||||
\
|
||||
@@ -348,7 +341,7 @@
|
||||
if (PFX##_count(_heap_) % 2 == 1) \
|
||||
{ \
|
||||
/* Discard last node */ \
|
||||
last_node->data[0] = PFX##_impl_default_value(); \
|
||||
last_node->data[0] = (V){0}; \
|
||||
\
|
||||
_heap_->size--; \
|
||||
} \
|
||||
@@ -356,7 +349,7 @@
|
||||
{ \
|
||||
/* Place the MaxHeap value in the MinHeap value spot */ \
|
||||
last_node->data[0] = last_node->data[1]; \
|
||||
last_node->data[1] = PFX##_impl_default_value(); \
|
||||
last_node->data[1] = (V){0}; \
|
||||
} \
|
||||
\
|
||||
_heap_->count--; \
|
||||
@@ -367,30 +360,6 @@
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
bool PFX##_insert_if(SNAME *_heap_, V element, bool condition) \
|
||||
{ \
|
||||
if (condition) \
|
||||
return PFX##_insert(_heap_, element); \
|
||||
\
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
bool PFX##_remove_max_if(SNAME *_heap_, V *result, bool condition) \
|
||||
{ \
|
||||
if (condition) \
|
||||
return PFX##_remove_max(_heap_, result); \
|
||||
\
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
bool PFX##_remove_min_if(SNAME *_heap_, V *result, bool condition) \
|
||||
{ \
|
||||
if (condition) \
|
||||
return PFX##_remove_min(_heap_, result); \
|
||||
\
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
bool PFX##_update_max(SNAME *_heap_, V element) \
|
||||
{ \
|
||||
if (PFX##_empty(_heap_)) \
|
||||
@@ -506,6 +475,29 @@
|
||||
return _heap_->capacity; \
|
||||
} \
|
||||
\
|
||||
bool PFX##_resize(SNAME *_heap_, size_t capacity) \
|
||||
{ \
|
||||
if (PFX##_capacity(_heap_) == capacity) \
|
||||
return true; \
|
||||
\
|
||||
if (capacity < PFX##_count(_heap_)) \
|
||||
return false; \
|
||||
\
|
||||
capacity = capacity % 2 == 0 ? capacity / 2 : (capacity + 1) / 2; \
|
||||
\
|
||||
SNAME##_node *new_buffer = realloc(_heap_->buffer, sizeof(SNAME##_node) * capacity); \
|
||||
\
|
||||
if (!new_buffer) \
|
||||
return false; \
|
||||
\
|
||||
memset(new_buffer + _heap_->capacity, 0, sizeof(SNAME##_node) * _heap_->capacity); \
|
||||
\
|
||||
_heap_->buffer = new_buffer; \
|
||||
_heap_->capacity = capacity; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
SNAME *PFX##_copy_of(SNAME *_heap_, V (*copy_func)(V)) \
|
||||
{ \
|
||||
SNAME *result = malloc(sizeof(SNAME)); \
|
||||
@@ -715,7 +707,7 @@
|
||||
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 / 2].data[iter->cursor % 2]; \
|
||||
} \
|
||||
@@ -725,23 +717,6 @@
|
||||
return iter->cursor; \
|
||||
} \
|
||||
\
|
||||
static bool PFX##_impl_grow(SNAME *_heap_) \
|
||||
{ \
|
||||
size_t new_cap = _heap_->capacity * 2; \
|
||||
\
|
||||
SNAME##_node *new_buffer = realloc(_heap_->buffer, sizeof(SNAME##_node) * new_cap); \
|
||||
\
|
||||
if (!new_buffer) \
|
||||
return false; \
|
||||
\
|
||||
memset(new_buffer + _heap_->capacity, 0, sizeof(SNAME##_node) * _heap_->capacity); \
|
||||
\
|
||||
_heap_->buffer = new_buffer; \
|
||||
_heap_->capacity = new_cap; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
static void PFX##_impl_float_up_max(SNAME *_heap_) \
|
||||
{ \
|
||||
size_t index = _heap_->size - 1; \
|
||||
|
||||
+900
-915
File diff suppressed because it is too large.
Load diff
+1011
-1002
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 */
|
||||
+1204
-977
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 */
|
||||
+3
-3
@@ -83,7 +83,7 @@ static struct
|
||||
|
||||
} cmc_log_config = {0, 0, true, true, NULL, true};
|
||||
|
||||
typedef enum cmc_log_type_e
|
||||
enum cmc_log_type
|
||||
{
|
||||
CMC_LOG_TRACE = 1,
|
||||
CMC_LOG_DEBUG = 2,
|
||||
@@ -92,7 +92,7 @@ typedef enum cmc_log_type_e
|
||||
CMC_LOG_ERROR = 5,
|
||||
CMC_LOG_FATAL = 6
|
||||
|
||||
} cmc_log_type;
|
||||
};
|
||||
|
||||
#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__)
|
||||
@@ -101,7 +101,7 @@ typedef enum cmc_log_type_e
|
||||
#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;
|
||||
|
||||
+32
-29
@@ -59,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)
|
||||
@@ -102,18 +102,18 @@ static void cmc_test_log(const char *unit_name, const char *current_test, bool a
|
||||
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); \
|
||||
cmc_timer_start(timer); \
|
||||
\
|
||||
BODY; \
|
||||
\
|
||||
timer_stop(timer); \
|
||||
timer_calc(timer); \
|
||||
cmc_timer_stop(timer); \
|
||||
cmc_timer_calc(timer); \
|
||||
\
|
||||
unittest_abort: \
|
||||
if (tinfo.aborted) \
|
||||
@@ -133,29 +133,32 @@ static void cmc_test_log(const char *unit_name, const char *current_test, bool a
|
||||
return tinfo.failed; \
|
||||
}
|
||||
|
||||
#define CMC_CREATE_TEST(TNAME, BODY) \
|
||||
do \
|
||||
{ \
|
||||
current_test = #TNAME; \
|
||||
\
|
||||
tinfo.total += 1; \
|
||||
\
|
||||
/* Provided by assert.h */ \
|
||||
cmc_assert_state = true; \
|
||||
\
|
||||
BODY; \
|
||||
\
|
||||
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); \
|
||||
} \
|
||||
\
|
||||
#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() \
|
||||
|
||||
+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); \
|
||||
|
||||
+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__ */
|
||||
+7
-10
@@ -1,24 +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: FORCE
|
||||
$(CC) main.c -o main $(CFLAGS) $(CVFLAGS) -I $(INCLUDE)
|
||||
$(CC) main.c -o main $(CFLAGS) -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
|
||||
$(CC) main.c -o main.exe $(CFLAGS) -I $(INCLUDE)
|
||||
./main.exe
|
||||
rm *.exe
|
||||
|
||||
windev: FORCE
|
||||
$(CC) main.c -o main $(CFLAGS) $(CVFLAGS) -I $(INCLUDE)
|
||||
$(CC) main.c -o main $(CFLAGS) -I $(INCLUDE)
|
||||
./main
|
||||
gcov ./main.c -n
|
||||
del *.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.
|
||||
@@ -1,3 +1,5 @@
|
||||
#include <utl/timer.h>
|
||||
|
||||
#include "unt/deque.c"
|
||||
#include "unt/hashmap.c"
|
||||
#include "unt/hashset.c"
|
||||
@@ -9,11 +11,17 @@
|
||||
#include "unt/treemap.c"
|
||||
#include "unt/treeset.c"
|
||||
|
||||
#include "unt/bidimap.c"
|
||||
#include "unt/intervalheap.c"
|
||||
#include "unt/multimap.c"
|
||||
#include "unt/multiset.c"
|
||||
#include "unt/sortedlist.c"
|
||||
|
||||
int main(void)
|
||||
{
|
||||
cmc_timer timer;
|
||||
|
||||
cmc_timer_start(timer);
|
||||
uintmax_t failed = 0;
|
||||
|
||||
failed += deque_test();
|
||||
@@ -28,8 +36,18 @@ int main(void)
|
||||
failed += treeset_test();
|
||||
|
||||
/* ext */
|
||||
failed += bidimap_test();
|
||||
failed += intervalheap_test();
|
||||
failed += multimap_test();
|
||||
failed += multiset_test();
|
||||
failed += sortedlist_test();
|
||||
|
||||
cmc_timer_stop(timer);
|
||||
cmc_timer_calc(timer);
|
||||
|
||||
printf("+--------------------------------------------------+\n");
|
||||
printf("| Total running time : %14.0lf milliseconds |\n", timer.result);
|
||||
printf("+--------------------------------------------------+\n");
|
||||
|
||||
return failed;
|
||||
}
|
||||
@@ -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);
|
||||
});
|
||||
});
|
||||
+582
-10
@@ -1,6 +1,11 @@
|
||||
#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, {
|
||||
@@ -11,16 +16,16 @@ CMC_CREATE_UNIT(deque_test, true, {
|
||||
cmc_assert_equals(size_t, 1000000, d->capacity);
|
||||
cmc_assert_equals(size_t, 0, d_count(d));
|
||||
|
||||
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_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);
|
||||
@@ -36,15 +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));
|
||||
|
||||
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);
|
||||
@@ -55,7 +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));
|
||||
|
||||
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);
|
||||
});
|
||||
});
|
||||
+417
-10
@@ -1,8 +1,11 @@
|
||||
#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, {
|
||||
@@ -13,17 +16,17 @@ CMC_CREATE_UNIT(hashmap_test, true, {
|
||||
cmc_assert_equals(size_t, 0, hm_count(map));
|
||||
cmc_assert_greater_equals(size_t, (943722 / 0.6), hm_capacity(map));
|
||||
|
||||
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_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);
|
||||
});
|
||||
@@ -38,11 +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));
|
||||
|
||||
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);
|
||||
});
|
||||
});
|
||||
+322
-10
@@ -1,8 +1,11 @@
|
||||
#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, {
|
||||
@@ -13,17 +16,17 @@ CMC_CREATE_UNIT(hashset_test, true, {
|
||||
cmc_assert_equals(size_t, 0, hs_count(set));
|
||||
cmc_assert_greater_equals(size_t, (943722 / 0.6), hs_capacity(set));
|
||||
|
||||
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_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);
|
||||
});
|
||||
@@ -38,11 +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));
|
||||
|
||||
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);
|
||||
});
|
||||
});
|
||||
+114
-12
@@ -1,8 +1,11 @@
|
||||
#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, {
|
||||
@@ -13,16 +16,16 @@ CMC_CREATE_UNIT(heap_test, true, {
|
||||
cmc_assert_equals(size_t, 1000000, h_capacity(h));
|
||||
cmc_assert_equals(size_t, 0, h_count(h));
|
||||
|
||||
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_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);
|
||||
@@ -38,25 +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));
|
||||
|
||||
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));
|
||||
|
||||
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
-13
@@ -1,6 +1,11 @@
|
||||
#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, {
|
||||
@@ -11,7 +16,7 @@ CMC_CREATE_UNIT(linkedlist_test, true, {
|
||||
cmc_assert_equals(ptr, NULL, ll->head);
|
||||
cmc_assert_equals(ptr, NULL, ll->tail);
|
||||
|
||||
ll_free(ll);
|
||||
ll_free(ll, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(clear[count capacity], {
|
||||
@@ -24,23 +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));
|
||||
|
||||
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));
|
||||
|
||||
ll_free(ll);
|
||||
ll_free(ll, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(push_front[count], {
|
||||
@@ -54,10 +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));
|
||||
|
||||
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);
|
||||
@@ -68,7 +73,6 @@ CMC_CREATE_UNIT(linkedlist_test, true, {
|
||||
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);
|
||||
ll_free(ll, NULL);
|
||||
});
|
||||
|
||||
});
|
||||
+57
-52
@@ -1,6 +1,11 @@
|
||||
#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, {
|
||||
@@ -11,22 +16,22 @@ CMC_CREATE_UNIT(list_test, true, {
|
||||
cmc_assert_equals(size_t, 1000000, l_capacity(l));
|
||||
cmc_assert_equals(size_t, 0, l_count(l));
|
||||
|
||||
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_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_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++)
|
||||
@@ -41,10 +46,10 @@ CMC_CREATE_UNIT(list_test, true, {
|
||||
for (size_t i = 0; i < 5; i++)
|
||||
cmc_assert_equals(size_t, i, l_get(l, i));
|
||||
|
||||
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;
|
||||
@@ -53,7 +58,7 @@ CMC_CREATE_UNIT(list_test, true, {
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, l);
|
||||
|
||||
l_free(l);
|
||||
l_free(l, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(clear[count capacity], {
|
||||
@@ -66,15 +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));
|
||||
|
||||
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);
|
||||
@@ -87,7 +92,7 @@ CMC_CREATE_UNIT(list_test, true, {
|
||||
for (size_t i = 0; i < 100; i++)
|
||||
cmc_assert_equals(size_t, i, l_get(l, i));
|
||||
|
||||
l_free(l);
|
||||
l_free(l, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(push_front[count], {
|
||||
@@ -100,7 +105,7 @@ CMC_CREATE_UNIT(list_test, true, {
|
||||
|
||||
cmc_assert_equals(size_t, 250, l_count(l));
|
||||
|
||||
l_free(l);
|
||||
l_free(l, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(push_front[capacity], {
|
||||
@@ -113,10 +118,10 @@ CMC_CREATE_UNIT(list_test, true, {
|
||||
|
||||
cmc_assert_lesser_equals(size_t, l_capacity(l), l_count(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);
|
||||
@@ -127,10 +132,10 @@ CMC_CREATE_UNIT(list_test, true, {
|
||||
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);
|
||||
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);
|
||||
@@ -139,14 +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));
|
||||
|
||||
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);
|
||||
@@ -155,14 +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));
|
||||
|
||||
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);
|
||||
@@ -171,12 +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));
|
||||
cmc_assert(l_push_at(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);
|
||||
l_free(l, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(push_back[count], {
|
||||
@@ -189,7 +194,7 @@ CMC_CREATE_UNIT(list_test, true, {
|
||||
|
||||
cmc_assert_equals(size_t, 250, l_count(l));
|
||||
|
||||
l_free(l);
|
||||
l_free(l, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(push_back[capacity], {
|
||||
@@ -202,10 +207,10 @@ CMC_CREATE_UNIT(list_test, true, {
|
||||
|
||||
cmc_assert_lesser_equals(size_t, l_capacity(l), l_count(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);
|
||||
@@ -216,7 +221,7 @@ CMC_CREATE_UNIT(list_test, true, {
|
||||
for (size_t i = 0; i < l_count(l); i++)
|
||||
cmc_assert_equals(size_t, l_get(l, i), i);
|
||||
|
||||
l_free(l);
|
||||
l_free(l, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(pop_front[count], {
|
||||
@@ -229,10 +234,10 @@ CMC_CREATE_UNIT(list_test, true, {
|
||||
|
||||
cmc_assert(l_pop_front(l));
|
||||
|
||||
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);
|
||||
@@ -245,26 +250,26 @@ CMC_CREATE_UNIT(list_test, true, {
|
||||
for (size_t i = 0; i < l_count(l); i++)
|
||||
cmc_assert_equals(size_t, l_get(l, i), i + 1);
|
||||
|
||||
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));
|
||||
|
||||
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));
|
||||
|
||||
l_free(l);
|
||||
l_free(l, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(pop_front[buffer_clear], {
|
||||
@@ -278,58 +283,58 @@ CMC_CREATE_UNIT(list_test, true, {
|
||||
|
||||
cmc_assert_equals(size_t, 0, l->buffer[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));
|
||||
|
||||
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_assert(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));
|
||||
|
||||
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));
|
||||
|
||||
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));
|
||||
|
||||
l_free(l);
|
||||
l_free(l, NULL);
|
||||
});
|
||||
})
|
||||
+38
-51
@@ -1,8 +1,11 @@
|
||||
#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, {
|
||||
@@ -13,17 +16,17 @@ CMC_CREATE_UNIT(multimap_test, true, {
|
||||
cmc_assert_equals(size_t, 0, mm_count(map));
|
||||
cmc_assert_greater_equals(size_t, (943722 / 0.8), mm_capacity(map));
|
||||
|
||||
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_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);
|
||||
});
|
||||
@@ -38,11 +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));
|
||||
|
||||
mm_free(map);
|
||||
mm_free(map, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(insert[count], {
|
||||
@@ -50,12 +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));
|
||||
|
||||
mm_free(map);
|
||||
mm_free(map, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(remove[count], {
|
||||
@@ -73,10 +76,10 @@ CMC_CREATE_UNIT(multimap_test, true, {
|
||||
|
||||
cmc_assert_equals(size_t, 140, mm_count(map));
|
||||
|
||||
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);
|
||||
@@ -85,10 +88,10 @@ CMC_CREATE_UNIT(multimap_test, true, {
|
||||
|
||||
cmc_assert(!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);
|
||||
@@ -98,41 +101,10 @@ CMC_CREATE_UNIT(multimap_test, true, {
|
||||
cmc_assert(mm_insert(map, 10, 11));
|
||||
cmc_assert(mm_remove(map, 10, &r));
|
||||
|
||||
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));
|
||||
|
||||
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], {
|
||||
CMC_CREATE_TEST(get[key ordering], {
|
||||
multimap *map = mm_new(100, 0.8, cmp, hash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
@@ -145,7 +117,22 @@ CMC_CREATE_UNIT(multimap_test, true, {
|
||||
|
||||
cmc_assert_equals(size_t, 100, mm_get(map, 10));
|
||||
|
||||
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);
|
||||
});
|
||||
});
|
||||
+84
-17
@@ -1,8 +1,11 @@
|
||||
#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, {
|
||||
@@ -13,17 +16,17 @@ CMC_CREATE_UNIT(multiset_test, true, {
|
||||
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);
|
||||
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_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);
|
||||
});
|
||||
@@ -38,11 +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));
|
||||
|
||||
ms_free(set);
|
||||
ms_free(set, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(insert[count cardinality multiplicity], {
|
||||
@@ -63,24 +66,88 @@ CMC_CREATE_UNIT(multiset_test, true, {
|
||||
for (size_t i = 0; i <= 3; i++)
|
||||
cmc_assert_equals(size_t, i, ms_multiplicity_of(set, i));
|
||||
|
||||
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));
|
||||
cmc_assert_equals(size_t, 1000, ms_cardinality(set));
|
||||
|
||||
for (size_t i = 0; i < 20; i++)
|
||||
cmc_assert_equals(size_t, 5, ms_multiplicity_of(set, i));
|
||||
cmc_assert_equals(size_t, 50, ms_multiplicity_of(set, i));
|
||||
|
||||
ms_free(set);
|
||||
ms_free(set, NULL);
|
||||
});
|
||||
|
||||
});
|
||||
+359
-10
@@ -1,6 +1,11 @@
|
||||
#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, {
|
||||
@@ -12,16 +17,16 @@ CMC_CREATE_UNIT(queue_test, true, {
|
||||
cmc_assert_equals(size_t, 0, q_count(q));
|
||||
cmc_assert_not_equals(ptr, NULL, q->buffer);
|
||||
|
||||
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_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);
|
||||
@@ -37,15 +42,15 @@ CMC_CREATE_UNIT(queue_test, true, {
|
||||
|
||||
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));
|
||||
|
||||
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);
|
||||
@@ -55,7 +60,351 @@ CMC_CREATE_UNIT(queue_test, true, {
|
||||
|
||||
cmc_assert_equals(size_t, 50, q_count(q));
|
||||
|
||||
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);
|
||||
});
|
||||
});
|
||||
+66
-95
@@ -1,8 +1,11 @@
|
||||
#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, {
|
||||
@@ -14,16 +17,16 @@ CMC_CREATE_UNIT(stack_test, true, {
|
||||
cmc_assert_equals(size_t, 0, s_count(s));
|
||||
cmc_assert_not_equals(ptr, NULL, s->buffer);
|
||||
|
||||
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_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);
|
||||
@@ -39,15 +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));
|
||||
|
||||
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);
|
||||
@@ -58,7 +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));
|
||||
|
||||
s_free(s);
|
||||
s_free(s, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(push[count], {
|
||||
@@ -71,7 +74,7 @@ CMC_CREATE_UNIT(stack_test, true, {
|
||||
|
||||
cmc_assert_equals(size_t, 250, s_count(s));
|
||||
|
||||
s_free(s);
|
||||
s_free(s, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(push[capacity], {
|
||||
@@ -84,10 +87,10 @@ CMC_CREATE_UNIT(stack_test, true, {
|
||||
|
||||
cmc_assert_lesser_equals(size_t, s_capacity(s), s_count(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);
|
||||
@@ -98,7 +101,7 @@ CMC_CREATE_UNIT(stack_test, true, {
|
||||
for (size_t i = 0; i < s_count(s); i++)
|
||||
cmc_assert_equals(size_t, i, s->buffer[i]);
|
||||
|
||||
s_free(s);
|
||||
s_free(s, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(pop[count], {
|
||||
@@ -113,7 +116,7 @@ CMC_CREATE_UNIT(stack_test, true, {
|
||||
|
||||
cmc_assert_equals(size_t, 249, s_count(s));
|
||||
|
||||
s_free(s);
|
||||
s_free(s, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(pop[capacity], {
|
||||
@@ -128,10 +131,10 @@ CMC_CREATE_UNIT(stack_test, true, {
|
||||
|
||||
cmc_assert_lesser_equals(size_t, s_capacity(s), s_count(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);
|
||||
@@ -145,48 +148,17 @@ CMC_CREATE_UNIT(stack_test, true, {
|
||||
for (size_t i = 0; i < s_count(s); i++)
|
||||
cmc_assert_equals(size_t, i, s->buffer[i]);
|
||||
|
||||
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));
|
||||
|
||||
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);
|
||||
s_free(s, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(top, {
|
||||
@@ -202,10 +174,10 @@ CMC_CREATE_UNIT(stack_test, true, {
|
||||
|
||||
cmc_assert_equals(size_t, 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);
|
||||
@@ -214,12 +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));
|
||||
|
||||
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);
|
||||
@@ -228,7 +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));
|
||||
|
||||
s_free(s);
|
||||
s_free(s, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(contains, {
|
||||
@@ -242,17 +214,17 @@ CMC_CREATE_UNIT(stack_test, true, {
|
||||
for (size_t i = 0; i < 150; i++)
|
||||
cmc_assert(s_contains(s, i, cmp));
|
||||
|
||||
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));
|
||||
|
||||
s_free(s);
|
||||
s_free(s, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(empty, {
|
||||
@@ -262,7 +234,7 @@ CMC_CREATE_UNIT(stack_test, true, {
|
||||
|
||||
cmc_assert(s_empty(s));
|
||||
|
||||
s_free(s);
|
||||
s_free(s, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(empty[after_io], {
|
||||
@@ -274,7 +246,7 @@ CMC_CREATE_UNIT(stack_test, true, {
|
||||
cmc_assert(s_pop(s));
|
||||
cmc_assert(s_empty(s));
|
||||
|
||||
s_free(s);
|
||||
s_free(s, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(full, {
|
||||
@@ -287,10 +259,10 @@ CMC_CREATE_UNIT(stack_test, true, {
|
||||
|
||||
cmc_assert(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);
|
||||
@@ -299,7 +271,7 @@ CMC_CREATE_UNIT(stack_test, true, {
|
||||
|
||||
cmc_assert(s_full(s));
|
||||
|
||||
s_free(s);
|
||||
s_free(s, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(iter_alloc, {
|
||||
@@ -312,10 +284,10 @@ CMC_CREATE_UNIT(stack_test, true, {
|
||||
cmc_assert_not_equals(ptr, NULL, 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);
|
||||
@@ -329,10 +301,10 @@ CMC_CREATE_UNIT(stack_test, true, {
|
||||
cmc_assert(iter.start);
|
||||
cmc_assert(iter.end);
|
||||
|
||||
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);
|
||||
@@ -343,10 +315,10 @@ CMC_CREATE_UNIT(stack_test, true, {
|
||||
|
||||
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);
|
||||
@@ -357,7 +329,7 @@ CMC_CREATE_UNIT(stack_test, true, {
|
||||
|
||||
cmc_assert(s_iter_end(&iter));
|
||||
|
||||
s_free(s);
|
||||
s_free(s, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(iteration, {
|
||||
@@ -384,7 +356,7 @@ CMC_CREATE_UNIT(stack_test, true, {
|
||||
|
||||
cmc_assert_equals(size_t, 40200, total);
|
||||
|
||||
s_free(s);
|
||||
s_free(s, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(iteration[while loop], {
|
||||
@@ -414,10 +386,10 @@ CMC_CREATE_UNIT(stack_test, true, {
|
||||
|
||||
cmc_assert_equals(size_t, 40200, total);
|
||||
|
||||
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);
|
||||
@@ -437,10 +409,10 @@ CMC_CREATE_UNIT(stack_test, true, {
|
||||
|
||||
cmc_assert_equals(size_t, 20, total);
|
||||
|
||||
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);
|
||||
@@ -466,7 +438,7 @@ CMC_CREATE_UNIT(stack_test, true, {
|
||||
|
||||
cmc_assert_equals(size_t, 2000, total);
|
||||
|
||||
s_free(s);
|
||||
s_free(s, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(iteration[to_start = it_start and to_end = it_end], {
|
||||
@@ -501,10 +473,10 @@ CMC_CREATE_UNIT(stack_test, true, {
|
||||
cmc_assert_equals(bool, it1.start, it2.start);
|
||||
cmc_assert_equals(bool, it1.end, it2.end);
|
||||
|
||||
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);
|
||||
@@ -520,10 +492,10 @@ CMC_CREATE_UNIT(stack_test, true, {
|
||||
|
||||
cmc_assert_equals(bool, false, s_iter_prev(&iter));
|
||||
|
||||
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);
|
||||
@@ -542,10 +514,10 @@ CMC_CREATE_UNIT(stack_test, true, {
|
||||
|
||||
cmc_assert_equals(bool, false, s_iter_prev(&iter));
|
||||
|
||||
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);
|
||||
@@ -554,12 +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));
|
||||
|
||||
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);
|
||||
@@ -570,7 +542,7 @@ CMC_CREATE_UNIT(stack_test, true, {
|
||||
|
||||
cmc_assert_equals(ptr, NULL, s_iter_rvalue(&iter));
|
||||
|
||||
s_free(s);
|
||||
s_free(s, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(index, {
|
||||
@@ -585,12 +557,12 @@ CMC_CREATE_UNIT(stack_test, true, {
|
||||
|
||||
size_t total = 0;
|
||||
|
||||
for (stack_iter it = s->it_start(s); false; )
|
||||
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; )
|
||||
for (stack_iter it = s->it_start(s); false;)
|
||||
{
|
||||
cmc_assert_equals(size_t, s_count(s) - 1, s_iter_index(&it));
|
||||
}
|
||||
@@ -609,10 +581,10 @@ CMC_CREATE_UNIT(stack_test, true, {
|
||||
|
||||
cmc_assert_equals(size_t, 90, total);
|
||||
|
||||
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);
|
||||
@@ -622,7 +594,6 @@ CMC_CREATE_UNIT(stack_test, true, {
|
||||
|
||||
cmc_assert_equals(size_t, 0, s_iter_index(&iter));
|
||||
|
||||
s_free(s);
|
||||
s_free(s, NULL);
|
||||
});
|
||||
|
||||
});
|
||||
@@ -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,7 +13,7 @@ CMC_CREATE_UNIT(treemap_test, true, {
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
|
||||
tm_free(map);
|
||||
tm_free(map, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(clear[count], {
|
||||
@@ -23,12 +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);
|
||||
|
||||
tm_free(map);
|
||||
tm_free(map, NULL);
|
||||
});
|
||||
|
||||
});
|
||||
@@ -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,7 +13,7 @@ CMC_CREATE_UNIT(treeset_test, true, {
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, set);
|
||||
|
||||
ts_free(set);
|
||||
ts_free(set, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(clear[count], {
|
||||
@@ -23,12 +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);
|
||||
|
||||
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__ */
|
||||
Reference in new issue
Block a user