Skip to content

Commit

Permalink
♻️ (controller): Now allowing multiple implementations, added a root …
Browse files Browse the repository at this point in the history
…controlller
  • Loading branch information
theobori committed Aug 31, 2024
1 parent 42f60e0 commit 3e38fc6
Show file tree
Hide file tree
Showing 24 changed files with 587 additions and 405 deletions.
56 changes: 37 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
# Simple C hashmap
# C hashmap implementations

[![build](https://github.com/theobori/tinyhash/actions/workflows/build.yml/badge.svg)](https://github.com/theobori/tinyhash/actions/workflows/build.yml)

This is an implementation of the C hashmap that manages collisions using the ‘Separate chaining’ concept. The public API is deliberately simple and user-friendly.
This is a library containing multiple C implementations of hashmap. The public API is deliberately simple and user-friendly.

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

## 📖 Build and run

Expand Down Expand Up @@ -48,45 +51,37 @@ make test

Here is a basic example of how you could use the hashmap.

### With the root controller (high level)
```c
#include <stdint.h>
#include <stdio.h>
#include <string.h>

#include <tinyhash/table.h>
#include <tinyhash/tinyhash.h>

typedef struct {
char name[10];
bool is_hydrated;
} Person;

uint32_t custom_hash_function(uint8_t *bytes, size_t size)
{
return 123456;
}

int main(int argc, const char* argv[])
{
th_table_t table;
bool success;

Person person = { "James", true };

// Initialize the table
th_table_init(&table);
// Create a controller with the separate chaining method
th_t th = th_create(TH_SEPARATE_CHAINING);

// Insert a new key value pair
success = th_table_put(&table, "key_1", strlen("key_1"), &person);
success = th_put(&th, "key_1", strlen("key_1"), &person);
if (success == false) {
fprintf(stderr, "Unable to insert\n");
return 1;
}

// Get the last inserted value
Person *james;
james = th_table_get(&table, "key_1", strlen("key_1"));

success = james != NULL;
james = th_get(&th, "key_1", strlen("key_1"));
if (success == false) {
fprintf(stderr, "It does not exist\n");
return 1;
Expand All @@ -95,21 +90,44 @@ int main(int argc, const char* argv[])
printf("name -> %s, is_hydrated -> %d\n", james->name, james->is_hydrated);

// Delete the entry
success = th_table_delete(&table, "key_1", strlen("key_1"));
success = th_delete(&th, "key_1", strlen("key_1"));
if (success == false) {
fprintf(stderr, "Unable to delete\n");
return 1;
}

// Verify that it doesnt exist anymore
james = th_table_get(&table, "key_1", strlen("key_1"));
james = th_get(&th, "key_1", strlen("key_1"));
if (james != NULL) {
fprintf(stderr, "The entry still exists\n");
return 1;
}

// Free the allocated memory
th_table_free(&table);
th_free(&th);

return 0;
}
```
### Without the root controller (lower level)
This is exactly the same logic as using the root controller, although the prefix of functions and types will change.
For example, to use the ‘separate chaining’ method, the prefix will be `th_sc_table`.
```c
#include <string.h>
#include <tinyhash/separate_chaining/table.h>
int main(int argc, const char* argv[])
{
th_sc_table_t table;
th_sc_table_init(&table);
th_sc_table_put(&table, "hello", strlen("hello"), (th_any_t) 0);
// etc..
return 0;
}
Expand Down
29 changes: 14 additions & 15 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,23 @@ else ()
set (TINYHASH_LIB_TYPE SHARED)
endif ()

set (
TINYHASH_SRC
hash.c
entry.c
table.c
key.c
)
add_subdirectory(common)
add_subdirectory(separate_chaining)

set (
TINYHASH_HEADERS
entry.h
table.h
hash.h
types.h
key.h
set (TINYHASH_SRC
tinyhash.c
)

add_library (${TINYHASH_NAME} ${TINYHASH_LIB_TYPE} ${TINYHASH_SRC})
set (TINYHASH_HEADERS
tinyhash.h
)

add_library(
${TINYHASH_NAME} ${TINYHASH_LIB_TYPE}
${TINYHASH_SRC}
$<TARGET_OBJECTS:common_objects>
$<TARGET_OBJECTS:separate_chaining_objects>
)
install (TARGETS ${TINYHASH_NAME} DESTINATION lib)

install (FILES ${TINYHASH_HEADERS} DESTINATION include/${TINYHASH_NAME})
17 changes: 17 additions & 0 deletions src/common/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
set(COMMON_SRC
hash.c
key.c
)

set(COMMON_HEADERS
hash.h
key.h
types.h
)

add_library(common_objects OBJECT ${COMMON_SRC})

install(
FILES ${COMMON_HEADERS}
DESTINATION include/${TINYHASH_NAME}/common
)
File renamed without changes.
File renamed without changes.
2 changes: 1 addition & 1 deletion src/key.c → src/common/key.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
#include "key.h"
#include "hash.h"

th_key_t th_key_new(th_any_t data, size_t size)
th_key_t th_key_create(th_any_t data, size_t size)
{
return (th_key_t) {
.hash = th_hash(data, size),
Expand Down
4 changes: 2 additions & 2 deletions src/key.h → src/common/key.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@

typedef struct {
uint32_t hash;
int size;
size_t size;
th_any_t data;
} th_key_t;

th_key_t th_key_new(th_any_t data, size_t size);
th_key_t th_key_create(th_any_t data, size_t size);

bool th_key_is_equal(th_key_t *first, th_key_t *second);

Expand Down
2 changes: 2 additions & 0 deletions src/types.h → src/common/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,6 @@

typedef void *th_any_t;

typedef void *th_generic_table_t;

#endif
36 changes: 0 additions & 36 deletions src/entry.c

This file was deleted.

21 changes: 0 additions & 21 deletions src/entry.h

This file was deleted.

16 changes: 16 additions & 0 deletions src/separate_chaining/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
set(SEPARATE_CHAINING_SRC
entry.c
table.c
)

set(SEPARATE_CHAINING_HEADERS
entry.h
table.h
)

add_library(separate_chaining_objects OBJECT ${SEPARATE_CHAINING_SRC})

install(
FILES ${SEPARATE_CHAINING_HEADERS}
DESTINATION include/${TINYHASH_NAME}/separate_chaining
)
36 changes: 36 additions & 0 deletions src/separate_chaining/entry.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#include "entry.h"

static th_sc_entry_t *th_sc_entry_new(th_key_t *key, th_any_t value)
{
th_sc_entry_t *entry = malloc(sizeof(th_sc_entry_t));

if (entry == NULL) return NULL;

entry->key = *key;
entry->value = value;
entry->previous = NULL;
entry->next = NULL;

return entry;
}

static void th_sc_entry_raw_add(th_sc_entry_t **root, th_sc_entry_t *entry)
{
if (*root != NULL) {
(*root)->previous = entry;
}

entry->next = *root;
*root = entry;
}

bool th_sc_entry_add(th_sc_entry_t **root, th_key_t *key, th_any_t value)
{
th_sc_entry_t *entry = th_sc_entry_new(key, value);

if (entry == NULL) return false;

th_sc_entry_raw_add(root, entry);

return true;
}
21 changes: 21 additions & 0 deletions src/separate_chaining/entry.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#ifndef __TINYHASH_SC_ENTRY_H__
#define __TINYHASH_SC_ENTRY_H__

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

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

typedef struct th_sc_entry_s {
th_key_t key;
th_any_t value;
struct th_sc_entry_s *previous;
struct th_sc_entry_s *next;
} th_sc_entry_t;


bool th_sc_entry_add(th_sc_entry_t **root, th_key_t *key, th_any_t value);

#endif
Loading

0 comments on commit 3e38fc6

Please sign in to comment.