Implemented separate functions for uint32_t and uint64_t hash sets.

This commit is contained in:
LoRd_MuldeR 2022-11-27 19:46:01 +01:00
parent e8603e7fd6
commit 00764536ca
13 changed files with 331 additions and 223 deletions

View File

@ -1,7 +1,7 @@
SUBDIRS := libhashset hashset SUBDIRS := libhashset hashset
BUILD_ALL := $(patsubst %,build_rule\:%,$(SUBDIRS)) BUILD_ALL := $(patsubst %,build\:%,$(SUBDIRS))
CLEAN_ALL := $(patsubst %,clean_rule\:%,$(SUBDIRS)) CLEAN_ALL := $(patsubst %,clean\:%,$(SUBDIRS))
.PHONY: all clean $(BUILD_ALL) $(CLEAN_ALL) .PHONY: all clean $(BUILD_ALL) $(CLEAN_ALL)
@ -10,7 +10,7 @@ all: $(BUILD_ALL)
clean: $(CLEAN_ALL) clean: $(CLEAN_ALL)
$(BUILD_ALL): $(BUILD_ALL):
$(MAKE) -C $(patsubst build_rule:%,%,$@) $(MAKE) -C $(patsubst build:%,%,$@)
$(CLEAN_ALL): $(CLEAN_ALL):
$(MAKE) -C $(patsubst clean_rule:%,%,$@) clean $(MAKE) -C $(patsubst clean:%,%,$@) clean

View File

@ -3,7 +3,7 @@ Introduction
**LibHashSet** is a simple *hash set* implementation for C99. It uses open addressing and double hashing. **LibHashSet** is a simple *hash set* implementation for C99. It uses open addressing and double hashing.
At this time, the *only* type of elements (keys) supported is `uint64_t`. At this time, the *only* types of elements supported are `uint32_t` and `uint64_t`.
This hash set implementation has been tested to *efficiently* handle several billions of items 😏 This hash set implementation has been tested to *efficiently* handle several billions of items 😏
@ -23,7 +23,7 @@ int main(int argc, char* argv[])
uintptr_t cursor = 0U; uintptr_t cursor = 0U;
/* create new hash set instance */ /* create new hash set instance */
hash_set_t *const hash_set = hash_set_create(0U, -1.0); hash_set64_t *const hash_set = hash_set_create64(0U, -1.0);
if (!hash_set) if (!hash_set)
{ {
fputs("Allocation has failed!\n", stderr); fputs("Allocation has failed!\n", stderr);
@ -33,7 +33,7 @@ int main(int argc, char* argv[])
/* add a number of items to the hash set, the set will grow as needed */ /* add a number of items to the hash set, the set will grow as needed */
while (have_more_items()) while (have_more_items())
{ {
const errno_t error = hash_set_insert(hash_set, get_next_item()); const errno_t error = hash_set_insert64(hash_set, get_next_item());
if (error) if (error)
{ {
fprintf(stderr, "Insert operation has failed! (error: %d)\n", error); fprintf(stderr, "Insert operation has failed! (error: %d)\n", error);
@ -42,28 +42,28 @@ int main(int argc, char* argv[])
} }
/* test whether hash set contains a specific item */ /* test whether hash set contains a specific item */
if (hash_set_contains(hash_set, 42U) == 0) if (hash_set_contains64(hash_set, 42U) == 0)
{ {
puts("Set contains item!"); puts("Set contains item!");
/* remove the existing item from the hash set */ /* remove the existing item from the hash set */
if (hash_set_remove(hash_set, 42U) == 0) if (hash_set_remove64(hash_set, 42U) == 0)
{ {
puts("Item has been removed!"); puts("Item has been removed!");
} }
} }
/* print total number of items in the hash set*/ /* print total number of items in the hash set*/
printf("Total number of items: %zu\n", hash_set_size(hash_set)); printf("Total number of items: %zu\n", hash_set_size64(hash_set));
/* print all items in the set */ /* print all items in the set */
while (hash_set_iterate(hash_set, &cursor, &value) == 0) while (hash_set_iterate64(hash_set, &cursor, &value) == 0)
{ {
printf("Item: %016llX\n", value); printf("Item: %016llX\n", value);
} }
/* destroy the hash set, when it is no longer needed! */ /* destroy the hash set, when it is no longer needed! */
hash_set_destroy(hash_set); hash_set_destroy64(hash_set);
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
``` ```
@ -74,6 +74,8 @@ API Reference
This section describes the LibHashSet programming interface, as declared in the `<hash_set.h>` header file. This section describes the LibHashSet programming interface, as declared in the `<hash_set.h>` header file.
LibHashSet supports sets containing values of type `uint32_t` or `uint64_t`. For each value type, separate functions are provided. The functions for `uint32_t` and `uint64_t` hash sets can be distinguished by the suffix `…32` and `…64` suffix, respectively. In the following, the functions are described in their "generic" form.
***Note:*** On Microsoft Windows, when using LibHashSet as a "shared" library (DLL), the macro `HASHSET_DLL` must be defined *before* including `<hash_set.h>`! This is **not** required or allowed when using the "static" library. ***Note:*** On Microsoft Windows, when using LibHashSet as a "shared" library (DLL), the macro `HASHSET_DLL` must be defined *before* including `<hash_set.h>`! This is **not** required or allowed when using the "static" library.
Types Types
@ -164,7 +166,7 @@ Tries to insert the given value into the hash set. The operation fails, if the s
```C ```C
errno_t hash_set_insert( errno_t hash_set_insert(
hash_set_t *const instance, hash_set_t *const instance,
const uint64_t value const VALUE_TYPE value
); );
``` ```
@ -174,7 +176,7 @@ errno_t hash_set_insert(
A pointer to the hash set instance to be modified, as returned by the [hash_set_create()](#hash_set_create) function. A pointer to the hash set instance to be modified, as returned by the [hash_set_create()](#hash_set_create) function.
* `value` * `value`
The value (key) to be inserted into the hash set. It can be *any* value in the `0U` to `UINT64_MAX` range. The value (key) to be inserted into the hash set.
#### Return value #### Return value
@ -201,7 +203,7 @@ Tries to remove the given value from the hash set. The operation fails, if the s
```C ```C
errno_t hash_set_remove( errno_t hash_set_remove(
hash_set_t *const instance, hash_set_t *const instance,
const uint64_t value const VALUE_TYPE value
); );
``` ```
@ -211,7 +213,7 @@ errno_t hash_set_remove(
A pointer to the hash set instance to be modified, as returned by the [hash_set_create()](#hash_set_create) function. A pointer to the hash set instance to be modified, as returned by the [hash_set_create()](#hash_set_create) function.
* `value` * `value`
The value (key) to be removed from the hash set. It can be *any* value in the `0U` to `UINT64_MAX` range. The value (key) to be removed from the hash set.
#### Return value #### Return value
@ -260,7 +262,7 @@ Tests whether the hash set contains a value. The operation fails, if the set doe
```C ```C
errno_t hash_set_contains( errno_t hash_set_contains(
const hash_set_t *const instance, const hash_set_t *const instance,
const uint64_t value const VALUE_TYPE value
); );
``` ```
@ -270,7 +272,7 @@ errno_t hash_set_contains(
A pointer to the hash set instance to be examined, as returned by the [hash_set_create()](#hash_set_create) function. A pointer to the hash set instance to be examined, as returned by the [hash_set_create()](#hash_set_create) function.
* `value` * `value`
The value (key) to be searched in the hash set. It can be *any* value in the `0U` to `UINT64_MAX` range. The value (key) to be searched in the hash set.
#### Return value #### Return value
@ -297,7 +299,7 @@ This function returns one value at a time. It should be called repeatedly, until
errno_t hash_set_iterate( errno_t hash_set_iterate(
const hash_set_t *const instance, const hash_set_t *const instance,
uintptr_t *const cursor, uintptr_t *const cursor,
uint64_t *const value VALUE_TYPE *const value
); );
``` ```
@ -311,9 +313,8 @@ errno_t hash_set_iterate(
This variable **must** be initialized to the value `0U`, by the calling application, prior to the the *first* invocation! This variable **must** be initialized to the value `0U`, by the calling application, prior to the the *first* invocation!
Each invocation will update the value of `*cursor`; the value **shall not** be altered by the application. Each invocation will update the value of `*cursor`; the value **shall not** be altered by the application.
* `value` * `value`
A pointer to a variable of type `uint64_t` where the next value in the set is stored on success. A pointer to a variable of type `uint32_t` or `uint64_t` where the next value in the set is stored on success.
The content of the variable should be considered *undefined*, if the invocation has failed. The content of the variable should be considered *undefined*, if the invocation has failed.
#### Return value #### Return value

View File

@ -1,7 +1,7 @@
DUMPMACHINE := $(shell $(CC) -dumpmachine) DUMPMACHINE := $(shell $(CC) -dumpmachine)
ifneq ($(SANITIZE_ADDRESS),1) ifneq ($(SANITIZE_ADDRESS),1)
XCFLAGS = -O3 -DNDEBUG XCFLAGS = -Ofast -DNDEBUG -s -static
ifneq ($(firstword $(filter x86_64-%,$(DUMPMACHINE))),) ifneq ($(firstword $(filter x86_64-%,$(DUMPMACHINE))),)
XCFLAGS += -march=x86-64 -mtune=nocona XCFLAGS += -march=x86-64 -mtune=nocona
else ifneq ($(firstword $(filter i686-%,$(DUMPMACHINE))),) else ifneq ($(firstword $(filter i686-%,$(DUMPMACHINE))),)
@ -22,19 +22,22 @@ CFLAGS = -std=c99 -D_DEFAULT_SOURCE -Wpedantic -I../libhashset/include $(XCFLAGS
SRC_PATH := src SRC_PATH := src
BIN_PATH := bin BIN_PATH := bin
ALL_PATH := $(SRC_PATH) $(BIN_PATH)
BIN_FILE := $(BIN_PATH)/hashset-test$(EXE_SUFFIX) BIN_FILE := $(BIN_PATH)/hashset-test$(EXE_SUFFIX)
SRC_FILE := $(SRC_PATH)/main.c SRC_FILE := $(SRC_PATH)/main.c
LIB_FILE := ../libhashset/lib/libhashset-1.a LIB_FILE := ../libhashset/lib/libhashset-1.a
.PHONY: all clean .PHONY: all build clean
all: $(BIN_FILE) all: clean build
$(BIN_FILE): $(SRC_FILE) $(LIB_FILE) $(BIN_PATH) build: $(ALL_PATH) $(BIN_FILE)
$(CC) $(CFLAGS) $< -o $@ $(LIB_FILE)
$(SRC_PATH) $(BIN_PATH): $(BIN_FILE): $(SRC_FILE) $(LIB_FILE)
$(CC) $(CFLAGS) $^ -o $@
$(ALL_PATH):
mkdir -p $@ mkdir -p $@
clean: clean:

View File

@ -64,7 +64,7 @@ static INLINE uint64_t random_next(random_t *const rnd)
#define PRINT_SET_INFO(X) do \ #define PRINT_SET_INFO(X) do \
{\ {\
if (!hash_set_info(hash_set, &capacity, &valid, &deleted, &limit)) \ if (!hash_set_info64(hash_set, &capacity, &valid, &deleted, &limit)) \
{ \ { \
printf("[#%d] capacity: %010zu, valid: %010zu, deleted: %010zu, limit: %010zu\n", (X), capacity, valid, deleted, limit); \ printf("[#%d] capacity: %010zu, valid: %010zu, deleted: %010zu, limit: %010zu\n", (X), capacity, valid, deleted, limit); \
} \ } \
@ -77,7 +77,7 @@ while(0)
#define MAXIMUM 425984U #define MAXIMUM 425984U
static int test_function_1(hash_set_t *const hash_set) static int test_function_1(hash_set64_t *const hash_set)
{ {
size_t capacity, valid, deleted, limit; size_t capacity, valid, deleted, limit;
@ -87,7 +87,7 @@ static int test_function_1(hash_set_t *const hash_set)
{ {
if ((i != 3167U) && (i != 9887U) && (i != 185903U) && (i != 387083U)) if ((i != 3167U) && (i != 9887U) && (i != 185903U) && (i != 387083U))
{ {
const errno_t error = hash_set_insert(hash_set, i); const errno_t error = hash_set_insert64(hash_set, i);
if (error) if (error)
{ {
printf("Insert operation has failed! (error: %d)\n", error); printf("Insert operation has failed! (error: %d)\n", error);
@ -97,7 +97,7 @@ static int test_function_1(hash_set_t *const hash_set)
PRINT_SET_INFO(1); PRINT_SET_INFO(1);
} }
if (hash_set_size(hash_set) != MAXIMUM - 4U) if (hash_set_size64(hash_set) != MAXIMUM - 4U)
{ {
puts("Invalid size!"); puts("Invalid size!");
return EXIT_FAILURE; return EXIT_FAILURE;
@ -107,7 +107,7 @@ static int test_function_1(hash_set_t *const hash_set)
{ {
if ((i != 3167U) && (i != 9887U) && (i != 387083U)) if ((i != 3167U) && (i != 9887U) && (i != 387083U))
{ {
const errno_t error = hash_set_insert(hash_set, i); const errno_t error = hash_set_insert64(hash_set, i);
if (error != ((i != 185903U) ? EEXIST : 0)) if (error != ((i != 185903U) ? EEXIST : 0))
{ {
printf("Insert operation has failed! (error: %d)\n", error); printf("Insert operation has failed! (error: %d)\n", error);
@ -116,7 +116,7 @@ static int test_function_1(hash_set_t *const hash_set)
} }
} }
if (hash_set_size(hash_set) != MAXIMUM - 3U) if (hash_set_size64(hash_set) != MAXIMUM - 3U)
{ {
puts("Invalid size!"); puts("Invalid size!");
return EXIT_FAILURE; return EXIT_FAILURE;
@ -124,7 +124,7 @@ static int test_function_1(hash_set_t *const hash_set)
for (uint64_t i = 0; i < MAXIMUM; ++i) for (uint64_t i = 0; i < MAXIMUM; ++i)
{ {
const errno_t error = hash_set_contains(hash_set, i); const errno_t error = hash_set_contains64(hash_set, i);
if (error != ((i != 3167U) && (i != 9887U) && (i != 387083U)) ? 0 : ENOENT) if (error != ((i != 3167U) && (i != 9887U) && (i != 387083U)) ? 0 : ENOENT)
{ {
printf("Contains operation has failed! (error: %d)\n", error); printf("Contains operation has failed! (error: %d)\n", error);
@ -136,7 +136,7 @@ static int test_function_1(hash_set_t *const hash_set)
{ {
if ((i != 3167U) && (i != 9887U) && (i != 216263U) && (i != 387083U)) if ((i != 3167U) && (i != 9887U) && (i != 216263U) && (i != 387083U))
{ {
const errno_t error = hash_set_remove(hash_set, i); const errno_t error = hash_set_remove64(hash_set, i);
if (error) if (error)
{ {
printf("Remove operation has failed! (error: %d)\n", error); printf("Remove operation has failed! (error: %d)\n", error);
@ -146,7 +146,7 @@ static int test_function_1(hash_set_t *const hash_set)
PRINT_SET_INFO(1); PRINT_SET_INFO(1);
} }
if (hash_set_size(hash_set) != 1U) if (hash_set_size64(hash_set) != 1U)
{ {
puts("Invalid size!"); puts("Invalid size!");
return EXIT_FAILURE; return EXIT_FAILURE;
@ -154,7 +154,7 @@ static int test_function_1(hash_set_t *const hash_set)
for (uint64_t i = 0; i < MAXIMUM; ++i) for (uint64_t i = 0; i < MAXIMUM; ++i)
{ {
const errno_t error = hash_set_contains(hash_set, i); const errno_t error = hash_set_contains64(hash_set, i);
if (error != ((i != 216263U) ? ENOENT : 0)) if (error != ((i != 216263U) ? ENOENT : 0))
{ {
printf("Contains operation has failed! (error: %d)\n", error); printf("Contains operation has failed! (error: %d)\n", error);
@ -162,19 +162,19 @@ static int test_function_1(hash_set_t *const hash_set)
} }
} }
if (!hash_set_remove(hash_set, 9887U)) if (!hash_set_remove64(hash_set, 9887U))
{ {
puts("Final remove operation has failed!"); puts("Final remove operation has failed!");
return EXIT_FAILURE; return EXIT_FAILURE;
} }
if (hash_set_remove(hash_set, 216263U)) if (hash_set_remove64(hash_set, 216263U))
{ {
puts("Final remove operation has failed!"); puts("Final remove operation has failed!");
return EXIT_FAILURE; return EXIT_FAILURE;
} }
if (hash_set_size(hash_set) != 0U) if (hash_set_size64(hash_set) != 0U)
{ {
puts("Invalid size!"); puts("Invalid size!");
return EXIT_FAILURE; return EXIT_FAILURE;
@ -193,7 +193,7 @@ static int test_function_1(hash_set_t *const hash_set)
#define ARRSIZE 14867U #define ARRSIZE 14867U
static int test_function_2(hash_set_t *const hash_set) static int test_function_2(hash_set64_t *const hash_set)
{ {
size_t capacity, valid, deleted, limit; size_t capacity, valid, deleted, limit;
uint64_t value; uint64_t value;
@ -221,7 +221,7 @@ static int test_function_2(hash_set_t *const hash_set)
{ {
if (test[j]) if (test[j])
{ {
const errno_t error = hash_set_insert(hash_set, j); const errno_t error = hash_set_insert64(hash_set, j);
if (error) if (error)
{ {
printf("Insert operation has failed! (error: %d)\n", error); printf("Insert operation has failed! (error: %d)\n", error);
@ -230,7 +230,7 @@ static int test_function_2(hash_set_t *const hash_set)
PRINT_SET_INFO(2); PRINT_SET_INFO(2);
} }
} }
while (!hash_set_iterate(hash_set, &cursor, &value)) while (!hash_set_iterate64(hash_set, &cursor, &value))
{ {
if (!test[value]) if (!test[value])
{ {
@ -242,7 +242,7 @@ static int test_function_2(hash_set_t *const hash_set)
{ {
if (test[j]) if (test[j])
{ {
const errno_t error = hash_set_remove(hash_set, j); const errno_t error = hash_set_remove64(hash_set, j);
if (error) if (error)
{ {
printf("Remove operation has failed! (error: %d)\n", error); printf("Remove operation has failed! (error: %d)\n", error);
@ -252,7 +252,7 @@ static int test_function_2(hash_set_t *const hash_set)
test[j] = UINT8_C(0); test[j] = UINT8_C(0);
} }
} }
if (hash_set_size(hash_set) != 0U) if (hash_set_size64(hash_set) != 0U)
{ {
puts("Invalid size!"); puts("Invalid size!");
return EXIT_FAILURE; return EXIT_FAILURE;
@ -269,7 +269,7 @@ static int test_function_2(hash_set_t *const hash_set)
/* TEST #3 */ /* TEST #3 */
/* ========================================================================= */ /* ========================================================================= */
static int test_function_3(hash_set_t *const hash_set) static int test_function_3(hash_set64_t *const hash_set)
{ {
size_t capacity, valid, deleted, limit; size_t capacity, valid, deleted, limit;
uint8_t spinner = 0U; uint8_t spinner = 0U;
@ -283,7 +283,7 @@ static int test_function_3(hash_set_t *const hash_set)
for (;;) for (;;)
{ {
const uint64_t rnd = random_next(&random) & UINT64_C(0x3FFFFFFFFFFFFFF); const uint64_t rnd = random_next(&random) & UINT64_C(0x3FFFFFFFFFFFFFF);
const errno_t error = hash_set_insert(hash_set, rnd); const errno_t error = hash_set_insert64(hash_set, rnd);
if (error) if (error)
{ {
if (error != EEXIST) if (error != EEXIST)
@ -311,7 +311,7 @@ static int test_function_3(hash_set_t *const hash_set)
PRINT_SET_INFO(3); PRINT_SET_INFO(3);
if (hash_set_clear(hash_set)) if (hash_set_clear64(hash_set))
{ {
puts("Clear operation has failed!"); puts("Clear operation has failed!");
return EXIT_FAILURE; return EXIT_FAILURE;
@ -330,7 +330,7 @@ static int test_function_3(hash_set_t *const hash_set)
#define LIMIT (((uint64_t)UINT32_MAX) >> 2) #define LIMIT (((uint64_t)UINT32_MAX) >> 2)
static int test_function_4(hash_set_t *const hash_set) static int test_function_4(hash_set64_t *const hash_set)
{ {
size_t capacity, valid, deleted, limit; size_t capacity, valid, deleted, limit;
uint8_t spinner = 0U; uint8_t spinner = 0U;
@ -338,7 +338,7 @@ static int test_function_4(hash_set_t *const hash_set)
for (uint64_t value = 0U; value < LIMIT; ++value) for (uint64_t value = 0U; value < LIMIT; ++value)
{ {
const errno_t error = hash_set_insert(hash_set, value); const errno_t error = hash_set_insert64(hash_set, value);
if (error) if (error)
{ {
PRINT_SET_INFO(4); PRINT_SET_INFO(4);
@ -358,7 +358,7 @@ static int test_function_4(hash_set_t *const hash_set)
for (uint64_t value = 0U; value < LIMIT; ++value) for (uint64_t value = 0U; value < LIMIT; ++value)
{ {
const errno_t error = hash_set_remove(hash_set, value); const errno_t error = hash_set_remove64(hash_set, value);
if (error) if (error)
{ {
PRINT_SET_INFO(4); PRINT_SET_INFO(4);
@ -376,7 +376,7 @@ static int test_function_4(hash_set_t *const hash_set)
} }
} }
if (hash_set_size(hash_set) != 0U) if (hash_set_size64(hash_set) != 0U)
{ {
puts("Invalid size!"); puts("Invalid size!");
return EXIT_FAILURE; return EXIT_FAILURE;
@ -397,7 +397,7 @@ int main(void)
printf("LibHashSet Test v%" PRIu16 ".%" PRIu16 ".%" PRIu16 " [%s]\n\n", printf("LibHashSet Test v%" PRIu16 ".%" PRIu16 ".%" PRIu16 " [%s]\n\n",
HASHSET_VERSION_MAJOR, HASHSET_VERSION_MINOR, HASHSET_VERSION_PATCH, HASHSET_BUILD_DATE); HASHSET_VERSION_MAJOR, HASHSET_VERSION_MINOR, HASHSET_VERSION_PATCH, HASHSET_BUILD_DATE);
hash_set_t *const hash_set = hash_set_create(0U, -1.0); hash_set64_t *const hash_set = hash_set_create64(0U, -1.0);
if (!hash_set) if (!hash_set)
{ {
puts("Allocation has failed!"); puts("Allocation has failed!");
@ -424,12 +424,12 @@ int main(void)
goto failure; goto failure;
} }
hash_set_destroy(hash_set); hash_set_destroy64(hash_set);
puts("Test completed successfully."); puts("Test completed successfully.");
return EXIT_SUCCESS; return EXIT_SUCCESS;
failure: failure:
hash_set_destroy(hash_set); hash_set_destroy64(hash_set);
puts("Something went wrong !!!"); puts("Something went wrong !!!");
return EXIT_FAILURE; return EXIT_FAILURE;
} }

View File

@ -1,7 +1,7 @@
DUMPMACHINE := $(shell $(CC) -dumpmachine) DUMPMACHINE := $(shell $(CC) -dumpmachine)
ifneq ($(SANITIZE_ADDRESS),1) ifneq ($(SANITIZE_ADDRESS),1)
XCFLAGS = -O3 -DNDEBUG XCFLAGS = -Ofast -DNDEBUG
ifneq ($(firstword $(filter x86_64-%,$(DUMPMACHINE))),) ifneq ($(firstword $(filter x86_64-%,$(DUMPMACHINE))),)
XCFLAGS += -march=x86-64 -mtune=nocona XCFLAGS += -march=x86-64 -mtune=nocona
else ifneq ($(firstword $(filter i686-%,$(DUMPMACHINE))),) else ifneq ($(firstword $(filter i686-%,$(DUMPMACHINE))),)
@ -16,22 +16,26 @@ CFLAGS = -std=c99 -D_DEFAULT_SOURCE -Wpedantic -Iinclude $(XCFLAGS)
SRC_PATH := src SRC_PATH := src
OBJ_PATH := obj OBJ_PATH := obj
LIB_PATH := lib LIB_PATH := lib
ALL_PATH := $(SRC_PATH) $(OBJ_PATH) $(LIB_PATH)
SRC_FILE := $(wildcard $(SRC_PATH)/*.c)
OBJ_FILE := $(addprefix $(OBJ_PATH)/,$(patsubst %.c,%.o,$(notdir $(SRC_FILE))))
LIB_FILE := $(LIB_PATH)/libhashset-1.a LIB_FILE := $(LIB_PATH)/libhashset-1.a
OBJ_FILE := $(OBJ_PATH)/hash_set.o
.PHONY: all clean .PHONY: all build clean
all: $(LIB_FILE) all: clean build
$(LIB_FILE): $(OBJ_FILE) $(LIB_PATH) build: $(ALL_PATH) $(LIB_FILE)
$(AR) rcs $@ $<
$(OBJ_FILE): $(SRC_PATH) $(OBJ_PATH) $(LIB_FILE): $(OBJ_FILE)
$(AR) rcs $@ $(OBJ_FILE)
$(OBJ_FILE):
$(CC) $(CFLAGS) -c $(SRC_PATH)/$(patsubst %.o,%.c,$(notdir $@)) -o $@ $(CC) $(CFLAGS) -c $(SRC_PATH)/$(patsubst %.o,%.c,$(notdir $@)) -o $@
$(SRC_PATH) $(OBJ_PATH) $(LIB_PATH): $(ALL_PATH):
mkdir -p $@ mkdir -p $@
clean: clean:
rm -f $(LIB_FILE) $(OBJ_PATH)/*.o rm -vf $(LIB_FILE) $(OBJ_PATH)/*.o

View File

@ -3,8 +3,8 @@
/* This work has been released under the CC0 1.0 Universal license! */ /* This work has been released under the CC0 1.0 Universal license! */
/******************************************************************************/ /******************************************************************************/
#ifndef _INC_HASHSET_H #ifndef _LIBHASHSET_INCLUDED
#define _INC_HASHSET_H #define _LIBHASHSET_INCLUDED
#include <stdlib.h> #include <stdlib.h>
#include <stdint.h> #include <stdint.h>
@ -27,9 +27,6 @@ extern "C" {
typedef int errno_t; typedef int errno_t;
#endif #endif
struct _hash_set;
typedef struct _hash_set hash_set_t;
HASHSET_API const uint16_t HASHSET_VERSION_MAJOR; HASHSET_API const uint16_t HASHSET_VERSION_MAJOR;
HASHSET_API const uint16_t HASHSET_VERSION_MINOR; HASHSET_API const uint16_t HASHSET_VERSION_MINOR;
HASHSET_API const uint16_t HASHSET_VERSION_PATCH; HASHSET_API const uint16_t HASHSET_VERSION_PATCH;
@ -37,17 +34,38 @@ HASHSET_API const uint16_t HASHSET_VERSION_PATCH;
HASHSET_API const char *const HASHSET_BUILD_DATE; HASHSET_API const char *const HASHSET_BUILD_DATE;
HASHSET_API const char *const HASHSET_BUILD_TIME; HASHSET_API const char *const HASHSET_BUILD_TIME;
HASHSET_API hash_set_t *hash_set_create(const size_t initial_capacity, const double load_factor); struct _hash_set32;
HASHSET_API void hash_set_destroy(hash_set_t *const instance); struct _hash_set64;
HASHSET_API errno_t hash_set_insert(hash_set_t *const instance, const uint64_t value); typedef struct _hash_set32 hash_set32_t;
HASHSET_API errno_t hash_set_remove(hash_set_t *const instance, const uint64_t value); typedef struct _hash_set64 hash_set64_t;
HASHSET_API errno_t hash_set_clear(hash_set_t *const instance);
HASHSET_API errno_t hash_set_contains(const hash_set_t *const instance, const uint64_t value); HASHSET_API hash_set32_t *hash_set_create32(const size_t initial_capacity, const double load_factor);
HASHSET_API errno_t hash_set_iterate(const hash_set_t *const instance, uintptr_t *const cursor, uint64_t *const value); HASHSET_API hash_set64_t* hash_set_create64(const size_t initial_capacity, const double load_factor);
HASHSET_API size_t hash_set_size(const hash_set_t *const instance);
HASHSET_API errno_t hash_set_info(const hash_set_t *const instance, size_t *const capacity, size_t *const valid, size_t *const deleted, size_t *const limit); HASHSET_API void hash_set_destroy32(hash_set32_t *const instance);
HASHSET_API void hash_set_destroy64(hash_set64_t *const instance);
HASHSET_API errno_t hash_set_insert32(hash_set32_t *const instance, const uint32_t value);
HASHSET_API errno_t hash_set_insert64(hash_set64_t *const instance, const uint64_t value);
HASHSET_API errno_t hash_set_remove32(hash_set32_t *const instance, const uint32_t value);
HASHSET_API errno_t hash_set_remove64(hash_set64_t *const instance, const uint64_t value);
HASHSET_API errno_t hash_set_clear32(hash_set32_t *const instance);
HASHSET_API errno_t hash_set_clear64(hash_set64_t *const instance);
HASHSET_API errno_t hash_set_contains32(const hash_set32_t *const instance, const uint32_t value);
HASHSET_API errno_t hash_set_contains64(const hash_set64_t *const instance, const uint64_t value);
HASHSET_API errno_t hash_set_iterate32(const hash_set32_t *const instance, uintptr_t *const cursor, uint32_t *const value);
HASHSET_API errno_t hash_set_iterate64(const hash_set64_t *const instance, uintptr_t *const cursor, uint64_t *const value);
HASHSET_API size_t hash_set_size32(const hash_set32_t *const instance);
HASHSET_API size_t hash_set_size64(const hash_set64_t *const instance);
HASHSET_API errno_t hash_set_info32(const hash_set32_t *const instance, size_t *const capacity, size_t *const valid, size_t *const deleted, size_t *const limit);
HASHSET_API errno_t hash_set_info64(const hash_set64_t *const instance, size_t *const capacity, size_t *const valid, size_t *const deleted, size_t *const limit);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -40,9 +40,13 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="include\hash_set.h" /> <ClInclude Include="include\hash_set.h" />
<ClInclude Include="src\common.h" />
<ClInclude Include="src\generic.h" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="src\hash_set.c" /> <ClCompile Include="src\hash_set_32.c" />
<ClCompile Include="src\hash_set_64.c" />
<ClCompile Include="src\version.c" />
</ItemGroup> </ItemGroup>
<PropertyGroup Label="Globals"> <PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion> <VCProjectVersion>16.0</VCProjectVersion>

View File

@ -18,9 +18,21 @@
<ClInclude Include="include\hash_set.h"> <ClInclude Include="include\hash_set.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="src\common.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\generic.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="src\hash_set.c"> <ClCompile Include="src\hash_set_64.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\version.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\hash_set_32.c">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
</ItemGroup> </ItemGroup>

122
libhashset/src/common.h Normal file
View File

@ -0,0 +1,122 @@
/******************************************************************************/
/* HashSet for C99, by LoRd_MuldeR <MuldeR2@GMX.de> */
/* This work has been released under the CC0 1.0 Universal license! */
/******************************************************************************/
#ifndef _LIBHASHSET_COMMON_INCLUDED
#define _LIBHASHSET_COMMON_INCLUDED
/* CRT */
#include <string.h>
#include <errno.h>
#include <math.h>
#include <limits.h>
#include <float.h>
#include <assert.h>
typedef int bool_t;
#define TRUE 1
#define FALSE 0
#if defined(__GNUC__)
# define INLINE __inline__
# define FORCE_INLINE __attribute__((always_inline)) __inline__
#elif defined(_MSC_VER)
# define INLINE __inline
# define FORCE_INLINE __forceinline
#else
# define INLINE
#endif
static const size_t MINIMUM_CAPACITY = 128U;
static const size_t DEFAULT_CAPACITY = 8192U;
static const double DEFAULT_LOADFCTR = 0.8;
/* ------------------------------------------------- */
/* Utilities */
/* ------------------------------------------------- */
#define IS_VALID(X,Y) (get_flag((X).used, (Y)) && (!get_flag((X).deleted, (Y))))
#define BOUND(MIN,VAL,MAX) (((VAL) < (MIN)) ? (MIN) : (((VAL) > (MAX)) ? (MAX) : (VAL)))
#define SAFE_SET(X,Y) do { if((X)) { *(X) = (Y); } } while(0)
#define SAFE_FREE(X) do { if ((X)) { free((X)); (X) = NULL; } } while(0)
#define _NAME_GLUE_HELPER(X,Y) X##Y
#define NAME_GLUE(X,Y) _NAME_GLUE_HELPER(X,Y)
/* ------------------------------------------------- */
/* Math */
/* ------------------------------------------------- */
static FORCE_INLINE size_t div_ceil(const size_t value, const size_t divisor)
{
return (value / divisor) + ((value % divisor != 0U) ? 1U : 0U);
}
static FORCE_INLINE size_t round_sz(const double d)
{
return ((!isnan(d)) && (d >= 0.0)) ? ((d + 0.5 >= ((double)SIZE_MAX)) ? SIZE_MAX : ((size_t)(d + 0.5))) : 0U;
}
static FORCE_INLINE size_t safe_add(const size_t a, const size_t b)
{
return ((SIZE_MAX - a) > b) ? (a + b) : SIZE_MAX;
}
static FORCE_INLINE size_t safe_incr(const size_t value)
{
return (value < SIZE_MAX) ? (value + 1U) : value;
}
static FORCE_INLINE size_t safe_decr(const size_t value)
{
return (value > 0U) ? (value - 1U) : value;
}
static FORCE_INLINE size_t safe_mult(const size_t a, const size_t b)
{
const size_t result = a * b;
return ((a == 0U) || (result / a == b)) ? result : SIZE_MAX;
}
static FORCE_INLINE size_t safe_times2(const size_t value)
{
return (value <= (SIZE_MAX / 2U)) ? (2U * value) : SIZE_MAX;
}
static FORCE_INLINE size_t next_pow2(const size_t target)
{
size_t result = MINIMUM_CAPACITY;
while (result < target)
{
result = safe_times2(result);
}
return result;
}
/* ------------------------------------------------- */
/* Flags */
/* ------------------------------------------------- */
static INLINE bool_t get_flag(const uint8_t* const flags, const size_t index)
{
return (flags[index / 8U] >> (index % 8U)) & UINT8_C(1);
}
static INLINE void set_flag(uint8_t* const flags, const size_t index)
{
flags[index / 8U] |= UINT8_C(1) << (index % 8U);
}
static INLINE void clear_flag(uint8_t* const flags, const size_t index)
{
flags[index / 8U] &= ~(UINT8_C(1) << (index % 8U));
}
#endif

View File

@ -3,120 +3,44 @@
/* This work has been released under the CC0 1.0 Universal license! */ /* This work has been released under the CC0 1.0 Universal license! */
/******************************************************************************/ /******************************************************************************/
#include "hash_set.h" #ifndef _LIBHASHSET_COMMON_INCLUDED
#error File "common.h" must be included first!
/* CRT */
#include <string.h>
#include <errno.h>
#include <math.h>
#include <limits.h>
#include <float.h>
#include <assert.h>
typedef int bool_t;
#define TRUE 1
#define FALSE 0
#if defined(__GNUC__)
# define INLINE __inline__
# define FORCE_INLINE __attribute__((always_inline)) __inline__
#elif defined(_MSC_VER)
# define INLINE __inline
# define FORCE_INLINE __forceinline
#else
# define INLINE
#endif #endif
const uint16_t HASHSET_VERSION_MAJOR = UINT16_C(1); #ifndef NAME_SUFFIX
const uint16_t HASHSET_VERSION_MINOR = UINT16_C(0); #error NAME_SUFFIX must be defined!
const uint16_t HASHSET_VERSION_PATCH = UINT16_C(0); #endif
const char *const HASHSET_BUILD_DATE = __DATE__; #ifndef SET_TYPE
const char *const HASHSET_BUILD_TIME = __TIME__; #error SET_TYPE must be defined!
#endif
struct _hash_set_data #ifndef VALUE_TYPE
#error VALUE_TYPE must be defined!
#endif
#define MAKE_NAME(X) NAME_GLUE(X,NAME_SUFFIX)
/* ------------------------------------------------- */
/* Data types */
/* ------------------------------------------------- */
#define DATA_STRUCT MAKE_NAME(_hash_data)
struct DATA_STRUCT
{ {
uint64_t *values; VALUE_TYPE *values;
uint8_t *used, *deleted; uint8_t *used, *deleted;
size_t capacity; size_t capacity;
}; };
struct _hash_set struct MAKE_NAME(_hash_set)
{ {
double load_factor; double load_factor;
size_t valid, deleted, limit; size_t valid, deleted, limit;
struct _hash_set_data data; struct DATA_STRUCT data;
}; };
static const size_t MINIMUM_CAPACITY = 128U;
static const size_t DEFAULT_CAPACITY = 8192U;
static const double DEFAULT_LOADFCTR = 0.8;
/* ========================================================================= */
/* PRIVATE FUNCTIONS */
/* ========================================================================= */
#define IS_VALID(X,Y) (get_flag((X).used, (Y)) && (!get_flag((X).deleted, (Y))))
#define BOUND(MIN,VAL,MAX) (((VAL) < (MIN)) ? (MIN) : (((VAL) > (MAX)) ? (MAX) : (VAL)))
#define SAFE_SET(X,Y) do { if((X)) { *(X) = (Y); } } while(0)
#define SAFE_FREE(X) do { if ((X)) { free((X)); (X) = NULL; } } while(0)
/* ------------------------------------------------- */
/* Math */
/* ------------------------------------------------- */
static FORCE_INLINE size_t div_ceil(const size_t value, const size_t divisor)
{
return (value / divisor) + ((value % divisor != 0U) ? 1U : 0U);
}
static FORCE_INLINE size_t round_sz(const double d)
{
return ((!isnan(d)) && (d >= 0.0)) ? ((d + 0.5 >= ((double)SIZE_MAX)) ? SIZE_MAX : ((size_t)(d + 0.5))) : 0U;
}
static FORCE_INLINE size_t safe_add(const size_t a, const size_t b)
{
return ((SIZE_MAX - a) > b) ? (a + b) : SIZE_MAX;
}
static FORCE_INLINE size_t safe_incr(const size_t value)
{
return (value < SIZE_MAX) ? (value + 1U) : value;
}
static FORCE_INLINE size_t safe_decr(const size_t value)
{
return (value > 0U) ? (value - 1U) : value;
}
static FORCE_INLINE size_t safe_mult(const size_t a, const size_t b)
{
const size_t result = a * b;
return ((a == 0U) || (result / a == b)) ? result : SIZE_MAX;
}
static FORCE_INLINE size_t safe_times2(const size_t value)
{
return (value <= (SIZE_MAX / 2U)) ? (2U * value) : SIZE_MAX;
}
static FORCE_INLINE size_t next_pow2(const size_t target)
{
size_t result = MINIMUM_CAPACITY;
while (result < target)
{
result = safe_times2(result);
}
return result;
}
/* ------------------------------------------------- */ /* ------------------------------------------------- */
/* Hash function */ /* Hash function */
/* ------------------------------------------------- */ /* ------------------------------------------------- */
@ -131,7 +55,7 @@ static FORCE_INLINE void hash_update(uint64_t *const hash, uint64_t value)
while (value >>= CHAR_BIT); while (value >>= CHAR_BIT);
} }
static INLINE uint64_t hash_compute(const uint64_t i, const uint64_t value) static INLINE uint64_t hash_compute(const uint64_t i, const VALUE_TYPE value)
{ {
uint64_t hash = UINT64_C(14695981039346656037); uint64_t hash = UINT64_C(14695981039346656037);
hash_update(&hash, i); hash_update(&hash, i);
@ -148,11 +72,11 @@ static INLINE void zero_memory(void *const addr, const size_t count, const size_
memset(addr, 0, safe_mult(count, size)); memset(addr, 0, safe_mult(count, size));
} }
static INLINE bool_t alloc_data(struct _hash_set_data *const data, const size_t capacity) static INLINE bool_t alloc_data(struct DATA_STRUCT *const data, const size_t capacity)
{ {
zero_memory(data, 1U, sizeof(struct _hash_set_data)); zero_memory(data, 1U, sizeof(struct DATA_STRUCT));
data->values = (uint64_t*) calloc(capacity, sizeof(uint64_t)); data->values = (VALUE_TYPE*) calloc(capacity, sizeof(VALUE_TYPE));
if (!data->values) if (!data->values)
{ {
return FALSE; return FALSE;
@ -177,7 +101,7 @@ static INLINE bool_t alloc_data(struct _hash_set_data *const data, const size_t
return TRUE; return TRUE;
} }
static INLINE void free_data(struct _hash_set_data *const data) static INLINE void free_data(struct DATA_STRUCT *const data)
{ {
if (data) if (data)
{ {
@ -188,32 +112,13 @@ static INLINE void free_data(struct _hash_set_data *const data)
} }
} }
/* ------------------------------------------------- */
/* Flags */
/* ------------------------------------------------- */
static INLINE bool_t get_flag(const uint8_t *const flags, const size_t index)
{
return (flags[index / 8U] >> (index % 8U)) & UINT8_C(1);
}
static INLINE void set_flag(uint8_t *const flags, const size_t index)
{
flags[index / 8U] |= UINT8_C(1) << (index % 8U);
}
static INLINE void clear_flag(uint8_t *const flags, const size_t index)
{
flags[index / 8U] &= ~(UINT8_C(1) << (index % 8U));
}
/* ------------------------------------------------- */ /* ------------------------------------------------- */
/* Set functions */ /* Set functions */
/* ------------------------------------------------- */ /* ------------------------------------------------- */
#define INDEX(X) ((size_t)((X) % data->capacity)) #define INDEX(X) ((size_t)((X) % data->capacity))
static INLINE bool_t find_slot(const struct _hash_set_data *const data, const uint64_t value, size_t *const index_out, bool_t *const reused_out) static INLINE bool_t find_slot(const struct DATA_STRUCT *const data, const VALUE_TYPE value, size_t *const index_out, bool_t *const reused_out)
{ {
uint64_t loop = 0U; uint64_t loop = 0U;
bool_t is_saved = FALSE; bool_t is_saved = FALSE;
@ -250,7 +155,7 @@ static INLINE bool_t find_slot(const struct _hash_set_data *const data, const ui
return FALSE; return FALSE;
} }
static INLINE void put_value(struct _hash_set_data *const data, const size_t index, const uint64_t value, const bool_t reusing) static INLINE void put_value(struct DATA_STRUCT *const data, const size_t index, const VALUE_TYPE value, const bool_t reusing)
{ {
data->values[index] = value; data->values[index] = value;
if (reusing) if (reusing)
@ -277,9 +182,9 @@ static size_t INLINE compute_limit(const size_t capacity, const double load_fact
return limit; return limit;
} }
static INLINE errno_t rebuild_set(hash_set_t *const instance, const size_t new_capacity) static INLINE errno_t rebuild_set(SET_TYPE *const instance, const size_t new_capacity)
{ {
struct _hash_set_data temp; struct DATA_STRUCT temp;
size_t index, k; size_t index, k;
if (new_capacity < instance->valid) if (new_capacity < instance->valid)
@ -296,7 +201,7 @@ static INLINE errno_t rebuild_set(hash_set_t *const instance, const size_t new_c
{ {
if (IS_VALID(instance->data, k)) if (IS_VALID(instance->data, k))
{ {
const uint64_t value = instance->data.values[k]; const VALUE_TYPE value = instance->data.values[k];
if (find_slot(&temp, value, &index, NULL)) if (find_slot(&temp, value, &index, NULL))
{ {
free_data(&temp); free_data(&temp);
@ -318,9 +223,9 @@ static INLINE errno_t rebuild_set(hash_set_t *const instance, const size_t new_c
/* PUBLIC FUNCTIONS */ /* PUBLIC FUNCTIONS */
/* ========================================================================= */ /* ========================================================================= */
hash_set_t *hash_set_create(const size_t initial_capacity, const double load_factor) SET_TYPE* MAKE_NAME(hash_set_create)(const size_t initial_capacity, const double load_factor)
{ {
hash_set_t *instance = (hash_set_t*) calloc(1U, sizeof(hash_set_t)); SET_TYPE* instance = (SET_TYPE*) calloc(1U, sizeof(SET_TYPE));
if (!instance) if (!instance)
{ {
return NULL; return NULL;
@ -338,17 +243,17 @@ hash_set_t *hash_set_create(const size_t initial_capacity, const double load_fac
return instance; return instance;
} }
void hash_set_destroy(hash_set_t *instance) void MAKE_NAME(hash_set_destroy)(SET_TYPE *instance)
{ {
if (instance) if (instance)
{ {
free_data(&instance->data); free_data(&instance->data);
zero_memory(instance, 1U, sizeof(hash_set_t)); zero_memory(instance, 1U, sizeof(SET_TYPE));
SAFE_FREE(instance); SAFE_FREE(instance);
} }
} }
errno_t hash_set_insert(hash_set_t *const instance, const uint64_t value) errno_t MAKE_NAME(hash_set_insert)(SET_TYPE *const instance, const VALUE_TYPE value)
{ {
size_t index; size_t index;
bool_t slot_reused; bool_t slot_reused;
@ -387,7 +292,7 @@ errno_t hash_set_insert(hash_set_t *const instance, const uint64_t value)
return 0; return 0;
} }
errno_t hash_set_contains(const hash_set_t *const instance, const uint64_t value) errno_t MAKE_NAME(hash_set_contains)(const SET_TYPE *const instance, const VALUE_TYPE value)
{ {
if ((!instance) || (!instance->data.values)) if ((!instance) || (!instance->data.values))
{ {
@ -397,7 +302,7 @@ errno_t hash_set_contains(const hash_set_t *const instance, const uint64_t value
return (instance->valid && find_slot(&instance->data, value, NULL, NULL)) ? 0 : ENOENT; return (instance->valid && find_slot(&instance->data, value, NULL, NULL)) ? 0 : ENOENT;
} }
errno_t hash_set_remove(hash_set_t *const instance, const uint64_t value) errno_t MAKE_NAME(hash_set_remove)(SET_TYPE *const instance, const VALUE_TYPE value)
{ {
size_t index; size_t index;
@ -417,13 +322,13 @@ errno_t hash_set_remove(hash_set_t *const instance, const uint64_t value)
if (!instance->valid) if (!instance->valid)
{ {
return hash_set_clear(instance); return MAKE_NAME(hash_set_clear)(instance);
} }
if (instance->deleted > (instance->limit / 2U)) if (instance->deleted > (instance->limit / 2U))
{ {
const size_t min_capacity = next_pow2(round_sz(safe_incr(instance->valid) / instance->load_factor)); const size_t min_capacity = next_pow2(round_sz(safe_incr(instance->valid) / instance->load_factor));
const errno_t error = rebuild_set(instance, (instance->data.capacity > min_capacity) ? min_capacity : instance->data.capacity); const errno_t error = rebuild_set(instance, (instance->data.capacity > min_capacity) ? min_capacity : instance->data.capacity);
if (error && (error != ENOMEM)) if (error && (error != ENOMEM))
{ {
return error; return error;
@ -433,7 +338,7 @@ errno_t hash_set_remove(hash_set_t *const instance, const uint64_t value)
return 0; return 0;
} }
errno_t hash_set_clear(hash_set_t *const instance) errno_t MAKE_NAME(hash_set_clear)(SET_TYPE *const instance)
{ {
if ((!instance) || (!instance->data.values)) if ((!instance) || (!instance->data.values))
{ {
@ -444,7 +349,7 @@ errno_t hash_set_clear(hash_set_t *const instance)
{ {
const size_t count = div_ceil(instance->data.capacity, 8U); const size_t count = div_ceil(instance->data.capacity, 8U);
instance->valid = instance->deleted = 0U; instance->valid = instance->deleted = 0U;
zero_memory(instance->data.used, count, sizeof(uint8_t)); zero_memory(instance->data.used, count, sizeof(uint8_t));
zero_memory(instance->data.deleted, count, sizeof(uint8_t)); zero_memory(instance->data.deleted, count, sizeof(uint8_t));
} }
else else
@ -464,7 +369,7 @@ errno_t hash_set_clear(hash_set_t *const instance)
return 0; return 0;
} }
errno_t hash_set_iterate(const hash_set_t *const instance, uintptr_t *const cursor, uint64_t *const value) errno_t MAKE_NAME(hash_set_iterate)(const SET_TYPE *const instance, uintptr_t *const cursor, VALUE_TYPE *const value)
{ {
size_t index; size_t index;
@ -490,12 +395,12 @@ errno_t hash_set_iterate(const hash_set_t *const instance, uintptr_t *const curs
return ENOENT; return ENOENT;
} }
size_t hash_set_size(const hash_set_t *const instance) size_t MAKE_NAME(hash_set_size)(const SET_TYPE *const instance)
{ {
return instance ? instance->valid : 0U; return instance ? instance->valid : 0U;
} }
errno_t hash_set_info(const hash_set_t *const instance, size_t *const capacity, size_t *const valid, size_t *const deleted, size_t *const limit) errno_t MAKE_NAME(hash_set_info)(const SET_TYPE *const instance, size_t *const capacity, size_t *const valid, size_t *const deleted, size_t *const limit)
{ {
if ((!instance) || (!instance->data.values)) if ((!instance) || (!instance->data.values))
{ {

View File

@ -0,0 +1,13 @@
/******************************************************************************/
/* HashSet for C99, by LoRd_MuldeR <MuldeR2@GMX.de> */
/* This work has been released under the CC0 1.0 Universal license! */
/******************************************************************************/
#include <hash_set.h>
#include "common.h"
#define NAME_SUFFIX 32
#define SET_TYPE hash_set32_t
#define VALUE_TYPE uint32_t
#include "generic.h"

View File

@ -0,0 +1,13 @@
/******************************************************************************/
/* HashSet for C99, by LoRd_MuldeR <MuldeR2@GMX.de> */
/* This work has been released under the CC0 1.0 Universal license! */
/******************************************************************************/
#include <hash_set.h>
#include "common.h"
#define NAME_SUFFIX 64
#define SET_TYPE hash_set64_t
#define VALUE_TYPE uint64_t
#include "generic.h"

13
libhashset/src/version.c Normal file
View File

@ -0,0 +1,13 @@
/******************************************************************************/
/* HashSet for C99, by LoRd_MuldeR <MuldeR2@GMX.de> */
/* This work has been released under the CC0 1.0 Universal license! */
/******************************************************************************/
#include <hash_set.h>
const uint16_t HASHSET_VERSION_MAJOR = UINT16_C(1);
const uint16_t HASHSET_VERSION_MINOR = UINT16_C(1);
const uint16_t HASHSET_VERSION_PATCH = UINT16_C(0);
const char* const HASHSET_BUILD_DATE = __DATE__;
const char* const HASHSET_BUILD_TIME = __TIME__;