Updated with latest Tommy
Some checks failed
Build / build-mac (push) Has been cancelled
Build / build-linux (push) Has been cancelled
Build / build-win (push) Has been cancelled
CodeQL / Analyze (push) Has been cancelled

This commit is contained in:
Andrea Mazzoleni 2025-12-03 19:10:13 +01:00
parent 45d278483c
commit 3c7b90e93f
14 changed files with 163 additions and 120 deletions

View file

@ -30,7 +30,7 @@
/******************************************************************************/
/* array */
void tommy_array_init(tommy_array* array)
TOMMY_API void tommy_array_init(tommy_array* array)
{
tommy_uint_t i;
@ -44,7 +44,7 @@ void tommy_array_init(tommy_array* array)
array->count = 0;
}
void tommy_array_done(tommy_array* array)
TOMMY_API void tommy_array_done(tommy_array* array)
{
tommy_uint_t i;
@ -55,7 +55,7 @@ void tommy_array_done(tommy_array* array)
}
}
void tommy_array_grow(tommy_array* array, tommy_size_t count)
TOMMY_API void tommy_array_grow(tommy_array* array, tommy_size_t count)
{
if (array->count >= count)
return;
@ -76,7 +76,7 @@ void tommy_array_grow(tommy_array* array, tommy_size_t count)
}
}
tommy_size_t tommy_array_memory_usage(tommy_array* array)
TOMMY_API tommy_size_t tommy_array_memory_usage(tommy_array* array)
{
return array->bucket_max * (tommy_size_t)sizeof(void*);
}

View file

@ -26,12 +26,12 @@
*/
/** \file
* Dynamic array based on segments of exponential growing size.
* Dynamic array based on segments of exponentially growing size.
*
* This array is able to grow dynamically upon request, without any reallocation.
*
* The grow operation involves an allocation of a new array segment, without reallocating
* the already used memory, and then not increasing the heap fragmentation.
* the already used memory, and thus **not increasing** the heap fragmentation.
* This also implies that the address of the stored elements never change.
*
* Allocated segments grow in size exponentially.
@ -67,18 +67,18 @@ typedef struct tommy_array_struct {
/**
* Initializes the array.
*/
void tommy_array_init(tommy_array* array);
TOMMY_API void tommy_array_init(tommy_array* array);
/**
* Deinitializes the array.
*/
void tommy_array_done(tommy_array* array);
TOMMY_API void tommy_array_done(tommy_array* array);
/**
* Grows the size up to the specified value.
* All the new elements in the array are initialized with the 0 value.
*/
void tommy_array_grow(tommy_array* array, tommy_size_t size);
TOMMY_API void tommy_array_grow(tommy_array* array, tommy_size_t size);
/**
* Gets a reference of the element at the specified position.
@ -140,7 +140,6 @@ tommy_inline tommy_size_t tommy_array_size(tommy_array* array)
/**
* Gets the size of allocated memory.
*/
tommy_size_t tommy_array_memory_usage(tommy_array* array);
TOMMY_API tommy_size_t tommy_array_memory_usage(tommy_array* array);
#endif

View file

@ -30,7 +30,7 @@
/******************************************************************************/
/* array */
void tommy_arrayblkof_init(tommy_arrayblkof* array, tommy_size_t element_size)
TOMMY_API void tommy_arrayblkof_init(tommy_arrayblkof* array, tommy_size_t element_size)
{
tommy_array_init(&array->block);
@ -38,7 +38,7 @@ void tommy_arrayblkof_init(tommy_arrayblkof* array, tommy_size_t element_size)
array->count = 0;
}
void tommy_arrayblkof_done(tommy_arrayblkof* array)
TOMMY_API void tommy_arrayblkof_done(tommy_arrayblkof* array)
{
tommy_size_t i;
@ -48,7 +48,7 @@ void tommy_arrayblkof_done(tommy_arrayblkof* array)
tommy_array_done(&array->block);
}
void tommy_arrayblkof_grow(tommy_arrayblkof* array, tommy_size_t count)
TOMMY_API void tommy_arrayblkof_grow(tommy_arrayblkof* array, tommy_size_t count)
{
tommy_size_t block_max;
tommy_size_t block_mac;
@ -76,7 +76,7 @@ void tommy_arrayblkof_grow(tommy_arrayblkof* array, tommy_size_t count)
}
}
tommy_size_t tommy_arrayblkof_memory_usage(tommy_arrayblkof* array)
TOMMY_API tommy_size_t tommy_arrayblkof_memory_usage(tommy_arrayblkof* array)
{
return tommy_array_memory_usage(&array->block) + tommy_array_size(&array->block) * TOMMY_ARRAYBLKOF_SIZE * array->element_size;
}

View file

@ -30,7 +30,7 @@
*
* This array is able to grow dynamically upon request, without any reallocation.
*
* This is very similar at ::tommy_arrayblk, but it allows to store elements of any
* This is very similar to ::tommy_arrayblk, but it allows to store elements of any
* size and not just pointers.
*
* Note that in this case tommy_arrayblkof_ref() returns a pointer to the element,
@ -68,18 +68,18 @@ typedef struct tommy_arrayblkof_struct {
* Initializes the array.
* \param element_size Size in byte of the element to store in the array.
*/
void tommy_arrayblkof_init(tommy_arrayblkof* array, tommy_size_t element_size);
TOMMY_API void tommy_arrayblkof_init(tommy_arrayblkof* array, tommy_size_t element_size);
/**
* Deinitializes the array.
*/
void tommy_arrayblkof_done(tommy_arrayblkof* array);
TOMMY_API void tommy_arrayblkof_done(tommy_arrayblkof* array);
/**
* Grows the size up to the specified value.
* All the new elements in the array are initialized with the 0 value.
*/
void tommy_arrayblkof_grow(tommy_arrayblkof* array, tommy_size_t size);
TOMMY_API void tommy_arrayblkof_grow(tommy_arrayblkof* array, tommy_size_t size);
/**
* Gets a reference of the element at the specified position.
@ -108,7 +108,6 @@ tommy_inline tommy_size_t tommy_arrayblkof_size(tommy_arrayblkof* array)
/**
* Gets the size of allocated memory.
*/
tommy_size_t tommy_arrayblkof_memory_usage(tommy_arrayblkof* array);
TOMMY_API tommy_size_t tommy_arrayblkof_memory_usage(tommy_arrayblkof* array);
#endif

View file

@ -27,7 +27,7 @@
/** \file
* Chain of nodes.
* A chain of nodes is an abstraction used to implements complex list operations
* A chain of nodes is an abstraction used to implement complex list operations
* like sorting.
*
* Do not use this directly. Use lists instead.
@ -44,7 +44,7 @@
/**
* Chain of nodes.
* A chain of nodes is a sequence of nodes with the following properties:
* - It contains at least one node. A chains of zero nodes cannot exist.
* - It contains at least one node. A chain of zero nodes cannot exist.
* - The next field of the tail is of *undefined* value.
* - The prev field of the head is of *undefined* value.
* - All the other inner prev and next fields are correctly set.
@ -56,6 +56,10 @@ typedef struct tommy_chain_struct {
/**
* Splices a chain in the middle of another chain.
* \param first_before Node before the splice point.
* \param first_after Node after the splice point.
* \param second_head Head of the chain to splice in.
* \param second_tail Tail of the chain to splice in.
*/
tommy_inline void tommy_chain_splice(tommy_node* first_before, tommy_node* first_after, tommy_node* second_head, tommy_node* second_tail)
{
@ -69,7 +73,9 @@ tommy_inline void tommy_chain_splice(tommy_node* first_before, tommy_node* first
}
/**
* Concats two chains.
* Concatenates two chains.
* \param first_tail Tail of the first chain.
* \param second_head Head of the second chain.
*/
tommy_inline void tommy_chain_concat(tommy_node* first_tail, tommy_node* second_head)
{
@ -82,6 +88,9 @@ tommy_inline void tommy_chain_concat(tommy_node* first_tail, tommy_node* second_
/**
* Merges two chains.
* \param first First chain (will contain the result).
* \param second Second chain (will be empty after the merge).
* \param cmp Comparison function.
*/
tommy_inline void tommy_chain_merge(tommy_chain* first, tommy_chain* second, tommy_compare_func* cmp)
{
@ -114,7 +123,10 @@ tommy_inline void tommy_chain_merge(tommy_chain* first, tommy_chain* second, tom
/**
* Merges two chains managing special degenerated cases.
* It's functionally equivalent at tommy_chain_merge() but faster with already ordered chains.
* It's functionally equivalent to tommy_chain_merge() but faster with already ordered chains.
* \param first First chain (will contain the result).
* \param second Second chain (will be empty after the merge).
* \param cmp Comparison function.
*/
tommy_inline void tommy_chain_merge_degenerated(tommy_chain* first, tommy_chain* second, tommy_compare_func* cmp)
{
@ -139,7 +151,7 @@ tommy_inline void tommy_chain_merge_degenerated(tommy_chain* first, tommy_chain*
/**
* Sorts a chain.
* It's a stable merge sort using power of 2 buckets, with O(N*log(N)) complexity,
* similar at the one used in the SGI STL libraries and in the Linux Kernel,
* similar to the one used in the SGI STL libraries and in the Linux Kernel,
* but faster on degenerated cases like already ordered lists.
*
* SGI STL stl_list.h
@ -147,6 +159,9 @@ tommy_inline void tommy_chain_merge_degenerated(tommy_chain* first, tommy_chain*
*
* Linux Kernel lib/list_sort.c
* http://lxr.linux.no/#linux+v2.6.36/lib/list_sort.c
*
* \param chain Chain to sort.
* \param cmp Comparison function.
*/
tommy_inline void tommy_chain_mergesort(tommy_chain* chain, tommy_compare_func* cmp)
{
@ -160,7 +175,7 @@ tommy_inline void tommy_chain_mergesort(tommy_chain* chain, tommy_compare_func*
/**
* Value stored inside the bit bucket.
* It's used to know which bucket is empty of full.
* It's used to know which bucket is empty or full.
*/
tommy_size_t counter;
tommy_node* node = chain->head;
@ -216,4 +231,3 @@ tommy_inline void tommy_chain_mergesort(tommy_chain* chain, tommy_compare_func*
}
#endif

View file

@ -30,16 +30,33 @@
/******************************************************************************/
/* hash */
#include <string.h> /* for memcpy */
/**
* Swap endianness.
* They are needed only if BigEndian.
*/
#if defined(__GNUC__)
#define tommy_swap32(x) __builtin_bswap32(x)
#else
tommy_inline tommy_uint32_t tommy_swap32(tommy_uint32_t v)
{
return ((v & 0xFF000000) >> 24) |
((v & 0x00FF0000) >> 8) |
((v & 0x0000FF00) << 8) |
((v & 0x000000FF) << 24);
}
#endif
tommy_inline tommy_uint32_t tommy_le_uint32_read(const void* ptr)
{
/* allow unaligned read on Intel x86 and x86_64 platforms */
#if defined(__i386__) || defined(_M_IX86) || defined(_X86_) || defined(__x86_64__) || defined(_M_X64)
/* defines from http://predef.sourceforge.net/ */
return *(const tommy_uint32_t*)ptr;
#else
const unsigned char* ptr8 = tommy_cast(const unsigned char*, ptr);
return ptr8[0] + ((tommy_uint32_t)ptr8[1] << 8) + ((tommy_uint32_t)ptr8[2] << 16) + ((tommy_uint32_t)ptr8[3] << 24);
tommy_uint32_t v;
memcpy(&v, ptr, sizeof(v));
#if defined(WORDS_BIGENDIAN) || defined(__BIG_ENDIAN__) || \
(defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
v = tommy_swap32(v);
#endif
return v;
}
#define tommy_rot(x, k) \
@ -66,7 +83,7 @@ tommy_inline tommy_uint32_t tommy_le_uint32_read(const void* ptr)
c ^= b; c -= tommy_rot(b, 24); \
} while (0)
tommy_uint32_t tommy_hash_u32(tommy_uint32_t init_val, const void* void_key, tommy_size_t key_len)
TOMMY_API tommy_uint32_t tommy_hash_u32(tommy_uint32_t init_val, const void* void_key, tommy_size_t key_len)
{
const unsigned char* key = tommy_cast(const unsigned char*, void_key);
tommy_uint32_t a, b, c;
@ -115,7 +132,7 @@ tommy_uint32_t tommy_hash_u32(tommy_uint32_t init_val, const void* void_key, tom
return c;
}
tommy_uint64_t tommy_hash_u64(tommy_uint64_t init_val, const void* void_key, tommy_size_t key_len)
TOMMY_API tommy_uint64_t tommy_hash_u64(tommy_uint64_t init_val, const void* void_key, tommy_size_t key_len)
{
const unsigned char* key = tommy_cast(const unsigned char*, void_key);
tommy_uint32_t a, b, c;
@ -165,7 +182,7 @@ tommy_uint64_t tommy_hash_u64(tommy_uint64_t init_val, const void* void_key, tom
return c + ((tommy_uint64_t)b << 32);
}
tommy_uint32_t tommy_strhash_u32(tommy_uint32_t init_val, const void* void_key)
TOMMY_API tommy_uint32_t tommy_strhash_u32(tommy_uint32_t init_val, const void* void_key)
{
const unsigned char* key = tommy_cast(const unsigned char*, void_key);
tommy_uint32_t a, b, c;

View file

@ -42,7 +42,7 @@
* Implementation of the Robert Jenkins "lookup3" hash 32 bits version,
* from http://www.burtleburtle.net/bob/hash/doobs.html, function hashlittle().
*
* This hash is designed to provide a good overall performance in all platforms,
* This hash is designed to provide a good overall performance on all platforms,
* including 32 bits. If you target only 64 bits, you can use faster hashes,
* like SpookyHash or FarmHash.
*
@ -55,14 +55,14 @@
* This function is endianness independent.
* \return The hash value of 32 bits.
*/
tommy_uint32_t tommy_hash_u32(tommy_uint32_t init_val, const void* void_key, tommy_size_t key_len);
TOMMY_API tommy_uint32_t tommy_hash_u32(tommy_uint32_t init_val, const void* void_key, tommy_size_t key_len);
/**
* Hash function with a 64 bits result.
* Implementation of the Robert Jenkins "lookup3" hash 64 bits versions,
* Implementation of the Robert Jenkins "lookup3" hash 64 bits version,
* from http://www.burtleburtle.net/bob/hash/doobs.html, function hashlittle2().
*
* This hash is designed to provide a good overall performance in all platforms,
* This hash is designed to provide a good overall performance on all platforms,
* including 32 bits. If you target only 64 bits, you can use faster hashes,
* like SpookyHash or FarmHash.
*
@ -75,7 +75,7 @@ tommy_uint32_t tommy_hash_u32(tommy_uint32_t init_val, const void* void_key, tom
* This function is endianness independent.
* \return The hash value of 64 bits.
*/
tommy_uint64_t tommy_hash_u64(tommy_uint64_t init_val, const void* void_key, tommy_size_t key_len);
TOMMY_API tommy_uint64_t tommy_hash_u64(tommy_uint64_t init_val, const void* void_key, tommy_size_t key_len);
/**
* String hash function with a 32 bits result.
@ -93,7 +93,7 @@ tommy_uint64_t tommy_hash_u64(tommy_uint64_t init_val, const void* void_key, tom
* This function is endianness independent.
* \return The hash value of 32 bits.
*/
tommy_uint32_t tommy_strhash_u32(tommy_uint32_t init_val, const void* void_key);
TOMMY_API tommy_uint32_t tommy_strhash_u32(tommy_uint32_t init_val, const void* void_key);
/**
* Integer reversible hash function for 32 bits.
@ -132,4 +132,3 @@ tommy_inline tommy_uint64_t tommy_inthash_u64(tommy_uint64_t key)
}
#endif

View file

@ -31,7 +31,7 @@
/******************************************************************************/
/* hashdyn */
void tommy_hashdyn_init(tommy_hashdyn* hashdyn)
TOMMY_API void tommy_hashdyn_init(tommy_hashdyn* hashdyn)
{
/* fixed initial size */
hashdyn->bucket_bit = TOMMY_HASHDYN_BIT;
@ -42,7 +42,7 @@ void tommy_hashdyn_init(tommy_hashdyn* hashdyn)
hashdyn->count = 0;
}
void tommy_hashdyn_done(tommy_hashdyn* hashdyn)
TOMMY_API void tommy_hashdyn_done(tommy_hashdyn* hashdyn)
{
tommy_free(hashdyn->bucket);
}
@ -50,7 +50,7 @@ void tommy_hashdyn_done(tommy_hashdyn* hashdyn)
/**
* Resize the bucket vector.
*/
static void tommy_hashdyn_resize(tommy_hashdyn* hashdyn, tommy_size_t new_bucket_bit)
static void tommy_hashdyn_resize(tommy_hashdyn* hashdyn, tommy_uint_t new_bucket_bit)
{
tommy_size_t bucket_bit;
tommy_size_t bucket_max;
@ -134,7 +134,7 @@ tommy_inline void hashdyn_shrink_step(tommy_hashdyn* hashdyn)
tommy_hashdyn_resize(hashdyn, hashdyn->bucket_bit - 1);
}
void tommy_hashdyn_insert(tommy_hashdyn* hashdyn, tommy_hashdyn_node* node, void* data, tommy_hash_t hash)
TOMMY_API void tommy_hashdyn_insert(tommy_hashdyn* hashdyn, tommy_hashdyn_node* node, void* data, tommy_hash_t hash)
{
tommy_size_t pos = hash & hashdyn->bucket_mask;
@ -147,7 +147,7 @@ void tommy_hashdyn_insert(tommy_hashdyn* hashdyn, tommy_hashdyn_node* node, void
hashdyn_grow_step(hashdyn);
}
void* tommy_hashdyn_remove_existing(tommy_hashdyn* hashdyn, tommy_hashdyn_node* node)
TOMMY_API void* tommy_hashdyn_remove_existing(tommy_hashdyn* hashdyn, tommy_hashdyn_node* node)
{
tommy_size_t pos = node->index & hashdyn->bucket_mask;
@ -160,7 +160,7 @@ void* tommy_hashdyn_remove_existing(tommy_hashdyn* hashdyn, tommy_hashdyn_node*
return node->data;
}
void* tommy_hashdyn_remove(tommy_hashdyn* hashdyn, tommy_search_func* cmp, const void* cmp_arg, tommy_hash_t hash)
TOMMY_API void* tommy_hashdyn_remove(tommy_hashdyn* hashdyn, tommy_search_func* cmp, const void* cmp_arg, tommy_hash_t hash)
{
tommy_size_t pos = hash & hashdyn->bucket_mask;
tommy_hashdyn_node* node = hashdyn->bucket[pos];
@ -182,7 +182,7 @@ void* tommy_hashdyn_remove(tommy_hashdyn* hashdyn, tommy_search_func* cmp, const
return 0;
}
void tommy_hashdyn_foreach(tommy_hashdyn* hashdyn, tommy_foreach_func* func)
TOMMY_API void tommy_hashdyn_foreach(tommy_hashdyn* hashdyn, tommy_foreach_func* func)
{
tommy_size_t bucket_max = hashdyn->bucket_max;
tommy_hashdyn_node** bucket = hashdyn->bucket;
@ -199,7 +199,7 @@ void tommy_hashdyn_foreach(tommy_hashdyn* hashdyn, tommy_foreach_func* func)
}
}
void tommy_hashdyn_foreach_arg(tommy_hashdyn* hashdyn, tommy_foreach_arg_func* func, void* arg)
TOMMY_API void tommy_hashdyn_foreach_arg(tommy_hashdyn* hashdyn, tommy_foreach_arg_func* func, void* arg)
{
tommy_size_t bucket_max = hashdyn->bucket_max;
tommy_hashdyn_node** bucket = hashdyn->bucket;
@ -216,7 +216,7 @@ void tommy_hashdyn_foreach_arg(tommy_hashdyn* hashdyn, tommy_foreach_arg_func* f
}
}
tommy_size_t tommy_hashdyn_memory_usage(tommy_hashdyn* hashdyn)
TOMMY_API tommy_size_t tommy_hashdyn_memory_usage(tommy_hashdyn* hashdyn)
{
return hashdyn->bucket_max * (tommy_size_t)sizeof(hashdyn->bucket[0])
+ tommy_hashdyn_count(hashdyn) * (tommy_size_t)sizeof(tommy_hashdyn_node);

View file

@ -29,8 +29,8 @@
* Dynamic chained hashtable.
*
* This hashtable resizes dynamically. It starts with the minimal size of 16 buckets, it doubles
* the size then it reaches a load factor greater than 0.5 and it halves the size with a load
* factor lower than 0.125.
* the size when it reaches a load factor greater than 0.5 and it halves the size when the load
* factor is lower than 0.125.
*
* All the elements are reallocated in a single resize operation done inside
* tommy_hashdyn_insert() or tommy_hashdyn_remove().
@ -38,15 +38,15 @@
* Note that the resize operation takes approximately 100 [ms] with 1 million of elements,
* and 1 [second] with 10 millions. This could be a problem in real-time applications.
*
* The resize also fragment the heap, as it involves allocating a double-sized table, copy elements,
* and deallocating the older table. Leaving a big hole in the heap.
* The resize also **fragments** the heap, as it involves allocating a double-sized table, **copying** elements,
* and deallocating the older table, **leaving** a big hole in the heap.
*
* The ::tommy_hashlin hashtable fixes both problems.
*
* To initialize the hashtable you have to call tommy_hashdyn_init().
*
* \code
* tommy_hashslin hashdyn;
* tommy_hashdyn hashdyn;
*
* tommy_hashdyn_init(&hashdyn);
* \endcode
@ -72,7 +72,7 @@
* tommy_hashdyn_insert(&hashdyn, &obj->node, obj, tommy_inthash_u32(obj->value)); // inserts the object
* \endcode
*
* To find and element in the hashtable you have to call tommy_hashtable_search()
* To find an element in the hashtable you have to call tommy_hashtable_search()
* providing a comparison function, its argument, and the hash of the key to search.
*
* \code
@ -92,7 +92,7 @@
*
* To iterate over all the elements in the hashtable with the same key, you have to
* use tommy_hashdyn_bucket() and follow the tommy_node::next pointer until NULL.
* You have also to check explicitly for the key, as the bucket may contains
* You have also to check explicitly for the key, as the bucket may contain
* different keys.
*
* \code
@ -169,7 +169,7 @@ typedef struct tommy_hashdyn_struct {
/**
* Initializes the hashtable.
*/
void tommy_hashdyn_init(tommy_hashdyn* hashdyn);
TOMMY_API void tommy_hashdyn_init(tommy_hashdyn* hashdyn);
/**
* Deinitializes the hashtable.
@ -177,12 +177,12 @@ void tommy_hashdyn_init(tommy_hashdyn* hashdyn);
* You can call this function with elements still contained,
* but such elements are not going to be freed by this call.
*/
void tommy_hashdyn_done(tommy_hashdyn* hashdyn);
TOMMY_API void tommy_hashdyn_done(tommy_hashdyn* hashdyn);
/**
* Inserts an element in the hashtable.
*/
void tommy_hashdyn_insert(tommy_hashdyn* hashdyn, tommy_hashdyn_node* node, void* data, tommy_hash_t hash);
TOMMY_API void tommy_hashdyn_insert(tommy_hashdyn* hashdyn, tommy_hashdyn_node* node, void* data, tommy_hash_t hash);
/**
* Searches and removes an element from the hashtable.
@ -195,7 +195,7 @@ void tommy_hashdyn_insert(tommy_hashdyn* hashdyn, tommy_hashdyn_node* node, void
* \param hash Hash of the element to find and remove.
* \return The removed element, or 0 if not found.
*/
void* tommy_hashdyn_remove(tommy_hashdyn* hashdyn, tommy_search_func* cmp, const void* cmp_arg, tommy_hash_t hash);
TOMMY_API void* tommy_hashdyn_remove(tommy_hashdyn* hashdyn, tommy_search_func* cmp, const void* cmp_arg, tommy_hash_t hash);
/**
* Gets the bucket of the specified hash.
@ -225,7 +225,7 @@ tommy_inline void* tommy_hashdyn_search(tommy_hashdyn* hashdyn, tommy_search_fun
tommy_hashdyn_node* i = tommy_hashdyn_bucket(hashdyn, hash);
while (i) {
/* we first check if the hash matches, as in the same bucket we may have multiples hash values */
/* we first check if the hash matches, as in the same bucket we may have multiple hash values */
if (i->index == hash && cmp(cmp_arg, i->data) == 0)
return i->data;
i = i->next;
@ -238,7 +238,7 @@ tommy_inline void* tommy_hashdyn_search(tommy_hashdyn* hashdyn, tommy_search_fun
* You must already have the address of the element to remove.
* \return The tommy_node::data field of the node removed.
*/
void* tommy_hashdyn_remove_existing(tommy_hashdyn* hashdyn, tommy_hashdyn_node* node);
TOMMY_API void* tommy_hashdyn_remove_existing(tommy_hashdyn* hashdyn, tommy_hashdyn_node* node);
/**
* Calls the specified function for each element in the hashtable.
@ -271,12 +271,12 @@ void* tommy_hashdyn_remove_existing(tommy_hashdyn* hashdyn, tommy_hashdyn_node*
* tommy_hashdyn_done(&hashdyn);
* \endcode
*/
void tommy_hashdyn_foreach(tommy_hashdyn* hashdyn, tommy_foreach_func* func);
TOMMY_API void tommy_hashdyn_foreach(tommy_hashdyn* hashdyn, tommy_foreach_func* func);
/**
* Calls the specified function with an argument for each element in the hashtable.
*/
void tommy_hashdyn_foreach_arg(tommy_hashdyn* hashdyn, tommy_foreach_arg_func* func, void* arg);
TOMMY_API void tommy_hashdyn_foreach_arg(tommy_hashdyn* hashdyn, tommy_foreach_arg_func* func, void* arg);
/**
* Gets the number of elements.
@ -290,7 +290,6 @@ tommy_inline tommy_size_t tommy_hashdyn_count(tommy_hashdyn* hashdyn)
* Gets the size of allocated memory.
* It includes the size of the ::tommy_hashdyn_node of the stored elements.
*/
tommy_size_t tommy_hashdyn_memory_usage(tommy_hashdyn* hashdyn);
TOMMY_API tommy_size_t tommy_hashdyn_memory_usage(tommy_hashdyn* hashdyn);
#endif

View file

@ -38,7 +38,7 @@ tommy_inline void tommy_list_set(tommy_list* list, tommy_node* head, tommy_node*
*list = head;
}
void tommy_list_sort(tommy_list* list, tommy_compare_func* cmp)
TOMMY_API void tommy_list_sort(tommy_list* list, tommy_compare_func* cmp)
{
tommy_chain chain;
tommy_node* head;

View file

@ -28,14 +28,14 @@
/** \file
* Double linked list for collisions into hashtables.
*
* This list is a double linked list mainly targeted for handling collisions
* into an hashtables, but useable also as a generic list.
* This list is a **doubly** linked list mainly targeted for handling collisions
* into an hashtable, but **usable** also as a generic list.
*
* The main feature of this list is to require only one pointer to represent the
* list, compared to a classic implementation requiring a head an a tail pointers.
* list, compared to a classic implementation requiring a head **and** a tail pointers.
* This reduces the memory usage in hashtables.
*
* Another feature is to support the insertion at the end of the list. This allow to store
* Another feature is to support the insertion at the end of the list. This **allows** to store
* collisions in a stable order. Where for stable order we mean that equal elements keep
* their insertion order.
*
@ -103,7 +103,7 @@
/* list */
/**
* Double linked list type.
* Doubly linked list type.
*/
typedef tommy_node* tommy_list;
@ -156,7 +156,7 @@ tommy_inline void tommy_list_insert_first(tommy_list* list, tommy_node* node)
}
/** \internal
* Inserts an element at the head of a not empty list.
* Inserts an element at the head of a non-empty list.
* The element is inserted at the head of the list. The list cannot be empty.
* \param list The list. The list cannot be empty.
* \param node The node to insert.
@ -176,7 +176,7 @@ tommy_inline void tommy_list_insert_head_not_empty(tommy_list* list, tommy_node*
}
/** \internal
* Inserts an element at the tail of a not empty list.
* Inserts an element at the tail of a non-empty list.
* The element is inserted at the tail of the list. The list cannot be empty.
* \param head The node at the list head. It cannot be 0.
* \param node The node to insert.
@ -194,6 +194,7 @@ tommy_inline void tommy_list_insert_tail_not_empty(tommy_node* head, tommy_node*
/**
* Inserts an element at the head of a list.
* \param list The list.
* \param node The node to insert.
* \param data The object containing the node. It's used to set the tommy_node::data field of the node.
*/
@ -211,6 +212,7 @@ tommy_inline void tommy_list_insert_head(tommy_list* list, tommy_node* node, voi
/**
* Inserts an element at the tail of a list.
* \param list The list.
* \param node The node to insert.
* \param data The object containing the node. It's used to set the tommy_node::data field of the node.
*/
@ -230,7 +232,8 @@ tommy_inline void tommy_list_insert_tail(tommy_list* list, tommy_node* node, voi
* Removes an element from the list.
* You must already have the address of the element to remove.
* \note The node content is left unchanged, including the tommy_node::next
* and tommy_node::prev fields that still contain pointers at the list.
* and tommy_node::prev fields that still contain pointers **in** the list.
* \param list The list.
* \param node The node to remove. The node must be in the list.
* \return The tommy_node::data field of the node removed.
*/
@ -296,7 +299,7 @@ tommy_inline void tommy_list_concat(tommy_list* first, tommy_list* second)
* \param cmp Compare function called with two elements.
* The function should return <0 if the first element is less than the second, ==0 if equal, and >0 if greater.
*/
void tommy_list_sort(tommy_list* list, tommy_compare_func* cmp);
TOMMY_API void tommy_list_sort(tommy_list* list, tommy_compare_func* cmp);
/**
* Checks if empty.
@ -378,4 +381,3 @@ tommy_inline void tommy_list_foreach_arg(tommy_list* list, tommy_foreach_arg_fun
}
#endif

View file

@ -32,7 +32,7 @@
/******************************************************************************/
/* tree */
void tommy_tree_init(tommy_tree* tree, tommy_compare_func* cmp)
TOMMY_API void tommy_tree_init(tommy_tree* tree, tommy_compare_func* cmp)
{
tree->root = 0;
tree->count = 0;
@ -138,7 +138,7 @@ static tommy_tree_node* tommy_tree_insert_node(tommy_compare_func* cmp, tommy_tr
return root;
}
void* tommy_tree_insert(tommy_tree* tree, tommy_tree_node* node, void* data)
TOMMY_API void* tommy_tree_insert(tommy_tree* tree, tommy_tree_node* node, void* data)
{
tommy_tree_node* insert = node;
@ -180,7 +180,7 @@ static tommy_tree_node* tommy_tree_remove_node(tommy_compare_func* cmp, tommy_tr
return tommy_tree_move_right(root->prev, root->next);
}
void* tommy_tree_remove(tommy_tree* tree, void* data)
TOMMY_API void* tommy_tree_remove(tommy_tree* tree, void* data)
{
tommy_tree_node* node = 0;
@ -212,7 +212,7 @@ static tommy_tree_node* tommy_tree_search_node(tommy_compare_func* cmp, tommy_tr
return root;
}
void* tommy_tree_search(tommy_tree* tree, void* data)
TOMMY_API void* tommy_tree_search(tommy_tree* tree, void* data)
{
tommy_tree_node* node = tommy_tree_search_node(tree->cmp, tree->root, data);
@ -222,7 +222,7 @@ void* tommy_tree_search(tommy_tree* tree, void* data)
return node->data;
}
void* tommy_tree_search_compare(tommy_tree* tree, tommy_compare_func* cmp, void* cmp_arg)
TOMMY_API void* tommy_tree_search_compare(tommy_tree* tree, tommy_compare_func* cmp, void* cmp_arg)
{
tommy_tree_node* node = tommy_tree_search_node(cmp, tree->root, cmp_arg);
@ -232,7 +232,7 @@ void* tommy_tree_search_compare(tommy_tree* tree, tommy_compare_func* cmp, void*
return node->data;
}
void* tommy_tree_remove_existing(tommy_tree* tree, tommy_tree_node* node)
TOMMY_API void* tommy_tree_remove_existing(tommy_tree* tree, tommy_tree_node* node)
{
void* data = tommy_tree_remove(tree, node->data);
@ -258,7 +258,7 @@ static void tommy_tree_foreach_node(tommy_tree_node* root, tommy_foreach_func* f
tommy_tree_foreach_node(next, func);
}
void tommy_tree_foreach(tommy_tree* tree, tommy_foreach_func* func)
TOMMY_API void tommy_tree_foreach(tommy_tree* tree, tommy_foreach_func* func)
{
tommy_tree_foreach_node(tree->root, func);
}
@ -280,12 +280,12 @@ static void tommy_tree_foreach_arg_node(tommy_tree_node* root, tommy_foreach_arg
tommy_tree_foreach_arg_node(next, func, arg);
}
void tommy_tree_foreach_arg(tommy_tree* tree, tommy_foreach_arg_func* func, void* arg)
TOMMY_API void tommy_tree_foreach_arg(tommy_tree* tree, tommy_foreach_arg_func* func, void* arg)
{
tommy_tree_foreach_arg_node(tree->root, func, arg);
}
tommy_size_t tommy_tree_memory_usage(tommy_tree* tree)
TOMMY_API tommy_size_t tommy_tree_memory_usage(tommy_tree* tree)
{
return tommy_tree_count(tree) * sizeof(tommy_tree_node);
}

View file

@ -31,7 +31,7 @@
* This tree is a standard AVL tree implementation that stores elements in the
* order defined by the comparison function.
*
* As difference than other tommy containers, duplicate elements cannot be inserted.
* As a difference from other tommy containers, duplicate elements cannot be inserted.
*
* To initialize a tree you have to call tommy_tree_init() specifying a comparison
* function that will define the order in the tree.
@ -63,7 +63,7 @@
* tommy_tree_insert(&tree, &obj->node, obj); // inserts the object
* \endcode
*
* To find and element in the tree you have to call tommy_tree_search() providing
* To find an element in the tree you have to call tommy_tree_search() providing
* the key to search.
*
* \code
@ -94,7 +94,7 @@
* tommy_tree_foreach() or tommy_tree_foreach_arg().
* If you need a more precise control with a real iteration, you have to insert
* all the elements also in a ::tommy_list, and use the list to iterate.
* See the \ref multiindex example for more detail.
* See the \ref multiindex example for more detail.
*/
#ifndef __TOMMYTREE_H
@ -125,7 +125,7 @@ typedef struct tommy_tree_struct {
* Initializes the tree.
* \param cmp The comparison function that defines the order in the tree.
*/
void tommy_tree_init(tommy_tree* tree, tommy_compare_func* cmp);
TOMMY_API void tommy_tree_init(tommy_tree* tree, tommy_compare_func* cmp);
/**
* Inserts an element in the tree.
@ -137,7 +137,7 @@ void tommy_tree_init(tommy_tree* tree, tommy_compare_func* cmp);
* \param data Pointer to the object to insert.
* \return The element in the tree. Either the already existing one, or the one just inserted.
*/
void* tommy_tree_insert(tommy_tree* tree, tommy_tree_node* node, void* data);
TOMMY_API void* tommy_tree_insert(tommy_tree* tree, tommy_tree_node* node, void* data);
/**
* Searches and removes an element.
@ -145,15 +145,15 @@ void* tommy_tree_insert(tommy_tree* tree, tommy_tree_node* node, void* data);
* \param data Element used for comparison.
* \return The removed element, or 0 if not found.
*/
void* tommy_tree_remove(tommy_tree* tree, void* data);
TOMMY_API void* tommy_tree_remove(tommy_tree* tree, void* data);
/**
* Searches an element in the tree.
* If the element is not found, 0 is returned.
* If the element is not found, 0 is returned.
* \param data Element used for comparison.
* \return The first element found, or 0 if none.
*/
void* tommy_tree_search(tommy_tree* tree, void* data);
TOMMY_API void* tommy_tree_search(tommy_tree* tree, void* data);
/**
* Searches an element in the tree with a specific comparison function.
@ -162,16 +162,16 @@ void* tommy_tree_search(tommy_tree* tree, void* data);
* Note that this function must define a suborder of the original one.
*
* The ::data argument will be the first argument of the comparison function,
* and it can be of a different type of the objects in the tree.
* and it can be of a different type than the objects in the tree.
*/
void* tommy_tree_search_compare(tommy_tree* tree, tommy_compare_func* cmp, void* cmp_arg);
TOMMY_API void* tommy_tree_search_compare(tommy_tree* tree, tommy_compare_func* cmp, void* cmp_arg);
/**
* Removes an element from the tree.
* You must already have the address of the element to remove.
* \return The tommy_node::data field of the node removed.
*/
void* tommy_tree_remove_existing(tommy_tree* tree, tommy_tree_node* node);
TOMMY_API void* tommy_tree_remove_existing(tommy_tree* tree, tommy_tree_node* node);
/**
* Calls the specified function for each element in the tree.
@ -203,12 +203,12 @@ void* tommy_tree_remove_existing(tommy_tree* tree, tommy_tree_node* node);
* tommy_tree_foreach(&tree, free);
* \endcode
*/
void tommy_tree_foreach(tommy_tree* tree, tommy_foreach_func* func);
TOMMY_API void tommy_tree_foreach(tommy_tree* tree, tommy_foreach_func* func);
/**
* Calls the specified function with an argument for each element in the tree.
*/
void tommy_tree_foreach_arg(tommy_tree* tree, tommy_foreach_arg_func* func, void* arg);
TOMMY_API void tommy_tree_foreach_arg(tommy_tree* tree, tommy_foreach_arg_func* func, void* arg);
/**
* Gets the number of elements.
@ -222,7 +222,6 @@ tommy_inline tommy_size_t tommy_tree_count(tommy_tree* tree)
* Gets the size of allocated memory.
* It includes the size of the ::tommy_tree_node of the stored elements.
*/
tommy_size_t tommy_tree_memory_usage(tommy_tree* tree);
TOMMY_API tommy_size_t tommy_tree_memory_usage(tommy_tree* tree);
#endif

View file

@ -24,6 +24,7 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/** \file
* Generic types.
*/
@ -42,8 +43,8 @@ typedef unsigned _int64 tommy_uint64_t; /**< Generic uint64_t type. */
typedef size_t tommy_uintptr_t; /**< Generic uintptr_t type. */
#ifdef _WIN64
#define TOMMY_SIZE_BIT 64
typedef unsigned _int64_t tommy_size_t; /**< Generic size_t type. */
typedef _int64_t tommy_ssize_t; /**< Generic ssize_t type. */
typedef unsigned _int64 tommy_size_t; /**< Generic size_t type. */
typedef _int64 tommy_ssize_t; /**< Generic ssize_t type. */
#else
#define TOMMY_SIZE_BIT 32
typedef unsigned tommy_size_t; /**< Generic size_t type. */
@ -73,15 +74,22 @@ typedef int tommy_bool_t; /**< Generic boolean type. */
/**
* Generic unsigned integer type.
*
* It has no specific size, as is used to store only small values.
* It has no specific size, as it is used to store only small values.
* To make the code more efficient, a full 32 bit integer is used.
*/
typedef tommy_uint32_t tommy_uint_t;
/** \internal
* Type cast required for the C++ compilation.
* When compiling in C++ we cannot convert a void* pointer to another pointer.
* In such case we need an explicit cast.
* Explicit cast helper used to smooth out the difference between C and C++.
*
* In C, a void* can be assigned to any pointer type without an explicit cast.
* This is not allowed in C++, where converting a void* to another pointer type
* always requires an explicit cast.
*
* tommy_cast should be used only for this specific purpose, so it should be
* applied when converting a void* to a more specific pointer type in code that
* must compile as both C and C++. It is not intended for arbitrary pointer
* conversions or for casts that are unrelated to the C to C++ difference.
*/
#ifdef __cplusplus
#define tommy_cast(type, value) static_cast<type>(value)
@ -117,6 +125,14 @@ typedef tommy_uint32_t tommy_uint_t;
/******************************************************************************/
/* modificators */
/** \internal
* Definition of TOMMY_API.
* Provide the ability to override linkage features of the interface.
*/
#if !defined(TOMMY_API)
#define TOMMY_API
#endif
/** \internal
* Definition of the inline keyword if available.
*/
@ -167,12 +183,12 @@ typedef tommy_uint32_t tommy_uint_t;
/* key/hash */
/**
* Type used in indexed data structures to store the key of a object.
* Type used in indexed data structures to store the key of an object.
*/
typedef tommy_size_t tommy_key_t;
/**
* Type used in hashtables to store the hash of a object.
* Type used in hashtables to store the hash of an object.
*/
typedef tommy_size_t tommy_hash_t;
@ -227,7 +243,7 @@ typedef struct tommy_node_struct {
* Compare function for elements.
* \param obj_a Pointer to the first object to compare.
* \param obj_b Pointer to the second object to compare.
* \return <0 if the first element is less than the second, ==0 equal, >0 if greater.
* \return <0 if the first element is less than the second, ==0 if equal, >0 if greater.
*
* This function is like the C strcmp().
*
@ -393,8 +409,8 @@ tommy_inline tommy_uint_t tommy_ilog2_u64(tommy_uint64_t value)
#elif defined(__GNUC__)
return __builtin_clzll(value) ^ 63;
#else
uint32_t l = value & 0xFFFFFFFFU;
uint32_t h = value >> 32;
tommy_uint32_t l = value & 0xFFFFFFFFU;
tommy_uint32_t h = value >> 32;
if (h)
return tommy_ilog2_u32(h) + 32;
else
@ -444,8 +460,8 @@ tommy_inline tommy_uint_t tommy_ctz_u64(tommy_uint64_t value)
#elif defined(__GNUC__)
return __builtin_ctzll(value);
#else
uint32_t l = value & 0xFFFFFFFFU;
uint32_t h = value >> 32;
tommy_uint32_t l = value & 0xFFFFFFFFU;
tommy_uint32_t h = value >> 32;
if (l)
return tommy_ctz_u32(l);
else
@ -515,4 +531,3 @@ tommy_inline int tommy_haszero_u32(tommy_uint32_t value)
#endif
#endif