Update to latest TommyDS

This commit is contained in:
Andrea Mazzoleni 2016-10-26 23:23:05 +02:00
parent 9b2c5514c0
commit 272853e40a
9 changed files with 234 additions and 66 deletions

View file

@ -39,6 +39,11 @@ struct hash32_test_vector {
uint32_t digest;
};
struct strhash32_test_vector {
char* data;
uint32_t digest;
};
struct hash64_test_vector {
const char* data;
int len;
@ -77,6 +82,36 @@ static struct hash32_test_vector TEST_HASH32[] = {
{ 0, 0, 0 }
};
/**
* Test vectors for tommy_strhash32
*/
struct strhash32_test_vector TEST_STRHASH32[] = {
{ "", 0x0af1416d },
{ "a", 0x68fa0f3f },
{ "abc", 0xfc68ffc5 },
{ "message digest", 0x08477b63 },
{ "abcdefghijklmnopqrstuvwxyz", 0x5b9c25e5 },
{ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", 0x1e530ce7 },
{ "The quick brown fox jumps over the lazy dog", 0xaf93eefe },
{ "\xff", 0xfc88801b },
{ "\x16\x27", 0xcd7216db },
{ "\xe2\x56\xb4", 0x05f98d02 },
{ "\xc9\x4d\x9c\xda", 0xf65206f8 },
{ "\x79\xf1\x29\x69\x5d", 0x72bd6bda },
{ "\xff\x7e\xdf\x1e\x31\x1c", 0x57dfb9b4 },
{ "\x2a\x4c\xe1\xff\x9e\x6f\x53", 0x499ff634 },
{ "\xba\x02\xab\x18\x30\xc5\x0e\x8a", 0xe896b7ce },
{ "\xec\x4e\x7a\x72\x1e\x71\x2a\xc9\x33", 0xfe3939f0 },
{ "\xfd\xe2\x9c\x0f\x72\xb7\x08\xea\xd0\x78", 0x4351d482 },
{ "\x65\xc4\x8a\xb8\x80\x86\x9a\x79\xff\xb7\xae", 0x88e92135 },
{ "\x77\xe9\xd7\x80\x0e\x3f\x5c\x43\xc8\xc2\x46\x39", 0x01109c16 },
{ "\x87\xd8\x61\x61\x4c\x89\x17\x4e\xa1\xa4\xef\x13\xa9", 0xbcb050dc },
{ "\xfe\xa6\x5b\xc2\xda\xe8\x95\xd4\x64\xab\x4c\x39\x58\x29", 0xbe5e1fd5 },
{ "\x94\x49\xc0\x78\xa0\x80\xda\xc7\x71\x4e\x17\x37\xa9\x7c\x40", 0x70d8c97f },
{ "\x53\x7e\x36\xb4\x2e\xc9\xb9\xcc\x18\x3e\x9a\x5f\xfc\xb7\xb0\x61", 0x957440a9 },
{ 0, 0 }
};
/**
* Test vectors for tommy_hash64
*/
@ -157,7 +192,7 @@ static void test_hash(void)
for (i = 0; TEST_HASH32[i].data; ++i) {
uint32_t digest;
memcpy(buffer_aligned, TEST_HASH32[i].data, TEST_HASH32[i].len);
digest = tommy_hash_u32(seed32, buffer_aligned, TEST_MURMUR3[i].len);
digest = tommy_hash_u32(seed32, buffer_aligned, TEST_HASH32[i].len);
if (digest != TEST_HASH32[i].digest) {
/* LCOV_EXCL_START */
log_fatal("Failed hash32 test\n");
@ -166,10 +201,22 @@ static void test_hash(void)
}
}
for (i = 0; TEST_STRHASH32[i].data; ++i) {
uint32_t digest;
memcpy(buffer_aligned, TEST_STRHASH32[i].data, strlen(TEST_STRHASH32[i].data) + 1);
digest = tommy_strhash_u32(seed32, buffer_aligned);
if (digest != TEST_STRHASH32[i].digest) {
/* LCOV_EXCL_START */
log_fatal("Failed strhash32 test\n");
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
}
for (i = 0; TEST_HASH64[i].data; ++i) {
uint64_t digest;
memcpy(buffer_aligned, TEST_HASH64[i].data, TEST_HASH64[i].len);
digest = tommy_hash_u64(seed64, buffer_aligned, TEST_MURMUR3[i].len);
digest = tommy_hash_u64(seed64, buffer_aligned, TEST_HASH64[i].len);
if (digest != TEST_HASH64[i].digest) {
/* LCOV_EXCL_START */
log_fatal("Failed hash64 test\n");

View file

@ -50,8 +50,8 @@
* - All the other inner prev and next fields are correctly set.
*/
typedef struct tommy_chain_struct {
tommy_node* head; /**< Pointer at the head of the chain. */
tommy_node* tail; /**< Pointer at the tail of the chain. */
tommy_node* head; /**< Pointer to the head of the chain. */
tommy_node* tail; /**< Pointer to the tail of the chain. */
} tommy_chain;
/**

View file

@ -165,3 +165,77 @@ 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_uint64_t init_val, const void* void_key)
{
const unsigned char* key = tommy_cast(const unsigned char*, void_key);
tommy_uint32_t a, b, c;
tommy_uint32_t m[3] = { 0xff, 0xff00, 0xff0000 };
a = b = c = 0xdeadbeef + init_val;
/* this is different than original lookup3 and the result won't match */
while (1) {
tommy_uint32_t v = tommy_le_uint32_read(key);
if (tommy_haszero_u32(v)) {
if (v & m[0]) {
a += v & m[0];
if (v & m[1]) {
a += v & m[1];
if (v & m[2])
a += v & m[2];
}
}
break;
}
a += v;
v = tommy_le_uint32_read(key + 4);
if (tommy_haszero_u32(v)) {
if (v & m[0]) {
b += v & m[0];
if (v & m[1]) {
b += v & m[1];
if (v & m[2])
b += v & m[2];
}
}
break;
}
b += v;
v = tommy_le_uint32_read(key + 8);
if (tommy_haszero_u32(v)) {
if (v & m[0]) {
c += v & m[0];
if (v & m[1]) {
c += v & m[1];
if (v & m[2])
c += v & m[2];
}
}
break;
}
c += v;
tommy_mix(a, b, c);
key += 12;
}
/* for lengths that are multiplers of 12 we already have called mix */
/* this is different than the original lookup3 and the result won't match */
tommy_final(a, b, c);
return c;
}

View file

@ -46,10 +46,15 @@ typedef tommy_key_t tommy_hash_t;
* Hash function with a 32 bits result.
* 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,
* including 32 bits. If you target only 64 bits, you can use faster hashes,
* like SpookyHash or FarmHash.
*
* \param init_val Initialization value.
* Using a different initialization value, you can generate a completely different set of hash values.
* Use 0 if not relevant.
* \param void_key Pointer at the data to hash.
* \param void_key Pointer to the data to hash.
* \param key_len Size of the data to hash.
* \note
* This function is endianess independent.
@ -61,10 +66,15 @@ tommy_uint32_t tommy_hash_u32(tommy_uint32_t init_val, const void* void_key, tom
* Hash function with a 64 bits result.
* Implementation of the Robert Jenkins "lookup3" hash 64 bits versions,
* from http://www.burtleburtle.net/bob/hash/doobs.html, function hashlittle2().
*
* This hash is designed to provide a good overall performance in all platforms,
* including 32 bits. If you target only 64 bits, you can use faster hashes,
* like SpookyHash or FarmHash.
*
* \param init_val Initialization value.
* Using a different initialization value, you can generate a completely different set of hash values.
* Use 0 if not relevant.
* \param void_key Pointer at the data to hash.
* \param void_key Pointer to the data to hash.
* \param key_len Size of the data to hash.
* \note
* This function is endianess independent.
@ -73,7 +83,25 @@ tommy_uint32_t tommy_hash_u32(tommy_uint32_t init_val, const void* void_key, tom
tommy_uint64_t tommy_hash_u64(tommy_uint64_t init_val, const void* void_key, tommy_size_t key_len);
/**
* Integer hash of 32 bits.
* String hash function with a 32 bits result.
* Implementation is based on the the Robert Jenkins "lookup3" hash 32 bits version,
* from http://www.burtleburtle.net/bob/hash/doobs.html, function hashlittle().
*
* This hash is designed to handle strings with an unknown length. If you
* know the string length, the other hash functions are surely faster.
*
* \param init_val Initialization value.
* Using a different initialization value, you can generate a completely different set of hash values.
* Use 0 if not relevant.
* \param void_key Pointer to the string to hash. It has to be 0 terminated.
* \note
* This function is endianess independent.
* \return The hash value of 32 bits.
*/
tommy_uint32_t tommy_strhash_u32(tommy_uint64_t init_val, const void* void_key);
/**
* Integer reversible hash function for 32 bits.
* Implementation of the Robert Jenkins "4-byte Integer Hashing",
* from http://burtleburtle.net/bob/hash/integer.html
*/
@ -91,9 +119,9 @@ tommy_inline tommy_uint32_t tommy_inthash_u32(tommy_uint32_t key)
}
/**
* Integer hash of 64 bits.
* Integer reversible hash function for 64 bits.
* Implementation of the Thomas Wang "Integer Hash Function",
* from http://www.cris.com/~Ttwang/tech/inthash.htm
* from http://web.archive.org/web/20071223173210/http://www.concentric.net/~Ttwang/tech/inthash.htm
*/
tommy_inline tommy_uint64_t tommy_inthash_u64(tommy_uint64_t key)
{

View file

@ -60,9 +60,9 @@
*
* \code
* struct object {
* tommy_node node;
* // other fields
* int value;
* // other fields
* tommy_node node;
* };
*
* struct object* obj = malloc(sizeof(struct object)); // creates the object
@ -243,7 +243,8 @@ void* tommy_hashdyn_remove_existing(tommy_hashdyn* hashdyn, tommy_hashdyn_node*
/**
* Calls the specified function for each element in the hashtable.
*
* You can use this function to deallocate all the elements inserted.
* You cannot add or remove elements from the inside of the callback,
* but can use it to deallocate them.
*
* \code
* tommy_hashdyn hashdyn;

View file

@ -28,32 +28,6 @@
#include "tommylist.h"
#include "tommychain.h"
void tommy_list_concat(tommy_list* first, tommy_list* second)
{
tommy_node* first_head;
tommy_node* first_tail;
tommy_node* second_head;
if (tommy_list_empty(second))
return;
if (tommy_list_empty(first)) {
*first = *second;
return;
}
first_head = tommy_list_head(first);
second_head = tommy_list_head(second);
first_tail = tommy_list_tail(first);
/* set the "circular" prev list */
first_head->prev = second_head->prev;
second_head->prev = first_tail;
/* set the "0 terminated" next list */
first_tail->next = second_head;
}
/** \internal
* Setup a list.
*/

View file

@ -57,9 +57,9 @@
*
* \code
* struct object {
* tommy_node node;
* // other fields
* int value;
* // other fields
* tommy_node node;
* };
*
* struct object* obj = malloc(sizeof(struct object)); // creates the object
@ -278,7 +278,34 @@ tommy_inline void* tommy_list_remove_existing(tommy_list* list, tommy_node* node
* \param second The second list. After this call the list content is undefined,
* and you should not use it anymore.
*/
void tommy_list_concat(tommy_list* first, tommy_list* second);
tommy_inline void tommy_list_concat(tommy_list* first, tommy_list* second)
{
tommy_node* first_head;
tommy_node* first_tail;
tommy_node* second_head;
/* if the second is empty, nothing to do */
second_head = tommy_list_head(second);
if (second_head == 0)
return;
/* if the first is empty, copy the second */
first_head = tommy_list_head(first);
if (first_head == 0) {
*first = *second;
return;
}
/* tail of the first list */
first_tail = first_head->prev;
/* set the "circular" prev list */
first_head->prev = second_head->prev;
second_head->prev = first_tail;
/* set the "0 terminated" next list */
first_tail->next = second_head;
}
/**
* Sorts a list.
@ -318,8 +345,8 @@ tommy_inline tommy_count_t tommy_list_count(tommy_list* list)
/**
* Calls the specified function for each element in the list.
*
* You can use this function to deallocate all the elements
* inserted in a list.
* You cannot add or remove elements from the inside of the callback,
* but can use it to deallocate them.
*
* \code
* tommy_list list;

View file

@ -29,16 +29,16 @@
* AVL tree.
*
* This tree is a standard AVL tree implementation that stores elements in the
* order defined by the comparsion function.
* order defined by the comparison function.
*
* As difference from other tommy containers, duplicate elements cannot be inserted.
*
* \code
* tommy_tree tree;
* As difference than other tommy containers, duplicate elements cannot be inserted.
*
* To initialize a tree you have to call tommy_tree_init() specifing a comparison
* function that will define the order in the tree.
*
* \code
* tommy_tree tree;
*
* tommy_tree_init(&tree, cmp);
* \endcode
*
@ -79,7 +79,7 @@
* To remove an element from the tree you have to call tommy_tree_remove()
* providing the key to search and remove.
*
 * \code
* \code
* struct object value_to_remove = { 1 };
* struct object* obj = tommy_tree_remove(&tree, &value_to_remove);
* if (obj) {
@ -87,7 +87,8 @@
* }
* \endcode
*
* To destroy the tree you have to remove all the elements.
* To destroy the tree you have to remove or destroy all the contained elements.
* The tree itself doesn't have or need a deallocation function.
*
* If you need to iterate over all the elements in the tree, you can use
* tommy_tree_foreach() or tommy_tree_foreach_arg().
@ -129,10 +130,11 @@ void tommy_tree_init(tommy_tree* tree, tommy_compare_func* cmp);
/**
* Inserts an element in the tree.
* If the element is already present, it's not inserted again.
* Check the return value to identify if the element was already present or not.
* You have to provide the pointer of the node embedded into the object and
* the pointer at the object.
* \param node Pointer at the node embedded into the object to insert.
* \param data Pointer at the object to insert.
* \param node Pointer to the node embedded into the object to insert.
* \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);
@ -176,7 +178,8 @@ void* tommy_tree_remove_existing(tommy_tree* tree, tommy_tree_node* node);
*
* The elements are processed in order.
*
* You can use this function to deallocate all the elements inserted.
* You cannot add or remove elements from the inside of the callback,
* but can use it to deallocate them.
*
* \code
* tommy_tree tree;

View file

@ -194,7 +194,7 @@ typedef struct tommy_node_struct {
struct tommy_node_struct* prev;
/**
* Pointer at the object containing the node.
* Pointer to the object containing the node.
* This field is initialized when inserting nodes into a data structure.
*/
void* data;
@ -212,8 +212,8 @@ typedef struct tommy_node_struct {
/**
* Compare function for elements.
* \param obj_a Pointer at the first object to compare.
* \param obj_b Pointer at the second object to compare.
* \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 greather.
*
* This function is like the C strcmp().
@ -241,13 +241,15 @@ typedef int tommy_compare_func(const void* obj_a, const void* obj_b);
/**
* Search function for elements.
* \param arg Pointer at the value to search.
* \param obj Pointer at the object to compare to.
* \param arg Pointer to the value to search as passed at the search function.
* \param obj Pointer to the object to compare to.
* \return ==0 if the value matches the element. !=0 if different.
*
* Note that the first argument is a pointer to the value to search and
* the second one is a pointer to the object to compare.
* They are pointers of two different types.
* The first argument is a pointer to the value to search exactly
* as it's passed at the search function called.
* The second argument is a pointer to the object inside the hashtable to compare.
*
* The return value has to be 0 if the values are equal. != 0 if they are different.
*
* \code
* struct object {
@ -257,7 +259,10 @@ typedef int tommy_compare_func(const void* obj_a, const void* obj_b);
*
* int compare(const void* arg, const void* obj)
* {
* return *(const int*)arg != ((const struct object*)obj)->value;
* const int* value_to_find = arg;
* const struct object* object_to_compare = obj;
*
* return *value_to_find != object_to_compare->value;
* }
*
* int value_to_find = 1;
@ -274,7 +279,7 @@ typedef int tommy_search_func(const void* arg, const void* obj);
/**
* Foreach function.
* \param obj Pointer at the object to iterate.
* \param obj Pointer to the object to iterate.
*
* A typical example is to use free() to deallocate all the objects in a list.
* \code
@ -285,8 +290,8 @@ typedef void tommy_foreach_func(void* obj);
/**
* Foreach function with an argument.
* \param arg Pointer at a generic argument.
* \param obj Pointer at the object to iterate.
* \param arg Pointer to a generic argument.
* \param obj Pointer to the object to iterate.
*/
typedef void tommy_foreach_arg_func(void* arg, void* obj);
@ -394,7 +399,7 @@ tommy_inline tommy_uint_t tommy_ctz_u32(tommy_uint32_t value)
tommy_inline tommy_uint32_t tommy_roundup_pow2_u32(tommy_uint32_t value)
{
/* Round up to the next highest power of 2 */
/* from http://www-graphics.stanford.edu/~seander/bithacks.html */
/* from http://graphics.stanford.edu/~seander/bithacks.html */
--value;
value |= value >> 1;
@ -406,5 +411,14 @@ tommy_inline tommy_uint32_t tommy_roundup_pow2_u32(tommy_uint32_t value)
return value;
}
/**
* Check if the specified word has a byte at 0.
* \return 0 or 1.
*/
tommy_inline int tommy_haszero_u32(tommy_uint32_t value)
{
return ((value - 0x01010101) & ~value & 0x80808080) != 0;
}
#endif