From 38620ba457b243a723c6ced91d839cfbbfc6e17b Mon Sep 17 00:00:00 2001 From: Leonardo Date: Tue, 16 Jul 2019 23:55:30 -0300 Subject: [PATCH] Added to_string methods to cmc, ./utl/cmc_string.h, fixed some variable names and fixed includes --- src/cmc/deque.h | 40 +++++- src/cmc/hashmap.h | 20 ++- src/cmc/hashset.h | 20 ++- src/cmc/heap.h | 40 +++++- src/cmc/linkedlist.h | 37 +++++- src/cmc/list.h | 52 +++++++- src/cmc/queue.h | 66 ++++++++-- src/cmc/stack.h | 37 +++++- src/cmc/treemap.h | 20 ++- src/cmc/treeset.h | 20 ++- src/ext/multimap.h | 308 +++++++++++++++++++++++-------------------- src/utl/cmc_string.h | 38 ++++++ 12 files changed, 523 insertions(+), 175 deletions(-) create mode 100644 src/utl/cmc_string.h diff --git a/src/cmc/deque.h b/src/cmc/deque.h index b5f80ab..811fe91 100644 --- a/src/cmc/deque.h +++ b/src/cmc/deque.h @@ -8,16 +8,34 @@ * */ -/*****************************************************************************/ -/********************************************************************* DEQUE */ -/*****************************************************************************/ +/** + * Deque + * + * A Deque (double-ended queue) is a linear data structure that is able to add + * or remove elements from both ends. It can also be thought of a double-ended + * stack since you can push and pop elements from two ends. The Deque can also + * be used as a Queue. + * + * There is no random access for a Deque. The only elements accessible are the + * front element and the back. + * + * Implementation + * + * This implementation uses a circular buffer (ring buffer or cyclic buffer) in + * order to operate on O(1) for push and pop on either ends (only case where it + * takes longer than O(1) is when the buffer is reallocated). If it was + * implemented as a regular array, adding or removing elements from the front + * would take O(N) due to the need to shift all elements in the deque. + */ #ifndef CMC_DEQUE_H #define CMC_DEQUE_H -#include #include +#include +#include #include +#include "../utl/cmc_string.h" #define DEQUE_GENERATE(PFX, SNAME, FMOD, V) \ DEQUE_GENERATE_HEADER(PFX, SNAME, FMOD, V) \ @@ -102,6 +120,8 @@ FMOD bool PFX##_full(SNAME *_deque_); \ FMOD size_t PFX##_count(SNAME *_deque_); \ FMOD size_t PFX##_capacity(SNAME *_deque_); \ + /* Collection Utility */ \ + FMOD cmc_string PFX##_to_string(SNAME *_deque_); \ \ /* Iterator Functions */ \ /* Iterator Allocation and Deallocation */ \ @@ -327,6 +347,18 @@ return _deque_->capacity; \ } \ \ + FMOD cmc_string PFX##_to_string(SNAME *_deque_) \ + { \ + cmc_string str; \ + SNAME *d_ = _deque_; \ + const char *name = #SNAME; \ + \ + snprintf(str.s, cmc_string_len, cmc_string_fmt_deque, \ + name, d_, d_->buffer, d_->capacity, d_->count, d_->front, d_->back); \ + \ + return str; \ + } \ + \ FMOD SNAME##_iter *PFX##_iter_new(SNAME *target) \ { \ SNAME##_iter *iter = malloc(sizeof(SNAME##_iter)); \ diff --git a/src/cmc/hashmap.h b/src/cmc/hashmap.h index 5fd9f17..768277b 100644 --- a/src/cmc/hashmap.h +++ b/src/cmc/hashmap.h @@ -9,6 +9,8 @@ */ /** + * HashMap + * * A HashMap is an implementation of a Map with unique keys, where every key is * mapped to a value. The keys are not sorted. It is implemented as a hashtable * with robin hood hashing. @@ -17,9 +19,11 @@ #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 @@ -171,6 +175,8 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531, FMOD bool PFX##_empty(SNAME *_map_); \ FMOD size_t PFX##_count(SNAME *_map_); \ FMOD size_t PFX##_capacity(SNAME *_map_); \ + /* Collection Utility */ \ + FMOD cmc_string PFX##_to_string(SNAME *_map_); \ \ /* Iterator Functions */ \ /* Iterator Allocation and Deallocation */ \ @@ -462,6 +468,18 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531, return _map_->capacity; \ } \ \ + FMOD 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_hashmap, \ + name, m_, m_->buffer, m_->capacity, m_->count, m_->load, m_->cmp, m_->hash); \ + \ + return str; \ + } \ + \ FMOD SNAME##_iter *PFX##_iter_new(SNAME *target) \ { \ SNAME##_iter *iter = malloc(sizeof(SNAME##_iter)); \ diff --git a/src/cmc/hashset.h b/src/cmc/hashset.h index c6f1986..61c0aa4 100644 --- a/src/cmc/hashset.h +++ b/src/cmc/hashset.h @@ -9,6 +9,8 @@ */ /** + * HashSet + * * A HashSet is an implementation of a Set with unique keys. The keys are not * sorted. It is implemented as a hashtable with robin hood hashing. */ @@ -16,9 +18,11 @@ #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 @@ -164,6 +168,8 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531, FMOD bool PFX##_empty(SNAME *_set_); \ FMOD size_t PFX##_count(SNAME *_set_); \ FMOD size_t PFX##_capacity(SNAME *_set_); \ + /* Collection Utility */ \ + FMOD cmc_string PFX##_to_string(SNAME *_set_); \ \ /* Set Operations */ \ FMOD SNAME *PFX##_union(SNAME *_set1_, SNAME *_set2_); \ @@ -412,6 +418,18 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531, return _set_->capacity; \ } \ \ + FMOD cmc_string PFX##_to_string(SNAME *_set_) \ + { \ + cmc_string str; \ + SNAME *s_ = _set_; \ + const char *name = #SNAME; \ + \ + snprintf(str.s, cmc_string_len, cmc_string_fmt_hashset, \ + name, s_, s_->buffer, s_->capacity, s_->count, s_->load, s_->cmp, s_->hash); \ + \ + return str; \ + } \ + \ FMOD SNAME *PFX##_union(SNAME *_set1_, SNAME *_set2_) \ { \ SNAME *_set_r_ = PFX##_new(_set1_->capacity, _set1_->load, _set1_->cmp, _set1_->hash); \ diff --git a/src/cmc/heap.h b/src/cmc/heap.h index 7254bf6..2ace3b3 100644 --- a/src/cmc/heap.h +++ b/src/cmc/heap.h @@ -8,16 +8,33 @@ * */ -/*****************************************************************************/ -/********************************************************************** HEAP */ -/*****************************************************************************/ +/** + * Heap + * + * The Heap is a specialized tree-based data structure which is essentially a + * complete tree that satisfies the heap property: + * - MaxHeap: + * - The root node is the greatest element of the unique set of keys. + * - A node key is always greater than or equal to its children keys. + * - Minheap: + * - The root node is the smallest element of the unique set of keys. + * - A node Key is always greater than or equal to its children keys. + * + * The heap is mostly used to implement priority queues. Sometimes it can also + * be used to sort elements. There are three main functions: + * - insert : Adds an element to the heap + * - remove_(min/max): Removes the min/max element from the heap + * - min/max : Accesses the min/max element from the heap + */ #ifndef CMC_HEAP_H #define CMC_HEAP_H -#include #include +#include +#include #include +#include "../utl/cmc_string.h" typedef enum cmc_heap_order_e { @@ -101,6 +118,8 @@ typedef enum cmc_heap_order_e FMOD bool PFX##_full(SNAME *_heap_); \ FMOD size_t PFX##_count(SNAME *_heap_); \ FMOD size_t PFX##_capacity(SNAME *_heap_); \ + /* Collection Utility */ \ + FMOD cmc_string PFX##_to_string(SNAME *_heap_); \ \ /* Iterator Functions */ \ /* Iterator Allocation and Deallocation */ \ @@ -289,6 +308,19 @@ typedef enum cmc_heap_order_e return _heap_->capacity; \ } \ \ + FMOD cmc_string PFX##_to_string(SNAME *_heap_) \ + { \ + cmc_string str; \ + SNAME *h_ = _heap_; \ + const char *name = #SNAME; \ + const char *t = h_->HO == 1 ? "MaxHeap" : "MinHeap"; \ + \ + snprintf(str.s, cmc_string_len, cmc_string_fmt_heap, \ + name, h_, h_->buffer, h_->capacity, h_->count, t, h_->cmp); \ + \ + return str; \ + } \ + \ FMOD SNAME##_iter *PFX##_iter_new(SNAME *target) \ { \ SNAME##_iter *iter = malloc(sizeof(SNAME##_iter)); \ diff --git a/src/cmc/linkedlist.h b/src/cmc/linkedlist.h index 388bee0..c2fba4d 100644 --- a/src/cmc/linkedlist.h +++ b/src/cmc/linkedlist.h @@ -8,16 +8,31 @@ * */ -/*****************************************************************************/ -/**************************************************************** LINKEDLIST */ -/*****************************************************************************/ +/** + * LinkedList + * + * A LinkedList is a linear collection of elements, whose order is not given by + * their physical placement in memory. Instead, each element points to the next + * (singly-linked list) and to a previous one (doubly-linked list). It consists + * of nodes connected by these next or previous pointers. Unlike an array, the + * LinkedList can indefinitely grow. + * + * Implementation + * + * The LinkedList is implemented as a doubly-linked list and allows insertions + * and removals at both ends in O(1) and in a given index in O(N). The list has + * a head and tail pointer. The head points to the first element in the sequence + * and tail points to the last. + */ #ifndef CMC_LINKEDLIST_H #define CMC_LINKEDLIST_H -#include #include +#include +#include #include +#include "../utl/cmc_string.h" #define LINKEDLIST_GENERATE(PFX, SNAME, FMOD, V) \ LINKEDLIST_GENERATE_HEADER(PFX, SNAME, FMOD, V) \ @@ -110,6 +125,8 @@ FMOD bool PFX##_contains(SNAME *_list_, V element, int (*comparator)(V, V)); \ FMOD bool PFX##_empty(SNAME *_list_); \ FMOD size_t PFX##_count(SNAME *_list_); \ + /* Collection Utility */ \ + FMOD cmc_string PFX##_to_string(SNAME *_list_); \ \ /* Node Related Functions */ \ /* Node Allocation and Deallocation */ \ @@ -443,6 +460,18 @@ return _list_->count; \ } \ \ + FMOD 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_linkedlist, \ + name, l_, l_->count, l_->head, l_->tail); \ + \ + return str; \ + } \ + \ FMOD SNAME##_node *PFX##_new_node(V element) \ { \ SNAME##_node *_node_ = malloc(sizeof(SNAME##_node)); \ diff --git a/src/cmc/list.h b/src/cmc/list.h index e20a278..4418f41 100644 --- a/src/cmc/list.h +++ b/src/cmc/list.h @@ -8,16 +8,46 @@ * */ -/*****************************************************************************/ -/********************************************************************** LIST */ -/*****************************************************************************/ +/** + * List + * + * A List is a Dynamic Array that store its elements contiguously. It has an + * internal buffer that is pre-allocated with a greater capacity than necessary + * in order to foresee new elements being added. The items can be added at both + * ends of the list and at the middle (with a given index). + * + * Insertions at the start are more costly as it is necessary to shift all + * elements one position to the right to give space to a new element being added + * at index 0. Insertions at the end are instantaneous as long as there is + * enough space in the buffer. Insertions at the middle will be based on an + * index. The index represents where the element being added will be located + * once the operation ends. This operation might also need to shift elements. It + * is also possible to add arrays of elements in the list. + * + * When the buffer is filled, it is reallocated with a greater capacity, usually + * being doubled. + * + * Removing elements follows the same principle. Removing the front element will + * require to shift all other elements one position to the left, thus being + * slower than removing from the end in which is done in constant time. Removing + * elements in the middle of the list will also require shifting elements to the + * left. Is is also possible to remove a range of elements or extract them, + * creating a new list with the removed items. + * + * The iterator is a simple structure that is capable of going back and + * forwards. Any modifications to the target list during iteration is considered + * undefined behavior. Its sole purpose is to facilitate navigation through a + * list. + */ #ifndef CMC_LIST_H #define CMC_LIST_H -#include #include +#include +#include #include +#include "../utl/cmc_string.h" #define LIST_GENERATE(PFX, SNAME, FMOD, V) \ LIST_GENERATE_HEADER(PFX, SNAME, FMOD, V) \ @@ -104,6 +134,8 @@ FMOD size_t PFX##_count(SNAME *_list_); \ FMOD bool PFX##_fits(SNAME *_list_, size_t size); \ FMOD size_t PFX##_capacity(SNAME *_list_); \ + /* Collection Utility */ \ + FMOD cmc_string PFX##_to_string(SNAME *_list_); \ \ /* Iterator Functions */ \ /* Iterator Allocation and Deallocation */ \ @@ -520,6 +552,18 @@ return _list_->capacity; \ } \ \ + FMOD 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_list, \ + name, l_, l_->buffer, l_->capacity, l_->count); \ + \ + return str; \ + } \ + \ FMOD SNAME##_iter *PFX##_iter_new(SNAME *target) \ { \ SNAME##_iter *iter = malloc(sizeof(SNAME##_iter)); \ diff --git a/src/cmc/queue.h b/src/cmc/queue.h index 13d0437..5812481 100644 --- a/src/cmc/queue.h +++ b/src/cmc/queue.h @@ -8,16 +8,46 @@ * */ -/*****************************************************************************/ -/********************************************************************* QUEUE */ -/*****************************************************************************/ +/** + * Queue + * + * A Queue is a First-In First-out (or Last-in Last-out) data structure. It is + * a Dynamic Circular Array where elements are added from one end of the array + * and removed from the other end. The circular array here (also known as + * circular buffer or ring buffer) is very important so that both adding and + * removing elements from the Queue are done instantly. The array is linear but + * with the modulo operator it is treated as a circular sequence of elements. + * + * If the Queue was implemented as a regular Dynamic Array, when adding or + * removing an element at the front, it would be necessary to shift all elements + * currently present in the Queue and this would add up a lot of computing time. + * Shifting `100000` elements in memory by one position every time an element is + * added to the Queue is simply not efficient. + * + * The Queue has two ends. The `front` and `back`. In this implementation all + * elements are added to the back of the Queue and removed from the front, which + * is more or less how queues work in real life. Unlike a Stack that only has + * operations at one end of the buffer, the Queue needs to be implemented as a + * circular array in order to quickly add or remove elements. + * + * The Queue has three main functions: `enqueue` which adds an element to the + * Queue; `dequeue` which removes an element from the Queue; and `peek` which + * return the element at the front of the Queue, that is, the next element to + * be removed from it. + * + * The Queue is used in many applications where a resource is shared among + * multiple consumers and the Queue is responsible for scheduling the access to + * the resource. + */ #ifndef CMC_QUEUE_H #define CMC_QUEUE_H -#include #include +#include +#include #include +#include "../utl/cmc_string.h" #define QUEUE_GENERATE(PFX, SNAME, FMOD, V) \ QUEUE_GENERATE_HEADER(PFX, SNAME, FMOD, V) \ @@ -48,7 +78,7 @@ size_t front; \ \ /* Index representing the back of the queue */ \ - size_t rear; \ + size_t back; \ \ /* Function that returns an iterator to the start of the queue */ \ struct SNAME##_iter_s (*it_start)(struct SNAME##_s *); \ @@ -97,6 +127,8 @@ FMOD bool PFX##_full(SNAME *_queue_); \ FMOD size_t PFX##_count(SNAME *_queue_); \ FMOD size_t PFX##_capacity(SNAME *_queue_); \ + /* Collection Utility */ \ + FMOD cmc_string PFX##_to_string(SNAME *_queue_); \ \ /* Iterator Functions */ \ /* Iterator Allocation and Deallocation */ \ @@ -158,7 +190,7 @@ _queue_->capacity = capacity; \ _queue_->count = 0; \ _queue_->front = 0; \ - _queue_->rear = 0; \ + _queue_->back = 0; \ \ _queue_->it_start = PFX##_impl_it_start; \ _queue_->it_end = PFX##_impl_it_end; \ @@ -172,7 +204,7 @@ \ _queue_->count = 0; \ _queue_->front = 0; \ - _queue_->rear = 0; \ + _queue_->back = 0; \ } \ \ FMOD void PFX##_free(SNAME *_queue_) \ @@ -189,9 +221,9 @@ return false; \ } \ \ - _queue_->buffer[_queue_->rear] = element; \ + _queue_->buffer[_queue_->back] = element; \ \ - _queue_->rear = (_queue_->rear == _queue_->capacity - 1) ? 0 : _queue_->rear + 1; \ + _queue_->back = (_queue_->back == _queue_->capacity - 1) ? 0 : _queue_->back + 1; \ _queue_->count++; \ \ return true; \ @@ -265,6 +297,18 @@ return _queue_->capacity; \ } \ \ + FMOD cmc_string PFX##_to_string(SNAME *_queue_) \ + { \ + cmc_string str; \ + SNAME *q_ = _queue_; \ + const char *name = #SNAME; \ + \ + snprintf(str.s, cmc_string_len, cmc_string_fmt_queue, \ + name, q_, q_->buffer, q_->capacity, q_->count, q_->front, q_->back); \ + \ + return str; \ + } \ + \ FMOD SNAME##_iter *PFX##_iter_new(SNAME *target) \ { \ SNAME##_iter *iter = malloc(sizeof(SNAME##_iter)); \ @@ -314,7 +358,7 @@ if (PFX##_empty(iter->target)) \ iter->cursor = 0; \ else \ - iter->cursor = (iter->target->rear == 0) ? iter->target->capacity - 1 : iter->target->rear - 1; \ + 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); \ @@ -398,7 +442,7 @@ _queue_->buffer = new_buffer; \ _queue_->capacity = new_capacity; \ _queue_->front = 0; \ - _queue_->rear = _queue_->count; \ + _queue_->back = _queue_->count; \ \ return true; \ } \ diff --git a/src/cmc/stack.h b/src/cmc/stack.h index 2d02d3b..a33e596 100644 --- a/src/cmc/stack.h +++ b/src/cmc/stack.h @@ -8,16 +8,31 @@ * */ -/*****************************************************************************/ -/********************************************************************* STACK */ -/*****************************************************************************/ +/** + * Stack + * + * A Stack is a Last-in First-out (or First-in Last-out) data structure used in + * a variety of algorithms. It is a Dynamic Array that can only add or remove + * its elements at the end of the buffer, in this case, it represents the top of + * the stack. + * + * It has three main functions: `push` which adds an element at the top of the + * stack; `pop` which removes the top element from the stack; and `top` which + * returns the top element without removing it (it is also sometimes called + * `peek`). + * + * A Stack is used in algorithms like backtracking, depth-first search, + * expression evaluation, syntax parsing and many more. + */ #ifndef CMC_STACK_H #define CMC_STACK_H -#include #include +#include +#include #include +#include "../utl/cmc_string.h" #define STACK_GENERATE(PFX, SNAME, FMOD, V) \ STACK_GENERATE_HEADER(PFX, SNAME, FMOD, V) \ @@ -88,6 +103,8 @@ FMOD bool PFX##_full(SNAME *_stack_); \ FMOD size_t PFX##_count(SNAME *_stack_); \ FMOD size_t PFX##_capacity(SNAME *_stack_); \ + /* Collection Utility */ \ + FMOD cmc_string PFX##_to_string(SNAME *_stack_); \ \ /* Iterator Functions */ \ /* Iterator Allocation and Deallocation */ \ @@ -246,6 +263,18 @@ return _stack_->capacity; \ } \ \ + FMOD 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; \ + } \ + \ FMOD SNAME##_iter *PFX##_iter_new(SNAME *target) \ { \ SNAME##_iter *iter = malloc(sizeof(SNAME##_iter)); \ diff --git a/src/cmc/treemap.h b/src/cmc/treemap.h index 9adf224..76ab23a 100644 --- a/src/cmc/treemap.h +++ b/src/cmc/treemap.h @@ -9,6 +9,8 @@ */ /** + * TreeMap + * * A TreeMap is an implementation of a Map that keeps its keys sorted. Like a * Map, it has only unique keys. This implementation uses a balanced binary * tree called AVL Tree that uses the height of nodes to keep its keys balanced. @@ -17,9 +19,11 @@ #ifndef CMC_TREEMAP_H #define CMC_TREEMAP_H -#include #include +#include +#include #include +#include "../utl/cmc_string.h" #define TREEMAP_GENERATE(PFX, SNAME, FMOD, K, V) \ TREEMAP_GENERATE_HEADER(PFX, SNAME, FMOD, K, V) \ @@ -123,6 +127,8 @@ FMOD bool PFX##_contains(SNAME *_map_, K key); \ FMOD bool PFX##_empty(SNAME *_map_); \ FMOD size_t PFX##_count(SNAME *_map_); \ + /* Collection Utility */ \ + FMOD cmc_string PFX##_to_string(SNAME *_map_); \ \ /* Iterator Functions */ \ /* Iterator Allocation and Deallocation */ \ @@ -534,6 +540,18 @@ return _map_->count; \ } \ \ + FMOD 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_treemap, \ + name, m_, m_->root, m_->count, m_->cmp); \ + \ + return str; \ + } \ + \ FMOD SNAME##_iter *PFX##_iter_new(SNAME *target) \ { \ SNAME##_iter *iter = malloc(sizeof(SNAME##_iter)); \ diff --git a/src/cmc/treeset.h b/src/cmc/treeset.h index d4b1882..44407a9 100644 --- a/src/cmc/treeset.h +++ b/src/cmc/treeset.h @@ -9,6 +9,8 @@ */ /** + * TreeSet + * * A TreeSet is an implementation of a Set that keeps its elements sorted. Like * a Set it has only unique keys. This implementation uses a balanced binary * tree called AVL Tree that uses the height of nodes to keep its keys balanced. @@ -17,9 +19,11 @@ #ifndef CMC_TREESET_H #define CMC_TREESET_H -#include #include +#include +#include #include +#include "../utl/cmc_string.h" #define TREESET_GENERATE(PFX, SNAME, FMOD, V) \ TREESET_GENERATE_HEADER(PFX, SNAME, FMOD, V) \ @@ -118,6 +122,8 @@ FMOD bool PFX##_contains(SNAME *_set_, V element); \ FMOD bool PFX##_empty(SNAME *_set_); \ FMOD size_t PFX##_count(SNAME *_set_); \ + /* Collection Utility */ \ + FMOD cmc_string PFX##_to_string(SNAME *_map_); \ \ /* Set Operations */ \ FMOD SNAME *PFX##_union(SNAME *_set1_, SNAME *_set2_); \ @@ -502,6 +508,18 @@ return _set_->count; \ } \ \ + FMOD cmc_string PFX##_to_string(SNAME *_set_) \ + { \ + cmc_string str; \ + SNAME *s_ = _set_; \ + const char *name = #SNAME; \ + \ + snprintf(str.s, cmc_string_len, cmc_string_fmt_treeset, \ + name, s_, s_->root, s_->count, s_->cmp); \ + \ + return str; \ + } \ + \ FMOD SNAME *PFX##_union(SNAME *_set1_, SNAME *_set2_) \ { \ SNAME *_set_r_ = PFX##_new(_set1_->cmp); \ diff --git a/src/ext/multimap.h b/src/ext/multimap.h index 2556f51..dab2b7f 100644 --- a/src/ext/multimap.h +++ b/src/ext/multimap.h @@ -8,9 +8,37 @@ * */ -/*****************************************************************************/ -/******************************************************************* MULTIMAP */ -/*****************************************************************************/ +/** + * MultiMap + * + * The MultiMap is a Map that allows for multiple keys. This is a data structure + * that has a very narrow usage. A Map (either TreeMap or HashMap) can also work + * like a MultiMap if a certain key is mapped to another collection. + * + * Map> maps an integer to a list of integer. + * MultiMap maps many integer keys to integer values. + * + * The difference is that in a MultiMap you can store keys that are the same but + * might be different instances of the same value. This is also relevant if your + * data type is more complex like a struct where its ID is the same but some + * other members of this data type are different. + * + * Implementation + * + * The map uses separate chaining and robin hood hashing. Its internal buffer + * is made of a pair of pointers to entries that represent a linked list. So + * accessing map->buffer[0] would give the first pair of pointers. Each entry + * has both a pointer to a previous entry and a next entry. This design choice + * was made so that every collection in this library has a two-way iterator + * with a very few exceptions. + * + * Each entry is composed of a Key and a Value. Entries with the same key should + * always hash to the same linked list. Also, keys that hash to the same bucket + * will also be in the same linked list. + * + * The order of inserting and removing the same keys will behave like a FIFO. So + * the first key added will be the first to be removed. + */ #ifndef CMC_MULTIMAP_H #define CMC_MULTIMAP_H @@ -67,143 +95,143 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531, MULTIMAP_GENERATE_SOURCE(PFX, SNAME, FMOD, K, V) /* HEADER ********************************************************************/ -#define MULTIMAP_GENERATE_HEADER(PFX, SNAME, FMOD, K, V) \ - \ - /* Multimap Structure */ \ - typedef struct SNAME##_s \ - { \ - /* Array of linked list to entries */ \ - struct SNAME##_entry_s *(*buffer)[2]; \ - \ - /* Current array capacity */ \ - size_t capacity; \ - \ - /* Current amount of keys */ \ - size_t count; \ - \ - /* Load factor in range (0.0, infinity) */ \ - double load; \ - \ - /* Key comparison functions */ \ - int (*cmp)(K, K); \ - \ - /* Key hash function */ \ - size_t (*hash)(K); \ - \ - /* Function that returns an iterator to the start of the multimap */ \ - struct SNAME##_iter_s (*it_start)(struct SNAME##_s *); \ - \ - /* Function that returns an iterator to the end of the multimap */ \ - struct SNAME##_iter_s (*it_end)(struct SNAME##_s *); \ - \ - } SNAME, *SNAME##_ptr; \ - \ - /* Multimap Entry */ \ - typedef struct SNAME##_entry_s \ - { \ - /* Entry Key */ \ - K key; \ - \ - /* Entry Value */ \ - V value; \ - \ - /* Next entry on the linked list */ \ - struct SNAME##_entry_s *next; \ - \ - /* Previous entry on the linked list */ \ - struct SNAME##_entry_s *prev; \ - \ - } SNAME##_entry, *SNAME##_entry_ptr; \ - \ - typedef struct SNAME##_iter_s \ - { \ - /* Target multimap */ \ - struct SNAME##_s *target; \ - \ - /* Current entry */ \ - struct SNAME##_entry_s *curr_entry; \ - \ - /* Cursor`s position (index) */ \ - size_t cursor; \ - \ - /* Keeps track of relative index to the iteration of elements */ \ - size_t index; \ - \ - /* The index of the first element */ \ - size_t first; \ - \ - /* The index of the last element */ \ - size_t last; \ - \ - /* If the iterator has reached the start of the iteration */ \ - bool start; \ - \ - /* If the iterator has reached the end of the iteration */ \ - bool end; \ - } SNAME##_iter, *SNAME##_iter_ptr; \ - \ - /* Collection Functions */ \ - /* Collection Allocation and Deallocation */ \ - FMOD SNAME *PFX##_new(size_t size, double load, int (*compare)(K, K), size_t (*hash)(K)); \ - FMOD void PFX##_clear(SNAME *_map_); \ - FMOD void PFX##_free(SNAME *_map_); \ - /* Collection Input and Output */ \ - FMOD bool PFX##_insert(SNAME *_map_, K key, V value); \ - FMOD bool PFX##_remove(SNAME *_map_, K key, V *value); \ - FMOD size_t PFX##_remove_all(SNAME *_map_, K key); \ - /* Conditional Input and Output */ \ - FMOD bool PFX##_insert_if(SNAME *_map_, K key, V value, bool condition); \ - FMOD bool PFX##_remove_if(SNAME *_map_, K key, V *value, bool condition); \ - /* Element Access */ \ - FMOD bool PFX##_max(SNAME *_map_, K *key, V *value); \ - FMOD bool PFX##_min(SNAME *_map_, K *key, V *value); \ - FMOD V PFX##_get(SNAME *_map_, K key); \ - FMOD V *PFX##_get_ref(SNAME *_map_, K key); \ - /* Collection State */ \ - FMOD bool PFX##_contains(SNAME *_map_, K key); \ - FMOD bool PFX##_empty(SNAME *_map_); \ - FMOD size_t PFX##_count(SNAME *_map_); \ - FMOD size_t PFX##_capacity(SNAME *_map_); \ - \ - /* Iterator Functions */ \ - /* Iterator Allocation and Deallocation */ \ - FMOD SNAME##_iter *PFX##_iter_new(SNAME *target); \ - FMOD void PFX##_iter_free(SNAME##_iter *iter); \ - /* Iterator Initialization */ \ - FMOD void PFX##_iter_init(SNAME##_iter *iter, SNAME *target); \ - /* Iterator State */ \ - FMOD bool PFX##_iter_start(SNAME##_iter *iter); \ - FMOD bool PFX##_iter_end(SNAME##_iter *iter); \ - /* Iterator Movement */ \ - FMOD void PFX##_iter_to_start(SNAME##_iter *iter); \ - FMOD void PFX##_iter_to_end(SNAME##_iter *iter); \ - FMOD bool PFX##_iter_next(SNAME##_iter *iter); \ - FMOD bool PFX##_iter_prev(SNAME##_iter *iter); \ - /* Iterator Access */ \ - FMOD K PFX##_iter_key(SNAME##_iter *iter); \ - FMOD V PFX##_iter_value(SNAME##_iter *iter); \ - FMOD V *PFX##_iter_rvalue(SNAME##_iter *iter); \ - FMOD size_t PFX##_iter_index(SNAME##_iter *iter); \ - \ - /* 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_; \ - } \ +#define MULTIMAP_GENERATE_HEADER(PFX, SNAME, FMOD, K, V) \ + \ + /* Multimap Structure */ \ + typedef struct SNAME##_s \ + { \ + /* Array of linked list to entries */ \ + struct SNAME##_entry_s *(*buffer)[2]; \ + \ + /* Current array capacity */ \ + size_t capacity; \ + \ + /* Current amount of keys */ \ + size_t count; \ + \ + /* Load factor in range (0.0, infinity) */ \ + double load; \ + \ + /* Key comparison functions */ \ + int (*cmp)(K, K); \ + \ + /* Key hash function */ \ + size_t (*hash)(K); \ + \ + /* Function that returns an iterator to the start of the multimap */ \ + struct SNAME##_iter_s (*it_start)(struct SNAME##_s *); \ + \ + /* Function that returns an iterator to the end of the multimap */ \ + struct SNAME##_iter_s (*it_end)(struct SNAME##_s *); \ + \ + } SNAME, *SNAME##_ptr; \ + \ + /* Multimap Entry */ \ + typedef struct SNAME##_entry_s \ + { \ + /* Entry Key */ \ + K key; \ + \ + /* Entry Value */ \ + V value; \ + \ + /* Next entry on the linked list */ \ + struct SNAME##_entry_s *next; \ + \ + /* Previous entry on the linked list */ \ + struct SNAME##_entry_s *prev; \ + \ + } SNAME##_entry, *SNAME##_entry_ptr; \ + \ + typedef struct SNAME##_iter_s \ + { \ + /* Target multimap */ \ + struct SNAME##_s *target; \ + \ + /* Current entry */ \ + struct SNAME##_entry_s *curr_entry; \ + \ + /* Cursor`s position (index) */ \ + size_t cursor; \ + \ + /* Keeps track of relative index to the iteration of elements */ \ + size_t index; \ + \ + /* The index of the first element */ \ + size_t first; \ + \ + /* The index of the last element */ \ + size_t last; \ + \ + /* If the iterator has reached the start of the iteration */ \ + bool start; \ + \ + /* If the iterator has reached the end of the iteration */ \ + bool end; \ + } SNAME##_iter, *SNAME##_iter_ptr; \ + \ + /* Collection Functions */ \ + /* Collection Allocation and Deallocation */ \ + FMOD SNAME *PFX##_new(size_t capacity, double load, int (*compare)(K, K), size_t (*hash)(K)); \ + FMOD void PFX##_clear(SNAME *_map_); \ + FMOD void PFX##_free(SNAME *_map_); \ + /* Collection Input and Output */ \ + FMOD bool PFX##_insert(SNAME *_map_, K key, V value); \ + FMOD bool PFX##_remove(SNAME *_map_, K key, V *value); \ + FMOD size_t PFX##_remove_all(SNAME *_map_, K key); \ + /* Conditional Input and Output */ \ + FMOD bool PFX##_insert_if(SNAME *_map_, K key, V value, bool condition); \ + FMOD bool PFX##_remove_if(SNAME *_map_, K key, V *value, bool condition); \ + /* Element Access */ \ + FMOD bool PFX##_max(SNAME *_map_, K *key, V *value); \ + FMOD bool PFX##_min(SNAME *_map_, K *key, V *value); \ + FMOD V PFX##_get(SNAME *_map_, K key); \ + FMOD V *PFX##_get_ref(SNAME *_map_, K key); \ + /* Collection State */ \ + FMOD bool PFX##_contains(SNAME *_map_, K key); \ + FMOD bool PFX##_empty(SNAME *_map_); \ + FMOD size_t PFX##_count(SNAME *_map_); \ + FMOD size_t PFX##_capacity(SNAME *_map_); \ + \ + /* Iterator Functions */ \ + /* Iterator Allocation and Deallocation */ \ + FMOD SNAME##_iter *PFX##_iter_new(SNAME *target); \ + FMOD void PFX##_iter_free(SNAME##_iter *iter); \ + /* Iterator Initialization */ \ + FMOD void PFX##_iter_init(SNAME##_iter *iter, SNAME *target); \ + /* Iterator State */ \ + FMOD bool PFX##_iter_start(SNAME##_iter *iter); \ + FMOD bool PFX##_iter_end(SNAME##_iter *iter); \ + /* Iterator Movement */ \ + FMOD void PFX##_iter_to_start(SNAME##_iter *iter); \ + FMOD void PFX##_iter_to_end(SNAME##_iter *iter); \ + FMOD bool PFX##_iter_next(SNAME##_iter *iter); \ + FMOD bool PFX##_iter_prev(SNAME##_iter *iter); \ + /* Iterator Access */ \ + FMOD K PFX##_iter_key(SNAME##_iter *iter); \ + FMOD V PFX##_iter_value(SNAME##_iter *iter); \ + FMOD V *PFX##_iter_rvalue(SNAME##_iter *iter); \ + FMOD size_t PFX##_iter_index(SNAME##_iter *iter); \ + \ + /* 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 MULTIMAP_GENERATE_SOURCE(PFX, SNAME, FMOD, K, V) \ \ diff --git a/src/utl/cmc_string.h b/src/utl/cmc_string.h new file mode 100644 index 0000000..c7dac27 --- /dev/null +++ b/src/utl/cmc_string.h @@ -0,0 +1,38 @@ +/** + * cmc_string.h + * + * Creation Date: 17/07/2019 + * + * Authors: + * Leonardo Vencovsky (https://github.com/LeoVen) + * + */ + +/* A very simple fixed size string used by all collections' method to_string */ + +#ifndef CMC_STRING_H +#define CMC_STRING_H + +#include +#include + +static const size_t cmc_string_len = 200; + +typedef struct cmc_string_s +{ + char s[200]; +} cmc_string; + +/* To string formatting */ +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, }"; + +#endif /* CMC_STRING_H */