diff --git a/CHANGELOG b/CHANGELOG index 8894064..67520be 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,12 @@ # RELEASE.MAJOR.MINOR +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 diff --git a/README.md b/README.md index 2cd47d8..f555b60 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,22 @@ -# C-Macro-Collections +# C Macro Collections -Header only, macro generated, generic and type-safe Collections in C. +

+ C Macro Collections Logo +

-![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) +

Header only, macro generated, generic and type-safe Collections in C.

+ +

+ LinkToRepo + LinkToDocs +

+ +

+ License + Version + travis-ci + codecov +

## 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,14 @@ 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 - -Check out **Documentation.md** for more information about each collection. The documentation is still being written. +* Linear Collections + * List, LinkedList, Deque, Stack, Queue +* Sets + * HashSet, TreeSet, MultiSet +* Maps + * HashMap, TreeMap, MultiMap +* Heaps + * Heap, IntervalHeap ## Overall To-Do @@ -117,21 +114,21 @@ 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. ### 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. +* `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. -Check out the **Documentation.md** to know exactly what represents the *end* and the *start* of each collection. +Check out the documentation to know more. ### Parameters diff --git a/TODO b/TODO index 8226732..c6c1e80 100644 --- a/TODO +++ b/TODO @@ -5,12 +5,12 @@ TODO [~] - 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 @@ -57,9 +57,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 + diff --git a/src/cmc/deque.h b/src/cmc/deque.h index eff449e..3c5d0f0 100644 --- a/src/cmc/deque.h +++ b/src/cmc/deque.h @@ -31,12 +31,16 @@ #ifndef CMC_DEQUE_H #define CMC_DEQUE_H +#include #include #include #include #include #include "../utl/cmc_string.h" +/* to_string format */ +static const char *cmc_string_fmt_deque = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", count:%" PRIuMAX ", front:%" PRIuMAX ", back:%" PRIuMAX " }"; + #define CMC_GENERATE_DEQUE(PFX, SNAME, V) \ CMC_GENERATE_DEQUE_HEADER(PFX, SNAME, V) \ CMC_GENERATE_DEQUE_SOURCE(PFX, SNAME, V) @@ -403,7 +407,7 @@ size_t i, j, k; \ for (i = _deque1_->front, j = _deque2_->front, k = 0; k < PFX##_count(_deque1_); k++) \ { \ - if (comparator(_deque1_->buffer[i], _deque2_->buffer[j]) == 0) \ + if (comparator(_deque1_->buffer[i], _deque2_->buffer[j]) != 0) \ return false; \ \ i = (i + 1) % _deque1_->capacity; \ diff --git a/src/cmc/hashmap.h b/src/cmc/hashmap.h index 51fb88e..849bb65 100644 --- a/src/cmc/hashmap.h +++ b/src/cmc/hashmap.h @@ -19,21 +19,30 @@ #ifndef CMC_HASHMAP_H #define CMC_HASHMAP_H +#include #include #include #include #include #include "../utl/cmc_string.h" -#ifndef CMC_HASH_TABLE_SETUP -#define CMC_HASH_TABLE_SETUP +/* to_string format */ +static const char *cmc_string_fmt_hashmap = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", count:%" PRIuMAX ", load:%lf, cmp:%p, hash:%p }"; -typedef enum cmc_entry_state_e +#ifndef CMC_IMPL_HASHTABLE_STATE +#define CMC_IMPL_HASHTABLE_STATE + +enum cmc_entry_state_e { CMC_ES_DELETED = -1, CMC_ES_EMPTY = 0, CMC_ES_FILLED = 1 -} cmc_entry_state; +}; + +#endif /* CMC_IMPL_HASHTABLE_STATE */ + +#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, @@ -67,7 +76,7 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531, 6917529027641081903, 13835058055282163729llu}; -#endif /* CMC_HASH_TABLE_SETUP */ +#endif /* CMC_IMPL_HASHTABLE_SETUP */ #define CMC_GENERATE_HASHMAP(PFX, SNAME, K, V) \ CMC_GENERATE_HASHMAP_HEADER(PFX, SNAME, K, V) \ diff --git a/src/cmc/hashset.h b/src/cmc/hashset.h index bb4957e..19b7171 100644 --- a/src/cmc/hashset.h +++ b/src/cmc/hashset.h @@ -18,21 +18,30 @@ #ifndef CMC_HASHSET_H #define CMC_HASHSET_H +#include #include #include #include #include #include "../utl/cmc_string.h" -#ifndef CMC_HASH_TABLE_SETUP -#define CMC_HASH_TABLE_SETUP +/* to_string format */ +static const char *cmc_string_fmt_hashset = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", count:%" PRIuMAX ", load:%lf, cmp:%p, hash:%p }"; -typedef enum cmc_entry_state_e +#ifndef CMC_IMPL_HASHTABLE_STATE +#define CMC_IMPL_HASHTABLE_STATE + +enum cmc_entry_state_e { CMC_ES_DELETED = -1, CMC_ES_EMPTY = 0, CMC_ES_FILLED = 1 -} cmc_entry_state; +}; + +#endif /* CMC_IMPL_HASHTABLE_STATE */ + +#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, @@ -66,7 +75,7 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531, 6917529027641081903, 13835058055282163729llu}; -#endif /* CMC_HASH_TABLE_SETUP */ +#endif /* CMC_IMPL_HASHTABLE_SETUP */ #define CMC_GENERATE_HASHSET(PFX, SNAME, V) \ CMC_GENERATE_HASHSET_HEADER(PFX, SNAME, V) \ diff --git a/src/cmc/heap.h b/src/cmc/heap.h index 41ab263..b658f53 100644 --- a/src/cmc/heap.h +++ b/src/cmc/heap.h @@ -30,12 +30,16 @@ #ifndef CMC_HEAP_H #define CMC_HEAP_H +#include #include #include #include #include #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, diff --git a/src/cmc/linkedlist.h b/src/cmc/linkedlist.h index adc026a..062667d 100644 --- a/src/cmc/linkedlist.h +++ b/src/cmc/linkedlist.h @@ -28,12 +28,16 @@ #ifndef CMC_LINKEDLIST_H #define CMC_LINKEDLIST_H +#include #include #include #include #include #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,10 +112,10 @@ 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); \ @@ -259,7 +263,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 +338,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; \ @@ -389,7 +393,7 @@ bool PFX##_push_if(SNAME *_list_, V element, size_t index, bool condition) \ { \ if (condition) \ - return PFX##_push(_list_, element, index); \ + return PFX##_push_at(_list_, element, index); \ \ return false; \ } \ @@ -397,7 +401,7 @@ bool PFX##_pop_if(SNAME *_list_, size_t index, bool condition) \ { \ if (condition) \ - return PFX##_pop(_list_, index); \ + return PFX##_pop_at(_list_, index); \ \ return false; \ } \ diff --git a/src/cmc/list.h b/src/cmc/list.h index a976f19..18f3697 100644 --- a/src/cmc/list.h +++ b/src/cmc/list.h @@ -43,12 +43,16 @@ #ifndef CMC_LIST_H #define CMC_LIST_H +#include #include #include #include #include #include "../utl/cmc_string.h" +/* to_string format */ +static const char *cmc_string_fmt_list = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", count:%" PRIuMAX " }"; + #define CMC_GENERATE_LIST(PFX, SNAME, V) \ CMC_GENERATE_LIST_HEADER(PFX, SNAME, V) \ CMC_GENERATE_LIST_SOURCE(PFX, SNAME, V) @@ -107,20 +111,20 @@ 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); \ - /* Collection Range Input and Output */ \ - bool PFX##_prepend(SNAME *_list_, V *elements, size_t size); \ - bool PFX##_insert(SNAME *_list_, V *elements, size_t size, size_t index); \ - bool PFX##_append(SNAME *_list_, V *elements, size_t size); \ - bool PFX##_remove(SNAME *_list_, size_t from, size_t to); \ - SNAME *PFX##_extract(SNAME *_list_, size_t from, size_t to); \ + /* Collection Sequence Input and Output */ \ + bool PFX##_seq_push_front(SNAME *_list_, V *elements, size_t size); \ + bool PFX##_seq_push_at(SNAME *_list_, V *elements, size_t size, size_t index); \ + bool PFX##_seq_push_back(SNAME *_list_, V *elements, size_t size); \ + bool PFX##_seq_pop_at(SNAME *_list_, size_t from, size_t to); \ + SNAME *PFX##_seq_sublist(SNAME *_list_, size_t from, size_t to); \ /* Element Access */ \ V PFX##_front(SNAME *_list_); \ V PFX##_get(SNAME *_list_, size_t index); \ @@ -270,7 +274,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; \ @@ -324,7 +328,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; \ @@ -361,7 +365,7 @@ bool PFX##_push_if(SNAME *_list_, V element, size_t index, bool condition) \ { \ if (condition) \ - return PFX##_push(_list_, element, index); \ + return PFX##_push_at(_list_, element, index); \ \ return false; \ } \ @@ -369,12 +373,12 @@ bool PFX##_pop_if(SNAME *_list_, size_t index, bool condition) \ { \ if (condition) \ - return PFX##_pop(_list_, index); \ + return PFX##_pop_at(_list_, index); \ \ return false; \ } \ \ - bool PFX##_prepend(SNAME *_list_, V *elements, size_t size) \ + bool PFX##_seq_push_front(SNAME *_list_, V *elements, size_t size) \ { \ if (size == 0) \ return false; \ @@ -394,15 +398,15 @@ return true; \ } \ \ - bool PFX##_insert(SNAME *_list_, V *elements, size_t size, size_t index) \ + bool PFX##_seq_push_at(SNAME *_list_, V *elements, size_t size, size_t index) \ { \ if (size == 0 || index > _list_->count) \ return false; \ \ if (index == 0) \ - return PFX##_prepend(_list_, elements, size); \ + return PFX##_seq_push_front(_list_, elements, size); \ else if (index == _list_->count) \ - return PFX##_append(_list_, elements, size); \ + return PFX##_seq_push_back(_list_, elements, size); \ else \ { \ if (!PFX##_fits(_list_, size)) \ @@ -421,7 +425,7 @@ return true; \ } \ \ - bool PFX##_append(SNAME *_list_, V *elements, size_t size) \ + bool PFX##_seq_push_back(SNAME *_list_, V *elements, size_t size) \ { \ if (size == 0) \ return false; \ @@ -439,7 +443,7 @@ return true; \ } \ \ - bool PFX##_remove(SNAME *_list_, size_t from, size_t to) \ + bool PFX##_seq_pop_at(SNAME *_list_, size_t from, size_t to) \ { \ if (from > to || to >= _list_->count) \ return false; \ @@ -455,23 +459,26 @@ return true; \ } \ \ - SNAME *PFX##_extract(SNAME *_list_, size_t from, size_t to) \ + SNAME *PFX##_seq_sublist(SNAME *_list_, size_t from, size_t to) \ { \ if (from > to || to >= _list_->count) \ return false; \ \ size_t length = to - from + 1; \ \ - SNAME *result = PFX##_new_from(_list_->buffer + from, length); \ + SNAME *result = PFX##_new(length); \ \ if (!result) \ return NULL; \ \ + memcpy(result->buffer, _list_->buffer, _list_->count * sizeof(V)); \ + \ memmove(_list_->buffer + from, _list_->buffer + to + 1, (_list_->count - to - 1) * sizeof(V)); \ \ memset(_list_->buffer + _list_->count - length, 0, length * sizeof(V)); \ \ _list_->count -= length; \ + result->count = length; \ \ return result; \ } \ diff --git a/src/cmc/queue.h b/src/cmc/queue.h index 65a9c57..11af800 100644 --- a/src/cmc/queue.h +++ b/src/cmc/queue.h @@ -43,12 +43,16 @@ #ifndef CMC_QUEUE_H #define CMC_QUEUE_H +#include #include #include #include #include #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) diff --git a/src/cmc/stack.h b/src/cmc/stack.h index 11c3862..4687c62 100644 --- a/src/cmc/stack.h +++ b/src/cmc/stack.h @@ -28,12 +28,16 @@ #ifndef CMC_STACK_H #define CMC_STACK_H +#include #include #include #include #include #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) diff --git a/src/cmc/treemap.h b/src/cmc/treemap.h index 8d9f83b..4ce4245 100644 --- a/src/cmc/treemap.h +++ b/src/cmc/treemap.h @@ -19,12 +19,16 @@ #ifndef CMC_TREEMAP_H #define CMC_TREEMAP_H +#include #include #include #include #include #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) diff --git a/src/cmc/treeset.h b/src/cmc/treeset.h index b97b583..444ade2 100644 --- a/src/cmc/treeset.h +++ b/src/cmc/treeset.h @@ -19,12 +19,16 @@ #ifndef CMC_TREESET_H #define CMC_TREESET_H +#include #include #include #include #include #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) diff --git a/src/ext/intervalheap.h b/src/ext/intervalheap.h index e12d528..74fbbb6 100644 --- a/src/ext/intervalheap.h +++ b/src/ext/intervalheap.h @@ -21,12 +21,16 @@ #ifndef CMC_INTERVALHEAP_H #define CMC_INTERVALHEAP_H +#include #include #include #include #include #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) diff --git a/src/ext/multimap.h b/src/ext/multimap.h index fe4ad52..65c6266 100644 --- a/src/ext/multimap.h +++ b/src/ext/multimap.h @@ -43,14 +43,18 @@ #ifndef CMC_MULTIMAP_H #define CMC_MULTIMAP_H +#include #include #include #include #include #include "../utl/cmc_string.h" -#ifndef CMC_HASH_TABLE_SETUP -#define CMC_HASH_TABLE_SETUP +/* to_string format */ +static const char *cmc_string_fmt_multimap = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", count:%" PRIuMAX ", load:%lf, cmp:%p, hash:%p }"; + +#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, @@ -84,7 +88,7 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531, 6917529027641081903, 13835058055282163729llu}; -#endif /* CMC_HASH_TABLE_SETUP */ +#endif /* CMC_IMPL_HASHTABLE_SETUP */ #define CMC_GENERATE_MULTIMAP(PFX, SNAME, K, V) \ CMC_GENERATE_MULTIMAP_HEADER(PFX, SNAME, K, V) \ diff --git a/src/ext/multiset.h b/src/ext/multiset.h index 20cf699..90bc885 100644 --- a/src/ext/multiset.h +++ b/src/ext/multiset.h @@ -21,21 +21,30 @@ #ifndef CMC_MULTISET_H #define CMC_MULTISET_H +#include #include #include #include #include #include "../utl/cmc_string.h" -#ifndef CMC_HASH_TABLE_SETUP -#define CMC_HASH_TABLE_SETUP +/* to_string format */ +static const char *cmc_string_fmt_multiset = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", count:%" PRIuMAX ", cardinality:%" PRIuMAX ", load:%lf, cmp:%p, hash:%p }"; -typedef enum cmc_entry_state_e +#ifndef CMC_IMPL_HASHTABLE_STATE +#define CMC_IMPL_HASHTABLE_STATE + +enum cmc_entry_state_e { CMC_ES_DELETED = -1, CMC_ES_EMPTY = 0, CMC_ES_FILLED = 1 -} cmc_entry_state; +}; + +#endif /* CMC_IMPL_HASHTABLE_STATE */ + +#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, @@ -69,7 +78,7 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531, 6917529027641081903, 13835058055282163729llu}; -#endif /* CMC_HASH_TABLE_SETUP */ +#endif /* CMC_IMPL_HASHTABLE_SETUP */ #define CMC_GENERATE_MULTISET(PFX, SNAME, V) \ CMC_GENERATE_MULTISET_HEADER(PFX, SNAME, V) \ diff --git a/src/ext/sortedlist.h b/src/ext/sortedlist.h new file mode 100644 index 0000000..04c5553 --- /dev/null +++ b/src/ext/sortedlist.h @@ -0,0 +1,657 @@ +/** + * list.h + * + * Creation Date: 17/09/2019 + * + * Authors: + * Leonardo Vencovsky (https://github.com/LeoVen) + * + */ + +/** + * THIS IS ONLY A PREVIEW + */ + +#ifndef CMC_SORTEDLIST_H +#define CMC_SORTEDLIST_H + +#include +#include +#include +#include +#include +#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); \ + /* Conditional Input and Output */ \ + bool PFX##_insert_if(SNAME *_list_, V element, bool condition); \ + bool PFX##_remove_if(SNAME *_list_, size_t index, bool condition); \ + /* 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 */ \ + 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); \ + \ + /* 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_SORTEDLIST_SOURCE(PFX, SNAME, V) \ + \ + /* Implementation Detail Functions */ \ + static bool PFX##_impl_grow(SNAME *_list_, size_t required); \ + 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 = malloc(capacity * sizeof(V)); \ + \ + if (!_list_->buffer) \ + { \ + free(_list_); \ + return NULL; \ + } \ + \ + memset(_list_->buffer, 0, capacity * sizeof(V)); \ + \ + _list_->capacity = capacity; \ + _list_->count = 0; \ + _list_->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##_impl_grow(_list_, _list_->count + 1)) \ + return false; \ + } \ + \ + _list_->buffer[_list_->count++] = element; \ + \ + _list_->is_sorted = false; \ + \ + return false; \ + } \ + \ + bool PFX##_remove(SNAME *_list_, size_t index) \ + { \ + if (index >= PFX##_count(_list_)) \ + return false; \ + \ + return false; \ + } \ + \ + 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 || PFX##_empty(_list_)) \ + return PFX##_impl_default_value(); \ + \ + return _list_->buffer[index]; \ + } \ + \ + size_t PFX##_indexof(SNAME *_list_, V element, bool from_start) \ + { \ + if (PFX##_empty(_list_)) \ + return _list_->count; \ + \ + PFX##_sort(_list_); \ + \ + /* TODO Do a binary search */ \ + \ + /* Not found */ \ + return _list_->count; \ + } \ + \ + bool PFX##_contains(SNAME *_list_, V element) \ + { \ + if (PFX##_empty(_list_)) \ + return false; \ + \ + PFX##_sort(_list_); \ + \ + /* TODO Do a binary search */ \ + \ + return false; \ + } \ + \ + 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; \ + } \ + \ + 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 PFX##_impl_default_value(); \ + \ + return iter->target->buffer[iter->cursor]; \ + } \ + \ + size_t PFX##_iter_index(SNAME##_iter *iter) \ + { \ + return iter->cursor; \ + } \ + \ + static bool PFX##_impl_grow(SNAME *_list_, size_t required) \ + { \ + size_t new_capacity = _list_->capacity * 2; \ + \ + if (new_capacity < required) \ + new_capacity = required; \ + \ + V *new_buffer = realloc(_list_->buffer, sizeof(V) * new_capacity); \ + \ + if (!new_buffer) \ + return false; \ + \ + _list_->buffer = new_buffer; \ + _list_->capacity = new_capacity; \ + \ + return true; \ + } \ + \ + static size_t PFX##_impl_binary_search_first(SNAME *_list_, V value) \ + { \ + /* TODO */ \ + \ + /* Not found */ \ + return _list_->count; \ + } \ + \ + static size_t PFX##_impl_binary_search_last(SNAME *_list_, V value) \ + { \ + /* TODO */ \ + \ + /* Not found */ \ + return _list_->count; \ + } \ + \ + /* 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_; \ + \ + 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 */ diff --git a/src/utl/assert.h b/src/utl/assert.h index 2367410..65f3e13 100644 --- a/src/utl/assert.h +++ b/src/utl/assert.h @@ -40,6 +40,9 @@ * - ptr * - bool (only for equals and not_equals) * + * Specialized assertions: + * + * - cmc_assert_sorted */ #ifndef CMC_ASSERT_H @@ -158,6 +161,46 @@ static bool cmc_assert_state = true; CMC_ASSERT_GLUE(dtype, not_in_range) \ (lower_bound, upper_bound, actual) +/** + * dtype : The type of the array + * array : Array to be checked if it is sorted + * comparator : A function that has two 'dtype' arguments and returns -1 if the + * first is less then the second, 0 if both are equal or 1 if the + * first is greater then the second. + * from : First index to compare (inclusive) + * to : Last index to compare (inclusive) + * + * This macro can be used for any data type. + */ +#define cmc_assert_sorted(dtype, array, comparator, from, to) \ + do \ + { \ + const char *str = #array; \ + dtype *arr__ = array; \ + size_t from__ = from; \ + size_t to__ = to; \ + int (*cmp__)(dtype, dtype) = comparator; \ + \ + size_t iprev__ = from__; \ + \ + for (size_t i__ = from__ + 1; i__ <= to__; i__++) \ + { \ + if (cmp__(arr__[iprev__], arr__[i__]) > 0) \ + { \ + cmc_assert_state = false; \ + \ + fprintf(stderr, \ + "Assertion Failed at %s:%s:%u for { %s }: Not sorted when comparing indexes %" PRIuMAX " and %" PRIuMAX "\n", \ + __FILE__, __func__, __LINE__, str, iprev__, i__); \ + \ + break; \ + } \ + \ + iprev__ = i__; \ + } \ + \ + } while (0) + #define cmc_assert_equals_int8_t(expected, actual) \ do \ { \ diff --git a/src/utl/cmc_string.h b/src/utl/cmc_string.h index ecf726c..1a14043 100644 --- a/src/utl/cmc_string.h +++ b/src/utl/cmc_string.h @@ -13,8 +13,8 @@ #ifndef CMC_STRING_H #define CMC_STRING_H -#include #include +#include 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 */