Skip to content

Commit

Permalink
✨ (iterator): Added a hashamp iterator and the th_len function
Browse files Browse the repository at this point in the history
  • Loading branch information
theobori committed Sep 5, 2024
1 parent c20b2c7 commit eeedacb
Show file tree
Hide file tree
Showing 14 changed files with 391 additions and 15 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,4 @@ build
result
/debug.c
a.py
.vscode
38 changes: 31 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,8 @@ The Makefile `all` target will automatically build the documentation.
Here is a basic example of how you could use the hashmap.

### With the root controller (high level)

```c
#include "src/tinyhash.h"
#include <stdint.h>
#include <stdio.h>
#include <string.h>
Expand All @@ -71,11 +71,11 @@ Here is a basic example of how you could use the hashmap.
typedef struct {
char name[10];
bool is_hydrated;
} Person;
} person_t;

int main(int argc, const char *argv[]) {
bool success;
Person person = {"James", true};
person_t person = {"James", true};

// Create a controller with the open addressing method
th_t th = th_create(TH_OPEN_ADRESSING);
Expand All @@ -88,16 +88,40 @@ int main(int argc, const char *argv[]) {
}

// Get the last inserted value
Person *james;
person_t *james;
james = th_get(&th, "key_1", strlen("key_1"));
if (success == false) {
fprintf(stderr, "It does not exist\n");
return 1;
}

printf("name -> %s, is_hydrated -> %d\n", james->name, james->is_hydrated);
printf("name -> %s, is_hydrated -> %d, hashmap length -> %d\n", james->name,
james->is_hydrated, th_len(&th));

// Quick multiple insert with the same value (not important here)
th_put(&th, "key_2", strlen("key_2"), &person);
th_put(&th, "key_3", strlen("key_3"), &person);
th_put(&th, "key_4", strlen("key_4"), &person);

printf("hashmap length -> %d\n", th_len(&th));

th_iterator_t *it;
person_t *p;

// Iterate with a for loop
for (it = th_begin_iterator(&th); it != NULL; th_iterator_next(&it)) {
p = it->value;
printf("[for] key -> %s, name -> %s\n", it->key->data, p->name);
}

// Iterate with a while loop
it = th_empty_iterator(&th);
while (th_iterator_next(&it) == true) {
p = it->value;
printf("[while] key -> %s, name -> %s\n", it->key->data, p->name);
}

// Delete the entry
// Delete an entry
success = th_delete(&th, "key_1", strlen("key_1"));
if (success == false) {
fprintf(stderr, "Unable to delete\n");
Expand All @@ -122,7 +146,7 @@ int main(int argc, const char *argv[]) {
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`.
For example, to use the ‘separate chaining’ method, the prefix will be `th_sc_table`.f
```c
#include <string.h>
Expand Down
2 changes: 2 additions & 0 deletions src/common/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
set(COMMON_SRC
hash.c
key.c
iterator.c
)

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

add_library(common_objects OBJECT ${COMMON_SRC})
Expand Down
49 changes: 49 additions & 0 deletions src/common/iterator.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#include <stdlib.h>

#include "iterator.h"

static void th_iterator_init(th_iterator_t *it,
th_generic_table_t generic_table,
th_iterator_next_func_t next) {
it->index = 0;
it->key = NULL;
it->current = NULL;
it->value = NULL;
it->generic_table = generic_table;
it->next = next;
}

th_iterator_t *th_iterator_create(th_generic_table_t generic_table,
th_iterator_next_func_t next) {
th_iterator_t *it = malloc(sizeof(th_iterator_t));

if (it == NULL) {
return NULL;
}

th_iterator_init(it, generic_table, next);

return it;
}

void th_iterator_free(th_iterator_t *it) {
th_iterator_init(it, NULL, NULL);

free(it);
}

bool th_iterator_next(th_iterator_t **ptr) {
th_iterator_t *it = *ptr;

if (it->next == NULL) {
return false;
}

bool ret = it->next(ptr);

if (ret == false) {
th_iterator_free(it);
}

return ret;
}
53 changes: 53 additions & 0 deletions src/common/iterator.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#ifndef __TINYHASH_COMMON_ITERATOR_H__
#define __TINYHASH_COMMON_ITERATOR_H__

#include "key.h"
#include "types.h"

/**
* @brief Represents an iterator that allow to iterate over a generic table.
*
*/
typedef struct th_iterator_s {
int index;
th_any_t current;
th_key_t *key;
th_any_t value;
th_generic_table_t generic_table;
bool (*next)(struct th_iterator_s **);
} th_iterator_t;

/**
* @brief Pointer on function that get the next element.
*
*/
typedef bool (*th_iterator_next_func_t)(th_iterator_t **);

/**
* @brief Allocate then init a new iterator.
*
* @param generic_table
* @param next
* @return th_iterator_t*
*/
th_iterator_t *th_iterator_create(th_generic_table_t generic_table,
th_iterator_next_func_t next);

/**
* @brief Free an iterator.
*
* @param it
*/
void th_iterator_free(th_iterator_t *it);

/**
* @brief Try to get the next element.
* Free the iterator if it reachs the end.
*
* @param ptr
* @return true
* @return false
*/
bool th_iterator_next(th_iterator_t **ptr);

#endif
54 changes: 54 additions & 0 deletions src/open_addressing/table.c
Original file line number Diff line number Diff line change
Expand Up @@ -235,3 +235,57 @@ void th_oa_table_free(th_generic_table_t generic_table) {

th_oa_table_init(table);
}

/**
* @brief Get the next key value pair if it exists.
*
* @param ptr
* @return true
* @return false
*/
static bool th_oa_iterator_next(th_iterator_t **ptr) {
th_iterator_t *it = *ptr;
th_oa_table_t *table = (th_oa_table_t *)it->generic_table;

it->index++;

th_oa_entry_t *entry;
for (; it->index < table->capacity; it->index++) {
entry = &table->entries[it->index];

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

it->current = entry;
it->key = entry->key;
it->value = entry->value;

return true;
}

*ptr = NULL;

return false;
}

th_iterator_t *th_oa_iterator_begin(th_generic_table_t generic_table,
bool is_begin) {
th_iterator_t *it = th_iterator_create(generic_table, th_oa_iterator_next);

if (it == NULL) {
return NULL;
}

it->index--;

if (is_begin == true) {
th_oa_iterator_next(&it);
}

return it;
}

int th_oa_table_len(th_generic_table_t generic_table) {
return (((th_oa_table_t *)generic_table)->count);
}
22 changes: 22 additions & 0 deletions src/open_addressing/table.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <stdint.h>
#include <stdlib.h>

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

Expand Down Expand Up @@ -80,4 +81,25 @@ 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);

/**
* @brief Return a new iterator.
*
* If `is_begin` is true, it will initialize the iterator with the first
* element. Otherwise, it will be empty.
*
* @param generic_table
* @param is_begin
* @return th_iterator_t*
*/
th_iterator_t *th_oa_iterator_begin(th_generic_table_t generic_table,
bool is_begin);

/**
* @brief Returns the table length.
*
* @param generic_table
* @return int
*/
int th_oa_table_len(th_generic_table_t generic_table);

#endif
63 changes: 63 additions & 0 deletions src/separate_chaining/table.c
Original file line number Diff line number Diff line change
Expand Up @@ -241,3 +241,66 @@ void th_sc_table_free(th_generic_table_t generic_table) {

th_sc_table_init(table);
}

static void th_sc_iterator_copy_entry(th_iterator_t *it, th_sc_entry_t *entry) {
it->current = entry;
it->key = &entry->key;
it->value = entry->value;
}

/**
* @brief Get the next key value pair if it exists.
*
* @param ptr
* @return true
* @return false
*/
static bool th_sc_iterator_next(th_iterator_t **ptr) {
th_iterator_t *it = *ptr;
th_sc_table_t *table = (th_sc_table_t *)it->generic_table;
th_sc_entry_t *current = (th_sc_entry_t *)it->current;

if (current != NULL && current->next != NULL) {
th_sc_iterator_copy_entry(it, current->next);
return true;
}

it->index++;

th_sc_entry_t *entry;
for (; it->index < table->capacity; it->index++) {
entry = table->entries[it->index];

if (entry == NULL) {
continue;
}

th_sc_iterator_copy_entry(it, entry);
return true;
}

*ptr = NULL;

return false;
}

th_iterator_t *th_sc_iterator_begin(th_generic_table_t generic_table,
bool is_begin) {
th_iterator_t *it = th_iterator_create(generic_table, th_sc_iterator_next);

if (it == NULL) {
return NULL;
}

it->index--;

if (is_begin == true) {
th_sc_iterator_next(&it);
}

return it;
}

int th_sc_table_len(th_generic_table_t generic_table) {
return (((th_sc_table_t *)generic_table)->count);
}
22 changes: 22 additions & 0 deletions src/separate_chaining/table.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <stdint.h>
#include <stdlib.h>

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

Expand Down Expand Up @@ -78,4 +79,25 @@ void th_sc_table_free(th_generic_table_t table);
bool th_sc_table_delete(th_generic_table_t table, th_any_t data,
size_t data_size);

/**
* @brief Return a new iterator.
*
* If `is_begin` is true, it will initialize the iterator with the first
* element. Otherwise, it will be empty.
*
* @param generic_table
* @param is_begin
* @return th_iterator_t*
*/
th_iterator_t *th_sc_iterator_begin(th_generic_table_t generic_table,
bool is_begin);

/**
* @brief Returns the table length.
*
* @param generic_table
* @return int
*/
int th_sc_table_len(th_generic_table_t generic_table);

#endif
Loading

0 comments on commit eeedacb

Please sign in to comment.