-BidiMap bidimap.h | Bidirectional Map | Two Hashtables | A bijection between two sets of unique keys and unique values K <-> V using two hashtables |
-Deque deque.h | Double-Ended Queue | Dynamic Circular Array | A circular array that allows push and pop on both ends (only) at constant time |
-HashMap 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 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 heap.h | Priority Queue | Dynamic Array | A binary heap as a dynamic array as an implicit data structure |
-IntervalHeap 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 linkedlist.h | List | Doubly-Linked List | A default doubly-linked list |
-List list.h | List | Dynamic Array | A dynamic array with push and pop anywhere on the array |
-MultiMap multimap.h | Multimap | Custom Hashtable | A mapping of multiple keys with one node per key using a hashtable with separate chaining |
-Multiset multiset.h | Multiset | Hashtable | A mapping of a value and its multiplicity using a hashtable with open addressing and robin hood hashing |
-Queue 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 sortedlist.h | Sorted List | Sorted Dynamic Array | A lazily sorted dynamic array that is sorted only when necessary |
-Stack stack.h | FILO | Dynamic Array | A stack with push and pop at the end of a dynamic array |
-TreeMap 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 treeset.h | Sorted Set | AVL Tree | A unique set of keys using an AVL tree with log(n) look up and sorted iteration |
+
+Every collection comes with an interface of iterators where you can easily access the elements of a collection. These can move at any direction, can start at any 'end' of a collection and can move any amount of steps per iteration. Every collection generated comes with an iterator.
+By design choice these iterators do not support modifications to the collection. If a collection is modified, all iterators that have been initialized will most likely be invalidated and may cause undefined behavior if used afterwards.
+
+The main C Macro Collections.
+The C Macro Collections library was created out of necessity. To create powerful data structures of any type without the constant use of macros and void * pointers, but at the same time being type-safe. These collections are generated by macros containing a template. These templates allow for some much needed customizations including the data type you wish to handle.
+In the cmc folder is the default implementation of all collections. There is also a dev folder that pretty much has the same macros that expand to the same code, except that they have an extensive use of logging that might be useful for debugging or getting to know what is happening in your program. There is also the sac collections that are statically allocated (have a fixed sized buffer).
+
+Let's say you need a HashMap mapping keys of type char * to int. All you need to do is:
+#include "cmc/hashmap"
+
+// CMC_GENERATE_HASHMAP(PFX, SNAME, K, V)
+CMC_GENERATE_HASHMAP(map, hashmap, char *, int)
+
+int main(void)
+{
+ // Here you have full functionalities of a HashMap
+ // No more macros needed!
+ // Every function can be found in the 'map_' prefix and are all type-safe
+}
+
+You can customize the functions prefix (PFX) and the struct name (SNAME). The macro CMC_GENERATE_HASHMAP will expand to all the code that you will need to operate on a HashMap with char * keys and int values. The only thing left to do is to define a hash function and a comparator functions for the keys of this map. In case of char * you can find these functions in utl/futils.h or make your own. To know which collections require which functions check out Functions Table or the documentation for each collection.
+
+A Deque, also known as a double-ended queue, is a linear data structure that is able to add and 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. The only elements accessible from a Deque ar the two elements at its ends (front element and back element).
+
+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. The 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.
+Two indices are kept track of. The front index and the rear index. These represent the both ends of the Deque. If an index reaches one end of the real buffer, they wrap around to the other end and an element is added there. This abstracts the real buffer as a circular buffer with the cost os constantly checking for boundaries and using the modulo operator.
+
+
+CMC_GENERATE_DEQUE(PFX, SNAME, V) - Generate full definition.
+CMC_GENERATE_DEQUE_HEADER(PFX, SNAME, V) - Generate only the header portion
+CMC_GENERATE_DEQUE_SOURCE(PFX, SNAME, V) - Generate only the source portion
+
+| Parameter | Description |
+PFX | Functions namespace or prefix |
+SNAME | Structure name |
+V | Value type |
+
+| Declared structs | Description |
+struct SNAME | A double-ended queue data structure |
+struct SNAME##_fval | A function table for the V type |
+struct SNAME##_iter | A double-ended queue iterator |
+
+
+struct SNAME | Description |
+V *buffer | Dynamic circular array of elements. |
+size_t capacity | Current circular array capacity. |
+size_t count | Current amount of elements. |
+size_t front | Index representing the front of the Deque. |
+size_t rear | Index representing the back of the Deque. |
+int flag | Flag indicating errors or success. |
+struct SNAME##_fval *f_val | Functions table for the Value type. |
+struct cmc_alloc_node *alloc | Custom allocation functions. |
+struct cmc_callbacks *callbacks | Callback functions. |
+it_start [1] | Returns an iterator to the start of the Deque. |
+it_end [2] | Returns an iterator to the end of the Deque. |
+
+
+- Full definition:
struct SNAME##_iter (*it_start)(struct SNAME *);.
+- Full definition:
struct SNAME##_iter (*it_end)(struct SNAME *);.
+
+
+The Functions Table for V. Check out the Functions Table documentation here.
+
+struct SNAME##_iter | Description |
+struct SNAME *target | Deque being iterated over. |
+size_t cursor | Cursor's current position (index). |
+size_t index | Relative index to all elements in the iteration. |
+bool start | If the iterator reached the start of the iteration. |
+bool end | If the iterator reached the end of iteration. |
+
+
+This list associates which functions calls which callbacks.
+
+create
+
+PFX##_push_front()
+PFX##_push_back()
+
+
+read
+
+PFX##_front()
+PFX##_back()
+PFX##_contains()
+
+
+update
+delete
+
+PFX##_pop_front()
+PFX##_pop_back()
+
+
+resize
+
+
+
+
+
+
+The development collections. These collections are an exact copy of the cmc collections but they come with many logging throughout the generated code. Useful for debugging or during development.
+
+The Statically Allocated Collections. These collections have a fixed size. Its size is one of the parameters during macro expansion, producing a C array.
+
+The cmc collections hold their data either with nodes or a buffer that can be reallocated. The sac collections only have an array with fixed size and don't perform any allocation on the heap.
+// A CMC List
+struct List
+{
+ T *buffer;
+ /* Other fields */
+};
+
+// A SAC List
+struct List
+{
+ T buffer[SIZE];
+ /* Other fields */
+};
+
Inside the ./utl/ folder there are many utility functions and macros that can be extensively used with the C Macro Collections library. Most of these utilities can be used without the main library.
Definition of many typed non-abortive assertions. Every assertion that fails will print a message to stderr but will not abort the program execution. The macro parameters are first assigned to a temporary variable of the specified dtype in order to generate warnings from the compiler in case of type mismatch.
@@ -404,7 +709,7 @@ int main(void)
Note that ptr is used for any pointers. They are first casted to void * and then their address is compared.
Note that bool will be expanded to _Bool.
-
+
- cmc_assert - Asserts that an expression evaluates to true;
@@ -582,7 +887,7 @@ int main(void)
from_index - First index from the array to compare (inclusive)
to_index - Last index from the array to compare (inclusive)
-
+
For-Each macros. Since doing a for loop with iterators can be a lot to write, these macros solve that problem. There are two of them:
CMC_FOREACH - Goes from the beginning of a Collection to the end
@@ -606,6 +911,109 @@ int main(void)
ITERNAME - Iterator variable name
TARGET - Target collection variable name
+
+#include "cmc/list.h"
+#include "utl/foreach.h"
+
+CMC_GENERATE_LIST(i32l, i32list, int32_t)
+
+int main(void)
+{
+ struct i32list *list = i32l_new(100, &(struct i32list_fval) { NULL });
+
+ for (int i = 0; i < 100; i++)
+ i32l_push_back(list, i);
+
+ CMC_FOREACH(i32l, i32list, it, list)
+ {
+ int value = i32l_iter_value(&it);
+ size_t index = i32l_iter_index(&it);
+
+ if (index == 0)
+ printf("[ %d, ", value);
+ else if (index == i32l_count(list) - 1)
+ printf("%d ]\n", value);
+ else
+ printf("%d, ", value);
+ }
+
+ i32l_free(list);
+}
+
+
+Contains common functions that can be used by Functions Table, instead of writing another one every time.
+A quick list of functions present in this file:
+| cmp |
+static inline int cmc_i64_cmp(int64_t x1, int64_t x2); |
+static inline int cmc_i32_cmp(int32_t x1, int32_t x2); |
+static inline int cmc_i16_cmp(int16_t x1, int16_t x2); |
+static inline int cmc_i8_cmp(int8_t x1, int8_t x2); |
+static inline int cmc_u64_cmp(uint64_t x1, uint64_t x2); |
+static inline int cmc_u32_cmp(uint32_t x1, uint32_t x2); |
+static inline int cmc_u16_cmp(uint16_t x1, uint16_t x2); |
+static inline int cmc_u8_cmp(uint8_t x1, uint8_t x2); |
+static inline int cmc_size_cmp(size_t x1, size_t x2); |
+static inline int cmc_imax_cmp(intmax_t x1, intmax_t x2); |
+static inline int cmc_umax_cmp(uintmax_t x1, uintmax_t x2); |
+static inline int cmc_float_cmp(float x1, float x2); |
+static inline int cmc_double_cmp(double x1, double x2); |
+static inline int cmc_str_cmp(char *ch1, char *ch2); |
+
+
+
+| cpy |
+static inline char *cmc_str_cpy(char *str); |
+
+
+
+| str |
+static inline bool cmc_i8_str(FILE *file, int8_t element); |
+static inline bool cmc_i16_str(FILE *file, int16_t element); |
+static inline bool cmc_i32_str(FILE *file, int32_t element); |
+static inline bool cmc_i64_str(FILE *file, int64_t element); |
+static inline bool cmc_u8_str(FILE *file, uint8_t element); |
+static inline bool cmc_u16_str(FILE *file, uint16_t element); |
+static inline bool cmc_u32_str(FILE *file, uint32_t element); |
+static inline bool cmc_u64_str(FILE *file, uint64_t element); |
+static inline bool cmc_size_str(FILE *file, size_t element); |
+static inline bool cmc_imax_str(FILE *file, intmax_t element); |
+static inline bool cmc_umax_str(FILE *file, uintmax_t element); |
+static inline bool cmc_float_str(FILE *file, float element); |
+static inline bool cmc_double_str(FILE *file, double element); |
+static inline bool cmc_str_str(FILE *file, char *element); |
+
+
+
+
+
+
+| hash |
+static inline size_t cmc_i64_hash(int64_t e); |
+static inline size_t cmc_i32_hash(int32_t e); |
+static inline size_t cmc_i16_hash(int16_t e); |
+static inline size_t cmc_i8_hash(int8_t e); |
+static inline size_t cmc_u64_hash(uint64_t e); |
+static inline size_t cmc_u32_hash(uint32_t e); |
+static inline size_t cmc_u16_hash(uint16_t e); |
+static inline size_t cmc_u8_hash(uint8_t e); |
+static inline size_t cmc_size_hash(size_t e); |
+static inline size_t cmc_imax_hash(intmax_t e); |
+static inline size_t cmc_umax_hash(uintmax_t e); |
+static inline size_t cmc_float_hash(float e); |
+static inline size_t cmc_double_hash(double e); |
+static inline size_t cmc_str_hash_djb2(char *str); |
+static inline size_t cmc_str_hash_sdbm(char *str); |
+static inline size_t cmc_str_hash_java(char *str); |
+static inline size_t cmc_str_hash_murmur3(uint64_t e); |
+static inline size_t cmc_str_hash_murmur3_variant(uint64_t e); |
+static inline size_t cmc_i64_hash_mix(int64_t element); |
+static inline size_t cmc_u64_hash_mix(uint64_t element); |
+
+
+
+
Simple and customizable logging macros. Messages can have a custom logging level and a custom file output. This customization can be done via the global variable cmc_log_config. Logs are outputted to stderr.
@@ -784,7 +1192,7 @@ int main(void)
Define this macro if you wish to have color output from the messages printed by each test. Note that a Unit Test need to have VERBOSE equal to true.
-
+
#include "utl/test.h"
CMC_CREATE_UNIT(check_math, true, {
@@ -844,7 +1252,7 @@ int main(void)
timer - A struct cmc_timer variable
-
+
#include <stdio.h>
#include "utl/timer.h"
diff --git a/docs/Features/custom_allocation.html b/docs/sac/index.html
similarity index 67%
rename from docs/Features/custom_allocation.html
rename to docs/sac/index.html
index d181800..72f232c 100644
--- a/docs/Features/custom_allocation.html
+++ b/docs/sac/index.html
@@ -3,7 +3,7 @@
- Custom allocation - C Macro Collections
+ sac - C Macro Collections
@@ -81,7 +81,7 @@
@@ -148,27 +148,37 @@
-
-All collections have an allocation node. This node can be modified so that every allocation and de-allocation can be done with custom functions. The allocation node has pointers to functions that correspond to:
-
-calloc
-free
-malloc
-realloc
-
+
+The Statically Allocated Collections. These collections have a fixed size. Its size is one of the parameters during macro expansion, producing a C array.
+
+The cmc collections hold their data either with nodes or a buffer that can be reallocated. The sac collections only have an array with fixed size and don't perform any allocation on the heap.
+// A CMC List
+struct List
+{
+ T *buffer;
+ /* Other fields */
+};
+
+// A SAC List
+struct List
+{
+ T buffer[SIZE];
+ /* Other fields */
+};
+