Skip to content

Commit

Permalink
✨ (method): Implemented open addressing
Browse files Browse the repository at this point in the history
  • Loading branch information
theobori committed Aug 31, 2024
1 parent 3e38fc6 commit 59ff3b0
Show file tree
Hide file tree
Showing 17 changed files with 360 additions and 69 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ This is a library containing multiple C implementations of hashmap. The public A

Here are the different methods implemented:
- [Separate chaining](./src/separate_chaining/)
- [Open addressing](./src/open_addressing/)

## 📖 Build and run

Expand Down
4 changes: 3 additions & 1 deletion src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ endif ()

add_subdirectory(common)
add_subdirectory(separate_chaining)
add_subdirectory(open_addressing)

set (TINYHASH_SRC
tinyhash.c
Expand All @@ -24,7 +25,8 @@ add_library(
${TINYHASH_SRC}
$<TARGET_OBJECTS:common_objects>
$<TARGET_OBJECTS:separate_chaining_objects>
$<TARGET_OBJECTS:open_addressing_objects>
)
install (TARGETS ${TINYHASH_NAME} DESTINATION lib)

install (TARGETS ${TINYHASH_NAME} DESTINATION lib)
install (FILES ${TINYHASH_HEADERS} DESTINATION include/${TINYHASH_NAME})
1 change: 1 addition & 0 deletions src/common/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ set(COMMON_HEADERS
hash.h
key.h
types.h
table.h
)

add_library(common_objects OBJECT ${COMMON_SRC})
Expand Down
4 changes: 2 additions & 2 deletions src/common/hash.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#ifndef __TINYHASH_HASH_H__
#define __TINYHASH_HASH_H__
#ifndef __TINYHASH_COMMON_HASH_H__
#define __TINYHASH_COMMON_HASH_H__

#include <stdint.h>
#include <stdio.h>
Expand Down
4 changes: 2 additions & 2 deletions src/common/key.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#ifndef __TINYHASH_KEY_H__
#define __TINYHASH_KEY_H__
#ifndef __TINYHASH_COMMON_KEY_H__
#define __TINYHASH_COMMON_KEY_H__

#include <stdint.h>
#include <stdio.h>
Expand Down
7 changes: 7 additions & 0 deletions src/common/table.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#ifndef __TINYHASH_COMMON_TABLE_H__
#define __TINYHASH_COMMON_TABLE_H__

#define TH_TABLE_NEXT_CAPACITY(capacity) \
(capacity) == 0 ? 8 : (capacity) * 2

#endif
4 changes: 2 additions & 2 deletions src/common/types.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#ifndef __TINYHASH_TYPES_H__
#define __TINYHASH_TYPES_H__
#ifndef __TINYHASH_COMMON_TYPES_H__
#define __TINYHASH_COMMON_TYPES_H__

typedef void *th_any_t;

Expand Down
15 changes: 15 additions & 0 deletions src/open_addressing/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
set(OPEN_ADDRESSING_SRC
table.c
)

set(OPEN_ADDRESSING_HEADERS
entry.h
table.h
)

add_library(open_addressing_objects OBJECT ${OPEN_ADDRESSING_SRC})

install(
FILES ${OPEN_ADDRESSING_HEADERS}
DESTINATION include/${TINYHASH_NAME}/open_addressing
)
17 changes: 17 additions & 0 deletions src/open_addressing/entry.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#ifndef __TINYHASH_OA_ENTRY_H__
#define __TINYHASH_OA_ENTRY_H__

#include <stdint.h>
#include <stdlib.h>
#include <stdbool.h>

#include "../common/hash.h"
#include "../common/key.h"

typedef struct th_oa_entry_s {
th_key_t *key;
th_any_t value;
bool is_tombstone;
} th_oa_entry_t;

#endif
184 changes: 184 additions & 0 deletions src/open_addressing/table.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "table.h"
#include "../common/table.h"
#include "entry.h"

static bool th_oa_table_put_with_key(th_oa_table_t *table, th_key_t *key,
th_any_t value);

void th_oa_table_init(th_oa_table_t *table)
{
table->capacity = 0;
table->count = 0;
table->entries = NULL;
}

static th_oa_table_t *_th_oa_table_create()
{
th_oa_table_t *table = malloc(sizeof(th_oa_table_t));

if (table == NULL) return NULL;

th_oa_table_init(table);

return table;
}

th_generic_table_t th_oa_table_create()
{
return (th_generic_table_t) _th_oa_table_create();
}

static bool th_oa_table_copy(th_oa_table_t *dest, th_oa_table_t *src)
{
bool success;

for (int i = 0; i < src->capacity; i++) {
th_oa_entry_t *entry = &src->entries[i];

if (entry->key == NULL) continue;

success = th_oa_table_put_with_key(
dest,
entry->key,
entry->value
);

if (success == false) return false;
}

return true;
}

static bool th_oa_table_increase(th_oa_table_t *table)
{
th_oa_table_t new_table;
bool success;

th_oa_table_init(&new_table);

new_table.capacity = TH_TABLE_NEXT_CAPACITY(table->capacity);

size_t size = sizeof(th_oa_entry_t) * new_table.capacity;

new_table.entries = malloc(size);
if (new_table.entries == NULL) return false;

memset(new_table.entries, 0, size);

success = th_oa_table_copy(&new_table, table);
if (success == false) return false;

th_oa_table_free(table);

*table = new_table;

return true;
}

static th_oa_entry_t *th_oa_table_find(th_oa_table_t *table, th_key_t *key)
{
int index = key->hash % table->capacity;

th_oa_entry_t *tombstone = NULL;
for (;;) {
th_oa_entry_t *entry = &table->entries[index];

if (entry->key == NULL) {
if (entry->is_tombstone == false) {
return tombstone != NULL ? tombstone : entry;
} else {
if (tombstone == NULL) tombstone = entry;
}
} else if (th_key_is_equal(key, entry->key) == true) {
return entry;
}

index = (index + 1) % table->capacity;
}
}

th_any_t th_oa_table_get(th_generic_table_t generic_table, th_any_t data,
size_t data_size)
{
th_oa_table_t *table = (th_oa_table_t *) generic_table;
if (table->capacity == 0) return NULL;

th_key_t key = th_key_create(data, data_size);
th_oa_entry_t *entry = th_oa_table_find(table, &key);
if (entry->key == NULL) return NULL;

return entry->value;
}

static bool th_oa_table_put_with_key(th_oa_table_t *table, th_key_t *key,
th_any_t value)
{
if (table->count >= (table->capacity * TH_OA_LOAD_FACTOR)) {
if (th_oa_table_increase(table) == false) return false;
}

th_oa_entry_t *entry = th_oa_table_find(table, key);

if (entry->key == NULL) {
if (entry->is_tombstone == false) table->count++;
} else {
free(entry->key);
}

entry->key = malloc(sizeof(th_key_t));
*entry->key = *key;
entry->value = value;
entry->is_tombstone = false;

return true;
}

bool th_oa_table_put(th_generic_table_t generic_table, th_any_t data,
size_t data_size, th_any_t value)
{
th_oa_table_t *table = (th_oa_table_t *) generic_table;
th_key_t key = th_key_create(data, data_size);

return th_oa_table_put_with_key(table, &key, value);
}

bool th_oa_table_delete(th_generic_table_t generic_table, th_any_t data,
size_t data_size)
{
th_oa_table_t *table = (th_oa_table_t *) generic_table;
if (table->capacity == 0) return false;

th_key_t key = th_key_create(data, data_size);

th_oa_entry_t *entry = th_oa_table_find(table, &key);
if (entry->key == NULL) return false;

entry->is_tombstone = true;

free(entry->key);
entry->key = NULL;

return true;
}

void th_oa_table_free(th_generic_table_t generic_table)
{
th_oa_table_t *table = (th_oa_table_t *) generic_table;

for (int i = 0; i < table->capacity; i++) {
th_oa_entry_t *entry = &table->entries[i];

if (entry->key == NULL) continue;

free(entry->key);
}

if (table->entries != NULL) {
free(table->entries);
}
}
36 changes: 36 additions & 0 deletions src/open_addressing/table.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#ifndef __TINYHASH_OA_TABLE_H__
#define __TINYHASH_OA_TABLE_H__

#include <stdint.h>
#include <stdlib.h>
#include <stdbool.h>

#include "entry.h"
#include "../common/types.h"

#define TH_OA_LOAD_FACTOR 0.75

typedef struct {
uint32_t count;
uint32_t capacity;
th_oa_entry_t *entries;
} th_oa_table_t;

void th_oa_table_init(th_oa_table_t *table);

th_generic_table_t th_oa_table_create();

th_any_t th_oa_table_get(th_generic_table_t table, th_any_t data,
size_t data_size);

bool th_oa_table_put(th_generic_table_t table, th_any_t data,
size_t data_size, th_any_t value);

void th_oa_table_free(th_generic_table_t table);

bool th_oa_table_delete(th_generic_table_t table, th_any_t data,
size_t data_size);

void th_oa_table_debug(th_generic_table_t generic_table);

#endif
50 changes: 29 additions & 21 deletions src/separate_chaining/table.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <string.h>

#include "table.h"
#include "../common/table.h"

static bool th_sc_table_put_with_key(th_sc_table_t *table, th_key_t *key,
th_any_t value);
Expand Down Expand Up @@ -31,31 +32,16 @@ th_generic_table_t th_sc_table_create()
return (th_generic_table_t) _th_sc_table_create();
}

static bool th_sc_table_increase(th_sc_table_t *table)
static bool th_sc_table_copy(th_sc_table_t *dest, th_sc_table_t *src)
{
th_sc_table_t new_table;

th_sc_table_init(&new_table);
bool success;

// New capacity
new_table.capacity = TH_SC_TABLE_NEXT_CAPACITY(table->capacity);

// New entry array bytes size
size_t size = sizeof(th_sc_entry_t *) * new_table.capacity;

new_table.entries = (th_sc_entry_t **) malloc(size);
if (new_table.entries == NULL) return false;

memset(new_table.entries, 0, size);

// Re-compute the new index
for (int i = 0; i < table->capacity; i++) {
bool success;
th_sc_entry_t *entry = table->entries[i];
for (int i = 0; i < src->capacity; i++) {
th_sc_entry_t *entry = src->entries[i];

while (entry != NULL) {
success = th_sc_table_put_with_key(
&new_table,
dest,
&entry->key,
entry->value
);
Expand All @@ -66,7 +52,29 @@ static bool th_sc_table_increase(th_sc_table_t *table)
}
}

// Destroy the old table
return true;
}


static bool th_sc_table_increase(th_sc_table_t *table)
{
th_sc_table_t new_table;
bool success;

th_sc_table_init(&new_table);

new_table.capacity = TH_TABLE_NEXT_CAPACITY(table->capacity);

size_t size = sizeof(th_sc_entry_t *) * new_table.capacity;
new_table.entries = malloc(size);

if (new_table.entries == NULL) return false;

memset(new_table.entries, 0, size);

success = th_sc_table_copy(&new_table, table);
if (success == false) return false;

th_sc_table_free((th_generic_table_t) table);

*table = new_table;
Expand Down
Loading

0 comments on commit 59ff3b0

Please sign in to comment.