hashtable.h: Add compatibility with VS10 and MinGW, remove trailing whitespaces
This commit is contained in:
parent
8b3583e7b5
commit
acf06a5e40
@ -48,20 +48,20 @@ Example
|
||||
|
||||
#include <stdio.h> // for printf
|
||||
|
||||
int main( int argc, char** argv )
|
||||
{
|
||||
int main( int argc, char** argv )
|
||||
{
|
||||
(void) argc, argv;
|
||||
|
||||
// define some example key and value types
|
||||
typedef struct key_t { int a, b, c; } key_t;
|
||||
typedef struct value_t
|
||||
{
|
||||
char id[ 64 ];
|
||||
float x, y, z;
|
||||
int n[ 250 ];
|
||||
typedef struct value_t
|
||||
{
|
||||
char id[ 64 ];
|
||||
float x, y, z;
|
||||
int n[ 250 ];
|
||||
} value_t;
|
||||
|
||||
// create a couple of sample keys
|
||||
// create a couple of sample keys
|
||||
// (don't bother to fill in the fields for this sample)
|
||||
key_t* key_a = (key_t*)malloc( sizeof( key_t ) );
|
||||
key_t* key_b = (key_t*)malloc( sizeof( key_t ) );
|
||||
@ -80,7 +80,7 @@ Example
|
||||
|
||||
// find the values by key
|
||||
value_t* value_a = (value_t*)hashtable_find( &table, (HASHTABLE_U64)(uintptr_t)key_a );
|
||||
printf( "First item: %s\n", value_a->id );
|
||||
printf( "First item: %s\n", value_a->id );
|
||||
value_t* value_b = (value_t*)hashtable_find( &table, (HASHTABLE_U64)(uintptr_t)key_b );
|
||||
printf( "Second item: %s\n", value_b->id );
|
||||
|
||||
@ -106,46 +106,46 @@ Example
|
||||
API Documentation
|
||||
=================
|
||||
|
||||
hashtable.h is a small library for storing values in a table and access them efficiently by a 64-bit key. It is a
|
||||
single-header library, and does not need any .lib files or other binaries, or any build scripts. To use it, you just
|
||||
include hashtable.h to get the API declarations. To get the definitions, you must include hashtable.h from *one* single
|
||||
C or C++ file, and #define the symbol `HASHTABLE_IMPLEMENTATION` before you do.
|
||||
hashtable.h is a small library for storing values in a table and access them efficiently by a 64-bit key. It is a
|
||||
single-header library, and does not need any .lib files or other binaries, or any build scripts. To use it, you just
|
||||
include hashtable.h to get the API declarations. To get the definitions, you must include hashtable.h from *one* single
|
||||
C or C++ file, and #define the symbol `HASHTABLE_IMPLEMENTATION` before you do.
|
||||
|
||||
The key value must be unique per entry, and is hashed for efficient lookup using an internal hashing algorithm. This
|
||||
library does not support custom key types, so typically pointers or handles are used as key values.
|
||||
|
||||
The library is written with efficiency in mind. Data and keys are stored in separate structures, for better cache
|
||||
The library is written with efficiency in mind. Data and keys are stored in separate structures, for better cache
|
||||
coherency, and hash collisions are resolved with open addressing/linear probing using the next available slot, which is
|
||||
also good for the cache.
|
||||
also good for the cache.
|
||||
|
||||
|
||||
Customization
|
||||
-------------
|
||||
There are a few different things in hashtable.h which are configurable by #defines. Most of the API use the `int` data
|
||||
type, for integer values where the exact size is not important. However, for some functions, it specifically makes use
|
||||
There are a few different things in hashtable.h which are configurable by #defines. Most of the API use the `int` data
|
||||
type, for integer values where the exact size is not important. However, for some functions, it specifically makes use
|
||||
of 32 and 64 bit data types. These default to using `unsigned int` and `unsigned long long` by default, but can be
|
||||
redefined by #defining HASHTABLE_U32 and HASHTABLE_U64 respectively, before including hashtable.h. This is useful if
|
||||
you, for example, use the types from `<stdint.h>` in the rest of your program, and you want hashtable.h to use
|
||||
redefined by #defining HASHTABLE_U32 and HASHTABLE_U64 respectively, before including hashtable.h. This is useful if
|
||||
you, for example, use the types from `<stdint.h>` in the rest of your program, and you want hashtable.h to use
|
||||
compatible types. In this case, you would include hashtable.h using the following code:
|
||||
|
||||
#define HASHTABLE_U32 uint32_t
|
||||
#define HASHTABLE_U64 uint64_t
|
||||
#include "hashtable.h"
|
||||
|
||||
Note that when customizing the data types, you need to use the same definition in every place where you include
|
||||
Note that when customizing the data types, you need to use the same definition in every place where you include
|
||||
hashtable.h, as they affect the declarations as well as the definitions.
|
||||
|
||||
The rest of the customizations only affect the implementation, so will only need to be defined in the file where you
|
||||
have the #define HASHTABLE_IMPLEMENTATION.
|
||||
|
||||
Note that if all customizations are utilized, hashtable.h will include no external files whatsoever, which might be
|
||||
Note that if all customizations are utilized, hashtable.h will include no external files whatsoever, which might be
|
||||
useful if you need full control over what code is being built.
|
||||
|
||||
|
||||
### size_t
|
||||
|
||||
Internally, the hashtable.h implementation makes use of the standard `size_t` data type. This requires including the
|
||||
c runtime library header `<stddef.h>`. To allow full configurability, and avoid hashtable.h including stddef.h, you can
|
||||
c runtime library header `<stddef.h>`. To allow full configurability, and avoid hashtable.h including stddef.h, you can
|
||||
specify which type hashtable.h should use for its size_t, by #defining HASHTABLE_SIZE_T, like this:
|
||||
|
||||
#define HASHTABLE_IMPLEMENTATION
|
||||
@ -157,8 +157,8 @@ If not specified, hashtable.h will by default include stddef.h and use the stand
|
||||
|
||||
### Custom memory allocators
|
||||
|
||||
To store the internal data structures, hashtable.h needs to do dynamic allocation by calling `malloc`. Programs might
|
||||
want to keep track of allocations done, or use custom defined pools to allocate memory from. hashtable.h allows for
|
||||
To store the internal data structures, hashtable.h needs to do dynamic allocation by calling `malloc`. Programs might
|
||||
want to keep track of allocations done, or use custom defined pools to allocate memory from. hashtable.h allows for
|
||||
specifying custom memory allocation functions for `malloc` and `free`. This is done with the following code:
|
||||
|
||||
#define HASHTABLE_IMPLEMENTATION
|
||||
@ -167,10 +167,10 @@ specifying custom memory allocation functions for `malloc` and `free`. This is d
|
||||
#include "hashtable.h"
|
||||
|
||||
where `my_custom_malloc` and `my_custom_free` are your own memory allocation/deallocation functions. The `ctx` parameter
|
||||
is an optional parameter of type `void*`. When `hashtable_init` is called, you can pass in a `memctx` parameter, which
|
||||
can be a pointer to anything you like, and which will be passed through as the `ctx` parameter to every
|
||||
`HASHTABLE_MALLOC`/`HASHTABLE_FREE` call. For example, if you are doing memory tracking, you can pass a pointer to your
|
||||
tracking data as `memctx`, and in your custom allocation/deallocation function, you can cast the `ctx` param back to the
|
||||
is an optional parameter of type `void*`. When `hashtable_init` is called, you can pass in a `memctx` parameter, which
|
||||
can be a pointer to anything you like, and which will be passed through as the `ctx` parameter to every
|
||||
`HASHTABLE_MALLOC`/`HASHTABLE_FREE` call. For example, if you are doing memory tracking, you can pass a pointer to your
|
||||
tracking data as `memctx`, and in your custom allocation/deallocation function, you can cast the `ctx` param back to the
|
||||
right type, and access the tracking data.
|
||||
|
||||
If no custom allocator is defined, hashtable.h will default to `malloc` and `free` from the C runtime library.
|
||||
@ -178,7 +178,7 @@ If no custom allocator is defined, hashtable.h will default to `malloc` and `fre
|
||||
|
||||
### Custom assert
|
||||
|
||||
hashtable.h makes use of asserts to report usage errors and failed allocation errors. By default, it makes use of the C
|
||||
hashtable.h makes use of asserts to report usage errors and failed allocation errors. By default, it makes use of the C
|
||||
runtime library `assert` macro, which only executes in debug builds. However, it allows for substituting with your own
|
||||
assert function or macro using the following code:
|
||||
|
||||
@ -191,7 +191,7 @@ Note that if you only want the asserts to trigger in debug builds, you must add
|
||||
|
||||
### Custom C runtime functions
|
||||
|
||||
The library makes use of two additional functions from the C runtime library, and for full flexibility, it allows you
|
||||
The library makes use of two additional functions from the C runtime library, and for full flexibility, it allows you
|
||||
to substitute them for your own. Here's an example:
|
||||
|
||||
#define HASHTABLE_IMPLEMENTATION
|
||||
@ -214,7 +214,7 @@ grow as needed, by reallocating memory.
|
||||
|
||||
hashtable_term
|
||||
--------------
|
||||
|
||||
|
||||
void hashtable_term( hashtable_t* table )
|
||||
|
||||
Terminates a hashtable instance, releasing all memory used by it. No further calls to the hashtable API are valid until
|
||||
@ -226,8 +226,8 @@ hashtable_insert
|
||||
|
||||
int hashtable_insert( hashtable_t* table, HASHTABLE_U64 key, void const* item )
|
||||
|
||||
Inserts a data item into the hashtable, associating it with the specified key. The item is copied into the hashtable,
|
||||
rather than just storing the `item` pointer, so the `item` pointer can be safely released after the call to
|
||||
Inserts a data item into the hashtable, associating it with the specified key. The item is copied into the hashtable,
|
||||
rather than just storing the `item` pointer, so the `item` pointer can be safely released after the call to
|
||||
`hashtable_insert`. The value of `key` must be unique - it is not valid to store two items with the same key value. An
|
||||
assert is triggered if trying to add a key which already exists, which means that if the default assert is used, it will
|
||||
only be checked in debug builds - in release builds, it is up to the calling code to ensure this doesn't happen, or the
|
||||
@ -239,7 +239,7 @@ hashtable_remove
|
||||
|
||||
void hashtable_remove( hashtable_t* table, HASHTABLE_U64 key )
|
||||
|
||||
Removes the item associated with the specified key, and the instance of the key itself, from the hashtable. If the
|
||||
Removes the item associated with the specified key, and the instance of the key itself, from the hashtable. If the
|
||||
specified key could not be found, an assert is triggered.
|
||||
|
||||
|
||||
@ -256,7 +256,7 @@ hashtable_find
|
||||
|
||||
void* hashtable_find( hashtable_t const* table, HASHTABLE_U64 key )
|
||||
|
||||
Returns a pointer to the item associated with the specified key, or NULL it the key was not found. The lookup is
|
||||
Returns a pointer to the item associated with the specified key, or NULL it the key was not found. The lookup is
|
||||
designed for efficiency, and for minimizing cache missed.
|
||||
|
||||
|
||||
@ -284,7 +284,7 @@ hashtable_keys
|
||||
|
||||
HASHTABLE_U64 const* hashtable_keys( hashtable_t const* table )
|
||||
|
||||
Returns a pointer to the keys currently held in the table, in the same order as the items returned from
|
||||
Returns a pointer to the keys currently held in the table, in the same order as the items returned from
|
||||
`hashtable_items`. Can be indexed as an array with as many elements as returned by `hashtable_count`.
|
||||
|
||||
|
||||
@ -342,8 +342,8 @@ struct hashtable_t
|
||||
#undef HASHTABLE_IMPLEMENTATION
|
||||
|
||||
#ifndef HASHTABLE_SIZE_T
|
||||
#undef _CRT_NONSTDC_NO_DEPRECATE
|
||||
#define _CRT_NONSTDC_NO_DEPRECATE
|
||||
#undef _CRT_NONSTDC_NO_DEPRECATE
|
||||
#define _CRT_NONSTDC_NO_DEPRECATE
|
||||
#undef _CRT_SECURE_NO_WARNINGS
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#include <stddef.h>
|
||||
@ -351,8 +351,8 @@ struct hashtable_t
|
||||
#endif
|
||||
|
||||
#ifndef HASHTABLE_ASSERT
|
||||
#undef _CRT_NONSTDC_NO_DEPRECATE
|
||||
#define _CRT_NONSTDC_NO_DEPRECATE
|
||||
#undef _CRT_NONSTDC_NO_DEPRECATE
|
||||
#define _CRT_NONSTDC_NO_DEPRECATE
|
||||
#undef _CRT_SECURE_NO_WARNINGS
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#include <assert.h>
|
||||
@ -360,26 +360,26 @@ struct hashtable_t
|
||||
#endif
|
||||
|
||||
#ifndef HASHTABLE_MEMSET
|
||||
#undef _CRT_NONSTDC_NO_DEPRECATE
|
||||
#define _CRT_NONSTDC_NO_DEPRECATE
|
||||
#undef _CRT_NONSTDC_NO_DEPRECATE
|
||||
#define _CRT_NONSTDC_NO_DEPRECATE
|
||||
#undef _CRT_SECURE_NO_WARNINGS
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#include <string.h>
|
||||
#define HASHTABLE_MEMSET( ptr, val, cnt ) ( memset( ptr, val, cnt ) )
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef HASHTABLE_MEMCPY
|
||||
#undef _CRT_NONSTDC_NO_DEPRECATE
|
||||
#define _CRT_NONSTDC_NO_DEPRECATE
|
||||
#undef _CRT_NONSTDC_NO_DEPRECATE
|
||||
#define _CRT_NONSTDC_NO_DEPRECATE
|
||||
#undef _CRT_SECURE_NO_WARNINGS
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#include <string.h>
|
||||
#define HASHTABLE_MEMCPY( dst, src, cnt ) ( memcpy( dst, src, cnt ) )
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef HASHTABLE_MALLOC
|
||||
#undef _CRT_NONSTDC_NO_DEPRECATE
|
||||
#define _CRT_NONSTDC_NO_DEPRECATE
|
||||
#undef _CRT_NONSTDC_NO_DEPRECATE
|
||||
#define _CRT_NONSTDC_NO_DEPRECATE
|
||||
#undef _CRT_SECURE_NO_WARNINGS
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#include <stdlib.h>
|
||||
@ -404,22 +404,23 @@ static HASHTABLE_U32 hashtable_internal_pow2ceil( HASHTABLE_U32 v )
|
||||
|
||||
void hashtable_init( hashtable_t* table, int item_size, int initial_capacity, void* memctx )
|
||||
{
|
||||
int slots_size;
|
||||
initial_capacity = (int)hashtable_internal_pow2ceil( initial_capacity >=0 ? (HASHTABLE_U32) initial_capacity : 32U );
|
||||
table->memctx = memctx;
|
||||
table->count = 0;
|
||||
table->item_size = item_size;
|
||||
table->slot_capacity = (int) hashtable_internal_pow2ceil( (HASHTABLE_U32) ( initial_capacity + initial_capacity / 2 ) );
|
||||
int slots_size = (int)( table->slot_capacity * sizeof( *table->slots ) );
|
||||
slots_size = (int)( table->slot_capacity * sizeof( *table->slots ) );
|
||||
table->slots = (struct hashtable_internal_slot_t*) HASHTABLE_MALLOC( table->memctx, (HASHTABLE_SIZE_T) slots_size );
|
||||
HASHTABLE_ASSERT( table->slots );
|
||||
HASHTABLE_MEMSET( table->slots, 0, (HASHTABLE_SIZE_T) slots_size );
|
||||
table->item_capacity = (int) hashtable_internal_pow2ceil( (HASHTABLE_U32) initial_capacity );
|
||||
table->items_key = (HASHTABLE_U64*) HASHTABLE_MALLOC( table->memctx,
|
||||
table->items_key = (HASHTABLE_U64*) HASHTABLE_MALLOC( table->memctx,
|
||||
table->item_capacity * ( sizeof( *table->items_key ) + sizeof( *table->items_slot ) + table->item_size ) + table->item_size );
|
||||
HASHTABLE_ASSERT( table->items_key );
|
||||
table->items_slot = (int*)( table->items_key + table->item_capacity );
|
||||
table->items_data = (void*)( table->items_slot + table->item_capacity );
|
||||
table->swap_temp = (void*)( ( (uintptr_t) table->items_data ) + table->item_size * table->item_capacity );
|
||||
table->swap_temp = (void*)( ( (size_t) table->items_data ) + table->item_size * table->item_capacity );
|
||||
}
|
||||
|
||||
|
||||
@ -438,7 +439,7 @@ static HASHTABLE_U32 hashtable_internal_calculate_hash( HASHTABLE_U64 key )
|
||||
key = key * 21;
|
||||
key = key ^ ( key >> 11 );
|
||||
key = key + ( key << 6 );
|
||||
key = key ^ ( key >> 22 );
|
||||
key = key ^ ( key >> 22 );
|
||||
HASHTABLE_ASSERT( key );
|
||||
return (HASHTABLE_U32) key;
|
||||
}
|
||||
@ -459,7 +460,7 @@ static int hashtable_internal_find_slot( hashtable_t const* table, HASHTABLE_U64
|
||||
if( slot_hash )
|
||||
{
|
||||
int slot_base = (int)( slot_hash & (HASHTABLE_U32)slot_mask );
|
||||
if( slot_base == base_slot )
|
||||
if( slot_base == base_slot )
|
||||
{
|
||||
HASHTABLE_ASSERT( base_count > 0 );
|
||||
--base_count;
|
||||
@ -468,7 +469,7 @@ static int hashtable_internal_find_slot( hashtable_t const* table, HASHTABLE_U64
|
||||
}
|
||||
}
|
||||
slot = ( slot + 1 ) & slot_mask;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
@ -478,30 +479,32 @@ static void hashtable_internal_expand_slots( hashtable_t* table )
|
||||
{
|
||||
int const old_capacity = table->slot_capacity;
|
||||
struct hashtable_internal_slot_t* old_slots = table->slots;
|
||||
int slot_mask, size, i;
|
||||
|
||||
table->slot_capacity *= 2;
|
||||
int const slot_mask = table->slot_capacity - 1;
|
||||
slot_mask = table->slot_capacity - 1;
|
||||
|
||||
int const size = (int)( table->slot_capacity * sizeof( *table->slots ) );
|
||||
size = (int)( table->slot_capacity * sizeof( *table->slots ) );
|
||||
table->slots = (struct hashtable_internal_slot_t*) HASHTABLE_MALLOC( table->memctx, (HASHTABLE_SIZE_T) size );
|
||||
HASHTABLE_ASSERT( table->slots );
|
||||
HASHTABLE_MEMSET( table->slots, 0, (HASHTABLE_SIZE_T) size );
|
||||
|
||||
for( int i = 0; i < old_capacity; ++i )
|
||||
for( i = 0; i < old_capacity; ++i )
|
||||
{
|
||||
HASHTABLE_U32 const hash = old_slots[ i ].key_hash;
|
||||
if( hash )
|
||||
{
|
||||
int item_index;
|
||||
int const base_slot = (int)( hash & (HASHTABLE_U32)slot_mask );
|
||||
int slot = base_slot;
|
||||
while( table->slots[ slot ].key_hash )
|
||||
slot = ( slot + 1 ) & slot_mask;
|
||||
table->slots[ slot ].key_hash = hash;
|
||||
int item_index = old_slots[ i ].item_index;
|
||||
item_index = old_slots[ i ].item_index;
|
||||
table->slots[ slot ].item_index = item_index;
|
||||
table->items_slot[ item_index ] = slot;
|
||||
table->items_slot[ item_index ] = slot;
|
||||
++table->slots[ base_slot ].base_count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HASHTABLE_FREE( table->memctx, old_slots );
|
||||
@ -510,20 +513,24 @@ static void hashtable_internal_expand_slots( hashtable_t* table )
|
||||
|
||||
static int hashtable_internal_expand_items( hashtable_t* table )
|
||||
{
|
||||
HASHTABLE_U64* new_items_key;
|
||||
int* new_items_slot;
|
||||
void* new_items_data, * new_swap_temp;
|
||||
|
||||
table->item_capacity *= 2;
|
||||
HASHTABLE_U64* const new_items_key = (HASHTABLE_U64*) HASHTABLE_MALLOC( table->memctx,
|
||||
new_items_key = (HASHTABLE_U64*) HASHTABLE_MALLOC( table->memctx,
|
||||
table->item_capacity * ( sizeof( *table->items_key ) + sizeof( *table->items_slot ) + table->item_size ) + table->item_size);
|
||||
if( new_items_key == NULL )
|
||||
return 0;
|
||||
|
||||
int* const new_items_slot = (int*)( new_items_key + table->item_capacity );
|
||||
void* const new_items_data = (void*)( new_items_slot + table->item_capacity );
|
||||
void* const new_swap_temp = (void*)( ( (uintptr_t) new_items_data ) + table->item_size * table->item_capacity );
|
||||
new_items_slot = (int*)( new_items_key + table->item_capacity );
|
||||
new_items_data = (void*)( new_items_slot + table->item_capacity );
|
||||
new_swap_temp = (void*)( ( (size_t) new_items_data ) + table->item_size * table->item_capacity );
|
||||
|
||||
HASHTABLE_MEMCPY( new_items_key, table->items_key, table->count * sizeof( *table->items_key ) );
|
||||
HASHTABLE_MEMCPY( new_items_slot, table->items_slot, table->count * sizeof( *table->items_key ) );
|
||||
HASHTABLE_MEMCPY( new_items_data, table->items_data, (HASHTABLE_SIZE_T) table->count * table->item_size );
|
||||
|
||||
|
||||
HASHTABLE_FREE( table->memctx, table->items_key );
|
||||
|
||||
table->items_key = new_items_key;
|
||||
@ -537,27 +544,33 @@ static int hashtable_internal_expand_items( hashtable_t* table )
|
||||
|
||||
int hashtable_insert( hashtable_t* table, HASHTABLE_U64 key, void const* item )
|
||||
{
|
||||
int slot_mask, base_slot;
|
||||
int base_count, slot, first_free;
|
||||
void* dest_item;
|
||||
HASHTABLE_U32 hash;
|
||||
|
||||
HASHTABLE_ASSERT( hashtable_internal_find_slot( table, key ) < 0 );
|
||||
|
||||
if( table->count >= ( table->slot_capacity - table->slot_capacity / 3 ) )
|
||||
hashtable_internal_expand_slots( table );
|
||||
|
||||
int const slot_mask = table->slot_capacity - 1;
|
||||
HASHTABLE_U32 const hash = hashtable_internal_calculate_hash( key );
|
||||
|
||||
int const base_slot = (int)( hash & (HASHTABLE_U32)slot_mask );
|
||||
int base_count = table->slots[ base_slot ].base_count;
|
||||
int slot = base_slot;
|
||||
int first_free = slot;
|
||||
slot_mask = table->slot_capacity - 1;
|
||||
hash = hashtable_internal_calculate_hash( key );
|
||||
|
||||
base_slot = (int)( hash & (HASHTABLE_U32)slot_mask );
|
||||
base_count = table->slots[ base_slot ].base_count;
|
||||
slot = base_slot;
|
||||
first_free = slot;
|
||||
while( base_count )
|
||||
{
|
||||
int slot_base;
|
||||
HASHTABLE_U32 const slot_hash = table->slots[ slot ].key_hash;
|
||||
if( slot_hash == 0 && table->slots[ first_free ].key_hash != 0 ) first_free = slot;
|
||||
int slot_base = (int)( slot_hash & (HASHTABLE_U32)slot_mask );
|
||||
if( slot_base == base_slot )
|
||||
slot_base = (int)( slot_hash & (HASHTABLE_U32)slot_mask );
|
||||
if( slot_base == base_slot )
|
||||
--base_count;
|
||||
slot = ( slot + 1 ) & slot_mask;
|
||||
}
|
||||
}
|
||||
|
||||
slot = first_free;
|
||||
while( table->slots[ slot ].key_hash )
|
||||
@ -573,42 +586,46 @@ int hashtable_insert( hashtable_t* table, HASHTABLE_U64 key, void const* item )
|
||||
table->slots[ slot ].item_index = table->count;
|
||||
++table->slots[ base_slot ].base_count;
|
||||
|
||||
|
||||
void* dest_item = (void*)( ( (uintptr_t) table->items_data ) + table->count * table->item_size );
|
||||
|
||||
dest_item = (void*)( ( (size_t) table->items_data ) + table->count * table->item_size );
|
||||
memcpy( dest_item, item, (HASHTABLE_SIZE_T) table->item_size );
|
||||
table->items_key[ table->count ] = key;
|
||||
table->items_slot[ table->count ] = slot;
|
||||
++table->count;
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void hashtable_remove( hashtable_t* table, HASHTABLE_U64 key )
|
||||
{
|
||||
int const slot = hashtable_internal_find_slot( table, key );
|
||||
int slot, slot_mask, base_slot, index, last_index;
|
||||
HASHTABLE_U32 hash;
|
||||
|
||||
slot = hashtable_internal_find_slot( table, key );
|
||||
HASHTABLE_ASSERT( slot >= 0 );
|
||||
|
||||
int const slot_mask = table->slot_capacity - 1;
|
||||
HASHTABLE_U32 const hash = table->slots[ slot ].key_hash;
|
||||
int const base_slot = (int)( hash & (HASHTABLE_U32) slot_mask );
|
||||
slot_mask = table->slot_capacity - 1;
|
||||
hash = table->slots[ slot ].key_hash;
|
||||
base_slot = (int)( hash & (HASHTABLE_U32) slot_mask );
|
||||
HASHTABLE_ASSERT( hash );
|
||||
--table->slots[ base_slot ].base_count;
|
||||
table->slots[ slot ].key_hash = 0;
|
||||
|
||||
int index = table->slots[ slot ].item_index;
|
||||
int last_index = table->count - 1;
|
||||
index = table->slots[ slot ].item_index;
|
||||
last_index = table->count - 1;
|
||||
if( index != last_index )
|
||||
{
|
||||
void* src_item, * dst_item;
|
||||
table->items_key[ index ] = table->items_key[ last_index ];
|
||||
table->items_slot[ index ] = table->items_slot[ last_index ];
|
||||
void* dst_item = (void*)( ( (uintptr_t) table->items_data ) + index * table->item_size );
|
||||
void* src_item = (void*)( ( (uintptr_t) table->items_data ) + last_index * table->item_size );
|
||||
dst_item = (void*)( ( (size_t) table->items_data ) + index * table->item_size );
|
||||
src_item = (void*)( ( (size_t) table->items_data ) + last_index * table->item_size );
|
||||
HASHTABLE_MEMCPY( dst_item, src_item, (HASHTABLE_SIZE_T) table->item_size );
|
||||
table->slots[ table->items_slot[ last_index ] ].item_index = index;
|
||||
}
|
||||
--table->count;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void hashtable_clear( hashtable_t* table )
|
||||
@ -620,11 +637,14 @@ void hashtable_clear( hashtable_t* table )
|
||||
|
||||
void* hashtable_find( hashtable_t const* table, HASHTABLE_U64 key )
|
||||
{
|
||||
int const slot = hashtable_internal_find_slot( table, key );
|
||||
int slot, index;
|
||||
void* item;
|
||||
|
||||
slot = hashtable_internal_find_slot( table, key );
|
||||
if( slot < 0 ) return 0;
|
||||
|
||||
int const index = table->slots[ slot ].item_index;
|
||||
void* const item = (void*)( ( (uintptr_t) table->items_data ) + index * table->item_size );
|
||||
index = table->slots[ slot ].item_index;
|
||||
item = (void*)( ( (size_t) table->items_data ) + index * table->item_size );
|
||||
return item;
|
||||
}
|
||||
|
||||
@ -649,20 +669,24 @@ HASHTABLE_U64 const* hashtable_keys( hashtable_t const* table )
|
||||
|
||||
void hashtable_swap( hashtable_t* table, int index_a, int index_b )
|
||||
{
|
||||
int slot_a, slot_b;
|
||||
void* item_a, *item_b;
|
||||
HASHTABLE_U64 temp_key;
|
||||
|
||||
if( index_a < 0 || index_a >= table->count || index_b < 0 || index_b >= table->count ) return;
|
||||
|
||||
int slot_a = table->items_slot[ index_a ];
|
||||
int slot_b = table->items_slot[ index_b ];
|
||||
slot_a = table->items_slot[ index_a ];
|
||||
slot_b = table->items_slot[ index_b ];
|
||||
|
||||
table->items_slot[ index_a ] = slot_b;
|
||||
table->items_slot[ index_b ] = slot_a;
|
||||
|
||||
HASHTABLE_U64 temp_key = table->items_key[ index_a ];
|
||||
temp_key = table->items_key[ index_a ];
|
||||
table->items_key[ index_a ] = table->items_key[ index_b ];
|
||||
table->items_key[ index_b ] = temp_key;
|
||||
|
||||
void* item_a = (void*)( ( (uintptr_t) table->items_data ) + index_a * table->item_size );
|
||||
void* item_b = (void*)( ( (uintptr_t) table->items_data ) + index_b * table->item_size );
|
||||
item_a = (void*)( ( (size_t) table->items_data ) + index_a * table->item_size );
|
||||
item_b = (void*)( ( (size_t) table->items_data ) + index_b * table->item_size );
|
||||
HASHTABLE_MEMCPY( table->swap_temp, item_a, table->item_size );
|
||||
HASHTABLE_MEMCPY( item_a, item_b, table->item_size );
|
||||
HASHTABLE_MEMCPY( item_b, table->swap_temp, table->item_size );
|
||||
@ -681,7 +705,7 @@ contributors:
|
||||
|
||||
revision history:
|
||||
1.1 added hashtable_clear, hashtable_swap
|
||||
1.0 first released version
|
||||
1.0 first released version
|
||||
|
||||
*/
|
||||
|
||||
@ -696,22 +720,22 @@ ALTERNATIVE A - MIT License
|
||||
|
||||
Copyright (c) 2015 Mattias Gustavsson
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
@ -720,22 +744,22 @@ ALTERNATIVE B - Public Domain (www.unlicense.org)
|
||||
|
||||
This is free and unencumbered software released into the public domain.
|
||||
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
|
||||
software, either in source code form or as a compiled binary, for any purpose,
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
|
||||
software, either in source code form or as a compiled binary, for any purpose,
|
||||
commercial or non-commercial, and by any means.
|
||||
|
||||
In jurisdictions that recognize copyright laws, the author or authors of this
|
||||
software dedicate any and all copyright interest in the software to the public
|
||||
domain. We make this dedication for the benefit of the public at large and to
|
||||
the detriment of our heirs and successors. We intend this dedication to be an
|
||||
overt act of relinquishment in perpetuity of all present and future rights to
|
||||
In jurisdictions that recognize copyright laws, the author or authors of this
|
||||
software dedicate any and all copyright interest in the software to the public
|
||||
domain. We make this dedication for the benefit of the public at large and to
|
||||
the detriment of our heirs and successors. We intend this dedication to be an
|
||||
overt act of relinquishment in perpetuity of all present and future rights to
|
||||
this software under copyright law.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
Loading…
x
Reference in New Issue
Block a user