36 Commits
Author SHA1 Message Date
Leonardo de744f5822 v1.7.2 2019-10-18 11:15:52 -03:00
Leonardo 5583ca38b3 Changed default_type functions to compound literals 2019-10-17 01:37:55 -03:00
Leonardo 2d3b441d74 Added resize to multimap, multiset and sortedlist 2019-10-16 21:34:30 -03:00
Leonardo 99cd01ba1e Added intervalheap resize 2019-10-15 23:52:09 -03:00
Leonardo 1f11b6d2da Added preview of bidimap 2019-10-14 22:37:39 -03:00
Leonardo e41fe14502 Refactoring multiset code to be at most 100 characters per line 2019-10-12 00:27:38 -03:00
Leonardo 63d0453341 Finally releasing sortedlist 2019-10-11 02:14:33 -03:00
Leonardo 5e1a26b72e Added queue and stack resize 2019-10-10 15:10:37 -03:00
Leonardo e06e795ed8 hashmap quickfix 2019-10-09 00:53:40 -03:00
Leonardo b9b507bf07 Added heap and list resize function and refactored some tests and added some more 2019-10-08 13:57:58 -03:00
Leonardo 9f8671f75f Added resize function to hashmap and hashset 2019-10-07 19:57:20 -03:00
Leonardo f0b7b125b9 Added deque.h resize and added more deque and hashmap tests 2019-10-05 00:31:29 -03:00
Leonardo 8483eda701 Added two working examples, hanoi and printer 2019-10-04 01:19:18 -03:00
Leonardo b870649627 Refactoring tests 2019-10-03 11:29:35 -03:00
Leonardo 93ac623ffe Update README and benchmark 2019-10-02 00:11:08 -03:00
Leonardo 5997302a8c Fixed deque and queue bug and added more tests 2019-10-01 00:48:09 -03:00
Leonardo f52a9ff702 Refactoring tests and added sortedlist test 2019-09-30 18:27:19 -03:00
Leonardo 376c0ad4e7 Minor optimization to list.h and added finished more TODOs from sortedlist.h 2019-09-30 18:26:31 -03:00
Leonardo 34e649d82a Removed all conditional IO 2019-09-29 15:49:10 -03:00
Leonardo bfb8426183 Fixing travis 2019-09-28 15:01:02 -03:00
Leonardo 4f755f0915 Redone tests
./codecov is a stalled version for code coverage. It will be merged with main when the library is done with breaking changes
2019-09-28 14:58:10 -03:00
Leonardo dea77b5ca2 A minor fix to intervalheap.h 2019-09-27 00:06:26 -03:00
Leonardo b300c889f3 Added cmc prefix to timer 2019-09-27 00:05:22 -03:00
Leonardo 2126da3f25 Removed unnecessary typedefs for log.h and test.h and fixed the latter 2019-09-26 01:17:18 -03:00
Leonardo fb7854ef5d Update assert.h and removed
Added 3 new assertion macros:

cmc_assert_array_equals_any
cmc_assert_array_within_any
cmc_assert_array_outside_any
cmc_assert_array_sorted_any (renamed)
2019-09-25 16:41:40 -03:00
Leonardo 1ff3142769 Update assert.h
Renamed the parameters to and from to to_index and from_index
2019-09-24 23:35:00 -03:00
Leonardo 331fb32b73 Small additions and fixes to sortedlist 2019-09-23 22:34:23 -03:00
Leonardo Vencovsky fa03379580 Merge pull request #5 from LeoVen/dev
v1.7.1 fast forward master
2019-09-22 01:20:01 -03:00
Leonardo 43f4ae9f16 v1.7.1 2019-09-21 19:19:36 -03:00
Leonardo d9171a11cf Fixed some include guards for cmc_hashtable_primes and cmc_entry_state
Also removed unnecessary typedef for enum cmc_entry_state
Now cmc_entry state is in another guard, separated from the cmc_hashtable_primes guard
2019-09-21 18:25:01 -03:00
Leonardo 344e9f77fe Renamed list and linkedlist functions
push - push_at
pop - pop_at

The list prepend, append and insert - seq_push_front, seq_push_back, seq_push_at
2019-09-21 00:37:56 -03:00
Leonardo 2c84c35264 Adding sortedlist skeleton
Some functions are already working but there is still too much to be optimized
2019-09-18 02:29:11 -03:00
Leonardo c27edd53f6 Added cmc_assert_sorted 2019-09-18 02:28:20 -03:00
Leonardo a0db76b50d Update README.md
Trying to fix the shield's icon
2019-09-17 12:00:40 -03:00
Leonardo bb3efd75ff Update README and TODO 2019-09-17 00:37:12 -03:00
Leonardo 3d7e218195 Move the string format to each collection files and quick fix on deque
Now the format to print them is only declared if you actually include the header
2019-09-16 23:50:06 -03:00
75 changed files with 12877 additions and 7151 deletions

No files matched your search

+3 -4
View File
@@ -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)
+18
View File
@@ -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
+64 -51
View File
@@ -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>
![License](https://img.shields.io/badge/License-MIT-blue.svg)
![Version](https://img.shields.io/badge/Version-v1.7.0-orange.svg)
[![Build](https://travis-ci.org/LeoVen/C-Macro-Collections.svg?branch=master)](https://travis-ci.org/LeoVen/C-Macro-Collections)
[![codecov](https://codecov.io/gh/LeoVen/C-Macro-Collections/branch/master/graph/badge.svg)](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>
+16 -14
View File
@@ -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
View File
@@ -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);
+73
View File
@@ -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;
}
+208
View File
@@ -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
View File
File diff suppressed because it is too large. Load diff
+724 -718
View File
File diff suppressed because it is too large. Load diff
+830 -822
View File
File diff suppressed because it is too large. Load diff
+28 -58
View File
@@ -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
View File
@@ -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
View File
File diff suppressed because it is too large. Load diff
+441 -446
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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; \
} \
+873
View File
@@ -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
View File
@@ -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
View File
File diff suppressed because it is too large. Load diff
+1011 -1002
View File
File diff suppressed because it is too large. Load diff
+690
View File
@@ -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
View File
File diff suppressed because it is too large. Load diff
+1 -17
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+24
View File
@@ -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:
+7
View File
@@ -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().
+35
View File
@@ -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.
+61
View File
@@ -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);
});
});
+48
View File
@@ -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);
});
});
+48
View File
@@ -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);
});
});
+62
View File
@@ -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);
});
});
+74
View File
@@ -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);
});
});
+335
View File
@@ -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);
});
})
+151
View File
@@ -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);
});
});
+86
View File
@@ -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);
});
});
+61
View File
@@ -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);
});
});
+628
View File
@@ -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);
});
});
+34
View File
@@ -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);
});
});
+34
View File
@@ -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);
});
});
+23
View File
@@ -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
View File
@@ -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:
+2 -4
View File
@@ -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.
+18
View File
@@ -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;
}
+35
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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);
});
});
+134
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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);
});
});
+140
View File
@@ -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
View File
@@ -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);
});
});
+10 -8
View File
@@ -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);
});
});
+10 -8
View File
@@ -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);
});
});
+21
View File
@@ -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__ */