All collections now support custom allocation functions
Also some development was made towards callback functions Now all files are independent and include all necessary definitions within it
This commit is contained in:
1 parent
26cc284618
commit
49bed825c2
15 files changed
+3482
-2252
No files matched your search
+7
-6
@@ -798,9 +798,11 @@ struct cmc_callbacks_bidimap
|
||||
struct SNAME *PFX##_copy_of(struct SNAME *_map_, K (*key_copy_func)(K), \
|
||||
V (*value_copy_func)(V)) \
|
||||
{ \
|
||||
struct SNAME *result = PFX##_new(PFX##_capacity(_map_), PFX##_load(_map_), \
|
||||
_map_->key_cmp, _map_->key_hash, \
|
||||
_map_->val_cmp, _map_->val_hash); \
|
||||
/* TODO this function can be optimized */ \
|
||||
struct SNAME *result = PFX##_new_custom(PFX##_capacity(_map_), PFX##_load(_map_), \
|
||||
_map_->key_cmp, _map_->key_hash, \
|
||||
_map_->val_cmp, _map_->val_hash, \
|
||||
_map_->alloc, _map_->callbacks); \
|
||||
\
|
||||
for (size_t i = 0; i < _map_->capacity; i++) \
|
||||
{ \
|
||||
@@ -870,14 +872,13 @@ struct cmc_callbacks_bidimap
|
||||
{ \
|
||||
struct cmc_string str; \
|
||||
struct SNAME *m_ = _map_; \
|
||||
const char *name = #SNAME; \
|
||||
\
|
||||
int n = snprintf(str.s, cmc_string_len, cmc_string_fmt_bidimap, \
|
||||
name, #K, #V, m_, m_->key_buffer, m_->val_buffer, m_->capacity, \
|
||||
#SNAME, #K, #V, 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, m_->alloc, m_->callbacks); \
|
||||
\
|
||||
if (n < 0 || n == cmc_string_len) \
|
||||
if (n < 0 || n == (int)cmc_string_len) \
|
||||
return (struct cmc_string){0}; \
|
||||
\
|
||||
str.s[n] = '\0'; \
|
||||
|
||||
+2
-3
@@ -535,13 +535,12 @@ struct cmc_callbacks_deque
|
||||
{ \
|
||||
struct cmc_string str; \
|
||||
struct SNAME *d_ = _deque_; \
|
||||
const char *name = #SNAME; \
|
||||
\
|
||||
int n = snprintf(str.s, cmc_string_len, cmc_string_fmt_deque, \
|
||||
name, #V, d_, d_->buffer, d_->capacity, d_->count, \
|
||||
#SNAME, #V, d_, d_->buffer, d_->capacity, d_->count, \
|
||||
d_->front, d_->back, d_->alloc, d_->callbacks); \
|
||||
\
|
||||
if (n < 0 || n == cmc_string_len) \
|
||||
if (n < 0 || n == (int)cmc_string_len) \
|
||||
return (struct cmc_string){0}; \
|
||||
\
|
||||
str.s[n] = '\0'; \
|
||||
|
||||
+5
-6
@@ -12,8 +12,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.
|
||||
* mapped to a value. The keys are not sorted. It is implemented as a flat
|
||||
* hashtable with linear probing and robin hood hashing.
|
||||
*/
|
||||
|
||||
#ifndef CMC_HASHMAP_H
|
||||
@@ -100,7 +100,7 @@ static const char *cmc_string_fmt_hashmap = "struct %s<%s, %s> "
|
||||
"count:%" PRIuMAX ", "
|
||||
"load:%lf, "
|
||||
"cmp:%p, "
|
||||
"hash:%p "
|
||||
"hash:%p, "
|
||||
"alloc:%p, "
|
||||
"callbacks:%p }";
|
||||
|
||||
@@ -758,13 +758,12 @@ struct cmc_callbacks_hashmap
|
||||
{ \
|
||||
struct cmc_string str; \
|
||||
struct SNAME *m_ = _map_; \
|
||||
const char *name = #SNAME; \
|
||||
\
|
||||
int n = snprintf(str.s, cmc_string_len, cmc_string_fmt_hashmap, \
|
||||
name, #K, #V, m_, m_->buffer, m_->capacity, m_->count, \
|
||||
#SNAME, #K, #V, m_, m_->buffer, m_->capacity, m_->count, \
|
||||
m_->load, m_->cmp, m_->hash, m_->alloc, m_->callbacks); \
|
||||
\
|
||||
if (n < 0 || n == cmc_string_len) \
|
||||
if (n < 0 || n == (int)cmc_string_len) \
|
||||
return (struct cmc_string){0}; \
|
||||
\
|
||||
str.s[n] = '\0'; \
|
||||
|
||||
+11
-10
@@ -12,7 +12,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.
|
||||
* sorted. It is implemented as a flat hashtable with linear probing and robin
|
||||
* hood hashing.
|
||||
*/
|
||||
|
||||
#ifndef CMC_HASHSET_H
|
||||
@@ -99,7 +100,7 @@ static const char *cmc_string_fmt_hashset = "struct %s<%s> "
|
||||
"count:%" PRIuMAX ", "
|
||||
"load:%lf, "
|
||||
"cmp:%p, "
|
||||
"hash:%p "
|
||||
"hash:%p, "
|
||||
"alloc:%p, "
|
||||
"callbacks: %p }";
|
||||
|
||||
@@ -398,8 +399,8 @@ struct cmc_callbacks_hashset
|
||||
} \
|
||||
} \
|
||||
\
|
||||
free(_set_->buffer); \
|
||||
free(_set_); \
|
||||
_set_->alloc->free(_set_->buffer); \
|
||||
_set_->alloc->free(_set_); \
|
||||
} \
|
||||
\
|
||||
void PFX##_customize(struct SNAME *_set_, struct cmc_alloc_node *alloc, \
|
||||
@@ -611,7 +612,8 @@ struct cmc_callbacks_hashset
|
||||
\
|
||||
struct SNAME *PFX##_copy_of(struct SNAME *_set_, V (*copy_func)(V)) \
|
||||
{ \
|
||||
struct SNAME *result = PFX##_new(_set_->capacity, _set_->load, _set_->cmp, _set_->hash); \
|
||||
struct SNAME *result = PFX##_new_custom(_set_->capacity, _set_->load, _set_->cmp, \
|
||||
_set_->hash, _set_->alloc, _set_->callbacks); \
|
||||
\
|
||||
if (!result) \
|
||||
return NULL; \
|
||||
@@ -670,13 +672,12 @@ struct cmc_callbacks_hashset
|
||||
{ \
|
||||
struct cmc_string str; \
|
||||
struct SNAME *s_ = _set_; \
|
||||
const char *name = #SNAME; \
|
||||
\
|
||||
int n = snprintf(str.s, cmc_string_len, cmc_string_fmt_hashset, \
|
||||
name, #V, s_, s_->buffer, s_->capacity, s_->count, \
|
||||
#SNAME, #V, s_, s_->buffer, s_->capacity, s_->count, \
|
||||
s_->load, s_->cmp, s_->hash, s_->alloc, s_->callbacks); \
|
||||
\
|
||||
if (n < 0 || n == cmc_string_len) \
|
||||
if (n < 0 || n == (int)cmc_string_len) \
|
||||
return (struct cmc_string){0}; \
|
||||
\
|
||||
str.s[n] = '\0'; \
|
||||
@@ -894,7 +895,7 @@ struct cmc_callbacks_hashset
|
||||
\
|
||||
struct SNAME##_iter *PFX##_iter_new(struct SNAME *target) \
|
||||
{ \
|
||||
struct SNAME##_iter *iter = malloc(sizeof(struct SNAME##_iter)); \
|
||||
struct SNAME##_iter *iter = target->alloc->malloc(sizeof(struct SNAME##_iter)); \
|
||||
\
|
||||
if (!iter) \
|
||||
return NULL; \
|
||||
@@ -906,7 +907,7 @@ struct cmc_callbacks_hashset
|
||||
\
|
||||
void PFX##_iter_free(struct SNAME##_iter *iter) \
|
||||
{ \
|
||||
free(iter); \
|
||||
iter->target->alloc->free(iter); \
|
||||
} \
|
||||
\
|
||||
void PFX##_iter_init(struct SNAME##_iter *iter, struct SNAME *target) \
|
||||
|
||||
+16
-10
@@ -93,7 +93,7 @@ static const char *cmc_string_fmt_heap = "struct %s<%s> "
|
||||
"capacity:%" PRIuMAX ", "
|
||||
"count:%" PRIuMAX ", "
|
||||
"type:%s, "
|
||||
"cmp:%p "
|
||||
"cmp:%p, "
|
||||
"alloc:%p, "
|
||||
"callbacks: %p}";
|
||||
|
||||
@@ -336,8 +336,8 @@ struct cmc_callbacks_heap
|
||||
} \
|
||||
} \
|
||||
\
|
||||
free(_heap_->buffer); \
|
||||
free(_heap_); \
|
||||
_heap_->alloc->free(_heap_->buffer); \
|
||||
_heap_->alloc->free(_heap_); \
|
||||
} \
|
||||
\
|
||||
void PFX##_customize(struct SNAME *_heap_, struct cmc_alloc_node *alloc, \
|
||||
@@ -436,7 +436,7 @@ struct cmc_callbacks_heap
|
||||
if (capacity < PFX##_count(_heap_)) \
|
||||
return false; \
|
||||
\
|
||||
V *new_buffer = realloc(_heap_->buffer, sizeof(V) * capacity); \
|
||||
V *new_buffer = _heap_->alloc->realloc(_heap_->buffer, sizeof(V) * capacity); \
|
||||
\
|
||||
if (!new_buffer) \
|
||||
return false; \
|
||||
@@ -449,7 +449,8 @@ struct cmc_callbacks_heap
|
||||
\
|
||||
struct SNAME *PFX##_copy_of(struct SNAME *_heap_, V (*copy_func)(V)) \
|
||||
{ \
|
||||
struct SNAME *result = PFX##_new(_heap_->capacity, _heap_->HO, _heap_->cmp); \
|
||||
struct SNAME *result = PFX##_new_custom(_heap_->capacity, _heap_->HO, _heap_->cmp, \
|
||||
_heap_->alloc, _heap_->callbacks); \
|
||||
\
|
||||
if (!result) \
|
||||
return NULL; \
|
||||
@@ -485,18 +486,23 @@ struct cmc_callbacks_heap
|
||||
{ \
|
||||
struct cmc_string str; \
|
||||
struct 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); \
|
||||
int n = snprintf(str.s, cmc_string_len, cmc_string_fmt_heap, \
|
||||
#SNAME, #V, h_, h_->buffer, h_->capacity, h_->count, \
|
||||
t, h_->cmp, h_->alloc, h_->callbacks); \
|
||||
\
|
||||
if (n < 0 || n == (int)cmc_string_len) \
|
||||
return (struct cmc_string){0}; \
|
||||
\
|
||||
str.s[n] = '\0'; \
|
||||
\
|
||||
return str; \
|
||||
} \
|
||||
\
|
||||
struct SNAME##_iter *PFX##_iter_new(struct SNAME *target) \
|
||||
{ \
|
||||
struct SNAME##_iter *iter = malloc(sizeof(struct SNAME##_iter)); \
|
||||
struct SNAME##_iter *iter = target->alloc->malloc(sizeof(struct SNAME##_iter)); \
|
||||
\
|
||||
if (!iter) \
|
||||
return NULL; \
|
||||
@@ -508,7 +514,7 @@ struct cmc_callbacks_heap
|
||||
\
|
||||
void PFX##_iter_free(struct SNAME##_iter *iter) \
|
||||
{ \
|
||||
free(iter); \
|
||||
iter->target->alloc->free(iter); \
|
||||
} \
|
||||
\
|
||||
void PFX##_iter_init(struct SNAME##_iter *iter, struct SNAME *target) \
|
||||
|
||||
+1043
-903
File diff suppressed because it is too large.
Load diff
+149
-34
@@ -33,10 +33,66 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "../utl/cmc_string.h"
|
||||
|
||||
/* -------------------------------------------------------------------------------------------------
|
||||
* Core functionalities of the C Macro Collections Library
|
||||
------------------------------------------------------------------------------------------------ */
|
||||
#ifndef CMC_CORE_H
|
||||
#define CMC_CORE_H
|
||||
|
||||
/**
|
||||
* struct cmc_string
|
||||
*
|
||||
* Used by all collections when calling the to_string function.
|
||||
*/
|
||||
struct cmc_string
|
||||
{
|
||||
char s[400];
|
||||
};
|
||||
|
||||
static const size_t cmc_string_len = 400;
|
||||
|
||||
/**
|
||||
* struct cmc_alloc_node
|
||||
*
|
||||
* Custom allocation node. Allows collections to use custom allocation functions.
|
||||
*/
|
||||
struct cmc_alloc_node
|
||||
{
|
||||
void *(*malloc)(size_t);
|
||||
void *(*calloc)(size_t, size_t);
|
||||
void *(*realloc)(void *, size_t);
|
||||
void (*free)(void *);
|
||||
} cmc_alloc_node_default = {malloc, calloc, realloc, free};
|
||||
|
||||
#endif /* CMC_CORE_H */
|
||||
|
||||
/* -------------------------------------------------------------------------------------------------
|
||||
* LinkedList specific
|
||||
------------------------------------------------------------------------------------------------ */
|
||||
/* to_string format */
|
||||
static const char *cmc_string_fmt_linkedlist = "%s at %p { count:%" PRIuMAX ", head:%p, tail:%p }";
|
||||
static const char *cmc_string_fmt_linkedlist = "struct %s<%s> "
|
||||
"at %p { "
|
||||
"count:%" PRIuMAX ", "
|
||||
"head:%p, "
|
||||
"tail:%p, "
|
||||
"alloc:%p, "
|
||||
"callbacks:%p }";
|
||||
|
||||
/**
|
||||
* Custom LinkedList callbacks.
|
||||
*
|
||||
* There are two types of callbacks, 'before' and 'after':
|
||||
* <before|after>_<function_name>
|
||||
*/
|
||||
struct cmc_callbacks_linkedlist
|
||||
{
|
||||
void (*before_clear)(void *);
|
||||
void (*after_clear)(void *);
|
||||
void (*before_free)(void *);
|
||||
void (*after_free)(void *);
|
||||
// TODO implement all callbacks
|
||||
};
|
||||
|
||||
#define CMC_GENERATE_LINKEDLIST(PFX, SNAME, V) \
|
||||
CMC_GENERATE_LINKEDLIST_HEADER(PFX, SNAME, V) \
|
||||
@@ -48,7 +104,9 @@ static const char *cmc_string_fmt_linkedlist = "%s at %p { count:%" PRIuMAX ", h
|
||||
#define CMC_WRAPGEN_LINKEDLIST_SOURCE(PFX, SNAME, K, V) \
|
||||
CMC_GENERATE_LINKEDLIST_SOURCE(PFX, SNAME, V)
|
||||
|
||||
/* HEADER ********************************************************************/
|
||||
/* -------------------------------------------------------------------------------------------------
|
||||
* Header
|
||||
------------------------------------------------------------------------------------------------ */
|
||||
#define CMC_GENERATE_LINKEDLIST_HEADER(PFX, SNAME, V) \
|
||||
\
|
||||
/* Linked List Structure */ \
|
||||
@@ -68,6 +126,12 @@ static const char *cmc_string_fmt_linkedlist = "%s at %p { count:%" PRIuMAX ", h
|
||||
\
|
||||
/* Function that returns an iterator to the end of the list */ \
|
||||
struct SNAME##_iter (*it_end)(struct SNAME *); \
|
||||
\
|
||||
/* Custom allocation functions */ \
|
||||
struct cmc_alloc_node *alloc; \
|
||||
\
|
||||
/* Custom callback functions */ \
|
||||
struct cmc_callbacks_linkedlist *callbacks; \
|
||||
}; \
|
||||
\
|
||||
/* Doubly-linked list node */ \
|
||||
@@ -105,8 +169,13 @@ static const char *cmc_string_fmt_linkedlist = "%s at %p { count:%" PRIuMAX ", h
|
||||
/* Collection Functions */ \
|
||||
/* Collection Allocation and Deallocation */ \
|
||||
struct SNAME *PFX##_new(void); \
|
||||
struct SNAME *PFX##_new_custom(struct cmc_alloc_node *alloc, \
|
||||
struct cmc_callbacks_linkedlist *callbacks); \
|
||||
void PFX##_clear(struct SNAME *_list_, void (*deallocator)(V)); \
|
||||
void PFX##_free(struct SNAME *_list_, void (*deallocator)(V)); \
|
||||
/* Customization of Allocation and Callbacks */ \
|
||||
void PFX##_customize(struct SNAME *_list_, struct cmc_alloc_node *alloc, \
|
||||
struct cmc_callbacks_linkedlist *callbacks); \
|
||||
/* Collection Input and Output */ \
|
||||
bool PFX##_push_front(struct SNAME *_list_, V element); \
|
||||
bool PFX##_push_at(struct SNAME *_list_, V element, size_t index); \
|
||||
@@ -130,8 +199,8 @@ static const char *cmc_string_fmt_linkedlist = "%s at %p { count:%" PRIuMAX ", h
|
||||
\
|
||||
/* Node Related Functions */ \
|
||||
/* Node Allocation and Deallocation */ \
|
||||
struct SNAME##_node *PFX##_new_node(V element); \
|
||||
void PFX##_free_node(struct SNAME##_node *_node_); \
|
||||
struct SNAME##_node *PFX##_new_node(struct SNAME *_list_, V element); \
|
||||
void PFX##_free_node(struct SNAME *_list_, struct SNAME##_node *_node_); \
|
||||
/* Node Access Relative to a Linked List */ \
|
||||
struct SNAME##_node *PFX##_head(struct SNAME *_list_); \
|
||||
struct SNAME##_node *PFX##_get_node(struct SNAME *_list_, size_t index); \
|
||||
@@ -167,9 +236,11 @@ static const char *cmc_string_fmt_linkedlist = "%s at %p { count:%" PRIuMAX ", h
|
||||
V PFX##_iter_value(struct SNAME##_iter *iter); \
|
||||
V *PFX##_iter_rvalue(struct SNAME##_iter *iter); \
|
||||
size_t PFX##_iter_index(struct SNAME##_iter *iter); \
|
||||
struct SNAME##_node *PFX##_iter_node(struct SNAME##_iter *iter); \
|
||||
\
|
||||
/* SOURCE ********************************************************************/
|
||||
struct SNAME##_node *PFX##_iter_node(struct SNAME##_iter *iter);
|
||||
|
||||
/* -------------------------------------------------------------------------------------------------
|
||||
* Source
|
||||
------------------------------------------------------------------------------------------------ */
|
||||
#define CMC_GENERATE_LINKEDLIST_SOURCE(PFX, SNAME, V) \
|
||||
\
|
||||
/* Implementation Detail Functions */ \
|
||||
@@ -178,7 +249,9 @@ static const char *cmc_string_fmt_linkedlist = "%s at %p { count:%" PRIuMAX ", h
|
||||
\
|
||||
struct SNAME *PFX##_new(void) \
|
||||
{ \
|
||||
struct SNAME *_list_ = malloc(sizeof(struct SNAME)); \
|
||||
struct cmc_alloc_node *alloc = &cmc_alloc_node_default; \
|
||||
\
|
||||
struct SNAME *_list_ = alloc->malloc(sizeof(struct SNAME)); \
|
||||
\
|
||||
if (!_list_) \
|
||||
return NULL; \
|
||||
@@ -190,6 +263,33 @@ static const char *cmc_string_fmt_linkedlist = "%s at %p { count:%" PRIuMAX ", h
|
||||
_list_->it_start = PFX##_impl_it_start; \
|
||||
_list_->it_end = PFX##_impl_it_end; \
|
||||
\
|
||||
_list_->alloc = alloc; \
|
||||
_list_->callbacks = NULL; \
|
||||
\
|
||||
return _list_; \
|
||||
} \
|
||||
\
|
||||
struct SNAME *PFX##_new_custom(struct cmc_alloc_node *alloc, \
|
||||
struct cmc_callbacks_linkedlist *callbacks) \
|
||||
{ \
|
||||
if (!alloc) \
|
||||
alloc = &cmc_alloc_node_default; \
|
||||
\
|
||||
struct SNAME *_list_ = alloc->malloc(sizeof(struct SNAME)); \
|
||||
\
|
||||
if (!_list_) \
|
||||
return NULL; \
|
||||
\
|
||||
_list_->count = 0; \
|
||||
_list_->head = NULL; \
|
||||
_list_->tail = NULL; \
|
||||
\
|
||||
_list_->it_start = PFX##_impl_it_start; \
|
||||
_list_->it_end = PFX##_impl_it_end; \
|
||||
\
|
||||
_list_->alloc = alloc; \
|
||||
_list_->callbacks = callbacks; \
|
||||
\
|
||||
return _list_; \
|
||||
} \
|
||||
\
|
||||
@@ -206,7 +306,7 @@ static const char *cmc_string_fmt_linkedlist = "%s at %p { count:%" PRIuMAX ", h
|
||||
deallocator(scan->data); \
|
||||
} \
|
||||
\
|
||||
free(scan); \
|
||||
_list_->alloc->free(scan); \
|
||||
\
|
||||
scan = _list_->head; \
|
||||
} \
|
||||
@@ -220,12 +320,22 @@ static const char *cmc_string_fmt_linkedlist = "%s at %p { count:%" PRIuMAX ", h
|
||||
{ \
|
||||
PFX##_clear(_list_, deallocator); \
|
||||
\
|
||||
free(_list_); \
|
||||
_list_->alloc->free(_list_); \
|
||||
} \
|
||||
\
|
||||
void PFX##_customize(struct SNAME *_list_, struct cmc_alloc_node *alloc, \
|
||||
struct cmc_callbacks_linkedlist *callbacks) \
|
||||
{ \
|
||||
if (alloc) \
|
||||
_list_->alloc = alloc; \
|
||||
\
|
||||
if (callbacks) \
|
||||
_list_->callbacks = callbacks; \
|
||||
} \
|
||||
\
|
||||
bool PFX##_push_front(struct SNAME *_list_, V element) \
|
||||
{ \
|
||||
struct SNAME##_node *_node_ = PFX##_new_node(element); \
|
||||
struct SNAME##_node *_node_ = PFX##_new_node(_list_, element); \
|
||||
\
|
||||
if (!_node_) \
|
||||
return false; \
|
||||
@@ -261,7 +371,7 @@ static const char *cmc_string_fmt_linkedlist = "%s at %p { count:%" PRIuMAX ", h
|
||||
return PFX##_push_back(_list_, element); \
|
||||
} \
|
||||
\
|
||||
struct SNAME##_node *_node_ = PFX##_new_node(element); \
|
||||
struct SNAME##_node *_node_ = PFX##_new_node(_list_, element); \
|
||||
\
|
||||
if (!_node_) \
|
||||
return false; \
|
||||
@@ -280,7 +390,7 @@ static const char *cmc_string_fmt_linkedlist = "%s at %p { count:%" PRIuMAX ", h
|
||||
\
|
||||
bool PFX##_push_back(struct SNAME *_list_, V element) \
|
||||
{ \
|
||||
struct SNAME##_node *_node_ = PFX##_new_node(element); \
|
||||
struct SNAME##_node *_node_ = PFX##_new_node(_list_, element); \
|
||||
\
|
||||
if (!_node_) \
|
||||
return false; \
|
||||
@@ -310,7 +420,7 @@ static const char *cmc_string_fmt_linkedlist = "%s at %p { count:%" PRIuMAX ", h
|
||||
struct SNAME##_node *_node_ = _list_->head; \
|
||||
_list_->head = _list_->head->next; \
|
||||
\
|
||||
free(_node_); \
|
||||
_list_->alloc->free(_node_); \
|
||||
\
|
||||
if (_list_->head == NULL) \
|
||||
_list_->tail = NULL; \
|
||||
@@ -347,7 +457,7 @@ static const char *cmc_string_fmt_linkedlist = "%s at %p { count:%" PRIuMAX ", h
|
||||
_node_->next->prev = _node_->prev; \
|
||||
_node_->prev->next = _node_->next; \
|
||||
\
|
||||
free(_node_); \
|
||||
_list_->alloc->free(_node_); \
|
||||
\
|
||||
_list_->count--; \
|
||||
\
|
||||
@@ -362,7 +472,7 @@ static const char *cmc_string_fmt_linkedlist = "%s at %p { count:%" PRIuMAX ", h
|
||||
struct SNAME##_node *_node_ = _list_->tail; \
|
||||
_list_->tail = _list_->tail->prev; \
|
||||
\
|
||||
free(_node_); \
|
||||
_list_->alloc->free(_node_); \
|
||||
\
|
||||
if (_list_->tail == NULL) \
|
||||
_list_->head = NULL; \
|
||||
@@ -446,7 +556,7 @@ static const char *cmc_string_fmt_linkedlist = "%s at %p { count:%" PRIuMAX ", h
|
||||
\
|
||||
struct SNAME *PFX##_copy_of(struct SNAME *_list_, V (*copy_func)(V)) \
|
||||
{ \
|
||||
struct SNAME *result = PFX##_new(); \
|
||||
struct SNAME *result = PFX##_new_custom(_list_->alloc, _list_->callbacks); \
|
||||
\
|
||||
if (!result) \
|
||||
return NULL; \
|
||||
@@ -460,9 +570,9 @@ static const char *cmc_string_fmt_linkedlist = "%s at %p { count:%" PRIuMAX ", h
|
||||
struct SNAME##_node *new_node; \
|
||||
\
|
||||
if (copy_func) \
|
||||
new_node = PFX##_new_node(copy_func(scan->data)); \
|
||||
new_node = PFX##_new_node(_list_, copy_func(scan->data)); \
|
||||
else \
|
||||
new_node = PFX##_new_node(scan->data); \
|
||||
new_node = PFX##_new_node(_list_, scan->data); \
|
||||
\
|
||||
if (!result->head) \
|
||||
{ \
|
||||
@@ -508,17 +618,22 @@ static const char *cmc_string_fmt_linkedlist = "%s at %p { count:%" PRIuMAX ", h
|
||||
{ \
|
||||
struct cmc_string str; \
|
||||
struct 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); \
|
||||
int n = snprintf(str.s, cmc_string_len, cmc_string_fmt_linkedlist, \
|
||||
#SNAME, #V, l_, l_->count, l_->head, l_->tail, \
|
||||
l_->alloc, l_->callbacks); \
|
||||
\
|
||||
if (n < 0 || n == (int)cmc_string_len) \
|
||||
return (struct cmc_string){0}; \
|
||||
\
|
||||
str.s[n] = '\0'; \
|
||||
\
|
||||
return str; \
|
||||
} \
|
||||
\
|
||||
struct SNAME##_node *PFX##_new_node(V element) \
|
||||
struct SNAME##_node *PFX##_new_node(struct SNAME *_list_, V element) \
|
||||
{ \
|
||||
struct SNAME##_node *_node_ = malloc(sizeof(struct SNAME##_node)); \
|
||||
struct SNAME##_node *_node_ = _list_->alloc->malloc(sizeof(struct SNAME##_node)); \
|
||||
\
|
||||
if (!_node_) \
|
||||
return NULL; \
|
||||
@@ -530,9 +645,9 @@ static const char *cmc_string_fmt_linkedlist = "%s at %p { count:%" PRIuMAX ", h
|
||||
return _node_; \
|
||||
} \
|
||||
\
|
||||
void PFX##_free_node(struct SNAME##_node *_node_) \
|
||||
void PFX##_free_node(struct SNAME *_list_, struct SNAME##_node *_node_) \
|
||||
{ \
|
||||
free(_node_); \
|
||||
_list_->alloc->free(_node_); \
|
||||
} \
|
||||
\
|
||||
struct SNAME##_node *PFX##_head(struct SNAME *_list_) \
|
||||
@@ -577,7 +692,7 @@ static const char *cmc_string_fmt_linkedlist = "%s at %p { count:%" PRIuMAX ", h
|
||||
\
|
||||
bool PFX##_insert_after(struct SNAME *_owner_, struct SNAME##_node *_node_, V element) \
|
||||
{ \
|
||||
struct SNAME##_node *new_node = PFX##_new_node(element); \
|
||||
struct SNAME##_node *new_node = PFX##_new_node(_owner_, element); \
|
||||
\
|
||||
if (!new_node) \
|
||||
return false; \
|
||||
@@ -599,7 +714,7 @@ static const char *cmc_string_fmt_linkedlist = "%s at %p { count:%" PRIuMAX ", h
|
||||
\
|
||||
bool PFX##_insert_before(struct SNAME *_owner_, struct SNAME##_node *_node_, V element) \
|
||||
{ \
|
||||
struct SNAME##_node *new_node = PFX##_new_node(element); \
|
||||
struct SNAME##_node *new_node = PFX##_new_node(_owner_, element); \
|
||||
\
|
||||
if (!new_node) \
|
||||
return false; \
|
||||
@@ -634,7 +749,7 @@ static const char *cmc_string_fmt_linkedlist = "%s at %p { count:%" PRIuMAX ", h
|
||||
else \
|
||||
_owner_->tail = _node_; \
|
||||
\
|
||||
free(tmp); \
|
||||
_owner_->alloc->free(tmp); \
|
||||
\
|
||||
_owner_->count--; \
|
||||
\
|
||||
@@ -653,7 +768,7 @@ static const char *cmc_string_fmt_linkedlist = "%s at %p { count:%" PRIuMAX ", h
|
||||
else \
|
||||
_owner_->tail = _node_->prev; \
|
||||
\
|
||||
free(_node_); \
|
||||
_owner_->alloc->free(_node_); \
|
||||
\
|
||||
_owner_->count--; \
|
||||
\
|
||||
@@ -675,7 +790,7 @@ static const char *cmc_string_fmt_linkedlist = "%s at %p { count:%" PRIuMAX ", h
|
||||
else \
|
||||
_owner_->head = _node_; \
|
||||
\
|
||||
free(tmp); \
|
||||
_owner_->alloc->free(tmp); \
|
||||
\
|
||||
_owner_->count--; \
|
||||
\
|
||||
@@ -694,7 +809,7 @@ static const char *cmc_string_fmt_linkedlist = "%s at %p { count:%" PRIuMAX ", h
|
||||
\
|
||||
struct SNAME##_iter *PFX##_iter_new(struct SNAME *target) \
|
||||
{ \
|
||||
struct SNAME##_iter *iter = malloc(sizeof(struct SNAME##_iter)); \
|
||||
struct SNAME##_iter *iter = target->alloc->malloc(sizeof(struct SNAME##_iter)); \
|
||||
\
|
||||
if (!iter) \
|
||||
return NULL; \
|
||||
@@ -706,7 +821,7 @@ static const char *cmc_string_fmt_linkedlist = "%s at %p { count:%" PRIuMAX ", h
|
||||
\
|
||||
void PFX##_iter_free(struct SNAME##_iter *iter) \
|
||||
{ \
|
||||
free(iter); \
|
||||
iter->target->alloc->free(iter); \
|
||||
} \
|
||||
\
|
||||
void PFX##_iter_init(struct SNAME##_iter *iter, struct SNAME *target) \
|
||||
|
||||
+144
-18
@@ -48,10 +48,66 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "../utl/cmc_string.h"
|
||||
|
||||
/* -------------------------------------------------------------------------------------------------
|
||||
* Core functionalities of the C Macro Collections Library
|
||||
------------------------------------------------------------------------------------------------ */
|
||||
#ifndef CMC_CORE_H
|
||||
#define CMC_CORE_H
|
||||
|
||||
/**
|
||||
* struct cmc_string
|
||||
*
|
||||
* Used by all collections when calling the to_string function.
|
||||
*/
|
||||
struct cmc_string
|
||||
{
|
||||
char s[400];
|
||||
};
|
||||
|
||||
static const size_t cmc_string_len = 400;
|
||||
|
||||
/**
|
||||
* struct cmc_alloc_node
|
||||
*
|
||||
* Custom allocation node. Allows collections to use custom allocation functions.
|
||||
*/
|
||||
struct cmc_alloc_node
|
||||
{
|
||||
void *(*malloc)(size_t);
|
||||
void *(*calloc)(size_t, size_t);
|
||||
void *(*realloc)(void *, size_t);
|
||||
void (*free)(void *);
|
||||
} cmc_alloc_node_default = {malloc, calloc, realloc, free};
|
||||
|
||||
#endif /* CMC_CORE_H */
|
||||
|
||||
/* -------------------------------------------------------------------------------------------------
|
||||
* List specific
|
||||
------------------------------------------------------------------------------------------------ */
|
||||
/* to_string format */
|
||||
static const char *cmc_string_fmt_list = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", count:%" PRIuMAX " }";
|
||||
static const char *cmc_string_fmt_list = "struct %s<%s> "
|
||||
"at %p { "
|
||||
"buffer:%p, "
|
||||
"capacity:%" PRIuMAX ", "
|
||||
"count:%" PRIuMAX ", "
|
||||
"alloc:%p, "
|
||||
"callbacks:%p }";
|
||||
|
||||
/**
|
||||
* Custom List callbacks.
|
||||
*
|
||||
* There are two types of callbacks, 'before' and 'after':
|
||||
* <before|after>_<function_name>
|
||||
*/
|
||||
struct cmc_callbacks_list
|
||||
{
|
||||
void (*before_clear)(void *);
|
||||
void (*after_clear)(void *);
|
||||
void (*before_free)(void *);
|
||||
void (*after_free)(void *);
|
||||
// TODO implement all callbacks
|
||||
};
|
||||
|
||||
#define CMC_GENERATE_LIST(PFX, SNAME, V) \
|
||||
CMC_GENERATE_LIST_HEADER(PFX, SNAME, V) \
|
||||
@@ -63,7 +119,9 @@ static const char *cmc_string_fmt_list = "%s at %p { buffer:%p, capacity:%" PRIu
|
||||
#define CMC_WRAPGEN_LIST_SOURCE(PFX, SNAME, K, V) \
|
||||
CMC_GENERATE_LIST_SOURCE(PFX, SNAME, V)
|
||||
|
||||
/* HEADER ********************************************************************/
|
||||
/* -------------------------------------------------------------------------------------------------
|
||||
* Header
|
||||
------------------------------------------------------------------------------------------------ */
|
||||
#define CMC_GENERATE_LIST_HEADER(PFX, SNAME, V) \
|
||||
\
|
||||
/* List Structure */ \
|
||||
@@ -83,6 +141,12 @@ static const char *cmc_string_fmt_list = "%s at %p { buffer:%p, capacity:%" PRIu
|
||||
\
|
||||
/* Function that returns an iterator to the end of the list */ \
|
||||
struct SNAME##_iter (*it_end)(struct SNAME *); \
|
||||
\
|
||||
/* Custom allocation functions */ \
|
||||
struct cmc_alloc_node *alloc; \
|
||||
\
|
||||
/* Custom callback functions */ \
|
||||
struct cmc_callbacks_list *callbacks; \
|
||||
}; \
|
||||
\
|
||||
/* List Iterator */ \
|
||||
@@ -104,9 +168,14 @@ static const char *cmc_string_fmt_list = "%s at %p { buffer:%p, capacity:%" PRIu
|
||||
/* Collection Functions */ \
|
||||
/* Collection Allocation and Deallocation */ \
|
||||
struct SNAME *PFX##_new(size_t capacity); \
|
||||
struct SNAME *PFX##_new_custom(size_t capacity, struct cmc_alloc_node *alloc, \
|
||||
struct cmc_callbacks_list *callbacks); \
|
||||
struct SNAME *PFX##_new_from(V *elements, size_t size); \
|
||||
void PFX##_clear(struct SNAME *_list_, void (*deallocator)(V)); \
|
||||
void PFX##_free(struct SNAME *_list_, void (*deallocator)(V)); \
|
||||
/* Customization of Allocation and Callbacks */ \
|
||||
void PFX##_customize(struct SNAME *_list_, struct cmc_alloc_node *alloc, \
|
||||
struct cmc_callbacks_list *callbacks); \
|
||||
/* Collection Input and Output */ \
|
||||
bool PFX##_push_front(struct SNAME *_list_, V element); \
|
||||
bool PFX##_push_at(struct SNAME *_list_, V element, size_t index); \
|
||||
@@ -160,9 +229,11 @@ static const char *cmc_string_fmt_list = "%s at %p { buffer:%p, capacity:%" PRIu
|
||||
/* Iterator Access */ \
|
||||
V PFX##_iter_value(struct SNAME##_iter *iter); \
|
||||
V *PFX##_iter_rvalue(struct SNAME##_iter *iter); \
|
||||
size_t PFX##_iter_index(struct SNAME##_iter *iter); \
|
||||
\
|
||||
/* SOURCE ********************************************************************/
|
||||
size_t PFX##_iter_index(struct SNAME##_iter *iter);
|
||||
|
||||
/* -------------------------------------------------------------------------------------------------
|
||||
* Source
|
||||
------------------------------------------------------------------------------------------------ */
|
||||
#define CMC_GENERATE_LIST_SOURCE(PFX, SNAME, V) \
|
||||
\
|
||||
/* Implementation Detail Functions */ \
|
||||
@@ -171,19 +242,21 @@ static const char *cmc_string_fmt_list = "%s at %p { buffer:%p, capacity:%" PRIu
|
||||
\
|
||||
struct SNAME *PFX##_new(size_t capacity) \
|
||||
{ \
|
||||
struct cmc_alloc_node *alloc = &cmc_alloc_node_default; \
|
||||
\
|
||||
if (capacity < 1) \
|
||||
return NULL; \
|
||||
\
|
||||
struct SNAME *_list_ = malloc(sizeof(struct SNAME)); \
|
||||
struct SNAME *_list_ = alloc->malloc(sizeof(struct SNAME)); \
|
||||
\
|
||||
if (!_list_) \
|
||||
return NULL; \
|
||||
\
|
||||
_list_->buffer = calloc(capacity, sizeof(V)); \
|
||||
_list_->buffer = alloc->calloc(capacity, sizeof(V)); \
|
||||
\
|
||||
if (!_list_->buffer) \
|
||||
{ \
|
||||
free(_list_); \
|
||||
alloc->free(_list_); \
|
||||
return NULL; \
|
||||
} \
|
||||
\
|
||||
@@ -193,6 +266,43 @@ static const char *cmc_string_fmt_list = "%s at %p { buffer:%p, capacity:%" PRIu
|
||||
_list_->it_start = PFX##_impl_it_start; \
|
||||
_list_->it_end = PFX##_impl_it_end; \
|
||||
\
|
||||
_list_->alloc = alloc; \
|
||||
_list_->callbacks = NULL; \
|
||||
\
|
||||
return _list_; \
|
||||
} \
|
||||
\
|
||||
struct SNAME *PFX##_new_custom(size_t capacity, struct cmc_alloc_node *alloc, \
|
||||
struct cmc_callbacks_list *callbacks) \
|
||||
{ \
|
||||
if (capacity < 1) \
|
||||
return NULL; \
|
||||
\
|
||||
if (!alloc) \
|
||||
alloc = &cmc_alloc_node_default; \
|
||||
\
|
||||
struct SNAME *_list_ = alloc->malloc(sizeof(struct SNAME)); \
|
||||
\
|
||||
if (!_list_) \
|
||||
return NULL; \
|
||||
\
|
||||
_list_->buffer = alloc->calloc(capacity, sizeof(V)); \
|
||||
\
|
||||
if (!_list_->buffer) \
|
||||
{ \
|
||||
alloc->free(_list_); \
|
||||
return NULL; \
|
||||
} \
|
||||
\
|
||||
_list_->capacity = capacity; \
|
||||
_list_->count = 0; \
|
||||
\
|
||||
_list_->it_start = PFX##_impl_it_start; \
|
||||
_list_->it_end = PFX##_impl_it_end; \
|
||||
\
|
||||
_list_->alloc = alloc; \
|
||||
_list_->callbacks = callbacks; \
|
||||
\
|
||||
return _list_; \
|
||||
} \
|
||||
\
|
||||
@@ -234,8 +344,18 @@ static const char *cmc_string_fmt_list = "%s at %p { buffer:%p, capacity:%" PRIu
|
||||
deallocator(_list_->buffer[i]); \
|
||||
} \
|
||||
\
|
||||
free(_list_->buffer); \
|
||||
free(_list_); \
|
||||
_list_->alloc->free(_list_->buffer); \
|
||||
_list_->alloc->free(_list_); \
|
||||
} \
|
||||
\
|
||||
void PFX##_customize(struct SNAME *_list_, struct cmc_alloc_node *alloc, \
|
||||
struct cmc_callbacks_list *callbacks) \
|
||||
{ \
|
||||
if (alloc) \
|
||||
_list_->alloc = alloc; \
|
||||
\
|
||||
if (callbacks) \
|
||||
_list_->callbacks = callbacks; \
|
||||
} \
|
||||
\
|
||||
bool PFX##_push_front(struct SNAME *_list_, V element) \
|
||||
@@ -536,7 +656,7 @@ static const char *cmc_string_fmt_list = "%s at %p { buffer:%p, capacity:%" PRIu
|
||||
if (capacity < PFX##_count(_list_)) \
|
||||
return false; \
|
||||
\
|
||||
V *new_buffer = realloc(_list_->buffer, sizeof(V) * capacity); \
|
||||
V *new_buffer = _list_->alloc->realloc(_list_->buffer, sizeof(V) * capacity); \
|
||||
\
|
||||
if (!new_buffer) \
|
||||
return false; \
|
||||
@@ -549,7 +669,8 @@ static const char *cmc_string_fmt_list = "%s at %p { buffer:%p, capacity:%" PRIu
|
||||
\
|
||||
struct SNAME *PFX##_copy_of(struct SNAME *_list_, V (*copy_func)(V)) \
|
||||
{ \
|
||||
struct SNAME *result = PFX##_new(_list_->capacity); \
|
||||
struct SNAME *result = PFX##_new_custom(_list_->capacity, _list_->alloc, \
|
||||
_list_->callbacks); \
|
||||
\
|
||||
if (!result) \
|
||||
return NULL; \
|
||||
@@ -585,17 +706,22 @@ static const char *cmc_string_fmt_list = "%s at %p { buffer:%p, capacity:%" PRIu
|
||||
{ \
|
||||
struct cmc_string str; \
|
||||
struct 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); \
|
||||
int n = snprintf(str.s, cmc_string_len, cmc_string_fmt_list, \
|
||||
#SNAME, #V, l_, l_->buffer, l_->capacity, l_->count, \
|
||||
l_->alloc, l_->callbacks); \
|
||||
\
|
||||
if (n < 0 || n == (int)cmc_string_len) \
|
||||
return (struct cmc_string){0}; \
|
||||
\
|
||||
str.s[n] = '\0'; \
|
||||
\
|
||||
return str; \
|
||||
} \
|
||||
\
|
||||
struct SNAME##_iter *PFX##_iter_new(struct SNAME *target) \
|
||||
{ \
|
||||
struct SNAME##_iter *iter = malloc(sizeof(struct SNAME##_iter)); \
|
||||
struct SNAME##_iter *iter = target->alloc->malloc(sizeof(struct SNAME##_iter)); \
|
||||
\
|
||||
if (!iter) \
|
||||
return NULL; \
|
||||
@@ -607,7 +733,7 @@ static const char *cmc_string_fmt_list = "%s at %p { buffer:%p, capacity:%" PRIu
|
||||
\
|
||||
void PFX##_iter_free(struct SNAME##_iter *iter) \
|
||||
{ \
|
||||
free(iter); \
|
||||
iter->target->alloc->free(iter); \
|
||||
} \
|
||||
\
|
||||
void PFX##_iter_init(struct SNAME##_iter *iter, struct SNAME *target) \
|
||||
|
||||
+1177
-1053
File diff suppressed because it is too large.
Load diff
+171
-48
@@ -26,11 +26,43 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "../utl/cmc_string.h"
|
||||
|
||||
/* 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 }";
|
||||
/* -------------------------------------------------------------------------------------------------
|
||||
* Core functionalities of the C Macro Collections Library
|
||||
------------------------------------------------------------------------------------------------ */
|
||||
#ifndef CMC_CORE_H
|
||||
#define CMC_CORE_H
|
||||
|
||||
/**
|
||||
* struct cmc_string
|
||||
*
|
||||
* Used by all collections when calling the to_string function.
|
||||
*/
|
||||
struct cmc_string
|
||||
{
|
||||
char s[400];
|
||||
};
|
||||
|
||||
static const size_t cmc_string_len = 400;
|
||||
|
||||
/**
|
||||
* struct cmc_alloc_node
|
||||
*
|
||||
* Custom allocation node. Allows collections to use custom allocation functions.
|
||||
*/
|
||||
struct cmc_alloc_node
|
||||
{
|
||||
void *(*malloc)(size_t);
|
||||
void *(*calloc)(size_t, size_t);
|
||||
void *(*realloc)(void *, size_t);
|
||||
void (*free)(void *);
|
||||
} cmc_alloc_node_default = {malloc, calloc, realloc, free};
|
||||
|
||||
#endif /* CMC_CORE_H */
|
||||
|
||||
/* -------------------------------------------------------------------------------------------------
|
||||
* Hashtable Implementation
|
||||
------------------------------------------------------------------------------------------------ */
|
||||
#ifndef CMC_IMPL_HASHTABLE_STATE
|
||||
#define CMC_IMPL_HASHTABLE_STATE
|
||||
|
||||
@@ -43,42 +75,52 @@ enum cmc_entry_state
|
||||
|
||||
#endif /* CMC_IMPL_HASHTABLE_STATE */
|
||||
|
||||
#ifndef CMC_IMPL_HASHTABLE_SETUP
|
||||
#define CMC_IMPL_HASHTABLE_SETUP
|
||||
#ifndef CMC_IMPL_HASHTABLE_PRIMES
|
||||
#define CMC_IMPL_HASHTABLE_PRIMES
|
||||
|
||||
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};
|
||||
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 */
|
||||
#endif /* CMC_IMPL_HASHTABLE_PRIMES */
|
||||
|
||||
/* -------------------------------------------------------------------------------------------------
|
||||
* MultiSet specific
|
||||
------------------------------------------------------------------------------------------------ */
|
||||
/* to_string format */
|
||||
static const char *cmc_string_fmt_multiset = "struct %s<%s> "
|
||||
"at %p { "
|
||||
"buffer:%p, "
|
||||
"capacity:%" PRIuMAX ", "
|
||||
"count:%" PRIuMAX ", "
|
||||
"cardinality:%" PRIuMAX ", "
|
||||
"load:%lf, "
|
||||
"cmp:%p, "
|
||||
"hash:%p, "
|
||||
"alloc:%p, "
|
||||
"callbacks:%p }";
|
||||
|
||||
/**
|
||||
* Custom MultiSet callbacks.
|
||||
*
|
||||
* There are two types of callbacks, 'before' and 'after':
|
||||
* <before|after>_<function_name>
|
||||
*/
|
||||
struct cmc_callbacks_multiset
|
||||
{
|
||||
void (*before_clear)(void *);
|
||||
void (*after_clear)(void *);
|
||||
void (*before_free)(void *);
|
||||
void (*after_free)(void *);
|
||||
// TODO implement all callbacks
|
||||
};
|
||||
|
||||
#define CMC_GENERATE_MULTISET(PFX, SNAME, V) \
|
||||
CMC_GENERATE_MULTISET_HEADER(PFX, SNAME, V) \
|
||||
@@ -90,7 +132,9 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531,
|
||||
#define CMC_WRAPGEN_MULTISET_SOURCE(PFX, SNAME, K, V) \
|
||||
CMC_GENERATE_MULTISET_SOURCE(PFX, SNAME, V)
|
||||
|
||||
/* HEADER ********************************************************************/
|
||||
/* -------------------------------------------------------------------------------------------------
|
||||
* Header
|
||||
------------------------------------------------------------------------------------------------ */
|
||||
#define CMC_GENERATE_MULTISET_HEADER(PFX, SNAME, V) \
|
||||
\
|
||||
/* Hashset Structure */ \
|
||||
@@ -122,6 +166,12 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531,
|
||||
\
|
||||
/* Function that returns an iterator to the end of the hashset */ \
|
||||
struct SNAME##_iter (*it_end)(struct SNAME *); \
|
||||
\
|
||||
/* Custom allocation functions */ \
|
||||
struct cmc_alloc_node *alloc; \
|
||||
\
|
||||
/* Custom callback functions */ \
|
||||
struct cmc_callbacks_multiset *callbacks; \
|
||||
}; \
|
||||
\
|
||||
struct SNAME##_entry \
|
||||
@@ -168,8 +218,14 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531,
|
||||
/* Collection Allocation and Deallocation */ \
|
||||
struct SNAME *PFX##_new(size_t capacity, double load, int (*compare)(V, V), \
|
||||
size_t (*hash)(V)); \
|
||||
struct SNAME *PFX##_new_custom(size_t capacity, double load, int (*compare)(V, V), \
|
||||
size_t (*hash)(V), struct cmc_alloc_node *alloc, \
|
||||
struct cmc_callbacks_multiset *callbacks); \
|
||||
void PFX##_clear(struct SNAME *_set_, void (*deallocator)(V)); \
|
||||
void PFX##_free(struct SNAME *_set_, void (*deallocator)(V)); \
|
||||
/* Customization of Allocation and Callbacks */ \
|
||||
void PFX##_customize(struct SNAME *_set_, struct cmc_alloc_node *alloc, \
|
||||
struct cmc_callbacks_multiset *callbacks); \
|
||||
/* Collection Input and Output */ \
|
||||
bool PFX##_insert(struct SNAME *_set_, V element); \
|
||||
bool PFX##_insert_many(struct SNAME *_set_, V element, size_t count); \
|
||||
@@ -226,9 +282,11 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531,
|
||||
/* Iterator Access */ \
|
||||
V PFX##_iter_value(struct SNAME##_iter *iter); \
|
||||
size_t PFX##_iter_multiplicity(struct SNAME##_iter *iter); \
|
||||
size_t PFX##_iter_index(struct SNAME##_iter *iter); \
|
||||
\
|
||||
/* SOURCE ********************************************************************/
|
||||
size_t PFX##_iter_index(struct SNAME##_iter *iter);
|
||||
|
||||
/* -------------------------------------------------------------------------------------------------
|
||||
* Source
|
||||
------------------------------------------------------------------------------------------------ */
|
||||
#define CMC_GENERATE_MULTISET_SOURCE(PFX, SNAME, V) \
|
||||
\
|
||||
/* Implementation Detail Functions */ \
|
||||
@@ -241,6 +299,8 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531,
|
||||
\
|
||||
struct SNAME *PFX##_new(size_t capacity, double load, int (*compare)(V, V), size_t (*hash)(V)) \
|
||||
{ \
|
||||
struct cmc_alloc_node *alloc = &cmc_alloc_node_default; \
|
||||
\
|
||||
if (capacity == 0 || load <= 0 || load >= 1) \
|
||||
return NULL; \
|
||||
\
|
||||
@@ -250,16 +310,16 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531,
|
||||
\
|
||||
size_t real_capacity = PFX##_impl_calculate_size(capacity / load); \
|
||||
\
|
||||
struct SNAME *_set_ = malloc(sizeof(struct SNAME)); \
|
||||
struct SNAME *_set_ = alloc->malloc(sizeof(struct SNAME)); \
|
||||
\
|
||||
if (!_set_) \
|
||||
return NULL; \
|
||||
\
|
||||
_set_->buffer = calloc(real_capacity, sizeof(struct SNAME##_entry)); \
|
||||
_set_->buffer = alloc->calloc(real_capacity, sizeof(struct SNAME##_entry)); \
|
||||
\
|
||||
if (!_set_->buffer) \
|
||||
{ \
|
||||
free(_set_); \
|
||||
alloc->free(_set_); \
|
||||
return NULL; \
|
||||
} \
|
||||
\
|
||||
@@ -273,6 +333,54 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531,
|
||||
_set_->it_start = PFX##_impl_it_start; \
|
||||
_set_->it_end = PFX##_impl_it_end; \
|
||||
\
|
||||
_set_->alloc = alloc; \
|
||||
_set_->callbacks = NULL; \
|
||||
\
|
||||
return _set_; \
|
||||
} \
|
||||
\
|
||||
struct SNAME *PFX##_new_custom(size_t capacity, double load, int (*compare)(V, V), \
|
||||
size_t (*hash)(V), struct cmc_alloc_node *alloc, \
|
||||
struct cmc_callbacks_multiset *callbacks) \
|
||||
{ \
|
||||
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); \
|
||||
\
|
||||
if (!alloc) \
|
||||
alloc = &cmc_alloc_node_default; \
|
||||
\
|
||||
struct SNAME *_set_ = alloc->malloc(sizeof(struct SNAME)); \
|
||||
\
|
||||
if (!_set_) \
|
||||
return NULL; \
|
||||
\
|
||||
_set_->buffer = alloc->calloc(real_capacity, sizeof(struct SNAME##_entry)); \
|
||||
\
|
||||
if (!_set_->buffer) \
|
||||
{ \
|
||||
alloc->free(_set_); \
|
||||
return NULL; \
|
||||
} \
|
||||
\
|
||||
_set_->count = 0; \
|
||||
_set_->cardinality = 0; \
|
||||
_set_->capacity = real_capacity; \
|
||||
_set_->load = load; \
|
||||
_set_->cmp = compare; \
|
||||
_set_->hash = hash; \
|
||||
\
|
||||
_set_->it_start = PFX##_impl_it_start; \
|
||||
_set_->it_end = PFX##_impl_it_end; \
|
||||
\
|
||||
_set_->alloc = alloc; \
|
||||
_set_->callbacks = callbacks; \
|
||||
\
|
||||
return _set_; \
|
||||
} \
|
||||
\
|
||||
@@ -315,6 +423,16 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531,
|
||||
free(_set_); \
|
||||
} \
|
||||
\
|
||||
void PFX##_customize(struct SNAME *_set_, struct cmc_alloc_node *alloc, \
|
||||
struct cmc_callbacks_multiset *callbacks) \
|
||||
{ \
|
||||
if (alloc) \
|
||||
_set_->alloc = alloc; \
|
||||
\
|
||||
if (callbacks) \
|
||||
_set_->callbacks = callbacks; \
|
||||
} \
|
||||
\
|
||||
bool PFX##_insert(struct SNAME *_set_, V element) \
|
||||
{ \
|
||||
bool new_node; \
|
||||
@@ -628,11 +746,16 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531,
|
||||
{ \
|
||||
struct cmc_string str; \
|
||||
struct SNAME *s_ = _set_; \
|
||||
const char *name = #SNAME; \
|
||||
\
|
||||
snprintf(str.s, cmc_string_len, cmc_string_fmt_multiset, \
|
||||
name, s_, s_->buffer, s_->capacity, s_->count, \
|
||||
s_->cardinality, s_->load, s_->cmp, s_->hash); \
|
||||
int n = snprintf(str.s, cmc_string_len, cmc_string_fmt_multiset, \
|
||||
#SNAME, #V, s_, s_->buffer, s_->capacity, s_->count, \
|
||||
s_->cardinality, s_->load, s_->cmp, s_->hash, \
|
||||
s_->alloc, s_->callbacks); \
|
||||
\
|
||||
if (n < 0 || n == (int)cmc_string_len) \
|
||||
return (struct cmc_string){0}; \
|
||||
\
|
||||
str.s[n] = '\0'; \
|
||||
\
|
||||
return str; \
|
||||
} \
|
||||
|
||||
+147
-18
@@ -48,10 +48,68 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "../utl/cmc_string.h"
|
||||
|
||||
/* -------------------------------------------------------------------------------------------------
|
||||
* Core functionalities of the C Macro Collections Library
|
||||
------------------------------------------------------------------------------------------------ */
|
||||
#ifndef CMC_CORE_H
|
||||
#define CMC_CORE_H
|
||||
|
||||
/**
|
||||
* struct cmc_string
|
||||
*
|
||||
* Used by all collections when calling the to_string function.
|
||||
*/
|
||||
struct cmc_string
|
||||
{
|
||||
char s[400];
|
||||
};
|
||||
|
||||
static const size_t cmc_string_len = 400;
|
||||
|
||||
/**
|
||||
* struct cmc_alloc_node
|
||||
*
|
||||
* Custom allocation node. Allows collections to use custom allocation functions.
|
||||
*/
|
||||
struct cmc_alloc_node
|
||||
{
|
||||
void *(*malloc)(size_t);
|
||||
void *(*calloc)(size_t, size_t);
|
||||
void *(*realloc)(void *, size_t);
|
||||
void (*free)(void *);
|
||||
} cmc_alloc_node_default = {malloc, calloc, realloc, free};
|
||||
|
||||
#endif /* CMC_CORE_H */
|
||||
|
||||
/* -------------------------------------------------------------------------------------------------
|
||||
* Queue specific
|
||||
------------------------------------------------------------------------------------------------ */
|
||||
/* to_string format */
|
||||
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_queue = "struct %s<%s> "
|
||||
"at %p { "
|
||||
"buffer:%p, "
|
||||
"capacity:%" PRIuMAX ", "
|
||||
"count:%" PRIuMAX ", "
|
||||
"front:%" PRIuMAX ", "
|
||||
"back:%" PRIuMAX ", "
|
||||
"alloc:%p, "
|
||||
"callbacks:%p }";
|
||||
|
||||
/**
|
||||
* Custom Queue callbacks.
|
||||
*
|
||||
* There are two types of callbacks, 'before' and 'after':
|
||||
* <before|after>_<function_name>
|
||||
*/
|
||||
struct cmc_callbacks_queue
|
||||
{
|
||||
void (*before_clear)(void *);
|
||||
void (*after_clear)(void *);
|
||||
void (*before_free)(void *);
|
||||
void (*after_free)(void *);
|
||||
// TODO implement all callbacks
|
||||
};
|
||||
|
||||
#define CMC_GENERATE_QUEUE(PFX, SNAME, V) \
|
||||
CMC_GENERATE_QUEUE_HEADER(PFX, SNAME, V) \
|
||||
@@ -63,7 +121,9 @@ static const char *cmc_string_fmt_queue = "%s at %p { buffer:%p, capacity:%" PRI
|
||||
#define CMC_WRAPGEN_QUEUE_SOURCE(PFX, SNAME, K, V) \
|
||||
CMC_GENERATE_QUEUE_SOURCE(PFX, SNAME, V)
|
||||
|
||||
/* HEADER ********************************************************************/
|
||||
/* -------------------------------------------------------------------------------------------------
|
||||
* Header
|
||||
------------------------------------------------------------------------------------------------ */
|
||||
#define CMC_GENERATE_QUEUE_HEADER(PFX, SNAME, V) \
|
||||
\
|
||||
/* Queue Structure */ \
|
||||
@@ -89,6 +149,12 @@ static const char *cmc_string_fmt_queue = "%s at %p { buffer:%p, capacity:%" PRI
|
||||
\
|
||||
/* Function that returns an iterator to the end of the queue */ \
|
||||
struct SNAME##_iter (*it_end)(struct SNAME *); \
|
||||
\
|
||||
/* Custom allocation functions */ \
|
||||
struct cmc_alloc_node *alloc; \
|
||||
\
|
||||
/* Custom callback functions */ \
|
||||
struct cmc_callbacks_queue *callbacks; \
|
||||
}; \
|
||||
\
|
||||
/* Queue Iterator */ \
|
||||
@@ -113,8 +179,13 @@ static const char *cmc_string_fmt_queue = "%s at %p { buffer:%p, capacity:%" PRI
|
||||
/* Collection Functions */ \
|
||||
/* Collection Allocation and Deallocation */ \
|
||||
struct SNAME *PFX##_new(size_t capacity); \
|
||||
struct SNAME *PFX##_new_custom(size_t capacity, struct cmc_alloc_node *alloc, \
|
||||
struct cmc_callbacks_queue *callbacks); \
|
||||
void PFX##_clear(struct SNAME *_queue_, void (*deallocator)(V)); \
|
||||
void PFX##_free(struct SNAME *_queue_, void (*deallocator)(V)); \
|
||||
/* Customization of Allocation and Callbacks */ \
|
||||
void PFX##_customize(struct SNAME *_queue_, struct cmc_alloc_node *alloc, \
|
||||
struct cmc_callbacks_queue *callbacks); \
|
||||
/* Collection Input and Output */ \
|
||||
bool PFX##_enqueue(struct SNAME *_queue_, V element); \
|
||||
bool PFX##_dequeue(struct SNAME *_queue_); \
|
||||
@@ -152,9 +223,11 @@ static const char *cmc_string_fmt_queue = "%s at %p { buffer:%p, capacity:%" PRI
|
||||
/* Iterator Access */ \
|
||||
V PFX##_iter_value(struct SNAME##_iter *iter); \
|
||||
V *PFX##_iter_rvalue(struct SNAME##_iter *iter); \
|
||||
size_t PFX##_iter_index(struct SNAME##_iter *iter); \
|
||||
\
|
||||
/* SOURCE ********************************************************************/
|
||||
size_t PFX##_iter_index(struct SNAME##_iter *iter);
|
||||
|
||||
/* -------------------------------------------------------------------------------------------------
|
||||
* Source
|
||||
------------------------------------------------------------------------------------------------ */
|
||||
#define CMC_GENERATE_QUEUE_SOURCE(PFX, SNAME, V) \
|
||||
\
|
||||
/* Implementation Detail Functions */ \
|
||||
@@ -163,19 +236,21 @@ static const char *cmc_string_fmt_queue = "%s at %p { buffer:%p, capacity:%" PRI
|
||||
\
|
||||
struct SNAME *PFX##_new(size_t capacity) \
|
||||
{ \
|
||||
struct cmc_alloc_node *alloc = &cmc_alloc_node_default; \
|
||||
\
|
||||
if (capacity < 1) \
|
||||
return NULL; \
|
||||
\
|
||||
struct SNAME *_queue_ = malloc(sizeof(struct SNAME)); \
|
||||
struct SNAME *_queue_ = alloc->malloc(sizeof(struct SNAME)); \
|
||||
\
|
||||
if (!_queue_) \
|
||||
return NULL; \
|
||||
\
|
||||
_queue_->buffer = calloc(capacity, sizeof(V)); \
|
||||
_queue_->buffer = alloc->calloc(capacity, sizeof(V)); \
|
||||
\
|
||||
if (!_queue_->buffer) \
|
||||
{ \
|
||||
free(_queue_); \
|
||||
alloc->free(_queue_); \
|
||||
return NULL; \
|
||||
} \
|
||||
\
|
||||
@@ -187,6 +262,45 @@ static const char *cmc_string_fmt_queue = "%s at %p { buffer:%p, capacity:%" PRI
|
||||
_queue_->it_start = PFX##_impl_it_start; \
|
||||
_queue_->it_end = PFX##_impl_it_end; \
|
||||
\
|
||||
_queue_->alloc = alloc; \
|
||||
_queue_->callbacks = NULL; \
|
||||
\
|
||||
return _queue_; \
|
||||
} \
|
||||
\
|
||||
struct SNAME *PFX##_new_custom(size_t capacity, struct cmc_alloc_node *alloc, \
|
||||
struct cmc_callbacks_queue *callbacks) \
|
||||
{ \
|
||||
if (capacity < 1) \
|
||||
return NULL; \
|
||||
\
|
||||
if (!alloc) \
|
||||
alloc = &cmc_alloc_node_default; \
|
||||
\
|
||||
struct SNAME *_queue_ = alloc->malloc(sizeof(struct SNAME)); \
|
||||
\
|
||||
if (!_queue_) \
|
||||
return NULL; \
|
||||
\
|
||||
_queue_->buffer = alloc->calloc(capacity, sizeof(V)); \
|
||||
\
|
||||
if (!_queue_->buffer) \
|
||||
{ \
|
||||
alloc->free(_queue_); \
|
||||
return NULL; \
|
||||
} \
|
||||
\
|
||||
_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; \
|
||||
\
|
||||
_queue_->alloc = alloc; \
|
||||
_queue_->callbacks = callbacks; \
|
||||
\
|
||||
return _queue_; \
|
||||
} \
|
||||
\
|
||||
@@ -221,8 +335,18 @@ static const char *cmc_string_fmt_queue = "%s at %p { buffer:%p, capacity:%" PRI
|
||||
} \
|
||||
} \
|
||||
\
|
||||
free(_queue_->buffer); \
|
||||
free(_queue_); \
|
||||
_queue_->alloc->free(_queue_->buffer); \
|
||||
_queue_->alloc->free(_queue_); \
|
||||
} \
|
||||
\
|
||||
void PFX##_customize(struct SNAME *_queue_, struct cmc_alloc_node *alloc, \
|
||||
struct cmc_callbacks_queue *callbacks) \
|
||||
{ \
|
||||
if (alloc) \
|
||||
_queue_->alloc = alloc; \
|
||||
\
|
||||
if (callbacks) \
|
||||
_queue_->callbacks = callbacks; \
|
||||
} \
|
||||
\
|
||||
bool PFX##_enqueue(struct SNAME *_queue_, V element) \
|
||||
@@ -303,7 +427,7 @@ static const char *cmc_string_fmt_queue = "%s at %p { buffer:%p, capacity:%" PRI
|
||||
if (capacity < PFX##_count(_queue_)) \
|
||||
return false; \
|
||||
\
|
||||
V *new_buffer = malloc(sizeof(V) * capacity); \
|
||||
V *new_buffer = _queue_->alloc->malloc(sizeof(V) * capacity); \
|
||||
\
|
||||
if (!new_buffer) \
|
||||
return false; \
|
||||
@@ -315,7 +439,7 @@ static const char *cmc_string_fmt_queue = "%s at %p { buffer:%p, capacity:%" PRI
|
||||
i = (i + 1) % PFX##_capacity(_queue_); \
|
||||
} \
|
||||
\
|
||||
free(_queue_->buffer); \
|
||||
_queue_->alloc->free(_queue_->buffer); \
|
||||
\
|
||||
_queue_->buffer = new_buffer; \
|
||||
_queue_->capacity = capacity; \
|
||||
@@ -378,17 +502,22 @@ static const char *cmc_string_fmt_queue = "%s at %p { buffer:%p, capacity:%" PRI
|
||||
{ \
|
||||
struct cmc_string str; \
|
||||
struct 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); \
|
||||
int n = snprintf(str.s, cmc_string_len, cmc_string_fmt_queue, \
|
||||
#SNAME, #V, q_, q_->buffer, q_->capacity, q_->count, \
|
||||
q_->front, q_->back, q_->alloc, q_->callbacks); \
|
||||
\
|
||||
if (n < 0 || n == (int)cmc_string_len) \
|
||||
return (struct cmc_string){0}; \
|
||||
\
|
||||
str.s[n] = '\0'; \
|
||||
\
|
||||
return str; \
|
||||
} \
|
||||
\
|
||||
struct SNAME##_iter *PFX##_iter_new(struct SNAME *target) \
|
||||
{ \
|
||||
struct SNAME##_iter *iter = malloc(sizeof(struct SNAME##_iter)); \
|
||||
struct SNAME##_iter *iter = target->alloc->malloc(sizeof(struct SNAME##_iter)); \
|
||||
\
|
||||
if (!iter) \
|
||||
return NULL; \
|
||||
@@ -400,7 +529,7 @@ static const char *cmc_string_fmt_queue = "%s at %p { buffer:%p, capacity:%" PRI
|
||||
\
|
||||
void PFX##_iter_free(struct SNAME##_iter *iter) \
|
||||
{ \
|
||||
free(iter); \
|
||||
iter->target->alloc->free(iter); \
|
||||
} \
|
||||
\
|
||||
void PFX##_iter_init(struct SNAME##_iter *iter, struct SNAME *target) \
|
||||
|
||||
+237
-106
@@ -27,10 +27,68 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "../utl/cmc_string.h"
|
||||
|
||||
/* -------------------------------------------------------------------------------------------------
|
||||
* Core functionalities of the C Macro Collections Library
|
||||
------------------------------------------------------------------------------------------------ */
|
||||
#ifndef CMC_CORE_H
|
||||
#define CMC_CORE_H
|
||||
|
||||
/**
|
||||
* struct cmc_string
|
||||
*
|
||||
* Used by all collections when calling the to_string function.
|
||||
*/
|
||||
struct cmc_string
|
||||
{
|
||||
char s[400];
|
||||
};
|
||||
|
||||
static const size_t cmc_string_len = 400;
|
||||
|
||||
/**
|
||||
* struct cmc_alloc_node
|
||||
*
|
||||
* Custom allocation node. Allows collections to use custom allocation functions.
|
||||
*/
|
||||
struct cmc_alloc_node
|
||||
{
|
||||
void *(*malloc)(size_t);
|
||||
void *(*calloc)(size_t, size_t);
|
||||
void *(*realloc)(void *, size_t);
|
||||
void (*free)(void *);
|
||||
} cmc_alloc_node_default = {malloc, calloc, realloc, free};
|
||||
|
||||
#endif /* CMC_CORE_H */
|
||||
|
||||
/* -------------------------------------------------------------------------------------------------
|
||||
* SortedList specific
|
||||
------------------------------------------------------------------------------------------------ */
|
||||
/* to_string format */
|
||||
static const char *cmc_string_fmt_sortedlist = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", count:%" PRIuMAX ", is_sorted:%s, cmp:%p }";
|
||||
static const char *cmc_string_fmt_sortedlist = "struct %s<%s> "
|
||||
"at %p { "
|
||||
"buffer:%p, "
|
||||
"capacity:%" PRIuMAX ", "
|
||||
"count:%" PRIuMAX ", "
|
||||
"is_sorted:%s, "
|
||||
"cmp:%p, "
|
||||
"alloc:%p, "
|
||||
"callbacks:%p }";
|
||||
|
||||
/**
|
||||
* Custom SortedList callbacks.
|
||||
*
|
||||
* There are two types of callbacks, 'before' and 'after':
|
||||
* <before|after>_<function_name>
|
||||
*/
|
||||
struct cmc_callbacks_sortedlist
|
||||
{
|
||||
void (*before_clear)(void *);
|
||||
void (*after_clear)(void *);
|
||||
void (*before_free)(void *);
|
||||
void (*after_free)(void *);
|
||||
// TODO implement all callbacks
|
||||
};
|
||||
|
||||
#define CMC_GENERATE_SORTEDLIST(PFX, SNAME, V) \
|
||||
CMC_GENERATE_SORTEDLIST_HEADER(PFX, SNAME, V) \
|
||||
@@ -42,98 +100,114 @@ static const char *cmc_string_fmt_sortedlist = "%s at %p { buffer:%p, capacity:%
|
||||
#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 */ \
|
||||
struct SNAME \
|
||||
{ \
|
||||
/* 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 (*it_start)(struct SNAME *); \
|
||||
\
|
||||
/* Function that returns an iterator to the end of the list */ \
|
||||
struct SNAME##_iter (*it_end)(struct SNAME *); \
|
||||
}; \
|
||||
\
|
||||
/* List Iterator */ \
|
||||
struct SNAME##_iter \
|
||||
{ \
|
||||
/* Target list */ \
|
||||
struct SNAME *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; \
|
||||
}; \
|
||||
\
|
||||
/* Collection Functions */ \
|
||||
/* Collection Allocation and Deallocation */ \
|
||||
struct SNAME *PFX##_new(size_t capacity, int (*compare)(V, V)); \
|
||||
void PFX##_clear(struct SNAME *_list_, void (*deallocator)(V)); \
|
||||
void PFX##_free(struct SNAME *_list_, void (*deallocator)(V)); \
|
||||
/* Collection Input and Output */ \
|
||||
bool PFX##_insert(struct SNAME *_list_, V element); \
|
||||
bool PFX##_remove(struct SNAME *_list_, size_t index); \
|
||||
/* Element Access */ \
|
||||
bool PFX##_max(struct SNAME *_list_, V *result); \
|
||||
bool PFX##_min(struct SNAME *_list_, V *result); \
|
||||
V PFX##_get(struct SNAME *_list_, size_t index); \
|
||||
size_t PFX##_indexof(struct SNAME *_list_, V element, bool from_start); \
|
||||
/* Collection State */ \
|
||||
bool PFX##_contains(struct SNAME *_list_, V element); \
|
||||
bool PFX##_empty(struct SNAME *_list_); \
|
||||
bool PFX##_full(struct SNAME *_list_); \
|
||||
size_t PFX##_count(struct SNAME *_list_); \
|
||||
size_t PFX##_capacity(struct SNAME *_list_); \
|
||||
/* Collection Utility */ \
|
||||
bool PFX##_resize(struct SNAME *_list_, size_t capacity); \
|
||||
void PFX##_sort(struct SNAME *_list_); \
|
||||
struct SNAME *PFX##_copy_of(struct SNAME *_list_, V (*copy_func)(V)); \
|
||||
bool PFX##_equals(struct SNAME *_list1_, struct SNAME *_list2_); \
|
||||
struct cmc_string PFX##_to_string(struct SNAME *_list_); \
|
||||
\
|
||||
/* Iterator Functions */ \
|
||||
/* Iterator Allocation and Deallocation */ \
|
||||
struct SNAME##_iter *PFX##_iter_new(struct SNAME *target); \
|
||||
void PFX##_iter_free(struct SNAME##_iter *iter); \
|
||||
/* Iterator Initialization */ \
|
||||
void PFX##_iter_init(struct SNAME##_iter *iter, struct SNAME *target); \
|
||||
/* Iterator State */ \
|
||||
bool PFX##_iter_start(struct SNAME##_iter *iter); \
|
||||
bool PFX##_iter_end(struct SNAME##_iter *iter); \
|
||||
/* Iterator Movement */ \
|
||||
void PFX##_iter_to_start(struct SNAME##_iter *iter); \
|
||||
void PFX##_iter_to_end(struct SNAME##_iter *iter); \
|
||||
bool PFX##_iter_next(struct SNAME##_iter *iter); \
|
||||
bool PFX##_iter_prev(struct SNAME##_iter *iter); \
|
||||
bool PFX##_iter_advance(struct SNAME##_iter *iter, size_t steps); \
|
||||
bool PFX##_iter_rewind(struct SNAME##_iter *iter, size_t steps); \
|
||||
bool PFX##_iter_go_to(struct SNAME##_iter *iter, size_t index); \
|
||||
/* Iterator Access */ \
|
||||
V PFX##_iter_value(struct SNAME##_iter *iter); \
|
||||
size_t PFX##_iter_index(struct SNAME##_iter *iter); \
|
||||
\
|
||||
/* SOURCE ********************************************************************/
|
||||
/* -------------------------------------------------------------------------------------------------
|
||||
* Header
|
||||
------------------------------------------------------------------------------------------------ */
|
||||
#define CMC_GENERATE_SORTEDLIST_HEADER(PFX, SNAME, V) \
|
||||
\
|
||||
/* List Structure */ \
|
||||
struct SNAME \
|
||||
{ \
|
||||
/* 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 (*it_start)(struct SNAME *); \
|
||||
\
|
||||
/* Function that returns an iterator to the end of the list */ \
|
||||
struct SNAME##_iter (*it_end)(struct SNAME *); \
|
||||
\
|
||||
/* Custom allocation functions */ \
|
||||
struct cmc_alloc_node *alloc; \
|
||||
\
|
||||
/* Custom callback functions */ \
|
||||
struct cmc_callbacks_sortedlist *callbacks; \
|
||||
}; \
|
||||
\
|
||||
/* List Iterator */ \
|
||||
struct SNAME##_iter \
|
||||
{ \
|
||||
/* Target list */ \
|
||||
struct SNAME *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; \
|
||||
}; \
|
||||
\
|
||||
/* Collection Functions */ \
|
||||
/* Collection Allocation and Deallocation */ \
|
||||
struct SNAME *PFX##_new(size_t capacity, int (*compare)(V, V)); \
|
||||
struct SNAME *PFX##_new_custom(size_t capacity, int (*compare)(V, V), \
|
||||
struct cmc_alloc_node *alloc, \
|
||||
struct cmc_callbacks_sortedlist *callbacks); \
|
||||
void PFX##_clear(struct SNAME *_list_, void (*deallocator)(V)); \
|
||||
void PFX##_free(struct SNAME *_list_, void (*deallocator)(V)); \
|
||||
/* Customization of Allocation and Callbacks */ \
|
||||
void PFX##_customize(struct SNAME *_list_, struct cmc_alloc_node *alloc, \
|
||||
struct cmc_callbacks_sortedlist *callbacks); \
|
||||
/* Collection Input and Output */ \
|
||||
bool PFX##_insert(struct SNAME *_list_, V element); \
|
||||
bool PFX##_remove(struct SNAME *_list_, size_t index); \
|
||||
/* Element Access */ \
|
||||
bool PFX##_max(struct SNAME *_list_, V *result); \
|
||||
bool PFX##_min(struct SNAME *_list_, V *result); \
|
||||
V PFX##_get(struct SNAME *_list_, size_t index); \
|
||||
size_t PFX##_indexof(struct SNAME *_list_, V element, bool from_start); \
|
||||
/* Collection State */ \
|
||||
bool PFX##_contains(struct SNAME *_list_, V element); \
|
||||
bool PFX##_empty(struct SNAME *_list_); \
|
||||
bool PFX##_full(struct SNAME *_list_); \
|
||||
size_t PFX##_count(struct SNAME *_list_); \
|
||||
size_t PFX##_capacity(struct SNAME *_list_); \
|
||||
/* Collection Utility */ \
|
||||
bool PFX##_resize(struct SNAME *_list_, size_t capacity); \
|
||||
void PFX##_sort(struct SNAME *_list_); \
|
||||
struct SNAME *PFX##_copy_of(struct SNAME *_list_, V (*copy_func)(V)); \
|
||||
bool PFX##_equals(struct SNAME *_list1_, struct SNAME *_list2_); \
|
||||
struct cmc_string PFX##_to_string(struct SNAME *_list_); \
|
||||
\
|
||||
/* Iterator Functions */ \
|
||||
/* Iterator Allocation and Deallocation */ \
|
||||
struct SNAME##_iter *PFX##_iter_new(struct SNAME *target); \
|
||||
void PFX##_iter_free(struct SNAME##_iter *iter); \
|
||||
/* Iterator Initialization */ \
|
||||
void PFX##_iter_init(struct SNAME##_iter *iter, struct SNAME *target); \
|
||||
/* Iterator State */ \
|
||||
bool PFX##_iter_start(struct SNAME##_iter *iter); \
|
||||
bool PFX##_iter_end(struct SNAME##_iter *iter); \
|
||||
/* Iterator Movement */ \
|
||||
void PFX##_iter_to_start(struct SNAME##_iter *iter); \
|
||||
void PFX##_iter_to_end(struct SNAME##_iter *iter); \
|
||||
bool PFX##_iter_next(struct SNAME##_iter *iter); \
|
||||
bool PFX##_iter_prev(struct SNAME##_iter *iter); \
|
||||
bool PFX##_iter_advance(struct SNAME##_iter *iter, size_t steps); \
|
||||
bool PFX##_iter_rewind(struct SNAME##_iter *iter, size_t steps); \
|
||||
bool PFX##_iter_go_to(struct SNAME##_iter *iter, size_t index); \
|
||||
/* Iterator Access */ \
|
||||
V PFX##_iter_value(struct SNAME##_iter *iter); \
|
||||
size_t PFX##_iter_index(struct SNAME##_iter *iter);
|
||||
|
||||
/* -------------------------------------------------------------------------------------------------
|
||||
* Source
|
||||
------------------------------------------------------------------------------------------------ */
|
||||
#define CMC_GENERATE_SORTEDLIST_SOURCE(PFX, SNAME, V) \
|
||||
\
|
||||
/* Implementation Detail Functions */ \
|
||||
@@ -146,19 +220,21 @@ static const char *cmc_string_fmt_sortedlist = "%s at %p { buffer:%p, capacity:%
|
||||
\
|
||||
struct SNAME *PFX##_new(size_t capacity, int (*compare)(V, V)) \
|
||||
{ \
|
||||
struct cmc_alloc_node *alloc = &cmc_alloc_node_default; \
|
||||
\
|
||||
if (capacity < 1) \
|
||||
return NULL; \
|
||||
\
|
||||
struct SNAME *_list_ = malloc(sizeof(struct SNAME)); \
|
||||
struct SNAME *_list_ = alloc->malloc(sizeof(struct SNAME)); \
|
||||
\
|
||||
if (!_list_) \
|
||||
return NULL; \
|
||||
\
|
||||
_list_->buffer = calloc(capacity, sizeof(V)); \
|
||||
_list_->buffer = alloc->calloc(capacity, sizeof(V)); \
|
||||
\
|
||||
if (!_list_->buffer) \
|
||||
{ \
|
||||
free(_list_); \
|
||||
alloc->free(_list_); \
|
||||
return NULL; \
|
||||
} \
|
||||
\
|
||||
@@ -170,6 +246,46 @@ static const char *cmc_string_fmt_sortedlist = "%s at %p { buffer:%p, capacity:%
|
||||
_list_->it_start = PFX##_impl_it_start; \
|
||||
_list_->it_end = PFX##_impl_it_end; \
|
||||
\
|
||||
_list_->alloc = alloc; \
|
||||
_list_->callbacks = NULL; \
|
||||
\
|
||||
return _list_; \
|
||||
} \
|
||||
\
|
||||
struct SNAME *PFX##_new_custom(size_t capacity, int (*compare)(V, V), \
|
||||
struct cmc_alloc_node *alloc, \
|
||||
struct cmc_callbacks_sortedlist *callbacks) \
|
||||
{ \
|
||||
if (capacity < 1) \
|
||||
return NULL; \
|
||||
\
|
||||
if (!alloc) \
|
||||
alloc = &cmc_alloc_node_default; \
|
||||
\
|
||||
struct SNAME *_list_ = alloc->malloc(sizeof(struct SNAME)); \
|
||||
\
|
||||
if (!_list_) \
|
||||
return NULL; \
|
||||
\
|
||||
_list_->buffer = alloc->calloc(capacity, sizeof(V)); \
|
||||
\
|
||||
if (!_list_->buffer) \
|
||||
{ \
|
||||
alloc->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; \
|
||||
\
|
||||
_list_->alloc = alloc; \
|
||||
_list_->callbacks = callbacks; \
|
||||
\
|
||||
return _list_; \
|
||||
} \
|
||||
\
|
||||
@@ -194,8 +310,18 @@ static const char *cmc_string_fmt_sortedlist = "%s at %p { buffer:%p, capacity:%
|
||||
deallocator(_list_->buffer[i]); \
|
||||
} \
|
||||
\
|
||||
free(_list_->buffer); \
|
||||
free(_list_); \
|
||||
_list_->alloc->free(_list_->buffer); \
|
||||
_list_->alloc->free(_list_); \
|
||||
} \
|
||||
\
|
||||
void PFX##_customize(struct SNAME *_list_, struct cmc_alloc_node *alloc, \
|
||||
struct cmc_callbacks_sortedlist *callbacks) \
|
||||
{ \
|
||||
if (alloc) \
|
||||
_list_->alloc = alloc; \
|
||||
\
|
||||
if (callbacks) \
|
||||
_list_->callbacks = callbacks; \
|
||||
} \
|
||||
\
|
||||
bool PFX##_insert(struct SNAME *_list_, V element) \
|
||||
@@ -310,7 +436,7 @@ static const char *cmc_string_fmt_sortedlist = "%s at %p { buffer:%p, capacity:%
|
||||
if (capacity < PFX##_count(_list_)) \
|
||||
return false; \
|
||||
\
|
||||
V *new_buffer = realloc(_list_->buffer, sizeof(V) * capacity); \
|
||||
V *new_buffer = _list_->alloc->realloc(_list_->buffer, sizeof(V) * capacity); \
|
||||
\
|
||||
if (!new_buffer) \
|
||||
return false; \
|
||||
@@ -372,18 +498,23 @@ static const char *cmc_string_fmt_sortedlist = "%s at %p { buffer:%p, capacity:%
|
||||
{ \
|
||||
struct cmc_string str; \
|
||||
struct 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); \
|
||||
int n = snprintf(str.s, cmc_string_len, cmc_string_fmt_sortedlist, \
|
||||
#SNAME, #V, l_, l_->buffer, l_->capacity, l_->count, \
|
||||
l_->is_sorted ? "true" : "false", l_->cmp, \
|
||||
l_->alloc, l_->callbacks); \
|
||||
\
|
||||
if (n < 0 || n == (int)cmc_string_len) \
|
||||
return (struct cmc_string){0}; \
|
||||
\
|
||||
str.s[n] = '\0'; \
|
||||
\
|
||||
return str; \
|
||||
} \
|
||||
\
|
||||
struct SNAME##_iter *PFX##_iter_new(struct SNAME *target) \
|
||||
{ \
|
||||
struct SNAME##_iter *iter = malloc(sizeof(struct SNAME##_iter)); \
|
||||
struct SNAME##_iter *iter = target->alloc->malloc(sizeof(struct SNAME##_iter)); \
|
||||
\
|
||||
if (!iter) \
|
||||
return NULL; \
|
||||
@@ -395,7 +526,7 @@ static const char *cmc_string_fmt_sortedlist = "%s at %p { buffer:%p, capacity:%
|
||||
\
|
||||
void PFX##_iter_free(struct SNAME##_iter *iter) \
|
||||
{ \
|
||||
free(iter); \
|
||||
iter->target->alloc->free(iter); \
|
||||
} \
|
||||
\
|
||||
void PFX##_iter_init(struct SNAME##_iter *iter, struct SNAME *target) \
|
||||
|
||||
+143
-17
@@ -33,10 +33,66 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "../utl/cmc_string.h"
|
||||
|
||||
/* -------------------------------------------------------------------------------------------------
|
||||
* Core functionalities of the C Macro Collections Library
|
||||
------------------------------------------------------------------------------------------------ */
|
||||
#ifndef CMC_CORE_H
|
||||
#define CMC_CORE_H
|
||||
|
||||
/**
|
||||
* struct cmc_string
|
||||
*
|
||||
* Used by all collections when calling the to_string function.
|
||||
*/
|
||||
struct cmc_string
|
||||
{
|
||||
char s[400];
|
||||
};
|
||||
|
||||
static const size_t cmc_string_len = 400;
|
||||
|
||||
/**
|
||||
* struct cmc_alloc_node
|
||||
*
|
||||
* Custom allocation node. Allows collections to use custom allocation functions.
|
||||
*/
|
||||
struct cmc_alloc_node
|
||||
{
|
||||
void *(*malloc)(size_t);
|
||||
void *(*calloc)(size_t, size_t);
|
||||
void *(*realloc)(void *, size_t);
|
||||
void (*free)(void *);
|
||||
} cmc_alloc_node_default = {malloc, calloc, realloc, free};
|
||||
|
||||
#endif /* CMC_CORE_H */
|
||||
|
||||
/* -------------------------------------------------------------------------------------------------
|
||||
* Stack specific
|
||||
------------------------------------------------------------------------------------------------ */
|
||||
/* to_string format */
|
||||
static const char *cmc_string_fmt_stack = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", count:%" PRIuMAX " }";
|
||||
static const char *cmc_string_fmt_stack = "struct %s<%s> "
|
||||
"at %p { "
|
||||
"buffer:%p, "
|
||||
"capacity:%" PRIuMAX ", "
|
||||
"count:%" PRIuMAX ", "
|
||||
"alloc:%p, "
|
||||
"callbacks:%p }";
|
||||
|
||||
/**
|
||||
* Custom Stack callbacks.
|
||||
*
|
||||
* There are two types of callbacks, 'before' and 'after':
|
||||
* <before|after>_<function_name>
|
||||
*/
|
||||
struct cmc_callbacks_stack
|
||||
{
|
||||
void (*before_clear)(void *);
|
||||
void (*after_clear)(void *);
|
||||
void (*before_free)(void *);
|
||||
void (*after_free)(void *);
|
||||
// TODO implement all callbacks
|
||||
};
|
||||
|
||||
#define CMC_GENERATE_STACK(PFX, SNAME, V) \
|
||||
CMC_GENERATE_STACK_HEADER(PFX, SNAME, V) \
|
||||
@@ -48,7 +104,9 @@ static const char *cmc_string_fmt_stack = "%s at %p { buffer:%p, capacity:%" PRI
|
||||
#define CMC_WRAPGEN_STACK_SOURCE(PFX, SNAME, K, V) \
|
||||
CMC_GENERATE_STACK_SOURCE(PFX, SNAME, V)
|
||||
|
||||
/* HEADER ********************************************************************/
|
||||
/* -------------------------------------------------------------------------------------------------
|
||||
* Header
|
||||
------------------------------------------------------------------------------------------------ */
|
||||
#define CMC_GENERATE_STACK_HEADER(PFX, SNAME, V) \
|
||||
\
|
||||
/* Stack Structure */ \
|
||||
@@ -68,6 +126,12 @@ static const char *cmc_string_fmt_stack = "%s at %p { buffer:%p, capacity:%" PRI
|
||||
\
|
||||
/* Function that returns an iterator to the end of the stack */ \
|
||||
struct SNAME##_iter (*it_end)(struct SNAME *); \
|
||||
\
|
||||
/* Custom allocation functions */ \
|
||||
struct cmc_alloc_node *alloc; \
|
||||
\
|
||||
/* Custom callback functions */ \
|
||||
struct cmc_callbacks_stack *callbacks; \
|
||||
}; \
|
||||
\
|
||||
/* Stack Iterator */ \
|
||||
@@ -89,8 +153,13 @@ static const char *cmc_string_fmt_stack = "%s at %p { buffer:%p, capacity:%" PRI
|
||||
/* Collection Functions */ \
|
||||
/* Collection Allocation and Deallocation */ \
|
||||
struct SNAME *PFX##_new(size_t capacity); \
|
||||
struct SNAME *PFX##_new_custom(size_t capacity, struct cmc_alloc_node *alloc, \
|
||||
struct cmc_callbacks_stack *callbacks); \
|
||||
void PFX##_clear(struct SNAME *_stack_, void (*deallocator)(V)); \
|
||||
void PFX##_free(struct SNAME *_stack_, void (*deallocator)(V)); \
|
||||
/* Customization of Allocation and Callbacks */ \
|
||||
void PFX##_customize(struct SNAME *_stack_, struct cmc_alloc_node *alloc, \
|
||||
struct cmc_callbacks_stack *callbacks); \
|
||||
/* Collection Input and Output */ \
|
||||
bool PFX##_push(struct SNAME *_stack_, V element); \
|
||||
bool PFX##_pop(struct SNAME *_stack_); \
|
||||
@@ -128,9 +197,11 @@ static const char *cmc_string_fmt_stack = "%s at %p { buffer:%p, capacity:%" PRI
|
||||
/* Iterator Access */ \
|
||||
V PFX##_iter_value(struct SNAME##_iter *iter); \
|
||||
V *PFX##_iter_rvalue(struct SNAME##_iter *iter); \
|
||||
size_t PFX##_iter_index(struct SNAME##_iter *iter); \
|
||||
\
|
||||
/* SOURCE ********************************************************************/
|
||||
size_t PFX##_iter_index(struct SNAME##_iter *iter);
|
||||
|
||||
/* -------------------------------------------------------------------------------------------------
|
||||
* Source
|
||||
------------------------------------------------------------------------------------------------ */
|
||||
#define CMC_GENERATE_STACK_SOURCE(PFX, SNAME, V) \
|
||||
\
|
||||
/* Implementation Detail Functions */ \
|
||||
@@ -139,19 +210,21 @@ static const char *cmc_string_fmt_stack = "%s at %p { buffer:%p, capacity:%" PRI
|
||||
\
|
||||
struct SNAME *PFX##_new(size_t capacity) \
|
||||
{ \
|
||||
struct cmc_alloc_node *alloc = &cmc_alloc_node_default; \
|
||||
\
|
||||
if (capacity < 1) \
|
||||
return NULL; \
|
||||
\
|
||||
struct SNAME *_stack_ = malloc(sizeof(struct SNAME)); \
|
||||
struct SNAME *_stack_ = alloc->malloc(sizeof(struct SNAME)); \
|
||||
\
|
||||
if (!_stack_) \
|
||||
return NULL; \
|
||||
\
|
||||
_stack_->buffer = calloc(capacity, sizeof(V)); \
|
||||
_stack_->buffer = alloc->calloc(capacity, sizeof(V)); \
|
||||
\
|
||||
if (!_stack_->buffer) \
|
||||
{ \
|
||||
free(_stack_); \
|
||||
alloc->free(_stack_); \
|
||||
return NULL; \
|
||||
} \
|
||||
\
|
||||
@@ -161,6 +234,43 @@ static const char *cmc_string_fmt_stack = "%s at %p { buffer:%p, capacity:%" PRI
|
||||
_stack_->it_start = PFX##_impl_it_start; \
|
||||
_stack_->it_end = PFX##_impl_it_end; \
|
||||
\
|
||||
_stack_->alloc = alloc; \
|
||||
_stack_->callbacks = NULL; \
|
||||
\
|
||||
return _stack_; \
|
||||
} \
|
||||
\
|
||||
struct SNAME *PFX##_new_custom(size_t capacity, struct cmc_alloc_node *alloc, \
|
||||
struct cmc_callbacks_stack *callbacks) \
|
||||
{ \
|
||||
if (capacity < 1) \
|
||||
return NULL; \
|
||||
\
|
||||
if (!alloc) \
|
||||
alloc = &cmc_alloc_node_default; \
|
||||
\
|
||||
struct SNAME *_stack_ = alloc->malloc(sizeof(struct SNAME)); \
|
||||
\
|
||||
if (!_stack_) \
|
||||
return NULL; \
|
||||
\
|
||||
_stack_->buffer = alloc->calloc(capacity, sizeof(V)); \
|
||||
\
|
||||
if (!_stack_->buffer) \
|
||||
{ \
|
||||
alloc->free(_stack_); \
|
||||
return NULL; \
|
||||
} \
|
||||
\
|
||||
_stack_->capacity = capacity; \
|
||||
_stack_->count = 0; \
|
||||
\
|
||||
_stack_->it_start = PFX##_impl_it_start; \
|
||||
_stack_->it_end = PFX##_impl_it_end; \
|
||||
\
|
||||
_stack_->alloc = alloc; \
|
||||
_stack_->callbacks = callbacks; \
|
||||
\
|
||||
return _stack_; \
|
||||
} \
|
||||
\
|
||||
@@ -179,14 +289,25 @@ static const char *cmc_string_fmt_stack = "%s at %p { buffer:%p, capacity:%" PRI
|
||||
\
|
||||
void PFX##_free(struct SNAME *_stack_, void (*deallocator)(V)) \
|
||||
{ \
|
||||
free(_stack_->buffer); \
|
||||
_stack_->alloc->free(_stack_->buffer); \
|
||||
\
|
||||
if (deallocator) \
|
||||
{ \
|
||||
for (size_t i = 0; i < _stack_->count; i++) \
|
||||
deallocator(_stack_->buffer[i]); \
|
||||
} \
|
||||
\
|
||||
free(_stack_); \
|
||||
_stack_->alloc->free(_stack_); \
|
||||
} \
|
||||
\
|
||||
void PFX##_customize(struct SNAME *_stack_, struct cmc_alloc_node *alloc, \
|
||||
struct cmc_callbacks_stack *callbacks) \
|
||||
{ \
|
||||
if (alloc) \
|
||||
_stack_->alloc = alloc; \
|
||||
\
|
||||
if (callbacks) \
|
||||
_stack_->callbacks = callbacks; \
|
||||
} \
|
||||
\
|
||||
bool PFX##_push(struct SNAME *_stack_, V element) \
|
||||
@@ -259,7 +380,7 @@ static const char *cmc_string_fmt_stack = "%s at %p { buffer:%p, capacity:%" PRI
|
||||
if (capacity < PFX##_count(_stack_)) \
|
||||
return false; \
|
||||
\
|
||||
V *new_buffer = realloc(_stack_->buffer, sizeof(V) * capacity); \
|
||||
V *new_buffer = _stack_->alloc->realloc(_stack_->buffer, sizeof(V) * capacity); \
|
||||
\
|
||||
if (!new_buffer) \
|
||||
return false; \
|
||||
@@ -308,17 +429,22 @@ static const char *cmc_string_fmt_stack = "%s at %p { buffer:%p, capacity:%" PRI
|
||||
{ \
|
||||
struct cmc_string str; \
|
||||
struct 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); \
|
||||
int n = snprintf(str.s, cmc_string_len, cmc_string_fmt_stack, \
|
||||
#SNAME, #V, s_, s_->buffer, s_->capacity, s_->count, \
|
||||
s_->alloc, s_->callbacks); \
|
||||
\
|
||||
if (n < 0 || n == (int)cmc_string_len) \
|
||||
return (struct cmc_string){0}; \
|
||||
\
|
||||
str.s[n] = '\0'; \
|
||||
\
|
||||
return str; \
|
||||
} \
|
||||
\
|
||||
struct SNAME##_iter *PFX##_iter_new(struct SNAME *target) \
|
||||
{ \
|
||||
struct SNAME##_iter *iter = malloc(sizeof(struct SNAME##_iter)); \
|
||||
struct SNAME##_iter *iter = target->alloc->malloc(sizeof(struct SNAME##_iter)); \
|
||||
\
|
||||
if (!iter) \
|
||||
return NULL; \
|
||||
@@ -330,7 +456,7 @@ static const char *cmc_string_fmt_stack = "%s at %p { buffer:%p, capacity:%" PRI
|
||||
\
|
||||
void PFX##_iter_free(struct SNAME##_iter *iter) \
|
||||
{ \
|
||||
free(iter); \
|
||||
iter->target->alloc->free(iter); \
|
||||
} \
|
||||
\
|
||||
void PFX##_iter_init(struct SNAME##_iter *iter, struct SNAME *target) \
|
||||
|
||||
+115
-10
@@ -24,10 +24,66 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "../utl/cmc_string.h"
|
||||
|
||||
/* -------------------------------------------------------------------------------------------------
|
||||
* Core functionalities of the C Macro Collections Library
|
||||
------------------------------------------------------------------------------------------------ */
|
||||
#ifndef CMC_CORE_H
|
||||
#define CMC_CORE_H
|
||||
|
||||
/**
|
||||
* struct cmc_string
|
||||
*
|
||||
* Used by all collections when calling the to_string function.
|
||||
*/
|
||||
struct cmc_string
|
||||
{
|
||||
char s[400];
|
||||
};
|
||||
|
||||
static const size_t cmc_string_len = 400;
|
||||
|
||||
/**
|
||||
* struct cmc_alloc_node
|
||||
*
|
||||
* Custom allocation node. Allows collections to use custom allocation functions.
|
||||
*/
|
||||
struct cmc_alloc_node
|
||||
{
|
||||
void *(*malloc)(size_t);
|
||||
void *(*calloc)(size_t, size_t);
|
||||
void *(*realloc)(void *, size_t);
|
||||
void (*free)(void *);
|
||||
} cmc_alloc_node_default = {malloc, calloc, realloc, free};
|
||||
|
||||
#endif /* CMC_CORE_H */
|
||||
|
||||
/* -------------------------------------------------------------------------------------------------
|
||||
* TreeMap specific
|
||||
------------------------------------------------------------------------------------------------ */
|
||||
/* to_string format */
|
||||
static const char *cmc_string_fmt_treemap = "%s at %p { root:%p, count:%" PRIuMAX ", cmp:%p }";
|
||||
static const char *cmc_string_fmt_treemap = "struct %s<%s, %s> "
|
||||
"at %p { "
|
||||
"root:%p, "
|
||||
"count:%" PRIuMAX ", "
|
||||
"cmp:%p, "
|
||||
"alloc:%p, "
|
||||
"callbacks:%p }";
|
||||
|
||||
/**
|
||||
* Custom TreeMap callbacks.
|
||||
*
|
||||
* There are two types of callbacks, 'before' and 'after':
|
||||
* <before|after>_<function_name>
|
||||
*/
|
||||
struct cmc_callbacks_treemap
|
||||
{
|
||||
void (*before_clear)(void *);
|
||||
void (*after_clear)(void *);
|
||||
void (*before_free)(void *);
|
||||
void (*after_free)(void *);
|
||||
// TODO implement all callbacks
|
||||
};
|
||||
|
||||
#define CMC_GENERATE_TREEMAP(PFX, SNAME, K, V) \
|
||||
CMC_GENERATE_TREEMAP_HEADER(PFX, SNAME, K, V) \
|
||||
@@ -39,7 +95,9 @@ static const char *cmc_string_fmt_treemap = "%s at %p { root:%p, count:%" PRIuMA
|
||||
#define CMC_WRAPGEN_TREEMAP_SOURCE(PFX, SNAME, K, V) \
|
||||
CMC_GENERATE_TREEMAP_SOURCE(PFX, SNAME, K, V)
|
||||
|
||||
/* HEADER ********************************************************************/
|
||||
/* -------------------------------------------------------------------------------------------------
|
||||
* Header
|
||||
------------------------------------------------------------------------------------------------ */
|
||||
#define CMC_GENERATE_TREEMAP_HEADER(PFX, SNAME, K, V) \
|
||||
\
|
||||
/* Treemap Structure */ \
|
||||
@@ -59,6 +117,12 @@ static const char *cmc_string_fmt_treemap = "%s at %p { root:%p, count:%" PRIuMA
|
||||
\
|
||||
/* Function that returns an iterator to the end of the treemap */ \
|
||||
struct SNAME##_iter (*it_end)(struct SNAME *); \
|
||||
\
|
||||
/* Custom allocation functions */ \
|
||||
struct cmc_alloc_node *alloc; \
|
||||
\
|
||||
/* Custom callback functions */ \
|
||||
struct cmc_callbacks_treemap *callbacks; \
|
||||
}; \
|
||||
\
|
||||
/* Treemap Node */ \
|
||||
@@ -111,8 +175,13 @@ static const char *cmc_string_fmt_treemap = "%s at %p { root:%p, count:%" PRIuMA
|
||||
/* Collection Functions */ \
|
||||
/* Collection Allocation and Deallocation */ \
|
||||
struct SNAME *PFX##_new(int (*compare)(K, K)); \
|
||||
struct SNAME *PFX##_new_custom(int (*compare)(K, K), struct cmc_alloc_node *alloc, \
|
||||
struct cmc_callbacks_treemap *callbacks); \
|
||||
void PFX##_clear(struct SNAME *_map_, void (*deallocator)(K, V)); \
|
||||
void PFX##_free(struct SNAME *_map_, void (*deallocator)(K, V)); \
|
||||
/* Customization of Allocation and Callbacks */ \
|
||||
void PFX##_customize(struct SNAME *_map_, struct cmc_alloc_node *alloc, \
|
||||
struct cmc_callbacks_treemap *callbacks); \
|
||||
/* Collection Input and Output */ \
|
||||
bool PFX##_insert(struct SNAME *_map_, K key, V value); \
|
||||
bool PFX##_update(struct SNAME *_map_, K key, V new_value, V *old_value); \
|
||||
@@ -153,9 +222,11 @@ static const char *cmc_string_fmt_treemap = "%s at %p { root:%p, count:%" PRIuMA
|
||||
K PFX##_iter_key(struct SNAME##_iter *iter); \
|
||||
V PFX##_iter_value(struct SNAME##_iter *iter); \
|
||||
V *PFX##_iter_rvalue(struct SNAME##_iter *iter); \
|
||||
size_t PFX##_iter_index(struct SNAME##_iter *iter); \
|
||||
\
|
||||
/* SOURCE ********************************************************************/
|
||||
size_t PFX##_iter_index(struct SNAME##_iter *iter);
|
||||
|
||||
/* -------------------------------------------------------------------------------------------------
|
||||
* Source
|
||||
------------------------------------------------------------------------------------------------ */
|
||||
#define CMC_GENERATE_TREEMAP_SOURCE(PFX, SNAME, K, V) \
|
||||
\
|
||||
/* Implementation Detail Functions */ \
|
||||
@@ -171,7 +242,9 @@ static const char *cmc_string_fmt_treemap = "%s at %p { root:%p, count:%" PRIuMA
|
||||
\
|
||||
struct SNAME *PFX##_new(int (*compare)(K, K)) \
|
||||
{ \
|
||||
struct SNAME *_map_ = malloc(sizeof(struct SNAME)); \
|
||||
struct cmc_alloc_node *alloc = &cmc_alloc_node_default; \
|
||||
\
|
||||
struct SNAME *_map_ = alloc->malloc(sizeof(struct SNAME)); \
|
||||
\
|
||||
if (!_map_) \
|
||||
return NULL; \
|
||||
@@ -183,6 +256,33 @@ static const char *cmc_string_fmt_treemap = "%s at %p { root:%p, count:%" PRIuMA
|
||||
_map_->it_start = PFX##_impl_it_start; \
|
||||
_map_->it_end = PFX##_impl_it_end; \
|
||||
\
|
||||
_map_->alloc = alloc; \
|
||||
_map_->callbacks = NULL; \
|
||||
\
|
||||
return _map_; \
|
||||
} \
|
||||
\
|
||||
struct SNAME *PFX##_new_custom(int (*compare)(K, K), struct cmc_alloc_node *alloc, \
|
||||
struct cmc_callbacks_treemap *callbacks) \
|
||||
{ \
|
||||
if (!alloc) \
|
||||
alloc = &cmc_alloc_node_default; \
|
||||
\
|
||||
struct SNAME *_map_ = alloc->malloc(sizeof(struct SNAME)); \
|
||||
\
|
||||
if (!_map_) \
|
||||
return NULL; \
|
||||
\
|
||||
_map_->count = 0; \
|
||||
_map_->root = NULL; \
|
||||
_map_->cmp = compare; \
|
||||
\
|
||||
_map_->it_start = PFX##_impl_it_start; \
|
||||
_map_->it_end = PFX##_impl_it_end; \
|
||||
\
|
||||
_map_->alloc = alloc; \
|
||||
_map_->callbacks = callbacks; \
|
||||
\
|
||||
return _map_; \
|
||||
} \
|
||||
\
|
||||
@@ -590,10 +690,15 @@ static const char *cmc_string_fmt_treemap = "%s at %p { root:%p, count:%" PRIuMA
|
||||
{ \
|
||||
struct cmc_string str; \
|
||||
struct 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); \
|
||||
int n = snprintf(str.s, cmc_string_len, cmc_string_fmt_treemap, \
|
||||
#SNAME, #K, #V, m_, m_->root, m_->count, m_->cmp, \
|
||||
m_->alloc, m_->callbacks); \
|
||||
\
|
||||
if (n < 0 || n == (int)cmc_string_len) \
|
||||
return (struct cmc_string){0}; \
|
||||
\
|
||||
str.s[n] = '\0'; \
|
||||
\
|
||||
return str; \
|
||||
} \
|
||||
|
||||
+115
-10
@@ -24,10 +24,66 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "../utl/cmc_string.h"
|
||||
|
||||
/* -------------------------------------------------------------------------------------------------
|
||||
* Core functionalities of the C Macro Collections Library
|
||||
------------------------------------------------------------------------------------------------ */
|
||||
#ifndef CMC_CORE_H
|
||||
#define CMC_CORE_H
|
||||
|
||||
/**
|
||||
* struct cmc_string
|
||||
*
|
||||
* Used by all collections when calling the to_string function.
|
||||
*/
|
||||
struct cmc_string
|
||||
{
|
||||
char s[400];
|
||||
};
|
||||
|
||||
static const size_t cmc_string_len = 400;
|
||||
|
||||
/**
|
||||
* struct cmc_alloc_node
|
||||
*
|
||||
* Custom allocation node. Allows collections to use custom allocation functions.
|
||||
*/
|
||||
struct cmc_alloc_node
|
||||
{
|
||||
void *(*malloc)(size_t);
|
||||
void *(*calloc)(size_t, size_t);
|
||||
void *(*realloc)(void *, size_t);
|
||||
void (*free)(void *);
|
||||
} cmc_alloc_node_default = {malloc, calloc, realloc, free};
|
||||
|
||||
#endif /* CMC_CORE_H */
|
||||
|
||||
/* -------------------------------------------------------------------------------------------------
|
||||
* TreeSet specific
|
||||
------------------------------------------------------------------------------------------------ */
|
||||
/* to_string format */
|
||||
static const char *cmc_string_fmt_treeset = "%s at %p { root:%p, count:%" PRIuMAX ", cmp:%p }";
|
||||
static const char *cmc_string_fmt_treeset = "struct %s<%s> "
|
||||
"at %p { "
|
||||
"root:%p, "
|
||||
"count:%" PRIuMAX ", "
|
||||
"cmp:%p, "
|
||||
"alloc:%p, "
|
||||
"callbacks:%p }";
|
||||
|
||||
/**
|
||||
* Custom TreeSet callbacks.
|
||||
*
|
||||
* There are two types of callbacks, 'before' and 'after':
|
||||
* <before|after>_<function_name>
|
||||
*/
|
||||
struct cmc_callbacks_treeset
|
||||
{
|
||||
void (*before_clear)(void *);
|
||||
void (*after_clear)(void *);
|
||||
void (*before_free)(void *);
|
||||
void (*after_free)(void *);
|
||||
// TODO implement all callbacks
|
||||
};
|
||||
|
||||
#define CMC_GENERATE_TREESET(PFX, SNAME, V) \
|
||||
CMC_GENERATE_TREESET_HEADER(PFX, SNAME, V) \
|
||||
@@ -39,7 +95,9 @@ static const char *cmc_string_fmt_treeset = "%s at %p { root:%p, count:%" PRIuMA
|
||||
#define CMC_WRAPGEN_TREESET_SOURCE(PFX, SNAME, K, V) \
|
||||
CMC_GENERATE_TREESET_SOURCE(PFX, SNAME, V)
|
||||
|
||||
/* HEADER ********************************************************************/
|
||||
/* -------------------------------------------------------------------------------------------------
|
||||
* Header
|
||||
------------------------------------------------------------------------------------------------ */
|
||||
#define CMC_GENERATE_TREESET_HEADER(PFX, SNAME, V) \
|
||||
\
|
||||
/* Treeset Structure */ \
|
||||
@@ -59,6 +117,12 @@ static const char *cmc_string_fmt_treeset = "%s at %p { root:%p, count:%" PRIuMA
|
||||
\
|
||||
/* Function that returns an iterator to the end of the treeset */ \
|
||||
struct SNAME##_iter (*it_end)(struct SNAME *); \
|
||||
\
|
||||
/* Custom allocation functions */ \
|
||||
struct cmc_alloc_node *alloc; \
|
||||
\
|
||||
/* Custom callback functions */ \
|
||||
struct cmc_callbacks_treeset *callbacks; \
|
||||
}; \
|
||||
\
|
||||
/* Treeset Node */ \
|
||||
@@ -108,8 +172,13 @@ static const char *cmc_string_fmt_treeset = "%s at %p { root:%p, count:%" PRIuMA
|
||||
/* Collection Functions */ \
|
||||
/* Collection Allocation and Deallocation */ \
|
||||
struct SNAME *PFX##_new(int (*compare)(V, V)); \
|
||||
struct SNAME *PFX##_new_custom(int (*compare)(V, V), struct cmc_alloc_node *alloc, \
|
||||
struct cmc_callbacks_treeset *callbacks); \
|
||||
void PFX##_clear(struct SNAME *_set_, void (*deallocator)(V)); \
|
||||
void PFX##_free(struct SNAME *_set_, void (*deallocator)(V)); \
|
||||
/* Customization of Allocation and Callbacks */ \
|
||||
void PFX##_customize(struct SNAME *_set_, struct cmc_alloc_node *alloc, \
|
||||
struct cmc_callbacks_treeset *callbacks); \
|
||||
/* Collection Input and Output */ \
|
||||
bool PFX##_insert(struct SNAME *_set_, V element); \
|
||||
bool PFX##_remove(struct SNAME *_set_, V element); \
|
||||
@@ -165,9 +234,11 @@ static const char *cmc_string_fmt_treeset = "%s at %p { root:%p, count:%" PRIuMA
|
||||
memset(&_empty_value_, 0, sizeof(V)); \
|
||||
\
|
||||
return _empty_value_; \
|
||||
} \
|
||||
\
|
||||
/* SOURCE ********************************************************************/
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------------------------------
|
||||
* Source
|
||||
------------------------------------------------------------------------------------------------ */
|
||||
#define CMC_GENERATE_TREESET_SOURCE(PFX, SNAME, V) \
|
||||
\
|
||||
/* Implementation Detail Functions */ \
|
||||
@@ -183,7 +254,9 @@ static const char *cmc_string_fmt_treeset = "%s at %p { root:%p, count:%" PRIuMA
|
||||
\
|
||||
struct SNAME *PFX##_new(int (*compare)(V, V)) \
|
||||
{ \
|
||||
struct SNAME *_set_ = malloc(sizeof(struct SNAME)); \
|
||||
struct cmc_alloc_node *alloc = &cmc_alloc_node_default; \
|
||||
\
|
||||
struct SNAME *_set_ = alloc->malloc(sizeof(struct SNAME)); \
|
||||
\
|
||||
if (!_set_) \
|
||||
return NULL; \
|
||||
@@ -195,6 +268,33 @@ static const char *cmc_string_fmt_treeset = "%s at %p { root:%p, count:%" PRIuMA
|
||||
_set_->it_start = PFX##_impl_it_start; \
|
||||
_set_->it_end = PFX##_impl_it_end; \
|
||||
\
|
||||
_set_->alloc = alloc; \
|
||||
_set_->callbacks = NULL; \
|
||||
\
|
||||
return _set_; \
|
||||
} \
|
||||
\
|
||||
struct SNAME *PFX##_new_custom(int (*compare)(V, V), struct cmc_alloc_node *alloc, \
|
||||
struct cmc_callbacks_treeset *callbacks) \
|
||||
{ \
|
||||
if (!alloc) \
|
||||
alloc = &cmc_alloc_node_default; \
|
||||
\
|
||||
struct SNAME *_set_ = alloc->malloc(sizeof(struct SNAME)); \
|
||||
\
|
||||
if (!_set_) \
|
||||
return NULL; \
|
||||
\
|
||||
_set_->count = 0; \
|
||||
_set_->root = NULL; \
|
||||
_set_->cmp = compare; \
|
||||
\
|
||||
_set_->it_start = PFX##_impl_it_start; \
|
||||
_set_->it_end = PFX##_impl_it_end; \
|
||||
\
|
||||
_set_->alloc = alloc; \
|
||||
_set_->callbacks = callbacks; \
|
||||
\
|
||||
return _set_; \
|
||||
} \
|
||||
\
|
||||
@@ -546,10 +646,15 @@ static const char *cmc_string_fmt_treeset = "%s at %p { root:%p, count:%" PRIuMA
|
||||
{ \
|
||||
struct cmc_string str; \
|
||||
struct 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); \
|
||||
int n = snprintf(str.s, cmc_string_len, cmc_string_fmt_treeset, \
|
||||
#SNAME, #V, s_, s_->root, s_->count, s_->cmp, \
|
||||
s_->alloc, s_->callbacks); \
|
||||
\
|
||||
if (n < 0 || n == (int)cmc_string_len) \
|
||||
return (struct cmc_string){0}; \
|
||||
\
|
||||
str.s[n] = '\0'; \
|
||||
\
|
||||
return str; \
|
||||
} \
|
||||
|
||||
Reference in new issue
Block a user