From 2d7cbf9c1f1f9b5eb232191e3e44ecc9c184fb15 Mon Sep 17 00:00:00 2001 From: nakira974 Date: Mon, 26 Feb 2024 23:08:38 +0100 Subject: [PATCH 01/27] Add hash_set.h API --- headers/hash_set.h | 35 ++++++++++++++++++++++++++++ headers/set.h | 3 +++ src/set.c | 58 +++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 95 insertions(+), 1 deletion(-) create mode 100644 headers/hash_set.h diff --git a/headers/hash_set.h b/headers/hash_set.h new file mode 100644 index 0000000..2ffb4e0 --- /dev/null +++ b/headers/hash_set.h @@ -0,0 +1,35 @@ +/** + * @file set.h + * @brief This file contains the API for generic Set covering + * @author Maxime Loukhal + * @date 23/02/2024 + */ +#ifndef COLLECTIONS_COMMONS_HASH_SET_H +#define COLLECTIONS_COMMONS_HASH_SET_H +#include "set.h" + + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Data structure for a set identify by a generic key + */ +typedef struct HashSet{ + void *key; + Set set; +}HashSet; + +/** + * @brief Determine of elements to match are covering ALL elements + * @param elements Elements to be covered + * @param elements_to_match Sub sets to determine if they can cover ALL elements + * @param matched_elements Shortest list of elements that match ALL elements + * @return True if elements to match are covering ALL elements, false otherwise + */ +bool set_match_exact(Set *elements, Set* elements_to_match, Set * matched_elements); +#ifdef __cplusplus +} +#endif +#endif //COLLECTIONS_COMMONS_HASH_SET_H diff --git a/headers/set.h b/headers/set.h index dff68ec..7c1099f 100644 --- a/headers/set.h +++ b/headers/set.h @@ -13,6 +13,9 @@ extern "C" { #endif + /** + * @brief Data structure definition for a generic dataset + */ typedef LinkedList Set; /** diff --git a/src/set.c b/src/set.c index 7005d83..e855f67 100644 --- a/src/set.c +++ b/src/set.c @@ -2,8 +2,64 @@ // Created by maxim on 23/02/2024. // -#include "set.h" +#include +#include "hash_set.h" + + +bool set_match_exact(Set *elements, Set* elements_to_match, Set * matched_elements){ + Set intersection; + HashSet *hashSet; + LinkedElement *current_element,*element_max; + void * value; + uint32_t max_size; + + // Initialize the set cover + set_create(matched_elements, elements_to_match->match, NULL); + + // Continue until there are non-covering elements and candidates + + while(set_size(elements) > 0 && set_size(elements_to_match) > 0){ + // Search of the candidate covering the most elements as possible + max_size = 0; + + for(current_element= list_first(elements_to_match);current_element != NULL; current_element = list_next(current_element)){ + if(!set_intersection(&intersection, &((HashSet * ) list_value(current_element))->set, elements)) return false; + + if(set_size(&intersection) > max_size){ + element_max = current_element; + max_size = set_size(&intersection); + } + + set_destroy(&intersection); + } + } + + // A covering isn't possible if there's no intersection + + if(max_size == 0) return false; + + // Insert inside the covering the selected hashset + hashSet = (HashSet *) list_value(element_max); + + if(!set_add(matched_elements, hashSet)) return false; + + // Remove each current_element covered from the uncovered-elements set + for(current_element = list_first(&((HashSet*) list_value(element_max))->set); current_element != NULL; current_element= list_next(current_element)){ + value = list_value(current_element); + + if(set_remove(elements, (void**)&value) && elements->destroy != NULL) elements->destroy(value); + } + + // Remove the hashset from the hashset candidates + + if(!set_remove(elements_to_match, (void **)&hashSet)) return false; + + // No covering if there's still non-covered elements + if(set_size(elements) > 0) return false; + + return true; +} void set_create(Set *set, int (*match)(const void *left, const void *right), void (*destroy)(void *value)){ list_create(set, destroy); set->match = match; From 7488968de0c73b198a6146dcf414d2b985ab7eeb Mon Sep 17 00:00:00 2001 From: nakira974 Date: Tue, 27 Feb 2024 19:05:53 +0100 Subject: [PATCH 02/27] Add get_random --- headers/chtbl.h | 11 +++++ headers/clist.h | 8 +++ headers/dlist.h | 8 +++ headers/list.h | 8 +++ headers/queue.h | 12 +++++ headers/randomized_set.h | 77 ----------------------------- headers/set.h | 12 +++++ headers/{hash_set.h => set_entry.h} | 18 +++---- src/clist.c | 14 ++++++ src/dlist.c | 15 ++++++ src/list.c | 16 ++++++ src/randomized_set.c | 68 ------------------------- src/set.c | 14 +++--- tests/headers/RandomizedSetTest.h | 2 +- 14 files changed, 121 insertions(+), 162 deletions(-) create mode 100644 headers/chtbl.h delete mode 100644 headers/randomized_set.h rename headers/{hash_set.h => set_entry.h} (54%) delete mode 100644 src/randomized_set.c diff --git a/headers/chtbl.h b/headers/chtbl.h new file mode 100644 index 0000000..d3e6fae --- /dev/null +++ b/headers/chtbl.h @@ -0,0 +1,11 @@ +/** + * @file set.h + * @brief This file contains the API for hashed maps + * @author Maxime Loukhal + * @date 26/02/2024 + */ + +#ifndef COLLECTIONS_COMMONS_CHTBL_H +#define COLLECTIONS_COMMONS_CHTBL_H + +#endif //COLLECTIONS_COMMONS_CHTBL_H diff --git a/headers/clist.h b/headers/clist.h index 5998c83..21cb526 100644 --- a/headers/clist.h +++ b/headers/clist.h @@ -109,6 +109,14 @@ bool clist_add(CLinkedList *list, CLinkedElement *element, const void *value); */ bool clist_remove(CLinkedList *list, CLinkedElement *element, void **value); +/** + * @brief Returns a random element from the given list + * @param list List to return a random element from + * @param random_element Reference to a random element + * @return true if a random element has been returned, false otherwise + */ +bool clist_get_random(CLinkedList *list, CLinkedElement * random_element); + /* ----- MACRO C++ COMPATIBILITY -----*/ #ifdef __cplusplus /*** diff --git a/headers/dlist.h b/headers/dlist.h index 0aa174b..8b00e27 100644 --- a/headers/dlist.h +++ b/headers/dlist.h @@ -127,6 +127,14 @@ bool dlist_add_before(DLinkedList *list, DLinkedElement *element, const void *va */ bool dlist_remove(DLinkedList *list, DLinkedElement *element, void **value); +/** + * @brief Returns a random element from the given list + * @param list List to return a random element from + * @param value Reference to a random element + * @return true if a random element has been returned, false otherwise + */ +bool dlist_get_random(DLinkedList *list, DLinkedElement* value); + /* ----- MACRO C++ COMPATIBILITY -----*/ #ifdef __cplusplus diff --git a/headers/list.h b/headers/list.h index 0c30f5d..eca4ece 100644 --- a/headers/list.h +++ b/headers/list.h @@ -109,6 +109,14 @@ bool list_add(LinkedList *list, LinkedElement *element, const void *value); */ bool list_remove(LinkedList *list, LinkedElement *element, void **value); +/** + * @brief Returns a random element from the given list + * @param list List to return a random element from + * @param random_element Reference to a random element + * @return true if a random element has been returned, false otherwise + */ +bool list_get_random(LinkedList *list, LinkedElement* random_element); + /* ----- MACRO C++ COMPATIBILITY -----*/ #ifdef __cplusplus /** diff --git a/headers/queue.h b/headers/queue.h index 3860746..83d2be7 100644 --- a/headers/queue.h +++ b/headers/queue.h @@ -83,6 +83,13 @@ inline void queue_create(Queue * queue, void( *destroy)(void *value)){ inline void queue_destroy(Queue * queue){ list_destroy(queue); } + +/** + * @brief Inline function that returns a random element from the queue + */ +static inline bool queue_get_random(Queue* queue, LinkedElement *random_element){ + return list_get_random(queue, random_element); +} #else /** @@ -111,6 +118,11 @@ inline void queue_destroy(Queue * queue){ * @complexity O(1) */ #define queue_size list_size + +/** + * @brief Macro that evaluates a random element from the queue and returns it + */ +#define queue_get_random(queue, element) list_get_random #endif diff --git a/headers/randomized_set.h b/headers/randomized_set.h deleted file mode 100644 index 4ccd28c..0000000 --- a/headers/randomized_set.h +++ /dev/null @@ -1,77 +0,0 @@ -// -// Created by maxim on 14/02/2024. - - -#ifndef COLLECTIONS_UTILS_RANDOMIZED_SET_H -#define COLLECTIONS_UTILS_RANDOMIZED_SET_H - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef __cplusplus -#include -#include -#else -#include -#include -#endif - -/** - * Data structure for a randomized set of integers - */ -typedef struct RandomizedSet { - /** - * Array where are stored set values - */ - int *nums; - /** - * Current size of the randomized set - */ - int size; - /** - * Current capacity of the set - */ - int capacity; -} RandomizedSet; - - -/** - * Creates a randomized set with default values - * @param set Randomized set to create - */ -void randomized_set_create(RandomizedSet *set); - -/** - * Insert the value into the set - * @param obj The randomized set to insert value - * @param val The value to be inserted - * @return True if the value is not present, otherwise false - */ -bool randomized_set_add(RandomizedSet *obj, int val); - -/** - * Remove a value from the randomized set - * @param obj The randomized set to remove the value - * @param val The value to be removed - * @return True if the value has been removed, otherwise false - */ -bool randomized_set_remove(RandomizedSet *obj, int val); - -/** - * Return a random element from the set - * @param obj The randomized set to get value on - * @return A random value from the randomized set - */ -int randomized_set_get_random(RandomizedSet *obj); - -/** - * Destroy the target randomized set and clean up memory - * @param obj The randomized set to remove - */ -void randomized_set_destroy(RandomizedSet *obj); - -#ifdef __cplusplus -} -#endif -#endif //COLLECTIONS_UTILS_RANDOMIZED_SET_H \ No newline at end of file diff --git a/headers/set.h b/headers/set.h index 7c1099f..cb40f30 100644 --- a/headers/set.h +++ b/headers/set.h @@ -121,6 +121,13 @@ static inline int set_size(const Set * set){ static inline void set_destroy(Set *set){ list_destroy(set); } + +/** + * @brief Inline function that returns a random element from the set + */ +static inline bool set_get_random(Set* set, LinkedElement *random_element){ + return list_get_random(set, random_element); +} #else /** * @brief Macro that evaluates the size of a given Set @@ -136,6 +143,11 @@ static inline void set_destroy(Set *set){ * @complexity O(n) where n is the number of elements inside the given Set to destroy */ #define set_destroy(set) list_destroy + +/** + * @brief Macro that evaluates a random element from the set and returns it + */ +#define set_get_random(set, element) list_get_random #endif #ifdef __cplusplus diff --git a/headers/hash_set.h b/headers/set_entry.h similarity index 54% rename from headers/hash_set.h rename to headers/set_entry.h index 2ffb4e0..89445c9 100644 --- a/headers/hash_set.h +++ b/headers/set_entry.h @@ -1,11 +1,11 @@ /** * @file set.h - * @brief This file contains the API for generic Set covering + * @brief This file contains the API for key set entries * @author Maxime Loukhal - * @date 23/02/2024 + * @date 26/02/2024 */ -#ifndef COLLECTIONS_COMMONS_HASH_SET_H -#define COLLECTIONS_COMMONS_HASH_SET_H +#ifndef COLLECTIONS_COMMONS_SET_ENTRY_H +#define COLLECTIONS_COMMONS_SET_ENTRY_H #include "set.h" @@ -16,20 +16,20 @@ extern "C" { /** * @brief Data structure for a set identify by a generic key */ -typedef struct HashSet{ +typedef struct KeySetEntry{ void *key; Set set; -}HashSet; +}KeySetEntry; /** - * @brief Determine of elements to match are covering ALL elements + * @brief Determine if sets from elements to match are covering ALL elements, if true return the best solution * @param elements Elements to be covered * @param elements_to_match Sub sets to determine if they can cover ALL elements * @param matched_elements Shortest list of elements that match ALL elements * @return True if elements to match are covering ALL elements, false otherwise */ -bool set_match_exact(Set *elements, Set* elements_to_match, Set * matched_elements); +bool set_match_entries(Set *elements, Set* elements_to_match, Set * matched_elements); #ifdef __cplusplus } #endif -#endif //COLLECTIONS_COMMONS_HASH_SET_H +#endif //COLLECTIONS_COMMONS_SET_ENTRY_H diff --git a/src/clist.c b/src/clist.c index d7800e2..8ba6b4f 100644 --- a/src/clist.c +++ b/src/clist.c @@ -61,3 +61,17 @@ bool clist_remove(CLinkedList *list, CLinkedElement *element, void **value) { list->size--; return true; } + +bool clist_get_random(CLinkedList *list, CLinkedElement * random_element){ + if(clist_size(list) == 0) return false; + int rd_index = rand() % clist_size(list); + int count = 0; + + for(random_element= clist_first(list); random_element= clist_next(random_element)){ + if(rd_index == count){ + break; + } + count++; + } + return true; +} diff --git a/src/dlist.c b/src/dlist.c index 67d886b..8faf549 100644 --- a/src/dlist.c +++ b/src/dlist.c @@ -121,4 +121,19 @@ bool dlist_remove(DLinkedList *list, DLinkedElement *element, void **value) { list->size--; return true; +} + +bool dlist_get_random(DLinkedList *list, DLinkedElement * random_element){ + if(dlist_size(list) == 0) return false; + // Génère un index aléatoire dans la plage des indices valides du tableau. + int rd_index = rand() % dlist_size(list); + int count = 0; + + for(random_element= dlist_first(list);random_element!=NULL; random_element= dlist_next(random_element)){ + if(rd_index == count){ + break; + } + count++; + } + return true; } \ No newline at end of file diff --git a/src/list.c b/src/list.c index 36426a1..cb85f3a 100644 --- a/src/list.c +++ b/src/list.c @@ -82,3 +82,19 @@ bool list_remove(LinkedList *list, LinkedElement *element, void **value) { return true; } + +bool list_get_random(LinkedList *list, LinkedElement* random_element){ + if(list_size(list) == 0) return false; + // Génère un index aléatoire dans la plage des indices valides du tableau. + int rd_index = rand() % list_size(list); + + int count = 0; + + for(random_element= list_first(list);random_element!=NULL; random_element= list_next(random_element)){ + if(rd_index == count){ + break; + } + count++; + } + return true; +} diff --git a/src/randomized_set.c b/src/randomized_set.c deleted file mode 100644 index f19cf63..0000000 --- a/src/randomized_set.c +++ /dev/null @@ -1,68 +0,0 @@ -// -// Created by maxim on 14/02/2024. -// - -#include "randomized_set.h" - - -void randomized_set_create(RandomizedSet *set) { - // Alloue de la mémoire pour le tableau de nombres avec une capacité initiale de 1000. - set->nums = (int *) malloc(1000 * sizeof(int)); - // Initialise la taille actuelle du tableau à 0. - set->size = 0; - // Initialise la capacité maximale du tableau à 1000. - set->capacity = 1000; -} - -bool randomized_set_add(RandomizedSet *obj, int val) { - for (int i = 0; i < obj->size; i++) { - // Vérifie si l'élément existe déjà dans le tableau. - if (obj->nums[i] == val) { - // Si l'élément existe déjà, retourne faux. - return false; - } - } - - // Vérifie si le tableau est plein. - if (obj->size == obj->capacity) { - // Réalloue de la mémoire pour doubler la capacité du tableau. - obj->nums = (int *) realloc(obj->nums, (2 * obj->capacity) * sizeof(int)); - // Met à jour la capacité maximale. - obj->capacity *= 2; - } - - // Ajoute l'élément à la fin du tableau et met à jour la taille du tableau. - obj->nums[obj->size++] = val; - // Retourne vrai pour indiquer que l'insertion a réussi. - return true; -} - -bool randomized_set_remove(RandomizedSet *obj, int val) { - for (int i = 0; i < obj->size; i++) { - // Recherche l'élément dans le tableau. - if (obj->nums[i] == val) { - // Remplace l'élément par le dernier élément du tableau pour maintenir la continuité. - obj->nums[i] = obj->nums[obj->size - 1]; - // Réduit la taille du tableau. - obj->size--; - // Retourne vrai pour indiquer que la suppression a réussi. - return true; - } - } - // Si l'élément n'est pas trouvé, retourne faux. - return false; -} - -int randomized_set_get_random(RandomizedSet *obj) { - // Génère un index aléatoire dans la plage des indices valides du tableau. - int randomIndex = rand() % obj->size; - // Retourne l'élément correspondant à l'index aléatoire. - return obj->nums[randomIndex]; -} - -void randomized_set_destroy(RandomizedSet *obj) { - // Libère la mémoire du tableau de nombres. - free(obj->nums); - // Libère la mémoire de la structure RandomizedSet. - free(obj); -} \ No newline at end of file diff --git a/src/set.c b/src/set.c index e855f67..f6ffe1a 100644 --- a/src/set.c +++ b/src/set.c @@ -3,13 +3,13 @@ // #include -#include "hash_set.h" +#include "set_entry.h" +#include "set.h" - -bool set_match_exact(Set *elements, Set* elements_to_match, Set * matched_elements){ +bool set_match_entries(Set *elements, Set* elements_to_match, Set * matched_elements){ Set intersection; - HashSet *hashSet; + KeySetEntry *hashSet; LinkedElement *current_element,*element_max; void * value; uint32_t max_size; @@ -24,7 +24,7 @@ bool set_match_exact(Set *elements, Set* elements_to_match, Set * matched_elemen max_size = 0; for(current_element= list_first(elements_to_match);current_element != NULL; current_element = list_next(current_element)){ - if(!set_intersection(&intersection, &((HashSet * ) list_value(current_element))->set, elements)) return false; + if(!set_intersection(&intersection, &((KeySetEntry * ) list_value(current_element))->set, elements)) return false; if(set_size(&intersection) > max_size){ element_max = current_element; @@ -40,12 +40,12 @@ bool set_match_exact(Set *elements, Set* elements_to_match, Set * matched_elemen if(max_size == 0) return false; // Insert inside the covering the selected hashset - hashSet = (HashSet *) list_value(element_max); + hashSet = (KeySetEntry *) list_value(element_max); if(!set_add(matched_elements, hashSet)) return false; // Remove each current_element covered from the uncovered-elements set - for(current_element = list_first(&((HashSet*) list_value(element_max))->set); current_element != NULL; current_element= list_next(current_element)){ + for(current_element = list_first(&((KeySetEntry*) list_value(element_max))->set); current_element != NULL; current_element= list_next(current_element)){ value = list_value(current_element); if(set_remove(elements, (void**)&value) && elements->destroy != NULL) elements->destroy(value); diff --git a/tests/headers/RandomizedSetTest.h b/tests/headers/RandomizedSetTest.h index 8494a51..28b1a04 100644 --- a/tests/headers/RandomizedSetTest.h +++ b/tests/headers/RandomizedSetTest.h @@ -7,7 +7,7 @@ #include -#include "randomized_set.h" +#include "rd_set.h" class RandomizedSetTest : public ::testing::Test { protected: From e4f1dca2d4c4979d9019b983526b3e3804e7feac Mon Sep 17 00:00:00 2001 From: nakira974 Date: Tue, 27 Feb 2024 23:42:10 +0100 Subject: [PATCH 03/27] Update tests and comments --- headers/clist.h | 14 ++++---- headers/dlist.h | 20 ++++++------ headers/event.h | 4 +-- headers/frame.h | 2 +- headers/list.h | 18 +++++------ headers/queue.h | 8 ++--- headers/set.h | 20 ++++++------ headers/sort.h | 2 +- headers/stack.h | 20 +++++++++--- src/clist.c | 7 ++-- src/dlist.c | 7 ++-- src/list.c | 7 ++-- tests/headers/CLinkedList_Test.h | 10 +++--- tests/headers/DLinkedList_Test.h | 27 +++++++++++++--- tests/headers/LinkedList_Test.h | 27 +++++++++++++--- tests/headers/RandomizedSetTest.h | 53 ------------------------------- tests/main.cpp | 1 - 17 files changed, 122 insertions(+), 125 deletions(-) delete mode 100644 tests/headers/RandomizedSetTest.h diff --git a/headers/clist.h b/headers/clist.h index 21cb526..71ec6a1 100644 --- a/headers/clist.h +++ b/headers/clist.h @@ -53,7 +53,7 @@ typedef struct ClinkedList { * * @param val1 Left value to compare * @param val2 Right value to compare - * @return true if left is equals to right, otherwise false + * @return true if left is equals to right, false otherwise */ int (*match)(const void *val1, const void *val2); @@ -83,7 +83,7 @@ void clist_create(CLinkedList *list, void (*destroy)(void *value)); /** * @brief Destroy the specified list, after the call no other further operations will be permit - * @param list Reference of the list to destroy otherwise false + * @param list Reference of the list to destroy false otherwise * @complexity O(n) where n is the number of elements in the current list */ void clist_destroy(CLinkedList *list); @@ -94,7 +94,7 @@ void clist_destroy(CLinkedList *list); * @param element Reference element of the current list to add after * @param value A generic data to add after the element parameter * @complexity O(1) - * @return true if the element was added to the current list, otherwise false + * @return true if the element was added to the current list, false otherwise * */ bool clist_add(CLinkedList *list, CLinkedElement *element, const void *value); @@ -105,7 +105,7 @@ bool clist_add(CLinkedList *list, CLinkedElement *element, const void *value); * @param element Element of the list to be removed * @param value Output pointer on the value of the deleted list element reference * @complexity O(1) - * @return true if the element was correctly removed, otherwise false + * @return true if the element was correctly removed, false otherwise */ bool clist_remove(CLinkedList *list, CLinkedElement *element, void **value); @@ -115,7 +115,7 @@ bool clist_remove(CLinkedList *list, CLinkedElement *element, void **value); * @param random_element Reference to a random element * @return true if a random element has been returned, false otherwise */ -bool clist_get_random(CLinkedList *list, CLinkedElement * random_element); +CLinkedElement * clist_get_random(CLinkedList *list); /* ----- MACRO C++ COMPATIBILITY -----*/ #ifdef __cplusplus @@ -139,7 +139,7 @@ inline CLinkedElement* clist_first(CLinkedList * list){ /*** * Inline function that evaluates if the specified element is the first element of the specified list - * @return true if the element is the first of the current list, otherwise false + * @return true if the element is the first of the current list, false otherwise * @complexity O(1) */ inline bool clist_is_first(CLinkedList * list, CLinkedElement *element){ @@ -182,7 +182,7 @@ inline CLinkedElement *clist_next(CLinkedElement *element){ /** * @brief Macro that evaluates if the specified element is the first element of the specified list - * @return true if the element is the first of the current list, otherwise false + * @return true if the element is the first of the current list, false otherwise * @complexity O(1) */ #define list_is_first(list, element) ((element) == (list)->head ? true : false ) diff --git a/headers/dlist.h b/headers/dlist.h index 8b00e27..35aca1e 100644 --- a/headers/dlist.h +++ b/headers/dlist.h @@ -53,7 +53,7 @@ typedef struct DLinkedList { * * @param val1 Left value to compare * @param val2 Right value to compare - * @return true if left is equals to right, otherwise false + * @return true if left is equals to right, false otherwise */ int (*match)(const void *val1, const void *val2); @@ -90,7 +90,7 @@ void dlist_create(DLinkedList *list, void( *destroy)(void *value)); /** * @brief Destroy the specified list, after the call no other further operations will be permit - * @param list Reference of the list to destroy otherwise false + * @param list Reference of the list to destroy false otherwise * @complexity O(n) where n is the number of elements in the current list */ void dlist_destroy(DLinkedList *list); @@ -101,7 +101,7 @@ void dlist_destroy(DLinkedList *list); * @param element Reference element of the current list to add after * @param value A generic data to add after the element parameter * @complexity O(1) - * @return true if the element was added to the current list, otherwise false + * @return true if the element was added to the current list, false otherwise * */ bool dlist_add(DLinkedList *list, DLinkedElement *element, const void *value); @@ -112,7 +112,7 @@ bool dlist_add(DLinkedList *list, DLinkedElement *element, const void *value); * @param element Reference element of the current list to add after * @param value A generic data to add after the element parameter * @complexity O(1) - * @return true if the element was added to the current list, otherwise false + * @return true if the element was added to the current list, false otherwise * */ bool dlist_add_before(DLinkedList *list, DLinkedElement *element, const void *value); @@ -123,7 +123,7 @@ bool dlist_add_before(DLinkedList *list, DLinkedElement *element, const void *va * @param element Element of the list to be removed * @param value Output pointer on the value of the deleted list element reference * @complexity O(1) - * @return true if the element was correctly removed, otherwise false + * @return true if the element was correctly removed, false otherwise */ bool dlist_remove(DLinkedList *list, DLinkedElement *element, void **value); @@ -133,7 +133,7 @@ bool dlist_remove(DLinkedList *list, DLinkedElement *element, void **value); * @param value Reference to a random element * @return true if a random element has been returned, false otherwise */ -bool dlist_get_random(DLinkedList *list, DLinkedElement* value); +DLinkedElement * dlist_get_random(DLinkedList *list); /* ----- MACRO C++ COMPATIBILITY -----*/ #ifdef __cplusplus @@ -167,7 +167,7 @@ inline DLinkedElement *dlist_last(DLinkedList * list){ /*** * @brief Inline function that evaluates if the specified element is the first element of the specified list - * @return true if the element is the first of the current list, otherwise false + * @return true if the element is the first of the current list, false otherwise * @complexity O(1) */ inline bool dlist_is_first(DLinkedList * list, DLinkedElement *element){ @@ -176,7 +176,7 @@ inline bool dlist_is_first(DLinkedList * list, DLinkedElement *element){ /*** * @brief Inline function that evaluates if the specified element is the last element of the specified list - * @return true if the element is the last of the current list, otherwise false + * @return true if the element is the last of the current list, false otherwise * @complexity O(1) */ inline bool dlist_is_last(DLinkedList * list, DLinkedElement *element){ @@ -235,14 +235,14 @@ inline DLinkedElement *dlist_previous(DLinkedElement *element){ /*** * @brief Macro that evaluates if the specified element is the first element of the specified list - * @return true if the element is the first of the current list, otherwise false + * @return true if the element is the first of the current list, false otherwise * @complexity O(1) */ #define dlist_is_first(list, element) ((element)->previous == NULL ? true : false ) /*** * @brief Macro that evaluates if the specified element is the last element of the specified list - * @return true if the element is the last of the current list, otherwise false + * @return true if the element is the last of the current list, false otherwise * @complexity O(1) */ #define dlist_is_last(list, element) ((element)->next == NULL ? true : false ) diff --git a/headers/event.h b/headers/event.h index db51e52..7abb406 100644 --- a/headers/event.h +++ b/headers/event.h @@ -34,7 +34,7 @@ typedef struct Event{ * @brief A subscriber add an event into the queue for witch he subscribed * @param events Events queue * @param event Event to save into the queue - * @return true if the event was added in events, otherwise false + * @return true if the event was added in events, false otherwise */ bool event_receive(Queue * events, const Event *event); @@ -42,7 +42,7 @@ typedef struct Event{ * @brief Interruption handle to process subscribed events * @param events Events queue * @param on_event_received User function to process the event - * @return true if the event was computed, otherwise false + * @return true if the event was computed, false otherwise */ bool event_process(Queue *events, int(* on_event_received) (Event * event)); diff --git a/headers/frame.h b/headers/frame.h index 25d40ed..2f519cf 100644 --- a/headers/frame.h +++ b/headers/frame.h @@ -31,7 +31,7 @@ int frame_alloc(LinkedList *frames); * Try to deallocate a frame based on its id * @param frames List of frames where to remove the given frame index * @param frame_id Frame id to remove - * @return true if the frame was destroy, otherwise false + * @return true if the frame was destroy, false otherwise */ bool frame_destroy(LinkedList *frames, int frame_id); #ifdef __cplusplus diff --git a/headers/list.h b/headers/list.h index eca4ece..f9ec4bd 100644 --- a/headers/list.h +++ b/headers/list.h @@ -48,7 +48,7 @@ typedef struct LinkedList { * @brief Match handle * @param left Left value to compare * @param right Right value to compare - * @return true if left is equals to right, otherwise false + * @return true if left is equals to right, false otherwise */ int (*match)(const void *left, const void *right); @@ -82,7 +82,7 @@ void list_create(LinkedList *list, void( *destroy)(void *value)); /** * @brief Destroy the specified list, after the call no other further operations will be permit - * @param list Reference of the list to destroy otherwise false + * @param list Reference of the list to destroy false otherwise * @complexity O(n) where n is the number of elements in the current list */ void list_destroy(LinkedList *list); @@ -94,7 +94,7 @@ void list_destroy(LinkedList *list); * @param element Reference element of the current list to add after * @param value A generic data to add after the element parameter * @complexity O(1) - * @return true if the element was added to the current list, otherwise false + * @return true if the element was added to the current list, false otherwise * */ bool list_add(LinkedList *list, LinkedElement *element, const void *value); @@ -105,7 +105,7 @@ bool list_add(LinkedList *list, LinkedElement *element, const void *value); * @param element Element of the list to be removed * @param value Output pointer on the value of the deleted list element reference * @complexity O(1) - * @return true if the element was correctly removed, otherwise false + * @return true if the element was correctly removed, false otherwise */ bool list_remove(LinkedList *list, LinkedElement *element, void **value); @@ -115,7 +115,7 @@ bool list_remove(LinkedList *list, LinkedElement *element, void **value); * @param random_element Reference to a random element * @return true if a random element has been returned, false otherwise */ -bool list_get_random(LinkedList *list, LinkedElement* random_element); +LinkedElement* list_get_random(LinkedList *list); /* ----- MACRO C++ COMPATIBILITY -----*/ #ifdef __cplusplus @@ -149,7 +149,7 @@ inline LinkedElement * list_last(LinkedList * list){ /** * @brief Inline function that evaluates if the specified element is the first element of the specified list - * @return true if the element is the first of the current list, otherwise false + * @return true if the element is the first of the current list, false otherwise * @complexity O(1) */ inline bool list_is_first(LinkedList * list, LinkedElement *element){ @@ -158,7 +158,7 @@ inline bool list_is_first(LinkedList * list, LinkedElement *element){ /** * @brief Inline function that evaluates if the specified element is the last element of the specified list - * @return true if the element is the last of the current list, otherwise false + * @return true if the element is the last of the current list, false otherwise * @complexity O(1) */ inline bool list_is_last(LinkedList * list, LinkedElement *element){ @@ -209,14 +209,14 @@ inline LinkedElement *list_next(LinkedElement *element){ /** * @brief Macro that evaluates if the specified element is the first element of the specified list - * @return true if the element is the first of the current list, otherwise false + * @return true if the element is the first of the current list, false otherwise * @complexity O(1) */ #define list_is_first(list, element) ((element) == (list)->head ? true : false ) /** * @brief Macro that evaluates if the specified element is the last element of the specified list - * @return true if the element is the last of the current list, otherwise false + * @return true if the element is the last of the current list, false otherwise * @complexity O(1) */ #define list_is_last(list, element) ((element) == (list)->tail ? true : false ) diff --git a/headers/queue.h b/headers/queue.h index 83d2be7..db066c8 100644 --- a/headers/queue.h +++ b/headers/queue.h @@ -76,7 +76,7 @@ inline void queue_create(Queue * queue, void( *destroy)(void *value)){ /** * @brief Destroy the specified queue, after the call no other further operations will be permit - * @param queue Reference of the queue to destroy otherwise false + * @param queue Reference of the queue to destroy false otherwise * @complexity O(n) where n is the number of elements in the current list */ @@ -87,8 +87,8 @@ inline void queue_destroy(Queue * queue){ /** * @brief Inline function that returns a random element from the queue */ -static inline bool queue_get_random(Queue* queue, LinkedElement *random_element){ - return list_get_random(queue, random_element); +static inline LinkedElement *queue_peek_random(Queue* queue){ + return list_get_random(queue); } #else @@ -122,7 +122,7 @@ static inline bool queue_get_random(Queue* queue, LinkedElement *random_element) /** * @brief Macro that evaluates a random element from the queue and returns it */ -#define queue_get_random(queue, element) list_get_random +#define queue_peek_random(queue) list_get_random #endif diff --git a/headers/set.h b/headers/set.h index cb40f30..795735c 100644 --- a/headers/set.h +++ b/headers/set.h @@ -31,7 +31,7 @@ void set_create(Set *set, int (*match)(const void *left, const void *right), voi * @biref Try to insert a value in the given set * @param set Set to insert a value in * @param value Value to insert in the set - * @return True if the value was inserted in the given Set, otherwise false + * @return True if the value was inserted in the given Set, false otherwise * @complexity O(n) where n is the number of elements inside the given Set to compare with the parameter value */ bool set_add(Set *set, const void *value); @@ -50,7 +50,7 @@ bool set_remove(Set *set, void **value); * @param union_result Reference Set resulting of the union between left and right * @param left Left Set to compare for union operation * @param right Right Set to compare for union operation - * @return true if the union succeed, otherwise false + * @return true if the union succeed, false otherwise * @complexity O(mn) where m and n are the number of elements in each operand */ bool set_union(Set *union_result, const Set *left, const Set *right); @@ -60,7 +60,7 @@ bool set_union(Set *union_result, const Set *left, const Set *right); * @param intersection_result Reference Set resulting of the intersection between left and right * @param left Left Set to compare for intersection operation * @param right Right Set to compare for intersection operation - * @return true if the intersection succeed, otherwise false + * @return true if the intersection succeed, false otherwise * @complexity O(mn) where m and n are the number of elements in each operand */ bool set_intersection(Set *intersection_result, const Set *left, const Set *right); @@ -70,7 +70,7 @@ bool set_intersection(Set *intersection_result, const Set *left, const Set *righ * @param difference_result Reference Set resulting of the difference between left and right * @param left Left Set to compare for difference operation * @param right Right Set to compare for difference operation - * @return true if the difference succeed, otherwise false + * @return true if the difference succeed, false otherwise * @complexity O(mn) where m and n are the number of elements in each operand */ bool set_difference(Set *difference_result, const Set *left, const Set *right); @@ -79,7 +79,7 @@ bool set_difference(Set *difference_result, const Set *left, const Set *right); * @brief Test if the value is in the given Set * @param set Set to search in * @param value Value to search in the set - * @return true if the element is in the set, otherwise false + * @return true if the element is in the set, false otherwise * @complexity O(n) where n is the number of elements inside the given Set to compare with the parameter value */ bool set_is_member(const Set *set, const void *value); @@ -88,7 +88,7 @@ bool set_is_member(const Set *set, const void *value); * @brief Test if the left operand is a subset of the right operand * @param left Set to determine if it's a subset of right operand * @param right Set to be compared with left operand - * @return true if the left Set is a subset of the right Set, otherwise false + * @return true if the left Set is a subset of the right Set, false otherwise * @complexity O(mn) where m and n are the number of elements in each operand */ bool set_is_subset(const Set *left, const Set *right); @@ -97,7 +97,7 @@ bool set_is_subset(const Set *left, const Set *right); * @brief Test if left and right Set operands are equal * @param left Left Set reference operand * @param right Right Set reference operand - * @return true if left and right are equal, otherwise false + * @return true if left and right are equal, false otherwise * @complexity O(n ^ 2 ) where n is the number of elements inside left AND right */ bool set_is_equal(const Set *left, const Set *right); @@ -125,8 +125,8 @@ static inline void set_destroy(Set *set){ /** * @brief Inline function that returns a random element from the set */ -static inline bool set_get_random(Set* set, LinkedElement *random_element){ - return list_get_random(set, random_element); +static inline LinkedElement * set_get_random(Set* set){ + return list_get_random(set); } #else /** @@ -147,7 +147,7 @@ static inline bool set_get_random(Set* set, LinkedElement *random_element){ /** * @brief Macro that evaluates a random element from the set and returns it */ -#define set_get_random(set, element) list_get_random +#define set_get_random(set) list_get_random #endif #ifdef __cplusplus diff --git a/headers/sort.h b/headers/sort.h index 8ab6e87..3de151f 100644 --- a/headers/sort.h +++ b/headers/sort.h @@ -26,7 +26,7 @@ extern "C" { * @param element_count Number of elements inside the given array * @param element_size The size of the enumerable * @param compare User compare function - * @return true if the generic array is sorted, otherwise false + * @return true if the generic array is sorted, false otherwise */ bool array_is_sort(void * value, int element_count, size_t element_size, int (*compare)(const void *key1, const void *key2)); #ifdef __cplusplus diff --git a/headers/stack.h b/headers/stack.h index dbf6212..f30639a 100644 --- a/headers/stack.h +++ b/headers/stack.h @@ -30,7 +30,7 @@ typedef LinkedList Stack; * @brief Push a value on the top of the stack, the reference to the value MUST stay accessible while it's in the stack * @param stack The stack to push value on * @param value The value to be pushed on top of stack - * @return true if the value has been stacked, otherwise false + * @return true if the value has been stacked, false otherwise * @complexity O(1) */ bool stack_push(Stack *stack, const void *value); @@ -39,7 +39,7 @@ bool stack_push(Stack *stack, const void *value); * @brief Unstack the on-top value of the specified stack * @param stack The stack to unstack a value on * @param value The value of the element stored on top of the stack - * @return true if an element has been unstacked, otherwise false + * @return true if an element has been unstacked, false otherwise * @complexity O(1) */ bool stack_pop(Stack *stack, void **value); @@ -72,13 +72,20 @@ inline void stack_create(Stack * stack, void( *destroy)(void *value)){ /** * @brief Destroy the specified stack, after the call no other further operations will be permit - * @param stack Reference of the stack to destroy otherwise false + * @param stack Reference of the stack to destroy false otherwise * @complexity O(n) where n is the number of elements in the current list */ inline void stack_destory(Stack * stack){ list_destroy(stack); } + +/** + * @brief Inline function that returns a random element from the queue + */ +static inline LinkedElement * stack_peek_random(Stack * queue){ +return list_get_random(queue); +} #else /** @@ -101,10 +108,15 @@ inline void stack_destory(Stack * stack){ /** * @brief Destroy the specified stack, after the call no other further operations will be permit - * @param stack Reference of the stack to destroy otherwise false + * @param stack Reference of the stack to destroy false otherwise * @complexity O(n) where n is the number of elements in the current list */ #define stack_destroy list_destroy + +/** + * @brief Macro that evaluates a random element from the queue and returns it + */ +#define stack_peek_random(stack) list_get_random #endif #ifdef __cplusplus diff --git a/src/clist.c b/src/clist.c index 8ba6b4f..d3acc32 100644 --- a/src/clist.c +++ b/src/clist.c @@ -62,8 +62,9 @@ bool clist_remove(CLinkedList *list, CLinkedElement *element, void **value) { return true; } -bool clist_get_random(CLinkedList *list, CLinkedElement * random_element){ - if(clist_size(list) == 0) return false; +CLinkedElement * clist_get_random(CLinkedList *list){ + CLinkedElement * random_element; + if(clist_size(list) == 0) return NULL; int rd_index = rand() % clist_size(list); int count = 0; @@ -73,5 +74,5 @@ bool clist_get_random(CLinkedList *list, CLinkedElement * random_element){ } count++; } - return true; + return random_element; } diff --git a/src/dlist.c b/src/dlist.c index 8faf549..531b8c3 100644 --- a/src/dlist.c +++ b/src/dlist.c @@ -123,8 +123,9 @@ bool dlist_remove(DLinkedList *list, DLinkedElement *element, void **value) { return true; } -bool dlist_get_random(DLinkedList *list, DLinkedElement * random_element){ - if(dlist_size(list) == 0) return false; +DLinkedElement * dlist_get_random(DLinkedList *list){ + DLinkedElement * random_element; + if(dlist_size(list) == 0) return NULL; // Génère un index aléatoire dans la plage des indices valides du tableau. int rd_index = rand() % dlist_size(list); int count = 0; @@ -135,5 +136,5 @@ bool dlist_get_random(DLinkedList *list, DLinkedElement * random_element){ } count++; } - return true; + return random_element; } \ No newline at end of file diff --git a/src/list.c b/src/list.c index cb85f3a..1320fc7 100644 --- a/src/list.c +++ b/src/list.c @@ -83,8 +83,9 @@ bool list_remove(LinkedList *list, LinkedElement *element, void **value) { return true; } -bool list_get_random(LinkedList *list, LinkedElement* random_element){ - if(list_size(list) == 0) return false; +LinkedElement* list_get_random(LinkedList *list){ + LinkedElement* random_element; + if(list_size(list) == 0) return NULL; // Génère un index aléatoire dans la plage des indices valides du tableau. int rd_index = rand() % list_size(list); @@ -96,5 +97,5 @@ bool list_get_random(LinkedList *list, LinkedElement* random_element){ } count++; } - return true; + return random_element; } diff --git a/tests/headers/CLinkedList_Test.h b/tests/headers/CLinkedList_Test.h index ba93b86..f119aa5 100644 --- a/tests/headers/CLinkedList_Test.h +++ b/tests/headers/CLinkedList_Test.h @@ -46,7 +46,7 @@ TEST_F(CLinkedList_Test, PageTest) { TEST_F(CLinkedList_Test, ReplacePageTest) { for (int i = 10; i >= 0; --i) { - clist_add(obj, obj->head, new Page{i, i-1}); + clist_add(obj, clist_first(obj), new Page{i, i-1}); } CLinkedElement *current = obj->head; int replacedPage = replace_page(¤t); @@ -57,12 +57,14 @@ TEST_F(CLinkedList_Test, ReplacePageTest) { TEST_F(CLinkedList_Test, PerformanceTest) { // Vérifier les performances en ajoutant et supprimant un grand nombre d'éléments for (int i = 0; i < 100000; ++i) { - clist_add(obj, obj->head, new Page{i, i+1}); + clist_add(obj, clist_first(obj), new Page{i, i+1}); } + CLinkedElement *current_element; - for (int i = 0; i < 100000; ++i) { + // Remove random element until the list is not empty + for(current_element= clist_get_random(obj); clist_size(obj) > 0;current_element= clist_next(current_element)){ void *value = nullptr; - clist_remove(obj, obj->head, &value); + clist_remove(obj,current_element , &value); delete static_cast(value); } diff --git a/tests/headers/DLinkedList_Test.h b/tests/headers/DLinkedList_Test.h index b1143c9..b2dee18 100644 --- a/tests/headers/DLinkedList_Test.h +++ b/tests/headers/DLinkedList_Test.h @@ -25,18 +25,35 @@ TEST_F(DLinkedListTest, PerformanceTest) { for (int i = 0; i < 1000000; ++i) { int *value = (int *)malloc(sizeof(int)); *value = i; - dlist_add(&list, NULL, value); + dlist_add(&list, nullptr, value); } EXPECT_EQ(dlist_size(&list), 1); // Deletion test - DLinkedElement *cur = dlist_first(&list); - while (cur != nullptr) { + DLinkedElement *current_element; + + for(current_element= dlist_get_random(&list); current_element != nullptr;current_element= dlist_next(current_element)){ void *value; - dlist_remove(&list, cur, &value); + dlist_remove(&list, current_element, &value); delete static_cast(value); - cur = dlist_next(cur); + } + + EXPECT_EQ(dlist_size(&list), 0); + + for (int i = 0; i < 1000000; ++i) { + int *value = (int *)malloc(sizeof(int)); + *value = i; + dlist_add(&list, nullptr, value); + } + + current_element= dlist_first(&list); + + while (current_element != nullptr) { + void *value; + dlist_remove(&list, current_element, &value); + free(value); + current_element = dlist_next(current_element); } EXPECT_EQ(dlist_size(&list), 0); diff --git a/tests/headers/LinkedList_Test.h b/tests/headers/LinkedList_Test.h index af73589..143c9a3 100644 --- a/tests/headers/LinkedList_Test.h +++ b/tests/headers/LinkedList_Test.h @@ -26,18 +26,35 @@ TEST_F(LinkedListTest, PerformanceTest) { for (int i = 0; i < 1000000; ++i) { int *value = (int *) malloc(sizeof(int)); *value = i; - list_add(&list, NULL, value); + list_add(&list, nullptr, value); } EXPECT_EQ(list_size(&list), 1000000); // Deletion test - LinkedElement *cur = list_first(&list); - while (!list_is_last(&list, cur)) { + LinkedElement *current_element = list_first(&list); + + for(current_element= list_get_random(&list); current_element != nullptr;current_element= list_next(current_element)){ + void *value; + list_remove(&list, current_element, &value); + delete static_cast(value); + } + + EXPECT_EQ(list_size(&list), 0); + + for (int i = 0; i < 1000000; ++i) { + int *value = (int *) malloc(sizeof(int)); + *value = i; + list_add(&list, nullptr, value); + } + + current_element= list_first(&list); + + while (current_element != nullptr) { void *value; - list_remove(&list, cur, &value); + list_remove(&list, current_element, &value); free(value); - cur = list_next(cur); + current_element = list_next(current_element); } EXPECT_EQ(list_size(&list), 0); diff --git a/tests/headers/RandomizedSetTest.h b/tests/headers/RandomizedSetTest.h deleted file mode 100644 index 28b1a04..0000000 --- a/tests/headers/RandomizedSetTest.h +++ /dev/null @@ -1,53 +0,0 @@ -// -// Created by maxim on 14/02/2024. -// - -#ifndef COLLECTIONS_COMMONS_RANDOMIZEDSETTEST_H -#define COLLECTIONS_COMMONS_RANDOMIZEDSETTEST_H - - -#include -#include "rd_set.h" - -class RandomizedSetTest : public ::testing::Test { -protected: - RandomizedSet *obj{}; - - void SetUp() override { -// Code exécuté avant chaque test - obj = (RandomizedSet *) malloc(sizeof(RandomizedSet)); - randomized_set_create(obj); - } - - void TearDown() override { -// Code exécuté après chaque test - randomized_set_destroy(obj); - } - -}; - -TEST_F(RandomizedSetTest, InsertTest) { - ASSERT_TRUE(randomized_set_add(obj, 1)); - ASSERT_TRUE(randomized_set_add(obj, 2)); -} - -TEST_F(RandomizedSetTest, RemoveTest) { - randomized_set_add(obj, 1); - randomized_set_add(obj, 2); - - ASSERT_TRUE(randomized_set_remove(obj, 1)); - ASSERT_FALSE(randomized_set_remove(obj, 3)); - ASSERT_TRUE(randomized_set_remove(obj, 2)); -} - -TEST_F(RandomizedSetTest, GetRandomTest) { - randomized_set_add(obj, 1); - randomized_set_add(obj, 2); - - int result = randomized_set_get_random(obj); - ASSERT_TRUE(result == 1 || result == 2); - -} - - -#endif //COLLECTIONS_COMMONS_RANDOMIZEDSETTEST_H diff --git a/tests/main.cpp b/tests/main.cpp index 5489756..0e77eb4 100644 --- a/tests/main.cpp +++ b/tests/main.cpp @@ -6,7 +6,6 @@ #include "Stack_Test.h" #include "LinkedList_Test.h" #include "DLinkedList_Test.h" -#include "RandomizedSetTest.h" #include "Queue_Test.h" #include "EventBus_Test.h" #include "Exception_Test.h" From 3a0b6e09cdab91a99ed777fe863813be2472b75a Mon Sep 17 00:00:00 2001 From: nakira974 Date: Wed, 28 Feb 2024 00:44:29 +0100 Subject: [PATCH 04/27] Add lhtbl.h for Linked hash tables API --- headers/chtbl.h | 11 ---- headers/lhtbl.h | 131 ++++++++++++++++++++++++++++++++++++++++++++++++ headers/queue.h | 2 +- headers/stack.h | 6 +-- 4 files changed, 135 insertions(+), 15 deletions(-) delete mode 100644 headers/chtbl.h create mode 100644 headers/lhtbl.h diff --git a/headers/chtbl.h b/headers/chtbl.h deleted file mode 100644 index d3e6fae..0000000 --- a/headers/chtbl.h +++ /dev/null @@ -1,11 +0,0 @@ -/** - * @file set.h - * @brief This file contains the API for hashed maps - * @author Maxime Loukhal - * @date 26/02/2024 - */ - -#ifndef COLLECTIONS_COMMONS_CHTBL_H -#define COLLECTIONS_COMMONS_CHTBL_H - -#endif //COLLECTIONS_COMMONS_CHTBL_H diff --git a/headers/lhtbl.h b/headers/lhtbl.h new file mode 100644 index 0000000..d9adeb7 --- /dev/null +++ b/headers/lhtbl.h @@ -0,0 +1,131 @@ +/** + * @file set.h + * @brief This file contains the API for linked hash tables + * @author Maxime Loukhal + * @date 26/02/2024 + */ + +#ifndef COLLECTIONS_COMMONS_LHTBL_H +#define COLLECTIONS_COMMONS_LHTBL_H + +#ifdef __cplusplus +extern "C" { +#endif +#ifdef __cplusplus +#include +#include +#else +#include +#include +#endif + +#include "list.h" + +/** + * @brief Data structure definition for a linked hash table + */ +typedef struct LinkedHashTable{ + /** + * @brief Number of containers in the linked hash table + */ + int containers; + + /** + * @brief Pointer to the hash function for elements + * @param key The key to be hashed + * @return The hashed value of the key + */ + int (*hash)(const void *key); + + /** + * @brief Pointer to the match function for elements + * @param key1 The first key to be compared + * @param key2 The second key to be compared + * @return 0 if the keys match, non-zero otherwise + */ + int (*match)(const void* key1, const void* key2); + + /** + * @brief Pointer to the destroy function for elements + * @param value The value to be destroyed + */ + void(*destroy)(void *value); + + /** + * @brief Current element count of the hash table + */ + int size; + + /** + * @brief Pointer to the internal linked list for storing elements + */ + LinkedList *elements; +} LinkedHashTable; + +#ifdef __cplusplus +/*** +* @brief Inline function that evaluates the number of elements inside the specified queue +* @return The current element count of the current list +* @complexity O(1) +*/ +inline int lhtable_size(LinkedHashTable *queue){ + return queue->size; +}; +#else + +/*** +* @brief Inline function that evaluates the number of elements inside the specified queue +* @return The current element count of the current chained hash table +* @complexity O(1) +*/ +#define lhtable_size(table); +#endif + +/** + * @brief Tries to allocate a new linked hash table + * @param lhtable Linked hash table to create + * @param containers The number of containers in the hash table + * @param hash Element hash function + * @param match Element match function + * @param destroy Element destroy function + * @return true if the hash table has been created successfully, false otherwise + */ +bool lhtable_create(LinkedHashTable *lhtable, + int containers, + int (*hash)(const void *key), + int (*match)(const void* key1, const void* key2), + void(*destroy)(void *value)); + +/** + * @brief Destroy a given data table + * @param lhtable The data table to be destroyed + */ +void lhtable_destroy(LinkedHashTable *lhtable); + +/** + * @brief Associates the specified value with a new hash key + * @param lhtable Linked Hash Table to put a value in + * @param value Value to be put in the given data table + * @return true if the value has been correctly inserted, false otherwise + */ +bool lhtable_put(LinkedHashTable *lhtable, const void* value); + +/** + * @brief Remove a value from the data table, then if the operation has been compute value will contain the pointer on the destroyed value + * @param lhtable Linked Hash Table to remove a value in + * @param value Double pointer on the value to be removed, then if it has been correctly removed the pointer on the removed value + * @return true if the data table has been deleted from the data table, false otherwise + */ +bool lhtable_remove(LinkedHashTable *lhtable, void** value); + +/** + * @brief Test if the given value is present in the data table, if a match occurs value will contain the pointer on the matched value + * @param lhtable Linked Hash Table to lookup in + * @param value Double pointer to lookup the value in the given data table, if a match occurs returns the pointer on it + * @return true if the data table is present in the given data table, false otherwise + */ +bool lhtable_lookup(LinkedHashTable *lhtable, void** value); +#ifdef __cplusplus +} +#endif +#endif //COLLECTIONS_COMMONS_LHTBL_H diff --git a/headers/queue.h b/headers/queue.h index db066c8..f03fffb 100644 --- a/headers/queue.h +++ b/headers/queue.h @@ -50,7 +50,7 @@ bool queue_dequeue(Queue * queue, void *value); * @return The current element count of the current list * @complexity O(1) */ -inline int queue_size(LinkedList *queue){ +inline int queue_size(Queue *queue){ return queue->size; }; diff --git a/headers/stack.h b/headers/stack.h index f30639a..632b0b9 100644 --- a/headers/stack.h +++ b/headers/stack.h @@ -81,10 +81,10 @@ inline void stack_destory(Stack * stack){ } /** - * @brief Inline function that returns a random element from the queue + * @brief Inline function that returns a random element from the stack */ -static inline LinkedElement * stack_peek_random(Stack * queue){ -return list_get_random(queue); +static inline LinkedElement * stack_peek_random(Stack * stack){ +return list_get_random(stack); } #else From 3e241b388a1bed2a73619746acfcdc257bdc4bba Mon Sep 17 00:00:00 2001 From: nakira974 Date: Wed, 28 Feb 2024 00:46:11 +0100 Subject: [PATCH 05/27] fixe method prefix --- headers/lhtbl.h | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/headers/lhtbl.h b/headers/lhtbl.h index d9adeb7..074f944 100644 --- a/headers/lhtbl.h +++ b/headers/lhtbl.h @@ -68,7 +68,7 @@ typedef struct LinkedHashTable{ * @return The current element count of the current list * @complexity O(1) */ -inline int lhtable_size(LinkedHashTable *queue){ +inline int lhtbl_size(LinkedHashTable *queue){ return queue->size; }; #else @@ -78,19 +78,19 @@ inline int lhtable_size(LinkedHashTable *queue){ * @return The current element count of the current chained hash table * @complexity O(1) */ -#define lhtable_size(table); +#define lhtbl_size(table); #endif /** * @brief Tries to allocate a new linked hash table - * @param lhtable Linked hash table to create + * @param lhtbl Linked hash table to create * @param containers The number of containers in the hash table * @param hash Element hash function * @param match Element match function * @param destroy Element destroy function * @return true if the hash table has been created successfully, false otherwise */ -bool lhtable_create(LinkedHashTable *lhtable, +bool lhtbl_create(LinkedHashTable *lhtbl, int containers, int (*hash)(const void *key), int (*match)(const void* key1, const void* key2), @@ -98,33 +98,33 @@ bool lhtable_create(LinkedHashTable *lhtable, /** * @brief Destroy a given data table - * @param lhtable The data table to be destroyed + * @param lhtbl The data table to be destroyed */ -void lhtable_destroy(LinkedHashTable *lhtable); +void lhtbl_destroy(LinkedHashTable *lhtbl); /** * @brief Associates the specified value with a new hash key - * @param lhtable Linked Hash Table to put a value in + * @param lhtbl Linked Hash Table to put a value in * @param value Value to be put in the given data table * @return true if the value has been correctly inserted, false otherwise */ -bool lhtable_put(LinkedHashTable *lhtable, const void* value); +bool lhtbl_put(LinkedHashTable *lhtbl, const void* value); /** * @brief Remove a value from the data table, then if the operation has been compute value will contain the pointer on the destroyed value - * @param lhtable Linked Hash Table to remove a value in + * @param lhtbl Linked Hash Table to remove a value in * @param value Double pointer on the value to be removed, then if it has been correctly removed the pointer on the removed value * @return true if the data table has been deleted from the data table, false otherwise */ -bool lhtable_remove(LinkedHashTable *lhtable, void** value); +bool lhtbl_remove(LinkedHashTable *lhtbl, void** value); /** * @brief Test if the given value is present in the data table, if a match occurs value will contain the pointer on the matched value - * @param lhtable Linked Hash Table to lookup in + * @param lhtbl Linked Hash Table to lookup in * @param value Double pointer to lookup the value in the given data table, if a match occurs returns the pointer on it * @return true if the data table is present in the given data table, false otherwise */ -bool lhtable_lookup(LinkedHashTable *lhtable, void** value); +bool lhtbl_lookup(LinkedHashTable *lhtbl, void** value); #ifdef __cplusplus } #endif From 612181c38304c6a291de5e5379a2263ed1e61977 Mon Sep 17 00:00:00 2001 From: nakira974 Date: Wed, 28 Feb 2024 00:55:42 +0100 Subject: [PATCH 06/27] Add htbl_fun.h into lhtbl.h --- headers/htbl_fun.h | 20 ++++++++++++++++++++ headers/lhtbl.h | 6 +++--- 2 files changed, 23 insertions(+), 3 deletions(-) create mode 100644 headers/htbl_fun.h diff --git a/headers/htbl_fun.h b/headers/htbl_fun.h new file mode 100644 index 0000000..1c28cf0 --- /dev/null +++ b/headers/htbl_fun.h @@ -0,0 +1,20 @@ +/** + * @file htbl_fun.h + * @brief This file contains the API for basic hash table functions + * @author Maxime Loukhal + * @date 28/02/2024 + */ + + +#ifndef COLLECTIONS_COMMONS_HTBL_FUNC_H +#define COLLECTIONS_COMMONS_HTBL_FUNC_H + +/** + * @brief Convert the given key into a permuted integer using consecutive XOR shifts + * @param key Key to hash + * @return Generated hash table index + * @author P.J. WEINBERGER + * @see 'Compilers : Principles, Technics and Tools' from Alfred V. AHO + */ +int hashpjw(const void* key); +#endif //COLLECTIONS_COMMONS_HTBL_FUNC_H diff --git a/headers/lhtbl.h b/headers/lhtbl.h index 074f944..da3a239 100644 --- a/headers/lhtbl.h +++ b/headers/lhtbl.h @@ -1,8 +1,8 @@ /** - * @file set.h + * @file lhtbl.h * @brief This file contains the API for linked hash tables * @author Maxime Loukhal - * @date 26/02/2024 + * @date 27/02/2024 */ #ifndef COLLECTIONS_COMMONS_LHTBL_H @@ -20,7 +20,7 @@ extern "C" { #endif #include "list.h" - +#include "htbl_fun.h" /** * @brief Data structure definition for a linked hash table */ From 3201d60a5c5de077602940fbb6cc10cc31efe509 Mon Sep 17 00:00:00 2001 From: nakira974 Date: Wed, 28 Feb 2024 15:36:54 +0100 Subject: [PATCH 07/27] Update htbl impl --- README.md | 2 +- headers/clist.h | 8 +- headers/dlist.h | 8 +- headers/htbl.h | 50 +++++++++++++ headers/htbl_fun.h | 20 ----- headers/lhtbl.h | 48 ++++++------ headers/list.h | 8 +- headers/queue.h | 8 +- headers/set.h | 28 +++---- headers/set_entry.h | 10 +-- headers/sort.h | 2 +- headers/stack.h | 4 +- src/dlist.c | 4 +- src/htbl.c | 95 +++++++++++++++++++++++ src/lhtbl.c | 108 +++++++++++++++++++++++++++ src/list.c | 2 +- src/set.c | 18 ++--- tests/CMakeLists.txt | 2 +- tests/headers/LinkedHashTable_Test.h | 74 ++++++++++++++++++ tests/main.cpp | 1 + third-party/googletest | 2 +- 21 files changed, 408 insertions(+), 94 deletions(-) create mode 100644 headers/htbl.h delete mode 100644 headers/htbl_fun.h create mode 100644 src/htbl.c create mode 100644 src/lhtbl.c create mode 100644 tests/headers/LinkedHashTable_Test.h diff --git a/README.md b/README.md index e54fea8..f8d8c54 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ hash maps, and array lists. It allows you to efficiently manage and manipulate c - [ ] (Not release yet) Array list implementation for efficient random access and dynamic resizing. - [x] Binary trees implementations for organizing and efficiently searching data. - [x] Randomized set implementation for storing and traversing data in a dynamic manner. -- [x] Queues implementation for storing elements in the order they were added +- [x] Queues implementation for storing hashtable in the order they were added ## Usage diff --git a/headers/clist.h b/headers/clist.h index 71ec6a1..f6e431c 100644 --- a/headers/clist.h +++ b/headers/clist.h @@ -55,7 +55,7 @@ typedef struct ClinkedList { * @param val2 Right value to compare * @return true if left is equals to right, false otherwise */ - int (*match)(const void *val1, const void *val2); + int (*equals)(const void *val1, const void *val2); /** * @brief Destroy handle @@ -84,7 +84,7 @@ void clist_create(CLinkedList *list, void (*destroy)(void *value)); /** * @brief Destroy the specified list, after the call no other further operations will be permit * @param list Reference of the list to destroy false otherwise - * @complexity O(n) where n is the number of elements in the current list + * @complexity O(n) where n is the number of hashtable in the current list */ void clist_destroy(CLinkedList *list); @@ -120,7 +120,7 @@ CLinkedElement * clist_get_random(CLinkedList *list); /* ----- MACRO C++ COMPATIBILITY -----*/ #ifdef __cplusplus /*** - * Inline function that evaluates the number of elements inside the specified list + * Inline function that evaluates the number of hashtable inside the specified list * @return The current element count of the current list * @complexity O(1) */ @@ -167,7 +167,7 @@ inline CLinkedElement *clist_next(CLinkedElement *element){ /* ----- C MACRO -----*/ #else /** - * @brief Macro that evaluates the number of elements inside the specified list + * @brief Macro that evaluates the number of hashtable inside the specified list * @return The current element count of the current list * @complexity O(1) */ diff --git a/headers/dlist.h b/headers/dlist.h index 35aca1e..0e415f3 100644 --- a/headers/dlist.h +++ b/headers/dlist.h @@ -55,7 +55,7 @@ typedef struct DLinkedList { * @param val2 Right value to compare * @return true if left is equals to right, false otherwise */ - int (*match)(const void *val1, const void *val2); + int (*equals)(const void *val1, const void *val2); /** * @brief Destroy handle @@ -91,7 +91,7 @@ void dlist_create(DLinkedList *list, void( *destroy)(void *value)); /** * @brief Destroy the specified list, after the call no other further operations will be permit * @param list Reference of the list to destroy false otherwise - * @complexity O(n) where n is the number of elements in the current list + * @complexity O(n) where n is the number of hashtable in the current list */ void dlist_destroy(DLinkedList *list); @@ -139,7 +139,7 @@ DLinkedElement * dlist_get_random(DLinkedList *list); #ifdef __cplusplus /*** - * @brief Inline function that evaluates the number of elements inside the specified list + * @brief Inline function that evaluates the number of hashtable inside the specified list * @return The current element count of the current list * @complexity O(1) */ @@ -213,7 +213,7 @@ inline DLinkedElement *dlist_previous(DLinkedElement *element){ /* ----- C MACRO -----*/ #else /*** - * @brief Macro that evaluates the number of elements inside the specified list + * @brief Macro that evaluates the number of hashtable inside the specified list * @return The current element count of the current list * @complexity O(1) */ diff --git a/headers/htbl.h b/headers/htbl.h new file mode 100644 index 0000000..9b300c2 --- /dev/null +++ b/headers/htbl.h @@ -0,0 +1,50 @@ +// +// Created by maxim on 28/02/2024. +// + +#ifndef COLLECTIONS_COMMONS_HTBL_H +#define COLLECTIONS_COMMONS_HTBL_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __cplusplus +#include +#else +#include +#include +#endif + +/** + * @brief PJW method to convert the given key into a permuted integer using consecutive XOR shifts + * @param table_size Hash table size + * @param key Key to hash + * @return Generated hash table index + * @author P.J. WEINBERGER + * @see 'Compilers : Principles, Technics and Tools' from Alfred V. AHO + */ +int hashpjw(int table_size, const void* key); + +/** + * @brief Hashes the memory address of a reference and returns it as a uint64_t value + * @param table_size Hash table size + * @param ref The reference whose address is to be hashed + * @return The hashed value of the reference address + */ +int hashref(int table_size, const void *ref); + +/** + * Inline assembly implementation of integer comparison. + * @param a Pointer to the first value + * @param b Pointer to the second value + * @return Result of the comparison + */ +int cmp_int(const void *a, const void *b); + + +#ifdef __cplusplus +} +#endif + +#endif //COLLECTIONS_COMMONS_HTBL_H diff --git a/headers/htbl_fun.h b/headers/htbl_fun.h deleted file mode 100644 index 1c28cf0..0000000 --- a/headers/htbl_fun.h +++ /dev/null @@ -1,20 +0,0 @@ -/** - * @file htbl_fun.h - * @brief This file contains the API for basic hash table functions - * @author Maxime Loukhal - * @date 28/02/2024 - */ - - -#ifndef COLLECTIONS_COMMONS_HTBL_FUNC_H -#define COLLECTIONS_COMMONS_HTBL_FUNC_H - -/** - * @brief Convert the given key into a permuted integer using consecutive XOR shifts - * @param key Key to hash - * @return Generated hash table index - * @author P.J. WEINBERGER - * @see 'Compilers : Principles, Technics and Tools' from Alfred V. AHO - */ -int hashpjw(const void* key); -#endif //COLLECTIONS_COMMONS_HTBL_FUNC_H diff --git a/headers/lhtbl.h b/headers/lhtbl.h index da3a239..6182ccf 100644 --- a/headers/lhtbl.h +++ b/headers/lhtbl.h @@ -1,26 +1,29 @@ /** - * @file lhtbl.h + * @file lhtbl.h * @brief This file contains the API for linked hash tables * @author Maxime Loukhal * @date 27/02/2024 */ - #ifndef COLLECTIONS_COMMONS_LHTBL_H #define COLLECTIONS_COMMONS_LHTBL_H + #ifdef __cplusplus extern "C" { #endif + #ifdef __cplusplus #include #include +#include #else #include #include +#include #endif #include "list.h" -#include "htbl_fun.h" +#include "htbl.h" /** * @brief Data structure definition for a linked hash table */ @@ -31,22 +34,22 @@ typedef struct LinkedHashTable{ int containers; /** - * @brief Pointer to the hash function for elements + * @brief Pointer to the hash function for hashtable * @param key The key to be hashed * @return The hashed value of the key */ - int (*hash)(const void *key); + int (*hash)(int table_size, const void *key); /** - * @brief Pointer to the match function for elements + * @brief Pointer to the equals function for hashtable * @param key1 The first key to be compared * @param key2 The second key to be compared - * @return 0 if the keys match, non-zero otherwise + * @return 0 if the keys equals, non-zero otherwise */ - int (*match)(const void* key1, const void* key2); + int (*equals)(const void* key1, const void* key2); /** - * @brief Pointer to the destroy function for elements + * @brief Pointer to the destroy function for hashtable * @param value The value to be destroyed */ void(*destroy)(void *value); @@ -57,14 +60,14 @@ typedef struct LinkedHashTable{ int size; /** - * @brief Pointer to the internal linked list for storing elements + * @brief Pointer to the internal linked list for storing hashtable */ - LinkedList *elements; + LinkedList *hashtable; } LinkedHashTable; #ifdef __cplusplus /*** -* @brief Inline function that evaluates the number of elements inside the specified queue +* @brief Inline function that evaluates the number of hashtable inside the specified queue * @return The current element count of the current list * @complexity O(1) */ @@ -74,11 +77,11 @@ inline int lhtbl_size(LinkedHashTable *queue){ #else /*** -* @brief Inline function that evaluates the number of elements inside the specified queue +* @brief Inline function that evaluates the number of hashtable inside the specified queue * @return The current element count of the current chained hash table * @complexity O(1) */ -#define lhtbl_size(table); +#define lhtbl_size(table) list_size; #endif /** @@ -86,14 +89,14 @@ inline int lhtbl_size(LinkedHashTable *queue){ * @param lhtbl Linked hash table to create * @param containers The number of containers in the hash table * @param hash Element hash function - * @param match Element match function + * @param equals Element equals function * @param destroy Element destroy function * @return true if the hash table has been created successfully, false otherwise */ bool lhtbl_create(LinkedHashTable *lhtbl, int containers, - int (*hash)(const void *key), - int (*match)(const void* key1, const void* key2), + int (*hash)(int table_size, const void *key), + int (*equals)(const void* key1, const void* key2), void(*destroy)(void *value)); /** @@ -119,13 +122,16 @@ bool lhtbl_put(LinkedHashTable *lhtbl, const void* value); bool lhtbl_remove(LinkedHashTable *lhtbl, void** value); /** - * @brief Test if the given value is present in the data table, if a match occurs value will contain the pointer on the matched value + * @brief Test if the given value is present in the data table, if a equals occurs value will contain the pointer on the equalsed value * @param lhtbl Linked Hash Table to lookup in - * @param value Double pointer to lookup the value in the given data table, if a match occurs returns the pointer on it + * @param value Double pointer to lookup the value in the given data table, if a equals occurs returns the pointer on it * @return true if the data table is present in the given data table, false otherwise */ -bool lhtbl_lookup(LinkedHashTable *lhtbl, void** value); +bool lhtbl_containsKey(const LinkedHashTable *lhtbl, void** value); + #ifdef __cplusplus } #endif -#endif //COLLECTIONS_COMMONS_LHTBL_H + + +#endif //COLLECTIONS_COMMONS_LHTBL_H \ No newline at end of file diff --git a/headers/list.h b/headers/list.h index f9ec4bd..34d6e3c 100644 --- a/headers/list.h +++ b/headers/list.h @@ -50,7 +50,7 @@ typedef struct LinkedList { * @param right Right value to compare * @return true if left is equals to right, false otherwise */ - int (*match)(const void *left, const void *right); + int (*equals)(const void *left, const void *right); /** * @brief Destroy handle @@ -83,7 +83,7 @@ void list_create(LinkedList *list, void( *destroy)(void *value)); /** * @brief Destroy the specified list, after the call no other further operations will be permit * @param list Reference of the list to destroy false otherwise - * @complexity O(n) where n is the number of elements in the current list + * @complexity O(n) where n is the number of hashtable in the current list */ void list_destroy(LinkedList *list); @@ -120,7 +120,7 @@ LinkedElement* list_get_random(LinkedList *list); /* ----- MACRO C++ COMPATIBILITY -----*/ #ifdef __cplusplus /** - * @brief Inline function that evaluates the number of elements inside the specified list + * @brief Inline function that evaluates the number of hashtable inside the specified list * @return The current element count of the current list * @complexity O(1) */ @@ -187,7 +187,7 @@ inline LinkedElement *list_next(LinkedElement *element){ /* ----- C MACRO -----*/ #else /** - * @brief Macro that evaluates the number of elements inside the specified list + * @brief Macro that evaluates the number of hashtable inside the specified list * @return The current element count of the current list * @complexity O(1) */ diff --git a/headers/queue.h b/headers/queue.h index f03fffb..b14cd6d 100644 --- a/headers/queue.h +++ b/headers/queue.h @@ -46,7 +46,7 @@ bool queue_dequeue(Queue * queue, void *value); #ifdef __cplusplus /*** -* @brief Inline function that evaluates the number of elements inside the specified queue +* @brief Inline function that evaluates the number of hashtable inside the specified queue * @return The current element count of the current list * @complexity O(1) */ @@ -77,7 +77,7 @@ inline void queue_create(Queue * queue, void( *destroy)(void *value)){ /** * @brief Destroy the specified queue, after the call no other further operations will be permit * @param queue Reference of the queue to destroy false otherwise - * @complexity O(n) where n is the number of elements in the current list + * @complexity O(n) where n is the number of hashtable in the current list */ inline void queue_destroy(Queue * queue){ @@ -100,7 +100,7 @@ static inline LinkedElement *queue_peek_random(Queue* queue){ /** * @brief Macro that evaluates queue destruction - * @complexity O(n) where n is the number of elements in the current list + * @complexity O(n) where n is the number of hashtable in the current list */ #define queue_destroy list_destroy @@ -113,7 +113,7 @@ static inline LinkedElement *queue_peek_random(Queue* queue){ #define queue_peek(queue) ((queue)->head == NULL ? NUll : (queue)->head->value) /*** -* @brief Macro that evaluates the number of elements inside the specified queue +* @brief Macro that evaluates the number of hashtable inside the specified queue * @return The current element count of the current list * @complexity O(1) */ diff --git a/headers/set.h b/headers/set.h index 795735c..8410d6b 100644 --- a/headers/set.h +++ b/headers/set.h @@ -21,27 +21,27 @@ typedef LinkedList Set; /** * @brief Create a Set * @param set Set reference to create - * @param match User match function to determine if elements are equals or not - * @param destroy User destroy function to clean set elements on remove + * @param equals User equals function to determine if hashtable are equals or not + * @param destroy User destroy function to clean set hashtable on remove * @complexity O(1) */ -void set_create(Set *set, int (*match)(const void *left, const void *right), void (*destroy)(void *value)); +void set_create(Set *set, int (*equals)(const void *left, const void *right), void (*destroy)(void *value)); /** * @biref Try to insert a value in the given set * @param set Set to insert a value in * @param value Value to insert in the set * @return True if the value was inserted in the given Set, false otherwise - * @complexity O(n) where n is the number of elements inside the given Set to compare with the parameter value + * @complexity O(n) where n is the number of hashtable inside the given Set to compare with the parameter value */ bool set_add(Set *set, const void *value); /** - * @brief Remove from the set a value that match the value parameter then return a pointer to the removed value + * @brief Remove from the set a value that equals the value parameter then return a pointer to the removed value * @param set Set to remove a value in * @param value Reference to the delete value in the given set * @return True if the value was correctly removed, otherwise - * @complexity O(n) where n is the number of elements inside the given Set to compare with the parameter value + * @complexity O(n) where n is the number of hashtable inside the given Set to compare with the parameter value */ bool set_remove(Set *set, void **value); @@ -51,7 +51,7 @@ bool set_remove(Set *set, void **value); * @param left Left Set to compare for union operation * @param right Right Set to compare for union operation * @return true if the union succeed, false otherwise - * @complexity O(mn) where m and n are the number of elements in each operand + * @complexity O(mn) where m and n are the number of hashtable in each operand */ bool set_union(Set *union_result, const Set *left, const Set *right); @@ -61,7 +61,7 @@ bool set_union(Set *union_result, const Set *left, const Set *right); * @param left Left Set to compare for intersection operation * @param right Right Set to compare for intersection operation * @return true if the intersection succeed, false otherwise - * @complexity O(mn) where m and n are the number of elements in each operand + * @complexity O(mn) where m and n are the number of hashtable in each operand */ bool set_intersection(Set *intersection_result, const Set *left, const Set *right); @@ -71,7 +71,7 @@ bool set_intersection(Set *intersection_result, const Set *left, const Set *righ * @param left Left Set to compare for difference operation * @param right Right Set to compare for difference operation * @return true if the difference succeed, false otherwise - * @complexity O(mn) where m and n are the number of elements in each operand + * @complexity O(mn) where m and n are the number of hashtable in each operand */ bool set_difference(Set *difference_result, const Set *left, const Set *right); @@ -80,7 +80,7 @@ bool set_difference(Set *difference_result, const Set *left, const Set *right); * @param set Set to search in * @param value Value to search in the set * @return true if the element is in the set, false otherwise - * @complexity O(n) where n is the number of elements inside the given Set to compare with the parameter value + * @complexity O(n) where n is the number of hashtable inside the given Set to compare with the parameter value */ bool set_is_member(const Set *set, const void *value); @@ -89,7 +89,7 @@ bool set_is_member(const Set *set, const void *value); * @param left Set to determine if it's a subset of right operand * @param right Set to be compared with left operand * @return true if the left Set is a subset of the right Set, false otherwise - * @complexity O(mn) where m and n are the number of elements in each operand + * @complexity O(mn) where m and n are the number of hashtable in each operand */ bool set_is_subset(const Set *left, const Set *right); @@ -98,7 +98,7 @@ bool set_is_subset(const Set *left, const Set *right); * @param left Left Set reference operand * @param right Right Set reference operand * @return true if left and right are equal, false otherwise - * @complexity O(n ^ 2 ) where n is the number of elements inside left AND right + * @complexity O(n ^ 2 ) where n is the number of hashtable inside left AND right */ bool set_is_equal(const Set *left, const Set *right); @@ -116,7 +116,7 @@ static inline int set_size(const Set * set){ /** * @brief Inline function to destroy a set * @param set Set to destroy - * @complexity O(n) where n is the number of elements inside the given Set to destroy + * @complexity O(n) where n is the number of hashtable inside the given Set to destroy */ static inline void set_destroy(Set *set){ list_destroy(set); @@ -140,7 +140,7 @@ static inline LinkedElement * set_get_random(Set* set){ /** * @brief Macro that evaluates destruction of a given set * @param set Set to destroy - * @complexity O(n) where n is the number of elements inside the given Set to destroy + * @complexity O(n) where n is the number of hashtable inside the given Set to destroy */ #define set_destroy(set) list_destroy diff --git a/headers/set_entry.h b/headers/set_entry.h index 89445c9..fd1bf87 100644 --- a/headers/set_entry.h +++ b/headers/set_entry.h @@ -22,13 +22,13 @@ typedef struct KeySetEntry{ }KeySetEntry; /** - * @brief Determine if sets from elements to match are covering ALL elements, if true return the best solution + * @brief Determine if sets from hashtable to equals are covering ALL hashtable, if true return the best solution * @param elements Elements to be covered - * @param elements_to_match Sub sets to determine if they can cover ALL elements - * @param matched_elements Shortest list of elements that match ALL elements - * @return True if elements to match are covering ALL elements, false otherwise + * @param elements_to_equals Sub sets to determine if they can cover ALL hashtable + * @param equalsed_elements Shortest list of hashtable that equals ALL hashtable + * @return True if hashtable to equals are covering ALL hashtable, false otherwise */ -bool set_match_entries(Set *elements, Set* elements_to_match, Set * matched_elements); +bool set_equals_entries(Set *elements, Set* elements_to_equals, Set * equalsed_elements); #ifdef __cplusplus } #endif diff --git a/headers/sort.h b/headers/sort.h index 3de151f..080bf2e 100644 --- a/headers/sort.h +++ b/headers/sort.h @@ -23,7 +23,7 @@ extern "C" { /** * @brief Determine if a generic array is sorted or not * @param value Array to determine if it's sorted or not - * @param element_count Number of elements inside the given array + * @param element_count Number of hashtable inside the given array * @param element_size The size of the enumerable * @param compare User compare function * @return true if the generic array is sorted, false otherwise diff --git a/headers/stack.h b/headers/stack.h index 632b0b9..da7b4e8 100644 --- a/headers/stack.h +++ b/headers/stack.h @@ -73,7 +73,7 @@ inline void stack_create(Stack * stack, void( *destroy)(void *value)){ /** * @brief Destroy the specified stack, after the call no other further operations will be permit * @param stack Reference of the stack to destroy false otherwise - * @complexity O(n) where n is the number of elements in the current list + * @complexity O(n) where n is the number of hashtable in the current list */ inline void stack_destory(Stack * stack){ @@ -109,7 +109,7 @@ return list_get_random(stack); /** * @brief Destroy the specified stack, after the call no other further operations will be permit * @param stack Reference of the stack to destroy false otherwise - * @complexity O(n) where n is the number of elements in the current list + * @complexity O(n) where n is the number of hashtable in the current list */ #define stack_destroy list_destroy diff --git a/src/dlist.c b/src/dlist.c index 531b8c3..ef2a088 100644 --- a/src/dlist.c +++ b/src/dlist.c @@ -28,7 +28,7 @@ void dlist_destroy(DLinkedList *list) { bool dlist_add(DLinkedList *list, DLinkedElement *element, const void *value) { DLinkedElement *new_element = NULL; - // Reject null elements except if list is empty + // Reject null hashtable except if list is empty if (element == NULL && dlist_size(list) != 0) return false; // Allocate a new memory space for the element @@ -56,7 +56,7 @@ bool dlist_add(DLinkedList *list, DLinkedElement *element, const void *value) { bool dlist_add_before(DLinkedList *list, DLinkedElement *element, const void *value) { DLinkedElement *new_element = NULL; - // Reject null elements except if list is empty + // Reject null hashtable except if list is empty if (element == NULL && dlist_size(list) != 0) return false; // Allocate a new memory space for the element diff --git a/src/htbl.c b/src/htbl.c new file mode 100644 index 0000000..f8195d9 --- /dev/null +++ b/src/htbl.c @@ -0,0 +1,95 @@ +// +// Created by maxim on 28/02/2024. +// +#include "htbl.h" + +int cmp_int(const void *a, const void *b){ + int result; + +#ifdef __x86_64__ + asm volatile ( + "xor %[result], %[result]\n\t" + "cmp %[key1], %[key2]\n\t" + "sete %%al\n\t" + "movzb %%al, %[result]\n\t" + : [result] "+r" (result) + : [key1] "r" (*(int*)a), [key2] "r" (*(int*)b) + : "cc", "al" + ); +#endif + +#ifdef __AVR__ + asm volatile ( + "clr r24\n\t" + "cpse %[ref], r24\n\t" + "ldi %[hash], 1\n\t" + "rjmp end\n\t" + "ldi %[hash], 0\n\t" + "end:\n\t" + : [hash] "=r" (hash) + : [ref] "r" (ref) + : "r24" + ); +#endif + +#ifdef __riscv + asm volatile ( + "sub %[ref], %[ref], %[ref]\n\t" + "bgez %[ref], greater_or_equal\n\t" + "li %[hash], 0\n\t" + "j end\n\t" + "greater_or_equal:\n\t" + "li %[hash], 1\n\t" + "end:\n\t" + : [hash] "=r" (hash) + : [ref] "r" (ref) + : "t0" + ); +#endif + +#ifdef __ARM_ARCH + asm volatile ( + "sub %[ref], %[ref], %[ref]\n\t" + "bge %[ref], greater_or_equal\n\t" + "mov %[hash], #0\n\t" + "b end\n\t" + "greater_or_equal:\n\t" + "mov %[hash], #1\n\t" + "end:\n\t" + : [hash] "=r" (hash) + : [ref] "r" (ref) + : "cc" + ); +#endif + + return result; +} + +int hashref(int table_size, const void *ref) { + const double phi = (sqrt(5) - 1) / 2; + intptr_t address = (intptr_t) ref; + + return (int) (table_size * (int)( (int) address * phi)); +} + +int hashpjw(int table_size, const void* key){ + const char * string; + int value; + + // hash the key the bit to bit operations + + value = 0; + string = key; + + while(*string != '\0'){ + int temp; + value = (value<<4) + (*string); + if(temp=(value & 0xf0000000)){ + value = value ^(temp >> 24); + value = value ^temp; + } + string++; + } + + return (int) (value % table_size); +} \ No newline at end of file diff --git a/src/lhtbl.c b/src/lhtbl.c new file mode 100644 index 0000000..8e2ed2a --- /dev/null +++ b/src/lhtbl.c @@ -0,0 +1,108 @@ +// +// Created by maxim on 28/02/2024. +// + +#include "lhtbl.h" + +bool lhtbl_create(LinkedHashTable *lhtbl, + int containers, + int (*hash)(int table_size, const void *key), + int (*equals)(const void* key1, const void* key2), + void(*destroy)(void *value)){ + + int i; + + // Allocate memory space for the linked hash table + + if((lhtbl->hashtable = (LinkedList *) malloc(containers * sizeof(LinkedList))) == NULL) return false; + + // Creating containers + lhtbl->containers = containers; + + for(i = 0; i< lhtbl->containers;i++) + list_create(&lhtbl->hashtable[i], destroy); + + lhtbl->hash = hash; + lhtbl->equals = equals; + lhtbl->destroy = destroy; + lhtbl->size = 0; + + return true; +} + +void lhtbl_destroy(LinkedHashTable *lhtbl){ + int i; + + for(i=0;isize;i++) + list_destroy(&lhtbl->hashtable[i]); + + // Cleaning the memory location allocate to the internal hashtable + + free(lhtbl->hashtable); + + // Erasing the structure in case of + memset(lhtbl, 0, sizeof(LinkedHashTable)); +} + +bool lhtbl_put(LinkedHashTable *lhtbl, const void* value){ + void *temp; + int container; + bool result = false; + + temp = (void *) value; + // If the value is already in the table return false + if(lhtbl_containsKey(lhtbl, &temp)) return result; + + // Hash the given key with the user function + container = lhtbl->hash(lhtbl->size, value) % lhtbl->containers; + + // Add the value inside the result container + + if((result = list_add(&lhtbl->hashtable[container], NULL, value))) lhtbl->size++; + + return result; +} + +bool lhtbl_remove(LinkedHashTable *lhtbl, void** value){ + LinkedElement *current_element,*last_element; + int current_container; + current_container = lhtbl->hash(lhtbl->size, *value) % lhtbl->containers; + + // Search for the value inside the current container + last_element = NULL; + + for(current_element= list_first(&lhtbl->hashtable[current_container]); current_element != NULL; current_element = list_next(current_element)){ + // If the target value if equals to the current container element, then remove it + if(lhtbl->equals(*value, list_value(current_element))){ + // Remove the value from the current container + if(list_remove(&lhtbl->hashtable[current_container], last_element, value)){ + lhtbl->size--; + return true; + // Can't remove the data from the current container + }else return false; + } + last_element = current_element; + } + + // The given value to remove has not been found in the given linked hash table + return false; +} + +bool lhtbl_containsKey(const LinkedHashTable *lhtbl, void** value){ + LinkedElement *current_element; + int current_container; + + // Hash the given key value + current_container = lhtbl->hash(lhtbl->size, *value) % lhtbl->containers; + + // Search the value inside the current container + + for(current_element= list_first(&lhtbl->hashtable[current_container]); current_element != NULL; current_element= list_next(current_element) ){ + if(lhtbl->equals(*value, list_value(current_element))){ + *value = list_value(current_element); + return true; + } + } + + return false; +} \ No newline at end of file diff --git a/src/list.c b/src/list.c index 1320fc7..9c10c07 100644 --- a/src/list.c +++ b/src/list.c @@ -14,7 +14,7 @@ void list_create(LinkedList *list, void( *destroy)(void *value)) { } void list_destroy(LinkedList *list) { - // Remove each elements + // Remove each hashtable void **value = NULL; while (list_size(list) > 0) { if (list_remove(list, NULL, (void **) &value) && list->destroy != NULL) { diff --git a/src/set.c b/src/set.c index f6ffe1a..ed43cb2 100644 --- a/src/set.c +++ b/src/set.c @@ -15,7 +15,7 @@ bool set_match_entries(Set *elements, Set* elements_to_match, Set * matched_elem uint32_t max_size; // Initialize the set cover - set_create(matched_elements, elements_to_match->match, NULL); + set_create(matched_elements, elements_to_match->equals, NULL); // Continue until there are non-covering elements and candidates @@ -60,9 +60,9 @@ bool set_match_entries(Set *elements, Set* elements_to_match, Set * matched_elem return true; } -void set_create(Set *set, int (*match)(const void *left, const void *right), void (*destroy)(void *value)){ +void set_create(Set *set, int (*equals)(const void *left, const void *right), void (*destroy)(void *value)){ list_create(set, destroy); - set->match = match; + set->equals = equals; } bool set_add(Set *set, const void *value){ @@ -78,7 +78,7 @@ bool set_remove(Set *set, void **value){ // Search for a value to remove for(current_element= list_first(set);current_element!=NULL;current_element= list_next(current_element)){ - if(set->match(*value, list_value(current_element))) + if(set->equals(*value, list_value(current_element))) break; element_to_remove = current_element; } @@ -96,7 +96,7 @@ bool set_union(Set *union_result, const Set *left, const Set *right){ void * value; // Create the union set - set_create(union_result, left->match, NULL); + set_create(union_result, left->equals, NULL); // Insertion of left set elements for(current_element = list_first(left);current_element!=NULL;current_element= list_next(current_element)){ @@ -128,7 +128,7 @@ bool set_intersection(Set *intersection_result, const Set *left, const Set *righ // Create the intersection Set - set_create(intersection_result, left->match, NULL); + set_create(intersection_result, left->equals, NULL); // intersection of elements in left and right set @@ -150,7 +150,7 @@ bool set_difference(Set *difference_result, const Set *left, const Set *right){ void * value; // Creation of the difference Set - set_create(difference_result, left->match, NULL); + set_create(difference_result, left->equals, NULL); // Insert elements of left non present in right for(current_element = list_first(left);current_element != NULL;current_element= list_next(current_element)){ @@ -172,8 +172,8 @@ bool set_is_member(const Set *set, const void *value){ // Determine if the value is in set for(current_element = list_first(set); current_element != NULL;current_element= list_next(current_element)){ - // If any match occurs, then return false - if(set->match(value, list_value(current_element))) return false; + // If any equals occurs, then return false + if(set->equals(value, list_value(current_element))) return false; } return true; } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index f79b34a..49bf59b 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -16,4 +16,4 @@ include_directories(${PROJECT_SOURCE_DIR}/headers) add_executable(${PROJECT_NAME} ${TEST_SOURCES_FILES} ${TEST_HEADERS_FILES} main.cpp) add_dependencies(${PROJECT_NAME} ${CMAKE_PROJECT_NAME}) -target_link_libraries(${PROJECT_NAME} gtest gtest_main ${CMAKE_PROJECT_NAME}) +target_link_libraries(${PROJECT_NAME} gtest gtest_main collections_commons) diff --git a/tests/headers/LinkedHashTable_Test.h b/tests/headers/LinkedHashTable_Test.h new file mode 100644 index 0000000..867bfab --- /dev/null +++ b/tests/headers/LinkedHashTable_Test.h @@ -0,0 +1,74 @@ +// +// Created by maxim on 28/02/2024. +// + +#ifndef COLLECTIONS_COMMONS_LINKEDHASHTABLE_TEST_H +#define COLLECTIONS_COMMONS_LINKEDHASHTABLE_TEST_H +#include +#include "lhtbl.h" + +class LinkedHashTableTest : public ::testing::Test +{ +protected: + typedef struct Page { + int numero; + int reference; + } Page; + + LinkedHashTable *lhtbl; + + static void destroy(void *value); + + void SetUp() override { + ; + if(( lhtbl = (LinkedHashTable*) malloc(sizeof (LinkedHashTable))) != nullptr){ + lhtbl_create(lhtbl, 10, hashref, cmp_int, destroy); + }else{ + throw_exception(); + } + + } + + void TearDown() override { + lhtbl_destroy(lhtbl); + } +}; + +void LinkedHashTableTest::destroy(void *value) { + free(value); +} + +TEST_F(LinkedHashTableTest, TestHashRefFunction) { + int hash_val = hashref(2000, (void*)12345); + EXPECT_TRUE(hash_val != 0); +} + +TEST_F(LinkedHashTableTest, TestLhtblPutAndGet) { + Page* page = (Page*)malloc(sizeof(Page)); + page->numero = 1; + page->reference = 100; + + ASSERT_TRUE(lhtbl_put(lhtbl, page)); + + void* value = nullptr; + ASSERT_TRUE(lhtbl_containsKey(lhtbl, &value)); + Page* retrieved_page = (Page*)value; + EXPECT_EQ(retrieved_page->numero, page->numero); + EXPECT_EQ(retrieved_page->reference, page->reference); +} + +TEST_F(LinkedHashTableTest, TestLhtblRemove) { + Page* page = (Page*)malloc(sizeof(Page)); + page->numero = 1; + page->reference = 100; + + ASSERT_TRUE(lhtbl_put(lhtbl, page)); + + void* value = (void*)&page; + ASSERT_TRUE(lhtbl_remove(lhtbl, &value)); + + Page* removed_page = (Page*)value; + EXPECT_EQ(removed_page->numero, page->numero); + EXPECT_EQ(removed_page->reference, page->reference); +} +#endif //COLLECTIONS_COMMONS_LINKEDHASHTABLE_TEST_H diff --git a/tests/main.cpp b/tests/main.cpp index 0e77eb4..106959a 100644 --- a/tests/main.cpp +++ b/tests/main.cpp @@ -9,6 +9,7 @@ #include "Queue_Test.h" #include "EventBus_Test.h" #include "Exception_Test.h" +#include "LinkedHashTable_Test.h" int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); diff --git a/third-party/googletest b/third-party/googletest index 9d43b27..3397167 160000 --- a/third-party/googletest +++ b/third-party/googletest @@ -1 +1 @@ -Subproject commit 9d43b27f7a873596496a2ea70721b3f9eb82df01 +Subproject commit 339716709c7526f6efec605f3d241d5918e61857 From cb9dde95571901b4a16f03a3f0aecfc2eca2cfdd Mon Sep 17 00:00:00 2001 From: nakira974 Date: Wed, 28 Feb 2024 16:43:47 +0100 Subject: [PATCH 08/27] Fixed LinkedHashTable_Test.h and linked hash tables --- headers/htbl.h | 8 +-- headers/lhtbl.h | 8 +-- src/htbl.c | 78 +++++----------------------- src/lhtbl.c | 10 ++-- tests/headers/LinkedHashTable_Test.h | 6 +-- 5 files changed, 30 insertions(+), 80 deletions(-) diff --git a/headers/htbl.h b/headers/htbl.h index 9b300c2..b8bf8ab 100644 --- a/headers/htbl.h +++ b/headers/htbl.h @@ -24,7 +24,7 @@ extern "C" { * @author P.J. WEINBERGER * @see 'Compilers : Principles, Technics and Tools' from Alfred V. AHO */ -int hashpjw(int table_size, const void* key); +int hashpjw(const void* key); /** * @brief Hashes the memory address of a reference and returns it as a uint64_t value @@ -32,15 +32,15 @@ int hashpjw(int table_size, const void* key); * @param ref The reference whose address is to be hashed * @return The hashed value of the reference address */ -int hashref(int table_size, const void *ref); +int hashref(const void *ref); /** * Inline assembly implementation of integer comparison. * @param a Pointer to the first value * @param b Pointer to the second value - * @return Result of the comparison + * @return true if two numbers are stricly equals, false otherwise */ -int cmp_int(const void *a, const void *b); +bool cmp_int(const void *a, const void *b); #ifdef __cplusplus diff --git a/headers/lhtbl.h b/headers/lhtbl.h index 6182ccf..986b198 100644 --- a/headers/lhtbl.h +++ b/headers/lhtbl.h @@ -38,7 +38,7 @@ typedef struct LinkedHashTable{ * @param key The key to be hashed * @return The hashed value of the key */ - int (*hash)(int table_size, const void *key); + int (*hash)(const void *key); /** * @brief Pointer to the equals function for hashtable @@ -46,7 +46,7 @@ typedef struct LinkedHashTable{ * @param key2 The second key to be compared * @return 0 if the keys equals, non-zero otherwise */ - int (*equals)(const void* key1, const void* key2); + bool (*equals)(const void* key1, const void* key2); /** * @brief Pointer to the destroy function for hashtable @@ -95,8 +95,8 @@ inline int lhtbl_size(LinkedHashTable *queue){ */ bool lhtbl_create(LinkedHashTable *lhtbl, int containers, - int (*hash)(int table_size, const void *key), - int (*equals)(const void* key1, const void* key2), + int (*hash)(const void *key), + bool (*equals)(const void* key1, const void* key2), void(*destroy)(void *value)); /** diff --git a/src/htbl.c b/src/htbl.c index f8195d9..5f3d48a 100644 --- a/src/htbl.c +++ b/src/htbl.c @@ -3,76 +3,26 @@ // #include "htbl.h" -int cmp_int(const void *a, const void *b){ - int result; - -#ifdef __x86_64__ - asm volatile ( - "xor %[result], %[result]\n\t" - "cmp %[key1], %[key2]\n\t" - "sete %%al\n\t" - "movzb %%al, %[result]\n\t" - : [result] "+r" (result) - : [key1] "r" (*(int*)a), [key2] "r" (*(int*)b) - : "cc", "al" - ); -#endif - -#ifdef __AVR__ - asm volatile ( - "clr r24\n\t" - "cpse %[ref], r24\n\t" - "ldi %[hash], 1\n\t" - "rjmp end\n\t" - "ldi %[hash], 0\n\t" - "end:\n\t" - : [hash] "=r" (hash) - : [ref] "r" (ref) - : "r24" - ); -#endif - -#ifdef __riscv - asm volatile ( - "sub %[ref], %[ref], %[ref]\n\t" - "bgez %[ref], greater_or_equal\n\t" - "li %[hash], 0\n\t" - "j end\n\t" - "greater_or_equal:\n\t" - "li %[hash], 1\n\t" - "end:\n\t" - : [hash] "=r" (hash) - : [ref] "r" (ref) - : "t0" - ); -#endif - -#ifdef __ARM_ARCH - asm volatile ( - "sub %[ref], %[ref], %[ref]\n\t" - "bge %[ref], greater_or_equal\n\t" - "mov %[hash], #0\n\t" - "b end\n\t" - "greater_or_equal:\n\t" - "mov %[hash], #1\n\t" - "end:\n\t" - : [hash] "=r" (hash) - : [ref] "r" (ref) - : "cc" - ); -#endif - - return result; +bool cmp_int(const void *a, const void *b){ + if(a ==NULL || b == NULL ) return -1; + int* intA = (int*)a; + int* intB = (int*)b; + + if (*intA == *intB) { + return true; + } else { + return false; + } } -int hashref(int table_size, const void *ref) { +int hashref(const void *ref) { const double phi = (sqrt(5) - 1) / 2; intptr_t address = (intptr_t) ref; - return (int) (table_size * (int)( (int) address * phi)); + return ((int)( (int) address * phi)); } -int hashpjw(int table_size, const void* key){ +int hashpjw(const void* key){ const char * string; int value; @@ -91,5 +41,5 @@ int hashpjw(int table_size, const void* key){ string++; } - return (int) (value % table_size); + return (int) (value); } \ No newline at end of file diff --git a/src/lhtbl.c b/src/lhtbl.c index 8e2ed2a..0ee24d4 100644 --- a/src/lhtbl.c +++ b/src/lhtbl.c @@ -6,8 +6,8 @@ bool lhtbl_create(LinkedHashTable *lhtbl, int containers, - int (*hash)(int table_size, const void *key), - int (*equals)(const void* key1, const void* key2), + int (*hash)(const void *key), + bool (*equals)(const void* key1, const void* key2), void(*destroy)(void *value)){ int i; @@ -54,7 +54,7 @@ bool lhtbl_put(LinkedHashTable *lhtbl, const void* value){ if(lhtbl_containsKey(lhtbl, &temp)) return result; // Hash the given key with the user function - container = lhtbl->hash(lhtbl->size, value) % lhtbl->containers; + container = lhtbl->hash(value) % lhtbl->containers; // Add the value inside the result container @@ -66,7 +66,7 @@ bool lhtbl_put(LinkedHashTable *lhtbl, const void* value){ bool lhtbl_remove(LinkedHashTable *lhtbl, void** value){ LinkedElement *current_element,*last_element; int current_container; - current_container = lhtbl->hash(lhtbl->size, *value) % lhtbl->containers; + current_container = lhtbl->hash(*value) % lhtbl->containers; // Search for the value inside the current container last_element = NULL; @@ -93,7 +93,7 @@ bool lhtbl_containsKey(const LinkedHashTable *lhtbl, void** value){ int current_container; // Hash the given key value - current_container = lhtbl->hash(lhtbl->size, *value) % lhtbl->containers; + current_container = lhtbl->hash(*value) % lhtbl->containers; // Search the value inside the current container diff --git a/tests/headers/LinkedHashTable_Test.h b/tests/headers/LinkedHashTable_Test.h index 867bfab..ad40478 100644 --- a/tests/headers/LinkedHashTable_Test.h +++ b/tests/headers/LinkedHashTable_Test.h @@ -39,7 +39,7 @@ void LinkedHashTableTest::destroy(void *value) { } TEST_F(LinkedHashTableTest, TestHashRefFunction) { - int hash_val = hashref(2000, (void*)12345); + int hash_val = hashref((void*)12345); EXPECT_TRUE(hash_val != 0); } @@ -50,7 +50,7 @@ TEST_F(LinkedHashTableTest, TestLhtblPutAndGet) { ASSERT_TRUE(lhtbl_put(lhtbl, page)); - void* value = nullptr; + void* value = page; ASSERT_TRUE(lhtbl_containsKey(lhtbl, &value)); Page* retrieved_page = (Page*)value; EXPECT_EQ(retrieved_page->numero, page->numero); @@ -64,7 +64,7 @@ TEST_F(LinkedHashTableTest, TestLhtblRemove) { ASSERT_TRUE(lhtbl_put(lhtbl, page)); - void* value = (void*)&page; + void* value = (void*) page; ASSERT_TRUE(lhtbl_remove(lhtbl, &value)); Page* removed_page = (Page*)value; From e001b534d715a08159f8054b41c57c7d69e153d1 Mon Sep 17 00:00:00 2001 From: nakira974 Date: Wed, 28 Feb 2024 16:46:26 +0100 Subject: [PATCH 09/27] update .gitignore --- .gitignore | 1 + third-party/googletest | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index aef5dc1..bbe498d 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ /bin /thrid-party/ /mingw32_x86_build/ +/third-party/ diff --git a/third-party/googletest b/third-party/googletest index 3397167..9d43b27 160000 --- a/third-party/googletest +++ b/third-party/googletest @@ -1 +1 @@ -Subproject commit 339716709c7526f6efec605f3d241d5918e61857 +Subproject commit 9d43b27f7a873596496a2ea70721b3f9eb82df01 From 1f724e8581387c3bece6a8c1bc964b8c85429ebd Mon Sep 17 00:00:00 2001 From: nakira974 Date: Wed, 28 Feb 2024 18:58:15 +0100 Subject: [PATCH 10/27] Add hashmap.h --- headers/hashmap.h | 303 +++++++++++++++++++++++++++ headers/htbl.h | 10 +- headers/list.h | 4 +- tests/headers/LinkedHashTable_Test.h | 10 +- 4 files changed, 317 insertions(+), 10 deletions(-) create mode 100644 headers/hashmap.h diff --git a/headers/hashmap.h b/headers/hashmap.h new file mode 100644 index 0000000..4e2e70a --- /dev/null +++ b/headers/hashmap.h @@ -0,0 +1,303 @@ +/** + * @file sort.h + * @brief This file contains the API for hashmaps in C + * @author Maxime Loukhal + * @date 28/02/2024 + */ +#ifndef COLLECTIONS_COMMONS_HASHMAP_H +#define COLLECTIONS_COMMONS_HASHMAP_H + +#include "lhtbl.h" +#include "set.h" + +/** + * @brief Hashmap Key-Value pair entry + */ +typedef struct SimpleEntry { + /** + * @brief Entry identifier + */ + void *key; + /** + * @brief Identifier value + */ + void *value; + + /** + * @brief Next entry in the hashmap + */ + struct SimpleEntry *next; +} SimpleEntry; + +/** + * @brief Data structure to map a specific key with its associated value + */ +typedef struct HashMap { + /** + * @brief Key-Value pairs collection + */ + LinkedList *map; + /** + * @brief Internal key hashtable + */ + LinkedHashTable *hashTable; + /** + * @brief First entry in the hashmap + */ + SimpleEntry *head; + /** + * @brief Last entry in the hashmap + */ + SimpleEntry *tail; + /** + * @brief Hashmap current size + */ + int size; + + /** + * @brief Pointer to the User Keys equals function for hashmap + * @param key1 The first key to be compared + * @param key2 The second key to be compared + * @return true if the keys equals, false otherwise + */ + bool (*equals)(const void *key1, const void *key2); + + /** + * @brief Pointer to the destroy function for hashmap + * @param value The value to be destroyed + */ + void (*destroy)(void *value); +} HashMap; + +/** + * @brief Tries to allocate a new hashmap + * @param map hashmap to be created + * @param containers The number of containers in the internal hashtable of the hashmap + * @param hash Key hash function + * @param equals Key equals function + * @param destroy Entry destroy function + * @return true if the hashmap was created successfully, false otherwise + */ +bool hashmap_create(HashMap *map, + int containers, + int (*hash)(const void *key), + bool (*equals)(const void* key1, const void* key2), + void(*destroy)(void *value)); + +/** + * @brief Destroy the given hashmap and all its entries + * @param map The hashmap to be destroyed + */ +void hashmap_destroy(HashMap *map); + +/** + * @brief Associates the specified value to the specified key in the given hashmap if the key isn't already present + * @param map Hashmap to add an entry in + * @param key Key to be added with the specified value in the given hashmap + * @param value Value to be added with the specified key in the given hashmap + * @return true if the given key value pair was added, false otherwise + */ +bool hashmap_put(HashMap *map, void *key, void *value); + +/** + * @brief Puts an entry at the end of the given hashmap + * @param map Hashmap to add an entry in + * @param entry Entry to be added in the given hashmap + * @return true if the given entry was added, false otherwise + */ +bool hashmap_addEntry(HashMap *map, SimpleEntry *entry); + +/** + * @brief Compute the put operation only if the target key isn't already in the given hashmap + * @param map Hashmap to put a value if absent in + * @param key Key to put if absent in the given hashmap + * @param value Value of the key to put if absent in the given hashmap + * @return true if key value pair has been added to the given hashmap, false otherwise + */ +bool hashmap_putIfAbsent(HashMap *map, void *key, void *value); + +/** + * @brief Replace the value of a target key in a given hashmap + * @param map Hashmap to replace a key value in + * @param key Key to replace the value + * @param new_value New value of the key + * @param old_value Pointer on the old key value + * @return true if the replace occurs + */ +bool hashmap_replace(HashMap *map, void *key, void *new_value, void** old_value); + +/** + * @brief Remove a given entry from the current hashmap, then returns a pointer on the value of the deleted element + * @param map Reference of the hashmap to remove an element + * @param value Double pointer of the key to delete, if deletion occurs returns pointer on the value of the deleted entry value + * @return true if the element was correctly removed, false otherwise + */ +bool hashmap_remove(HashMap *map, void** value); + +/** + * @brief Remove a given entry from the current hashmap, then returns a pointer on the value of the deleted element + * @param map Reference of the hashmap to remove an element + * @param element Entry of the hashmap to be removed + * @param value Output pointer on the value of the deleted entry value + * @return true if the element was correctly removed, false otherwise + */ +bool hashmap_removeEntry( HashMap *map, SimpleEntry *entry, void **value); + +/** + * @brief Test if the given value is present in the hashmap, if a equals occurs value will contain the pointer on the equalsed value + * @param map Hashmap to lookup in + * @param value Double pointer to remove the key in the given hashmap, if a delete occurs returns the pointer on it + * @return true if the data table is present in the given hashmap, false otherwise + */ +bool hashmap_containsKey(const HashMap *map, void** value); + +/** + * @brief Returns the keys of the given hashmap as set + * @param map Hashmap to get keys as set + * @return A set of the given hashmap keys + */ +Set * hashmap_keySet(HashMap *map); + +/** + * @brief Returns entries of the given hashmap as set + * @param map Hashmap to get entries as set + * @return A set of the given hashmap entries + */ +Set * hashmap_entrySet(HashMap *map); + +#ifdef __cplusplus +/** + * @brief Inline function that evaluates the number of hashtable inside the specified hashmap + * @return The current entry count of the current hashmap + * @complexity O(1) + */ +inline int hashmap_size(HashMap *hashmap){ + return hashmap->size; +}; + + +/** + * @brief Inline function that evaluates the first entry of the specified hashmap + * @return The first entry of the current hashmap + * @complexity O(1) + */ +inline HashMap* hashmap_first(HashMap * hashmap){ + return hashmap->head; +}; + +/** + * @brief Inline function that evaluates the last entry of the specified hashmap + * @return The last entry of the current hashmap + * @complexity O(1) + */ +inline HashMap * hashmap_last(HashMap * hashmap){ + return hashmap->tail; +}; + +/** + * @brief Inline function that evaluates if the specified entry is the first entry of the specified hashmap + * @return true if the entry is the first of the current hashmap, false otherwise + * @complexity O(1) + */ +inline bool hashmap_is_first(LinkedList * hashmap, SimpleEntry *entry){ + return (hashmap)->head == entry; +}; + +/** + * @brief Inline function that evaluates if the specified entry is the last entry of the specified hashmap + * @return true if the entry is the last of the current hashmap, false otherwise + * @complexity O(1) + */ +inline bool hashmap_is_last(HashMap * hashmap, SimpleEntry *entry){ + return (hashmap)->tail == entry; +}; + +/** + * @brief Inline function that evaluates the value of a hashmap entry + * @return The value stored inside a hashmap entry + * @complexity O(1) + */ +inline void *hashmap_get(void * key){ + return ((entry)->value); +}; + +/** + * @brief Inline function that evaluates the next entry of the current hashmap entry + * @return The reference to the next entry of the current hashmap entry + * @complexity O(1) + */ +inline SimpleEntry *hashmap_next(SimpleEntry *entry){ + if (entry == nullptr) return nullptr; + else return (entry)->next == nullptr ? nullptr : (entry)->next; +} + +/** + * @brief Inline function that check if the given value is present in the hashmap, if a equals occurs value will contain the pointer on the equalsed value + * @param map Hashmap to lookup in + * @param value Double pointer to remove the key in the given hashmap, if a equals occurs returns the pointer on it + * @return true if the data table is present in the given hashmap, false otherwise + */ +inline bool hashmap_get(const HashMap *map, void** value){ + return hashmap_containsKey(map, value); +}; +#else +/** + * @brief Macro that evaluates the number of hashtable inside the specified hashmap + * @return The current entry count of the current hashmap + * @complexity O(1) + */ +#define hashmap_size(hashmap) ((hashmap)->size) + +/** + * @brief Macro that evaluates the first entry of the specified hashmap + * @return The first entry of the current hashmap + * @complexity O(1) + */ +#define hashmap_first(hashmap) ((hashmap)->head) + +/** + * @brief Macro that evaluates the last entry of the specified hashmap + * @return The last entry of the current hashmap + * @complexity O(1) + */ +#define hashmap_last(hashmap) ((hashmap)->tail) + +/** + * @brief Macro that evaluates if the specified entry is the first entry of the specified hashmap + * @return true if the entry is the first of the current hashmap, false otherwise + * @complexity O(1) + */ +#define hashmap_is_first(hashmap, entry) ((entry) == (hashmap)->head ? true : false ) + +/** + * @brief Macro that evaluates if the specified entry is the last entry of the specified hashmap + * @return true if the entry is the last of the current hashmap, false otherwise + * @complexity O(1) + */ +#define hashmap_is_last(hashmap, entry) ((entry) == (hashmap)->tail ? true : false ) + +/** + * @brief Macro that evaluates the value of a hashmap entry + * @return The value stored inside a hashmap entry + * @complexity O(1) + */ +#define hashmap_value(entry) ((entry)->value) + + +/** + * @brief Macro that evaluates the next entry of the current hashmap entry + * @return The reference to the next entry of the current hashmap entry + * @complexity O(1) + */ +#define hashmap_next(entry) ((entry)->next) + +/** + * @brief Macro that evaluates if the given value is present in the hashmap, if a equals occurs value will contain the pointer on the equalsed value + * @param map Hashmap to lookup in + * @param value Double pointer to remove the key in the given hashmap, if a equals occurs returns the pointer on it + * @return true if the data table is present in the given hashmap, false otherwise + */ +#define hashmap_get(map,value) hashmap_containsKey +#endif + +#endif //COLLECTIONS_COMMONS_HASHMAP_H diff --git a/headers/htbl.h b/headers/htbl.h index b8bf8ab..39b49cb 100644 --- a/headers/htbl.h +++ b/headers/htbl.h @@ -1,7 +1,9 @@ -// -// Created by maxim on 28/02/2024. -// - +/** + * @file sort.h + * @brief This file contains the API for hash tables functions + * @author Maxime Loukhal + * @date 27/02/2024 + */ #ifndef COLLECTIONS_COMMONS_HTBL_H #define COLLECTIONS_COMMONS_HTBL_H diff --git a/headers/list.h b/headers/list.h index 34d6e3c..2d817b6 100644 --- a/headers/list.h +++ b/headers/list.h @@ -107,13 +107,13 @@ bool list_add(LinkedList *list, LinkedElement *element, const void *value); * @complexity O(1) * @return true if the element was correctly removed, false otherwise */ -bool list_remove(LinkedList *list, LinkedElement *element, void **value); +bool list_remove( LinkedList*list, LinkedElement *element, void **value); /** * @brief Returns a random element from the given list * @param list List to return a random element from * @param random_element Reference to a random element - * @return true if a random element has been returned, false otherwise + * @return true if a random element was returned, false otherwise */ LinkedElement* list_get_random(LinkedList *list); diff --git a/tests/headers/LinkedHashTable_Test.h b/tests/headers/LinkedHashTable_Test.h index ad40478..a9fcd41 100644 --- a/tests/headers/LinkedHashTable_Test.h +++ b/tests/headers/LinkedHashTable_Test.h @@ -1,7 +1,9 @@ -// -// Created by maxim on 28/02/2024. -// - +/** + * @file sort.h + * @brief This file contains the API for page frames management + * @author Maxime Loukhal + * @date 24/02/2024 + */ #ifndef COLLECTIONS_COMMONS_LINKEDHASHTABLE_TEST_H #define COLLECTIONS_COMMONS_LINKEDHASHTABLE_TEST_H #include From d1f9a99292fa0061bf196f5b2db2d52eeffd4161 Mon Sep 17 00:00:00 2001 From: nakira974 Date: Wed, 28 Feb 2024 23:02:02 +0100 Subject: [PATCH 11/27] Add hashmap.c --- headers/clist.h | 9 +++ headers/dlist.h | 8 ++ headers/hashmap.h | 9 +-- headers/{htbl.h => hashset.h} | 7 +- headers/{lhtbl.h => lhashset.h} | 10 +-- headers/list.h | 9 +++ src/clist.c | 19 +++++ src/dlist.c | 17 ++++ src/hashmap.c | 113 +++++++++++++++++++++++++++ src/{htbl.c => hashset.c} | 4 +- src/{lhtbl.c => lhashset.c} | 2 +- src/list.c | 18 +++++ tests/headers/LinkedHashTable_Test.h | 2 +- 13 files changed, 209 insertions(+), 18 deletions(-) rename headers/{htbl.h => hashset.h} (89%) rename headers/{lhtbl.h => lhashset.h} (95%) create mode 100644 src/hashmap.c rename src/{htbl.c => hashset.c} (92%) rename src/{lhtbl.c => lhashset.c} (99%) diff --git a/headers/clist.h b/headers/clist.h index f6e431c..15a89c7 100644 --- a/headers/clist.h +++ b/headers/clist.h @@ -117,6 +117,15 @@ bool clist_remove(CLinkedList *list, CLinkedElement *element, void **value); */ CLinkedElement * clist_get_random(CLinkedList *list); +/** + * @brief Replace a specified element from the given list with the specified value + * @param list List where to replace the element value + * @param element Element to replace the value + * @param value Value to replace + * @return true if the given element's value was replaces, false otherwise + */ +bool clist_replace(CLinkedList *list, CLinkedElement *element, void **value); + /* ----- MACRO C++ COMPATIBILITY -----*/ #ifdef __cplusplus /*** diff --git a/headers/dlist.h b/headers/dlist.h index 0e415f3..4d79f54 100644 --- a/headers/dlist.h +++ b/headers/dlist.h @@ -135,6 +135,14 @@ bool dlist_remove(DLinkedList *list, DLinkedElement *element, void **value); */ DLinkedElement * dlist_get_random(DLinkedList *list); +/** + * @brief Replace a specified element from the given list with the specified value + * @param list List where to replace the element value + * @param element Element to replace the value + * @param value Value to replace + * @return true if the given element's value was replaces, false otherwise + */ +bool dlist_replace(DLinkedList *list, DLinkedElement *element, void **value); /* ----- MACRO C++ COMPATIBILITY -----*/ #ifdef __cplusplus diff --git a/headers/hashmap.h b/headers/hashmap.h index 4e2e70a..be9b298 100644 --- a/headers/hashmap.h +++ b/headers/hashmap.h @@ -7,7 +7,7 @@ #ifndef COLLECTIONS_COMMONS_HASHMAP_H #define COLLECTIONS_COMMONS_HASHMAP_H -#include "lhtbl.h" +#include "lhashset.h" #include "set.h" /** @@ -33,10 +33,7 @@ typedef struct SimpleEntry { * @brief Data structure to map a specific key with its associated value */ typedef struct HashMap { - /** - * @brief Key-Value pairs collection - */ - LinkedList *map; + /** * @brief Internal key hashtable */ @@ -124,7 +121,7 @@ bool hashmap_putIfAbsent(HashMap *map, void *key, void *value); * @param old_value Pointer on the old key value * @return true if the replace occurs */ -bool hashmap_replace(HashMap *map, void *key, void *new_value, void** old_value); +bool hashmap_replace(HashMap *map, void *key,void** value); /** * @brief Remove a given entry from the current hashmap, then returns a pointer on the value of the deleted element diff --git a/headers/htbl.h b/headers/hashset.h similarity index 89% rename from headers/htbl.h rename to headers/hashset.h index 39b49cb..a77f634 100644 --- a/headers/htbl.h +++ b/headers/hashset.h @@ -4,8 +4,8 @@ * @author Maxime Loukhal * @date 27/02/2024 */ -#ifndef COLLECTIONS_COMMONS_HTBL_H -#define COLLECTIONS_COMMONS_HTBL_H +#ifndef COLLECTIONS_COMMONS_HASHSET_H +#define COLLECTIONS_COMMONS_HASHSET_H #ifdef __cplusplus extern "C" { @@ -17,6 +17,7 @@ extern "C" { #include #include #endif +#include "lhashset.h" /** * @brief PJW method to convert the given key into a permuted integer using consecutive XOR shifts @@ -49,4 +50,4 @@ bool cmp_int(const void *a, const void *b); } #endif -#endif //COLLECTIONS_COMMONS_HTBL_H +#endif //COLLECTIONS_COMMONS_HASHSET_H diff --git a/headers/lhtbl.h b/headers/lhashset.h similarity index 95% rename from headers/lhtbl.h rename to headers/lhashset.h index 986b198..63013ba 100644 --- a/headers/lhtbl.h +++ b/headers/lhashset.h @@ -4,8 +4,8 @@ * @author Maxime Loukhal * @date 27/02/2024 */ -#ifndef COLLECTIONS_COMMONS_LHTBL_H -#define COLLECTIONS_COMMONS_LHTBL_H +#ifndef COLLECTIONS_COMMONS_LHASHSET_H +#define COLLECTIONS_COMMONS_LHASHSET_H #ifdef __cplusplus @@ -23,7 +23,7 @@ extern "C" { #endif #include "list.h" -#include "htbl.h" +#include "hashset.h" /** * @brief Data structure definition for a linked hash table */ @@ -122,7 +122,7 @@ bool lhtbl_put(LinkedHashTable *lhtbl, const void* value); bool lhtbl_remove(LinkedHashTable *lhtbl, void** value); /** - * @brief Test if the given value is present in the data table, if a equals occurs value will contain the pointer on the equalsed value + * @brief Test if the given value is present in the hash table, if a equals occurs value will contain the pointer on the equalsed value * @param lhtbl Linked Hash Table to lookup in * @param value Double pointer to lookup the value in the given data table, if a equals occurs returns the pointer on it * @return true if the data table is present in the given data table, false otherwise @@ -134,4 +134,4 @@ bool lhtbl_containsKey(const LinkedHashTable *lhtbl, void** value); #endif -#endif //COLLECTIONS_COMMONS_LHTBL_H \ No newline at end of file +#endif //COLLECTIONS_COMMONS_LHASHSET_H \ No newline at end of file diff --git a/headers/list.h b/headers/list.h index 2d817b6..c17337b 100644 --- a/headers/list.h +++ b/headers/list.h @@ -117,6 +117,15 @@ bool list_remove( LinkedList*list, LinkedElement *element, void **value); */ LinkedElement* list_get_random(LinkedList *list); +/** + * @brief Replace a specified element from the given list with the specified value + * @param list List where to replace the element value + * @param element Element to replace the value + * @param value Value to replace + * @return true if the given element's value was replaces, false otherwise + */ +bool list_replace(LinkedList *list, LinkedElement *element, void **value); + /* ----- MACRO C++ COMPATIBILITY -----*/ #ifdef __cplusplus /** diff --git a/src/clist.c b/src/clist.c index d3acc32..bde9e5d 100644 --- a/src/clist.c +++ b/src/clist.c @@ -76,3 +76,22 @@ CLinkedElement * clist_get_random(CLinkedList *list){ } return random_element; } + +bool clist_replace(CLinkedList *list, CLinkedElement *element, void **value){ + if(list == NULL || element == NULL ) return false; + int i; + CLinkedElement * current_element = clist_first(list); + for(i=0;i< clist_size(list);i++){ + if(current_element == element){ + void** temp = current_element->value; + current_element->value = *value; + value = temp; + free(temp); + break; + } + current_element=clist_next(current_element); + } + + free(current_element); + return true; +} \ No newline at end of file diff --git a/src/dlist.c b/src/dlist.c index ef2a088..5ae898f 100644 --- a/src/dlist.c +++ b/src/dlist.c @@ -137,4 +137,21 @@ DLinkedElement * dlist_get_random(DLinkedList *list){ count++; } return random_element; +} + +bool dlist_replace(DLinkedList *list, DLinkedElement *element, void **value){ + if(list == NULL || element == NULL ) return false; + DLinkedElement * current_element; + for(current_element= dlist_first(list); current_element!=NULL; current_element=dlist_next(current_element)){ + if(current_element == element){ + void** temp = current_element->value; + current_element->value = *value; + value = temp; + free(temp); + break; + } + } + + free(current_element); + return true; } \ No newline at end of file diff --git a/src/hashmap.c b/src/hashmap.c new file mode 100644 index 0000000..a1de6b4 --- /dev/null +++ b/src/hashmap.c @@ -0,0 +1,113 @@ +// +// Created by maxim on 28/02/2024. +// +#include "hashmap.h" + +bool hashmap_create(HashMap *map, + int containers, + int (*hash)(const void *key), + bool (*equals)(const void* key1, const void* key2), + void(*destroy)(void *value)){ + int i; + + // Try To Allocate memory space for the linked hash table + + if(!lhtbl_create(map->hashTable, containers, hash, equals, destroy)) return false; + + // Init the map + map->size = 0; + map->equals = equals; + map->destroy = destroy; + map->tail = NULL; + map->head = NULL; + + return true; +} + +void hashmap_destroy(HashMap *map){ + lhtbl_destroy(map->hashTable); + memset(map, 0, sizeof(HashMap)); +} + +bool hashmap_containsKey(const HashMap *map, void** value){ + LinkedElement *current_element; + int current_container; + + // Hash the given key value + current_container = map->hashTable->hash(*value) % map->hashTable->containers; + + // Search the value inside the current container + + for(current_element= list_first(&map->hashTable->hashtable[current_container]); current_element != NULL; current_element= list_next(current_element) ){ + SimpleEntry * current_entry = (SimpleEntry*)list_value(current_element); + if(map->hashTable->equals(*value, current_entry->key)){ + *value = list_value(current_element); + return true; + } + } + + return false; +} + +bool hashmap_put(HashMap *map, void *key, void *value){ + bool result = false; + + if(hashmap_containsKey((const HashMap *) map->hashTable, key)){ + void* old_value = value; + if(hashmap_replace(map,key, &old_value)){ + free(old_value); + return true; + } + }else{ + int container; + + // Hash the given key with the user function + container = map->hashTable->hash(key) % map->hashTable->containers; + + SimpleEntry * new_entry = (SimpleEntry*) malloc(sizeof(SimpleEntry)); + new_entry->key = key; + new_entry->value = value; + // Add the current key value pair to the container + if((result = list_add(&map->hashTable->hashtable[container], NULL, new_entry))){ + if (hashmap_size(map) == 0) map->tail = new_entry; + new_entry->next = map->head; + map->head = new_entry; + result = true; + } + + } + return result; +} + +bool hashmap_addEntry(HashMap *map, SimpleEntry *entry){ + bool result = false; + + if(hashmap_containsKey((const HashMap *) map->hashTable, entry->key)){ + void* old_value = entry->value; + if(hashmap_replace(map,entry->key, &old_value)){ + free(old_value); + return true; + } + }else{ + int container; + + // Hash the given key with the user function + container = map->hashTable->hash(entry->key) % map->hashTable->containers; + + SimpleEntry * new_entry; + if((new_entry=(SimpleEntry*) malloc(sizeof(SimpleEntry))) == NULL) return false; + memcpy(new_entry, entry, sizeof(SimpleEntry)); + // Add the current key value pair to the container + if((result = list_add(&map->hashTable->hashtable[container], NULL, new_entry))){ + if (hashmap_size(map) == 0) map->tail = new_entry; + new_entry->next = map->head; + map->head = new_entry; + result = true; + } + } + return result; +} + +bool hashmap_putIfAbsent(HashMap *map, void *key, void *value){ + +} \ No newline at end of file diff --git a/src/htbl.c b/src/hashset.c similarity index 92% rename from src/htbl.c rename to src/hashset.c index 5f3d48a..cf55713 100644 --- a/src/htbl.c +++ b/src/hashset.c @@ -1,10 +1,10 @@ // // Created by maxim on 28/02/2024. // -#include "htbl.h" +#include "hashset.h" bool cmp_int(const void *a, const void *b){ - if(a ==NULL || b == NULL ) return -1; + if(a ==NULL || b == NULL ) return false; int* intA = (int*)a; int* intB = (int*)b; diff --git a/src/lhtbl.c b/src/lhashset.c similarity index 99% rename from src/lhtbl.c rename to src/lhashset.c index 0ee24d4..ca978ae 100644 --- a/src/lhtbl.c +++ b/src/lhashset.c @@ -2,7 +2,7 @@ // Created by maxim on 28/02/2024. // -#include "lhtbl.h" +#include "lhashset.h" bool lhtbl_create(LinkedHashTable *lhtbl, int containers, diff --git a/src/list.c b/src/list.c index 9c10c07..ee23146 100644 --- a/src/list.c +++ b/src/list.c @@ -99,3 +99,21 @@ LinkedElement* list_get_random(LinkedList *list){ } return random_element; } + + +bool list_replace(LinkedList *list, LinkedElement *element, void **value){ + if(list == NULL || element == NULL ) return false; + LinkedElement * current_element; + for(current_element= list_first(list); current_element!=NULL; current_element=list_next(current_element)){ + if(current_element == element){ + void** temp = current_element->value; + current_element->value = *value; + value = temp; + free(temp); + break; + } + } + + free(current_element); + return true; +} \ No newline at end of file diff --git a/tests/headers/LinkedHashTable_Test.h b/tests/headers/LinkedHashTable_Test.h index a9fcd41..d0fb16d 100644 --- a/tests/headers/LinkedHashTable_Test.h +++ b/tests/headers/LinkedHashTable_Test.h @@ -7,7 +7,7 @@ #ifndef COLLECTIONS_COMMONS_LINKEDHASHTABLE_TEST_H #define COLLECTIONS_COMMONS_LINKEDHASHTABLE_TEST_H #include -#include "lhtbl.h" +#include "lhashset.h" class LinkedHashTableTest : public ::testing::Test { From 9a68005e2fe67d557db084a9d89bb71f21004eed Mon Sep 17 00:00:00 2001 From: nakira974 Date: Wed, 28 Feb 2024 23:04:41 +0100 Subject: [PATCH 12/27] reformat sources --- src/binary_tree.c | 8 ++-- src/clist.c | 24 +++++----- src/dlist.c | 22 ++++----- src/event.c | 22 ++++----- src/frame.c | 18 +++---- src/hashmap.c | 49 ++++++++++---------- src/hashset.c | 24 +++++----- src/lhashset.c | 38 ++++++++------- src/list.c | 22 ++++----- src/page.c | 8 ++-- src/queue.c | 4 +- src/set.c | 116 ++++++++++++++++++++++++---------------------- src/sort.c | 21 +++++---- src/stack.c | 4 +- 14 files changed, 194 insertions(+), 186 deletions(-) diff --git a/src/binary_tree.c b/src/binary_tree.c index e662bd8..31a4cb5 100644 --- a/src/binary_tree.c +++ b/src/binary_tree.c @@ -12,7 +12,7 @@ int **levelOrder(struct TreeNode *root, int *returnSize, } // Crée une file pour stocker les nœuds - Queue * queue = (Queue*) malloc(sizeof (Queue)); + Queue *queue = (Queue *) malloc(sizeof(Queue)); queue_create(queue, free); // Ajoute la racine à la file queue_enqueue(queue, root); @@ -27,15 +27,15 @@ int **levelOrder(struct TreeNode *root, int *returnSize, int levelIndex = 0; // Indice du niveau actuel // On instancie une autre file pour stocker les noeuds du prochain niveau - Queue *nextQueue = (Queue*) malloc(sizeof (Queue)); + Queue *nextQueue = (Queue *) malloc(sizeof(Queue)); - while (list_first(queue)!= NULL) { + while (list_first(queue) != NULL) { // Taille arbitraire pour le tableau du niveau actuel int *currentLevel = (int *) malloc(1000 * sizeof(int)); int count = 0; // Compteur pour les nœuds dans chaque niveau // Parcourt le niveau actuel jusqu'à ce que la file soit vide - while (list_first(queue)!= NULL) { + while (list_first(queue) != NULL) { // Récupère le nœud en tête de file struct TreeNode *currNode; queue_dequeue(queue, &currNode); diff --git a/src/clist.c b/src/clist.c index bde9e5d..9baa56c 100644 --- a/src/clist.c +++ b/src/clist.c @@ -62,14 +62,14 @@ bool clist_remove(CLinkedList *list, CLinkedElement *element, void **value) { return true; } -CLinkedElement * clist_get_random(CLinkedList *list){ - CLinkedElement * random_element; - if(clist_size(list) == 0) return NULL; +CLinkedElement *clist_get_random(CLinkedList *list) { + CLinkedElement *random_element; + if (clist_size(list) == 0) return NULL; int rd_index = rand() % clist_size(list); int count = 0; - for(random_element= clist_first(list); random_element= clist_next(random_element)){ - if(rd_index == count){ + for (random_element = clist_first(list); random_element = clist_next(random_element)) { + if (rd_index == count) { break; } count++; @@ -77,19 +77,19 @@ CLinkedElement * clist_get_random(CLinkedList *list){ return random_element; } -bool clist_replace(CLinkedList *list, CLinkedElement *element, void **value){ - if(list == NULL || element == NULL ) return false; +bool clist_replace(CLinkedList *list, CLinkedElement *element, void **value) { + if (list == NULL || element == NULL) return false; int i; - CLinkedElement * current_element = clist_first(list); - for(i=0;i< clist_size(list);i++){ - if(current_element == element){ - void** temp = current_element->value; + CLinkedElement *current_element = clist_first(list); + for (i = 0; i < clist_size(list); i++) { + if (current_element == element) { + void **temp = current_element->value; current_element->value = *value; value = temp; free(temp); break; } - current_element=clist_next(current_element); + current_element = clist_next(current_element); } free(current_element); diff --git a/src/dlist.c b/src/dlist.c index 5ae898f..ab35f3c 100644 --- a/src/dlist.c +++ b/src/dlist.c @@ -123,15 +123,15 @@ bool dlist_remove(DLinkedList *list, DLinkedElement *element, void **value) { return true; } -DLinkedElement * dlist_get_random(DLinkedList *list){ - DLinkedElement * random_element; - if(dlist_size(list) == 0) return NULL; +DLinkedElement *dlist_get_random(DLinkedList *list) { + DLinkedElement *random_element; + if (dlist_size(list) == 0) return NULL; // Génère un index aléatoire dans la plage des indices valides du tableau. int rd_index = rand() % dlist_size(list); int count = 0; - for(random_element= dlist_first(list);random_element!=NULL; random_element= dlist_next(random_element)){ - if(rd_index == count){ + for (random_element = dlist_first(list); random_element != NULL; random_element = dlist_next(random_element)) { + if (rd_index == count) { break; } count++; @@ -139,12 +139,12 @@ DLinkedElement * dlist_get_random(DLinkedList *list){ return random_element; } -bool dlist_replace(DLinkedList *list, DLinkedElement *element, void **value){ - if(list == NULL || element == NULL ) return false; - DLinkedElement * current_element; - for(current_element= dlist_first(list); current_element!=NULL; current_element=dlist_next(current_element)){ - if(current_element == element){ - void** temp = current_element->value; +bool dlist_replace(DLinkedList *list, DLinkedElement *element, void **value) { + if (list == NULL || element == NULL) return false; + DLinkedElement *current_element; + for (current_element = dlist_first(list); current_element != NULL; current_element = dlist_next(current_element)) { + if (current_element == element) { + void **temp = current_element->value; current_element->value = *value; value = temp; free(temp); diff --git a/src/event.c b/src/event.c index 7b8cbd2..3241abe 100644 --- a/src/event.c +++ b/src/event.c @@ -4,17 +4,17 @@ #include "event.h" -bool event_receive(Queue * events, const Event *event){ +bool event_receive(Queue *events, const Event *event) { - Event* new_event; + Event *new_event; /**Allocate memory for the new event*/ - if((new_event = (Event*) malloc(sizeof (Event))) == NULL){ + if ((new_event = (Event *) malloc(sizeof(Event))) == NULL) { free(new_event); return false; } /** Copy and add the event into the queue*/ - memcpy(new_event, event, sizeof (Event)); - if(!queue_enqueue(events, new_event)){ + memcpy(new_event, event, sizeof(Event)); + if (!queue_enqueue(events, new_event)) { free(new_event); return false; } @@ -23,13 +23,13 @@ bool event_receive(Queue * events, const Event *event){ return true; } -bool event_process(Queue *events, int(* on_event_received) (Event * current_event)){ - Event *current_event; - if(queue_size(events)==0) return false; - else{ - if(!queue_dequeue(events, (void**)¤t_event)) +bool event_process(Queue *events, int(*on_event_received)(Event *current_event)) { + Event *current_event; + if (queue_size(events) == 0) return false; + else { + if (!queue_dequeue(events, (void **) ¤t_event)) return false; - else{ + else { on_event_received(current_event); free(current_event); } diff --git a/src/frame.c b/src/frame.c index 50cb497..8ae9bff 100644 --- a/src/frame.c +++ b/src/frame.c @@ -4,14 +4,14 @@ #include "frame.h" -int frame_alloc(LinkedList *frames){ +int frame_alloc(LinkedList *frames) { int frame_id, *value; // If no frame available - if(list_size(frames) == 0) return -1; - else{ + if (list_size(frames) == 0) return -1; + else { // If we can't obtain a frame - if(!list_remove(frames, NULL, (void**)&value)) return -1; - else{ + if (!list_remove(frames, NULL, (void **) &value)) return -1; + else { frame_id = *value; free(value); } @@ -20,17 +20,17 @@ int frame_alloc(LinkedList *frames){ return frame_id; } -bool frame_destroy(LinkedList *frames, int frame_id){ +bool frame_destroy(LinkedList *frames, int frame_id) { int *value; // Allocate memory space for the frame id - if((value= (int *)malloc(sizeof (int))) == NULL){ + if ((value = (int *) malloc(sizeof(int))) == NULL) { free(value); return false; } // Replacing the current frame in the available pages - *value=frame_id; - if(!list_add(frames,NULL,value)) return false; + *value = frame_id; + if (!list_add(frames, NULL, value)) return false; return true; } \ No newline at end of file diff --git a/src/hashmap.c b/src/hashmap.c index a1de6b4..2e44272 100644 --- a/src/hashmap.c +++ b/src/hashmap.c @@ -6,13 +6,13 @@ bool hashmap_create(HashMap *map, int containers, int (*hash)(const void *key), - bool (*equals)(const void* key1, const void* key2), - void(*destroy)(void *value)){ + bool (*equals)(const void *key1, const void *key2), + void(*destroy)(void *value)) { int i; // Try To Allocate memory space for the linked hash table - if(!lhtbl_create(map->hashTable, containers, hash, equals, destroy)) return false; + if (!lhtbl_create(map->hashTable, containers, hash, equals, destroy)) return false; // Init the map map->size = 0; @@ -24,12 +24,12 @@ bool hashmap_create(HashMap *map, return true; } -void hashmap_destroy(HashMap *map){ +void hashmap_destroy(HashMap *map) { lhtbl_destroy(map->hashTable); memset(map, 0, sizeof(HashMap)); } -bool hashmap_containsKey(const HashMap *map, void** value){ +bool hashmap_containsKey(const HashMap *map, void **value) { LinkedElement *current_element; int current_container; @@ -38,9 +38,10 @@ bool hashmap_containsKey(const HashMap *map, void** value){ // Search the value inside the current container - for(current_element= list_first(&map->hashTable->hashtable[current_container]); current_element != NULL; current_element= list_next(current_element) ){ - SimpleEntry * current_entry = (SimpleEntry*)list_value(current_element); - if(map->hashTable->equals(*value, current_entry->key)){ + for (current_element = list_first(&map->hashTable->hashtable[current_container]); + current_element != NULL; current_element = list_next(current_element)) { + SimpleEntry *current_entry = (SimpleEntry *) list_value(current_element); + if (map->hashTable->equals(*value, current_entry->key)) { *value = list_value(current_element); return true; } @@ -49,26 +50,26 @@ bool hashmap_containsKey(const HashMap *map, void** value){ return false; } -bool hashmap_put(HashMap *map, void *key, void *value){ +bool hashmap_put(HashMap *map, void *key, void *value) { bool result = false; - if(hashmap_containsKey((const HashMap *) map->hashTable, key)){ - void* old_value = value; - if(hashmap_replace(map,key, &old_value)){ + if (hashmap_containsKey((const HashMap *) map->hashTable, key)) { + void *old_value = value; + if (hashmap_replace(map, key, &old_value)) { free(old_value); return true; } - }else{ + } else { int container; // Hash the given key with the user function container = map->hashTable->hash(key) % map->hashTable->containers; - SimpleEntry * new_entry = (SimpleEntry*) malloc(sizeof(SimpleEntry)); + SimpleEntry *new_entry = (SimpleEntry *) malloc(sizeof(SimpleEntry)); new_entry->key = key; new_entry->value = value; // Add the current key value pair to the container - if((result = list_add(&map->hashTable->hashtable[container], NULL, new_entry))){ + if ((result = list_add(&map->hashTable->hashtable[container], NULL, new_entry))) { if (hashmap_size(map) == 0) map->tail = new_entry; new_entry->next = map->head; map->head = new_entry; @@ -79,26 +80,26 @@ bool hashmap_put(HashMap *map, void *key, void *value){ return result; } -bool hashmap_addEntry(HashMap *map, SimpleEntry *entry){ +bool hashmap_addEntry(HashMap *map, SimpleEntry *entry) { bool result = false; - if(hashmap_containsKey((const HashMap *) map->hashTable, entry->key)){ - void* old_value = entry->value; - if(hashmap_replace(map,entry->key, &old_value)){ + if (hashmap_containsKey((const HashMap *) map->hashTable, entry->key)) { + void *old_value = entry->value; + if (hashmap_replace(map, entry->key, &old_value)) { free(old_value); return true; } - }else{ + } else { int container; // Hash the given key with the user function container = map->hashTable->hash(entry->key) % map->hashTable->containers; - SimpleEntry * new_entry; - if((new_entry=(SimpleEntry*) malloc(sizeof(SimpleEntry))) == NULL) return false; + SimpleEntry *new_entry; + if ((new_entry = (SimpleEntry *) malloc(sizeof(SimpleEntry))) == NULL) return false; memcpy(new_entry, entry, sizeof(SimpleEntry)); // Add the current key value pair to the container - if((result = list_add(&map->hashTable->hashtable[container], NULL, new_entry))){ + if ((result = list_add(&map->hashTable->hashtable[container], NULL, new_entry))) { if (hashmap_size(map) == 0) map->tail = new_entry; new_entry->next = map->head; map->head = new_entry; @@ -108,6 +109,6 @@ bool hashmap_addEntry(HashMap *map, SimpleEntry *entry){ return result; } -bool hashmap_putIfAbsent(HashMap *map, void *key, void *value){ +bool hashmap_putIfAbsent(HashMap *map, void *key, void *value) { } \ No newline at end of file diff --git a/src/hashset.c b/src/hashset.c index cf55713..c5ab5ee 100644 --- a/src/hashset.c +++ b/src/hashset.c @@ -3,10 +3,10 @@ // #include "hashset.h" -bool cmp_int(const void *a, const void *b){ - if(a ==NULL || b == NULL ) return false; - int* intA = (int*)a; - int* intB = (int*)b; +bool cmp_int(const void *a, const void *b) { + if (a == NULL || b == NULL) return false; + int *intA = (int *) a; + int *intB = (int *) b; if (*intA == *intB) { return true; @@ -19,11 +19,11 @@ int hashref(const void *ref) { const double phi = (sqrt(5) - 1) / 2; intptr_t address = (intptr_t) ref; - return ((int)( (int) address * phi)); + return ((int) ((int) address * phi)); } -int hashpjw(const void* key){ - const char * string; +int hashpjw(const void *key) { + const char *string; int value; // hash the key the bit to bit operations @@ -31,12 +31,12 @@ int hashpjw(const void* key){ value = 0; string = key; - while(*string != '\0'){ + while (*string != '\0') { int temp; - value = (value<<4) + (*string); - if(temp=(value & 0xf0000000)){ - value = value ^(temp >> 24); - value = value ^temp; + value = (value << 4) + (*string); + if (temp = (value & 0xf0000000)) { + value = value ^ (temp >> 24); + value = value ^ temp; } string++; } diff --git a/src/lhashset.c b/src/lhashset.c index ca978ae..22e3901 100644 --- a/src/lhashset.c +++ b/src/lhashset.c @@ -7,19 +7,19 @@ bool lhtbl_create(LinkedHashTable *lhtbl, int containers, int (*hash)(const void *key), - bool (*equals)(const void* key1, const void* key2), - void(*destroy)(void *value)){ + bool (*equals)(const void *key1, const void *key2), + void(*destroy)(void *value)) { int i; // Allocate memory space for the linked hash table - if((lhtbl->hashtable = (LinkedList *) malloc(containers * sizeof(LinkedList))) == NULL) return false; + if ((lhtbl->hashtable = (LinkedList *) malloc(containers * sizeof(LinkedList))) == NULL) return false; // Creating containers lhtbl->containers = containers; - for(i = 0; i< lhtbl->containers;i++) + for (i = 0; i < lhtbl->containers; i++) list_create(&lhtbl->hashtable[i], destroy); lhtbl->hash = hash; @@ -30,10 +30,10 @@ bool lhtbl_create(LinkedHashTable *lhtbl, return true; } -void lhtbl_destroy(LinkedHashTable *lhtbl){ +void lhtbl_destroy(LinkedHashTable *lhtbl) { int i; - for(i=0;isize;i++) + for (i = 0; i < lhtbl->size; i++) list_destroy(&lhtbl->hashtable[i]); // Cleaning the memory location allocate to the internal hashtable @@ -44,42 +44,43 @@ void lhtbl_destroy(LinkedHashTable *lhtbl){ memset(lhtbl, 0, sizeof(LinkedHashTable)); } -bool lhtbl_put(LinkedHashTable *lhtbl, const void* value){ +bool lhtbl_put(LinkedHashTable *lhtbl, const void *value) { void *temp; int container; bool result = false; temp = (void *) value; // If the value is already in the table return false - if(lhtbl_containsKey(lhtbl, &temp)) return result; + if (lhtbl_containsKey(lhtbl, &temp)) return result; // Hash the given key with the user function container = lhtbl->hash(value) % lhtbl->containers; // Add the value inside the result container - if((result = list_add(&lhtbl->hashtable[container], NULL, value))) lhtbl->size++; + if ((result = list_add(&lhtbl->hashtable[container], NULL, value))) lhtbl->size++; return result; } -bool lhtbl_remove(LinkedHashTable *lhtbl, void** value){ - LinkedElement *current_element,*last_element; +bool lhtbl_remove(LinkedHashTable *lhtbl, void **value) { + LinkedElement *current_element, *last_element; int current_container; current_container = lhtbl->hash(*value) % lhtbl->containers; // Search for the value inside the current container last_element = NULL; - for(current_element= list_first(&lhtbl->hashtable[current_container]); current_element != NULL; current_element = list_next(current_element)){ + for (current_element = list_first(&lhtbl->hashtable[current_container]); + current_element != NULL; current_element = list_next(current_element)) { // If the target value if equals to the current container element, then remove it - if(lhtbl->equals(*value, list_value(current_element))){ + if (lhtbl->equals(*value, list_value(current_element))) { // Remove the value from the current container - if(list_remove(&lhtbl->hashtable[current_container], last_element, value)){ + if (list_remove(&lhtbl->hashtable[current_container], last_element, value)) { lhtbl->size--; return true; // Can't remove the data from the current container - }else return false; + } else return false; } last_element = current_element; } @@ -88,7 +89,7 @@ bool lhtbl_remove(LinkedHashTable *lhtbl, void** value){ return false; } -bool lhtbl_containsKey(const LinkedHashTable *lhtbl, void** value){ +bool lhtbl_containsKey(const LinkedHashTable *lhtbl, void **value) { LinkedElement *current_element; int current_container; @@ -97,8 +98,9 @@ bool lhtbl_containsKey(const LinkedHashTable *lhtbl, void** value){ // Search the value inside the current container - for(current_element= list_first(&lhtbl->hashtable[current_container]); current_element != NULL; current_element= list_next(current_element) ){ - if(lhtbl->equals(*value, list_value(current_element))){ + for (current_element = list_first(&lhtbl->hashtable[current_container]); + current_element != NULL; current_element = list_next(current_element)) { + if (lhtbl->equals(*value, list_value(current_element))) { *value = list_value(current_element); return true; } diff --git a/src/list.c b/src/list.c index ee23146..f258020 100644 --- a/src/list.c +++ b/src/list.c @@ -83,16 +83,16 @@ bool list_remove(LinkedList *list, LinkedElement *element, void **value) { return true; } -LinkedElement* list_get_random(LinkedList *list){ - LinkedElement* random_element; - if(list_size(list) == 0) return NULL; +LinkedElement *list_get_random(LinkedList *list) { + LinkedElement *random_element; + if (list_size(list) == 0) return NULL; // Génère un index aléatoire dans la plage des indices valides du tableau. int rd_index = rand() % list_size(list); int count = 0; - for(random_element= list_first(list);random_element!=NULL; random_element= list_next(random_element)){ - if(rd_index == count){ + for (random_element = list_first(list); random_element != NULL; random_element = list_next(random_element)) { + if (rd_index == count) { break; } count++; @@ -101,12 +101,12 @@ LinkedElement* list_get_random(LinkedList *list){ } -bool list_replace(LinkedList *list, LinkedElement *element, void **value){ - if(list == NULL || element == NULL ) return false; - LinkedElement * current_element; - for(current_element= list_first(list); current_element!=NULL; current_element=list_next(current_element)){ - if(current_element == element){ - void** temp = current_element->value; +bool list_replace(LinkedList *list, LinkedElement *element, void **value) { + if (list == NULL || element == NULL) return false; + LinkedElement *current_element; + for (current_element = list_first(list); current_element != NULL; current_element = list_next(current_element)) { + if (current_element == element) { + void **temp = current_element->value; current_element->value = *value; value = temp; free(temp); diff --git a/src/page.c b/src/page.c index 56601a9..831ed5c 100644 --- a/src/page.c +++ b/src/page.c @@ -5,14 +5,14 @@ #include "page.h" -int page_replace(CLinkedElement **current){ +int page_replace(CLinkedElement **current) { // Second chance algorithm // Infinite loop until one page has been replaced - while(((Page*)(*current)->value)->state){ - ((Page*)(*current)->value)->state = false; + while (((Page *) (*current)->value)->state) { + ((Page *) (*current)->value)->state = false; *current = clist_next(*current); } - return ((Page*)(*current)->value)->id; + return ((Page *) (*current)->value)->id; } \ No newline at end of file diff --git a/src/queue.c b/src/queue.c index 7b614f8..0086f19 100644 --- a/src/queue.c +++ b/src/queue.c @@ -4,12 +4,12 @@ #include "queue.h" -bool queue_enqueue(Queue * queue, const void * value){ +bool queue_enqueue(Queue *queue, const void *value) { // Add the element at the end of the queue return list_add(queue, list_last(queue), value); } -bool queue_dequeue(Queue *queue, void * value){ +bool queue_dequeue(Queue *queue, void *value) { // Remove the head element of the queue return list_remove(queue, NULL, value); } diff --git a/src/set.c b/src/set.c index ed43cb2..36c7645 100644 --- a/src/set.c +++ b/src/set.c @@ -7,11 +7,11 @@ #include "set.h" -bool set_match_entries(Set *elements, Set* elements_to_match, Set * matched_elements){ +bool set_match_entries(Set *elements, Set *elements_to_match, Set *matched_elements) { Set intersection; KeySetEntry *hashSet; - LinkedElement *current_element,*element_max; - void * value; + LinkedElement *current_element, *element_max; + void *value; uint32_t max_size; // Initialize the set cover @@ -19,14 +19,16 @@ bool set_match_entries(Set *elements, Set* elements_to_match, Set * matched_elem // Continue until there are non-covering elements and candidates - while(set_size(elements) > 0 && set_size(elements_to_match) > 0){ + while (set_size(elements) > 0 && set_size(elements_to_match) > 0) { // Search of the candidate covering the most elements as possible max_size = 0; - for(current_element= list_first(elements_to_match);current_element != NULL; current_element = list_next(current_element)){ - if(!set_intersection(&intersection, &((KeySetEntry * ) list_value(current_element))->set, elements)) return false; + for (current_element = list_first(elements_to_match); + current_element != NULL; current_element = list_next(current_element)) { + if (!set_intersection(&intersection, &((KeySetEntry *) list_value(current_element))->set, elements)) + return false; - if(set_size(&intersection) > max_size){ + if (set_size(&intersection) > max_size) { element_max = current_element; max_size = set_size(&intersection); } @@ -37,83 +39,85 @@ bool set_match_entries(Set *elements, Set* elements_to_match, Set * matched_elem // A covering isn't possible if there's no intersection - if(max_size == 0) return false; + if (max_size == 0) return false; // Insert inside the covering the selected hashset hashSet = (KeySetEntry *) list_value(element_max); - if(!set_add(matched_elements, hashSet)) return false; + if (!set_add(matched_elements, hashSet)) return false; // Remove each current_element covered from the uncovered-elements set - for(current_element = list_first(&((KeySetEntry*) list_value(element_max))->set); current_element != NULL; current_element= list_next(current_element)){ + for (current_element = list_first(&((KeySetEntry *) list_value(element_max))->set); + current_element != NULL; current_element = list_next(current_element)) { value = list_value(current_element); - if(set_remove(elements, (void**)&value) && elements->destroy != NULL) elements->destroy(value); + if (set_remove(elements, (void **) &value) && elements->destroy != NULL) elements->destroy(value); } // Remove the hashset from the hashset candidates - if(!set_remove(elements_to_match, (void **)&hashSet)) return false; + if (!set_remove(elements_to_match, (void **) &hashSet)) return false; // No covering if there's still non-covered elements - if(set_size(elements) > 0) return false; + if (set_size(elements) > 0) return false; return true; } -void set_create(Set *set, int (*equals)(const void *left, const void *right), void (*destroy)(void *value)){ + +void set_create(Set *set, int (*equals)(const void *left, const void *right), void (*destroy)(void *value)) { list_create(set, destroy); set->equals = equals; } -bool set_add(Set *set, const void *value){ +bool set_add(Set *set, const void *value) { // No duplicated values - if(set_is_member(set, value)) return false; + if (set_is_member(set, value)) return false; // Add the value at the end return list_add(set, list_last(set), value); } -bool set_remove(Set *set, void **value){ - LinkedElement *current_element, *element_to_remove; +bool set_remove(Set *set, void **value) { + LinkedElement *current_element, *element_to_remove; // Search for a value to remove - for(current_element= list_first(set);current_element!=NULL;current_element= list_next(current_element)){ - if(set->equals(*value, list_value(current_element))) + for (current_element = list_first(set); current_element != NULL; current_element = list_next(current_element)) { + if (set->equals(*value, list_value(current_element))) break; element_to_remove = current_element; } // Element not found case - if(current_element == NULL) return false; + if (current_element == NULL) return false; // Remove the last element return list_remove(set, element_to_remove, value); } -bool set_union(Set *union_result, const Set *left, const Set *right){ - LinkedElement *current_element; - void * value; +bool set_union(Set *union_result, const Set *left, const Set *right) { + LinkedElement *current_element; + void *value; // Create the union set set_create(union_result, left->equals, NULL); // Insertion of left set elements - for(current_element = list_first(left);current_element!=NULL;current_element= list_next(current_element)){ + for (current_element = list_first(left); current_element != NULL; current_element = list_next(current_element)) { value = list_value(current_element); - if(!list_add(union_result, list_last(union_result), value)){ + if (!list_add(union_result, list_last(union_result), value)) { set_destroy(union_result); return false; } } // Insertion of right set elements - for(current_element = list_first(right);current_element!=NULL;current_element= list_next(current_element)){ - if(set_is_member(left, list_value(current_element))) continue; - else{ + for (current_element = list_first(right); current_element != NULL; current_element = list_next(current_element)) { + if (set_is_member(left, list_value(current_element))) continue; + else { value = list_value(current_element); - if(!list_add(union_result, list_last(union_result), value)){ + if (!list_add(union_result, list_last(union_result), value)) { set_destroy(union_result); return false; } @@ -122,9 +126,9 @@ bool set_union(Set *union_result, const Set *left, const Set *right){ return true; } -bool set_intersection(Set *intersection_result, const Set *left, const Set *right){ - LinkedElement *current_element; - void * value; +bool set_intersection(Set *intersection_result, const Set *left, const Set *right) { + LinkedElement *current_element; + void *value; // Create the intersection Set @@ -132,11 +136,11 @@ bool set_intersection(Set *intersection_result, const Set *left, const Set *righ // intersection of elements in left and right set - for(current_element = list_first(left);current_element!=NULL;current_element= list_next(current_element)){ + for (current_element = list_first(left); current_element != NULL; current_element = list_next(current_element)) { // If the current left element is in the right Set - if(set_is_member(right, list_value(current_element))){ + if (set_is_member(right, list_value(current_element))) { value = list_value(current_element); - if(!list_add(intersection_result, list_last(intersection_result), value)){ + if (!list_add(intersection_result, list_last(intersection_result), value)) { set_destroy(intersection_result); return false; } @@ -145,19 +149,19 @@ bool set_intersection(Set *intersection_result, const Set *left, const Set *righ return true; } -bool set_difference(Set *difference_result, const Set *left, const Set *right){ - LinkedElement *current_element; - void * value; +bool set_difference(Set *difference_result, const Set *left, const Set *right) { + LinkedElement *current_element; + void *value; // Creation of the difference Set set_create(difference_result, left->equals, NULL); // Insert elements of left non present in right - for(current_element = list_first(left);current_element != NULL;current_element= list_next(current_element)){ + for (current_element = list_first(left); current_element != NULL; current_element = list_next(current_element)) { // If the current left value is not in the right set - if(!set_is_member(right, list_value(current_element))){ + if (!set_is_member(right, list_value(current_element))) { value = list_value(current_element); - if(!list_add(difference_result, list_last(difference_result), value)){ + if (!list_add(difference_result, list_last(difference_result), value)) { set_destroy(difference_result); return false; } @@ -166,41 +170,41 @@ bool set_difference(Set *difference_result, const Set *left, const Set *right){ return true; } -bool set_is_member(const Set *set, const void *value){ - LinkedElement *current_element; +bool set_is_member(const Set *set, const void *value) { + LinkedElement *current_element; // Determine if the value is in set - for(current_element = list_first(set); current_element != NULL;current_element= list_next(current_element)){ + for (current_element = list_first(set); current_element != NULL; current_element = list_next(current_element)) { // If any equals occurs, then return false - if(set->equals(value, list_value(current_element))) return false; + if (set->equals(value, list_value(current_element))) return false; } return true; } -bool set_is_subset(const Set *left, const Set *right){ - LinkedElement *current_element; +bool set_is_subset(const Set *left, const Set *right) { + LinkedElement *current_element; // Quick test to eliminate some usual cases - if(set_size(left)> set_size(right)) return false; + if (set_size(left) > set_size(right)) return false; // Determine if left is a subset of right - for(current_element= list_first(left);current_element!= NULL;current_element = list_next(current_element)){ + for (current_element = list_first(left); current_element != NULL; current_element = list_next(current_element)) { // Validate one by one left elements in right set independently of their order - if(!set_is_member(right, list_value(current_element))) return false; + if (!set_is_member(right, list_value(current_element))) return false; } return true; } -bool set_is_equal(const Set *left, const Set *right){ - LinkedElement *current_element; +bool set_is_equal(const Set *left, const Set *right) { + LinkedElement *current_element; // Quick test to eliminate usual cases - if(set_size(left) != set_size(right)) return false; + if (set_size(left) != set_size(right)) return false; // Determine if left and right sets are equal - for(current_element= list_first(left);current_element!=NULL;current_element= list_next(current_element)){ + for (current_element = list_first(left); current_element != NULL; current_element = list_next(current_element)) { // If there is one element of left not present in right, sets are not equal - if(!set_is_member(right, list_value(current_element))) return false; + if (!set_is_member(right, list_value(current_element))) return false; } return true; diff --git a/src/sort.c b/src/sort.c index 2fec46b..881465d 100644 --- a/src/sort.c +++ b/src/sort.c @@ -4,28 +4,29 @@ #include "sort.h" -bool array_is_sort(void * value, int element_count, size_t element_size, int (*compare)(const void *key1, const void *key2)){ - char *array=value; +bool +array_is_sort(void *value, int element_count, size_t element_size, int (*compare)(const void *key1, const void *key2)) { + char *array = value; void *key; - int i,j; + int i, j; // Memory space allocation for key element - if((key= (char *)malloc(element_size)) == NULL){ + if ((key = (char *) malloc(element_size)) == NULL) { free(key); return false; } // Insert multiple time a key element inside sorted element - for(j = 1; j0 && compare(&array[i*element_size], key)>0){ - memcpy(&array[(i+1)*element_size],&array[i*element_size],element_size); + while (i > 0 && compare(&array[i * element_size], key) > 0) { + memcpy(&array[(i + 1) * element_size], &array[i * element_size], element_size); i--; } - memcpy(&array[(i+1)*element_size],key,element_size); + memcpy(&array[(i + 1) * element_size], key, element_size); } free(key); diff --git a/src/stack.c b/src/stack.c index d420276..2181e3d 100644 --- a/src/stack.c +++ b/src/stack.c @@ -4,10 +4,10 @@ #include "stack.h" -bool stack_push(Stack *stack, const void *value){ +bool stack_push(Stack *stack, const void *value) { return list_add(stack, NULL, value); } -bool stack_pop(Stack * stack, void **value){ +bool stack_pop(Stack *stack, void **value) { return list_remove(stack, NULL, value); } \ No newline at end of file From 5f2b88b427bc56f9ec4a39a6a6253c410a19f110 Mon Sep 17 00:00:00 2001 From: nakira974 Date: Wed, 28 Feb 2024 23:17:28 +0100 Subject: [PATCH 13/27] Add hash_utils --- headers/hash_utils.h | 46 ++++++++++++++++++++++++++++ headers/hashmap.h | 9 +++++- headers/hashset.h | 30 ++---------------- headers/{lhashset.h => lhashtable.h} | 6 ++-- src/hash_utils.c | 44 ++++++++++++++++++++++++++ src/hashset.c | 43 +------------------------- src/{lhashset.c => lhashtable.c} | 2 +- tests/headers/LinkedHashTable_Test.h | 4 ++- 8 files changed, 108 insertions(+), 76 deletions(-) create mode 100644 headers/hash_utils.h rename headers/{lhashset.h => lhashtable.h} (96%) create mode 100644 src/hash_utils.c rename src/{lhashset.c => lhashtable.c} (99%) diff --git a/headers/hash_utils.h b/headers/hash_utils.h new file mode 100644 index 0000000..147ed72 --- /dev/null +++ b/headers/hash_utils.h @@ -0,0 +1,46 @@ +// +// Created by maxim on 28/02/2024. +// + +#ifndef COLLECTIONS_COMMONS_HASH_UTILS_H +#define COLLECTIONS_COMMONS_HASH_UTILS_H +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __cplusplus +#include +#else +#include +#include +#endif +/** +* @brief PJW method to convert the given key into a permuted integer using consecutive XOR shifts +* @param table_size Hash table size +* @param key Key to hash +* @return Generated hash table index +* @author P.J. WEINBERGER +* @see 'Compilers : Principles, Technics and Tools' from Alfred V. AHO +*/ +int hashpjw(const void* key); + +/** + * @brief Hashes the memory address of a reference and returns it as a uint64_t value + * @param table_size Hash table size + * @param ref The reference whose address is to be hashed + * @return The hashed value of the reference address + */ +int hashref(const void *ref); + +/** + * Inline assembly implementation of integer comparison. + * @param a Pointer to the first value + * @param b Pointer to the second value + * @return true if two numbers are stricly equals, false otherwise + */ +bool cmp_int(const void *a, const void *b); +#ifdef __cplusplus +} +#endif + +#endif //COLLECTIONS_COMMONS_HASH_UTILS_H diff --git a/headers/hashmap.h b/headers/hashmap.h index be9b298..88eb8b8 100644 --- a/headers/hashmap.h +++ b/headers/hashmap.h @@ -7,7 +7,11 @@ #ifndef COLLECTIONS_COMMONS_HASHMAP_H #define COLLECTIONS_COMMONS_HASHMAP_H -#include "lhashset.h" +#ifdef __cplusplus +extern "C" { +#endif + +#include "lhashtable.h" #include "set.h" /** @@ -297,4 +301,7 @@ inline bool hashmap_get(const HashMap *map, void** value){ #define hashmap_get(map,value) hashmap_containsKey #endif +#ifdef __cplusplus +} +#endif #endif //COLLECTIONS_COMMONS_HASHMAP_H diff --git a/headers/hashset.h b/headers/hashset.h index a77f634..09ee731 100644 --- a/headers/hashset.h +++ b/headers/hashset.h @@ -1,6 +1,6 @@ /** * @file sort.h - * @brief This file contains the API for hash tables functions + * @brief This file contains the API for hash tables * @author Maxime Loukhal * @date 27/02/2024 */ @@ -17,33 +17,7 @@ extern "C" { #include #include #endif -#include "lhashset.h" - -/** - * @brief PJW method to convert the given key into a permuted integer using consecutive XOR shifts - * @param table_size Hash table size - * @param key Key to hash - * @return Generated hash table index - * @author P.J. WEINBERGER - * @see 'Compilers : Principles, Technics and Tools' from Alfred V. AHO - */ -int hashpjw(const void* key); - -/** - * @brief Hashes the memory address of a reference and returns it as a uint64_t value - * @param table_size Hash table size - * @param ref The reference whose address is to be hashed - * @return The hashed value of the reference address - */ -int hashref(const void *ref); - -/** - * Inline assembly implementation of integer comparison. - * @param a Pointer to the first value - * @param b Pointer to the second value - * @return true if two numbers are stricly equals, false otherwise - */ -bool cmp_int(const void *a, const void *b); +#include "lhashtable.h" #ifdef __cplusplus diff --git a/headers/lhashset.h b/headers/lhashtable.h similarity index 96% rename from headers/lhashset.h rename to headers/lhashtable.h index 63013ba..3b703a3 100644 --- a/headers/lhashset.h +++ b/headers/lhashtable.h @@ -4,8 +4,8 @@ * @author Maxime Loukhal * @date 27/02/2024 */ -#ifndef COLLECTIONS_COMMONS_LHASHSET_H -#define COLLECTIONS_COMMONS_LHASHSET_H +#ifndef COLLECTIONS_COMMONS_LHASHTABLE_H +#define COLLECTIONS_COMMONS_LHASHTABLE_H #ifdef __cplusplus @@ -134,4 +134,4 @@ bool lhtbl_containsKey(const LinkedHashTable *lhtbl, void** value); #endif -#endif //COLLECTIONS_COMMONS_LHASHSET_H \ No newline at end of file +#endif //COLLECTIONS_COMMONS_LHASHTABLE_H \ No newline at end of file diff --git a/src/hash_utils.c b/src/hash_utils.c new file mode 100644 index 0000000..d24708d --- /dev/null +++ b/src/hash_utils.c @@ -0,0 +1,44 @@ +// +// Created by maxim on 28/02/2024. +// +#include "hash_utils.h" +bool cmp_int(const void *a, const void *b){ + if(a ==NULL || b == NULL ) return false; + int* intA = (int*)a; + int* intB = (int*)b; + + if (*intA == *intB) { + return true; + } else { + return false; + } +} + +int hashref(const void *ref) { + const double phi = (sqrt(5) - 1) / 2; + intptr_t address = (intptr_t) ref; + + return ((int)( (int) address * phi)); +} + +int hashpjw(const void* key){ + const char * string; + int value; + + // hash the key the bit to bit operations + + value = 0; + string = key; + + while(*string != '\0'){ + int temp; + value = (value<<4) + (*string); + if(temp=(value & 0xf0000000)){ + value = value ^(temp >> 24); + value = value ^temp; + } + string++; + } + + return (int) (value); +} diff --git a/src/hashset.c b/src/hashset.c index cf55713..c67b120 100644 --- a/src/hashset.c +++ b/src/hashset.c @@ -1,45 +1,4 @@ // // Created by maxim on 28/02/2024. // -#include "hashset.h" - -bool cmp_int(const void *a, const void *b){ - if(a ==NULL || b == NULL ) return false; - int* intA = (int*)a; - int* intB = (int*)b; - - if (*intA == *intB) { - return true; - } else { - return false; - } -} - -int hashref(const void *ref) { - const double phi = (sqrt(5) - 1) / 2; - intptr_t address = (intptr_t) ref; - - return ((int)( (int) address * phi)); -} - -int hashpjw(const void* key){ - const char * string; - int value; - - // hash the key the bit to bit operations - - value = 0; - string = key; - - while(*string != '\0'){ - int temp; - value = (value<<4) + (*string); - if(temp=(value & 0xf0000000)){ - value = value ^(temp >> 24); - value = value ^temp; - } - string++; - } - - return (int) (value); -} \ No newline at end of file +#include "hashset.h" \ No newline at end of file diff --git a/src/lhashset.c b/src/lhashtable.c similarity index 99% rename from src/lhashset.c rename to src/lhashtable.c index ca978ae..b3389f3 100644 --- a/src/lhashset.c +++ b/src/lhashtable.c @@ -2,7 +2,7 @@ // Created by maxim on 28/02/2024. // -#include "lhashset.h" +#include "lhashtable.h" bool lhtbl_create(LinkedHashTable *lhtbl, int containers, diff --git a/tests/headers/LinkedHashTable_Test.h b/tests/headers/LinkedHashTable_Test.h index d0fb16d..f395386 100644 --- a/tests/headers/LinkedHashTable_Test.h +++ b/tests/headers/LinkedHashTable_Test.h @@ -7,7 +7,9 @@ #ifndef COLLECTIONS_COMMONS_LINKEDHASHTABLE_TEST_H #define COLLECTIONS_COMMONS_LINKEDHASHTABLE_TEST_H #include -#include "lhashset.h" +#include "hashset.h" +#include "hash_utils.h" + class LinkedHashTableTest : public ::testing::Test { From 1fd148962d7b968f9482b518b64edc1f4fee38dd Mon Sep 17 00:00:00 2001 From: nakira974 Date: Thu, 29 Feb 2024 13:32:39 +0100 Subject: [PATCH 14/27] Fixed hashmaps --- headers/dlist.h | 12 +- headers/hashmap.h | 40 ++----- headers/hashset.h | 2 +- headers/{lhashtable.h => lhtbl.h} | 7 +- headers/set.h | 2 +- src/dlist.c | 10 +- src/hash_utils.c | 6 +- src/hashmap.c | 178 +++++++++++++++++++++++++++--- src/{lhashtable.c => lhtbl.c} | 3 +- tests/headers/HashMap_Test.h | 43 ++++++++ tests/main.cpp | 1 + 11 files changed, 240 insertions(+), 64 deletions(-) rename headers/{lhashtable.h => lhtbl.h} (96%) rename src/{lhashtable.c => lhtbl.c} (97%) create mode 100644 tests/headers/HashMap_Test.h diff --git a/headers/dlist.h b/headers/dlist.h index 4d79f54..608dd00 100644 --- a/headers/dlist.h +++ b/headers/dlist.h @@ -118,14 +118,14 @@ bool dlist_add(DLinkedList *list, DLinkedElement *element, const void *value); bool dlist_add_before(DLinkedList *list, DLinkedElement *element, const void *value); /** - * @brief Remove a given element from the current list, then returns a pointer on the value of the deleted element - * @param list Reference of the list to remove an element - * @param element Element of the list to be removed - * @param value Output pointer on the value of the deleted list element reference + * @brief Remove a given entry from the current list, then returns a pointer on the value of the deleted entry + * @param list Reference of the list to remove an entry + * @param entry Element of the list to be removed + * @param value Output pointer on the value of the deleted list entry reference * @complexity O(1) - * @return true if the element was correctly removed, false otherwise + * @return true if the entry was correctly removed, false otherwise */ -bool dlist_remove(DLinkedList *list, DLinkedElement *element, void **value); +bool dlist_remove(DLinkedList *list, DLinkedElement *entry, void **value); /** * @brief Returns a random element from the given list diff --git a/headers/hashmap.h b/headers/hashmap.h index 88eb8b8..d904aff 100644 --- a/headers/hashmap.h +++ b/headers/hashmap.h @@ -11,7 +11,7 @@ extern "C" { #endif -#include "lhashtable.h" +#include "lhtbl.h" #include "set.h" /** @@ -31,6 +31,11 @@ typedef struct SimpleEntry { * @brief Next entry in the hashmap */ struct SimpleEntry *next; + + /** + * @brief Next entry in the hashmap + */ + struct SimpleEntry *last; } SimpleEntry; /** @@ -150,21 +155,7 @@ bool hashmap_removeEntry( HashMap *map, SimpleEntry *entry, void **value); * @param value Double pointer to remove the key in the given hashmap, if a delete occurs returns the pointer on it * @return true if the data table is present in the given hashmap, false otherwise */ -bool hashmap_containsKey(const HashMap *map, void** value); - -/** - * @brief Returns the keys of the given hashmap as set - * @param map Hashmap to get keys as set - * @return A set of the given hashmap keys - */ -Set * hashmap_keySet(HashMap *map); - -/** - * @brief Returns entries of the given hashmap as set - * @param map Hashmap to get entries as set - * @return A set of the given hashmap entries - */ -Set * hashmap_entrySet(HashMap *map); +bool hashmap_containsKey(HashMap *map, void** value); #ifdef __cplusplus /** @@ -182,7 +173,7 @@ inline int hashmap_size(HashMap *hashmap){ * @return The first entry of the current hashmap * @complexity O(1) */ -inline HashMap* hashmap_first(HashMap * hashmap){ +inline SimpleEntry * hashmap_first(HashMap * hashmap){ return hashmap->head; }; @@ -191,7 +182,7 @@ inline HashMap* hashmap_first(HashMap * hashmap){ * @return The last entry of the current hashmap * @complexity O(1) */ -inline HashMap * hashmap_last(HashMap * hashmap){ +inline SimpleEntry * hashmap_last(HashMap * hashmap){ return hashmap->tail; }; @@ -200,7 +191,7 @@ inline HashMap * hashmap_last(HashMap * hashmap){ * @return true if the entry is the first of the current hashmap, false otherwise * @complexity O(1) */ -inline bool hashmap_is_first(LinkedList * hashmap, SimpleEntry *entry){ +inline bool hashmap_is_first(HashMap * hashmap, SimpleEntry *entry){ return (hashmap)->head == entry; }; @@ -213,15 +204,6 @@ inline bool hashmap_is_last(HashMap * hashmap, SimpleEntry *entry){ return (hashmap)->tail == entry; }; -/** - * @brief Inline function that evaluates the value of a hashmap entry - * @return The value stored inside a hashmap entry - * @complexity O(1) - */ -inline void *hashmap_get(void * key){ - return ((entry)->value); -}; - /** * @brief Inline function that evaluates the next entry of the current hashmap entry * @return The reference to the next entry of the current hashmap entry @@ -238,7 +220,7 @@ inline SimpleEntry *hashmap_next(SimpleEntry *entry){ * @param value Double pointer to remove the key in the given hashmap, if a equals occurs returns the pointer on it * @return true if the data table is present in the given hashmap, false otherwise */ -inline bool hashmap_get(const HashMap *map, void** value){ +inline bool hashmap_get(HashMap *map, void** value){ return hashmap_containsKey(map, value); }; #else diff --git a/headers/hashset.h b/headers/hashset.h index 09ee731..6a800cb 100644 --- a/headers/hashset.h +++ b/headers/hashset.h @@ -17,7 +17,7 @@ extern "C" { #include #include #endif -#include "lhashtable.h" +#include "lhtbl.h" #ifdef __cplusplus diff --git a/headers/lhashtable.h b/headers/lhtbl.h similarity index 96% rename from headers/lhashtable.h rename to headers/lhtbl.h index 3b703a3..ffbff17 100644 --- a/headers/lhashtable.h +++ b/headers/lhtbl.h @@ -4,8 +4,8 @@ * @author Maxime Loukhal * @date 27/02/2024 */ -#ifndef COLLECTIONS_COMMONS_LHASHTABLE_H -#define COLLECTIONS_COMMONS_LHASHTABLE_H +#ifndef COLLECTIONS_COMMONS_LHTBL_H +#define COLLECTIONS_COMMONS_LHTBL_H #ifdef __cplusplus @@ -23,7 +23,6 @@ extern "C" { #endif #include "list.h" -#include "hashset.h" /** * @brief Data structure definition for a linked hash table */ @@ -134,4 +133,4 @@ bool lhtbl_containsKey(const LinkedHashTable *lhtbl, void** value); #endif -#endif //COLLECTIONS_COMMONS_LHASHTABLE_H \ No newline at end of file +#endif //COLLECTIONS_COMMONS_LHTBL_H \ No newline at end of file diff --git a/headers/set.h b/headers/set.h index 8410d6b..d61d1e5 100644 --- a/headers/set.h +++ b/headers/set.h @@ -110,7 +110,7 @@ bool set_is_equal(const Set *left, const Set *right); * @complexity O(1) */ static inline int set_size(const Set * set){ - return list_size(set); + return list_size((LinkedList*)set); }; /** diff --git a/src/dlist.c b/src/dlist.c index 5ae898f..2aa0b61 100644 --- a/src/dlist.c +++ b/src/dlist.c @@ -41,13 +41,15 @@ bool dlist_add(DLinkedList *list, DLinkedElement *element, const void *value) { list->head = new_element; list->head->previous = NULL; list->head->next = NULL; - list->tail = NULL; + list->tail = new_element; } else { // Non-empty list case new_element->next = element->next; new_element->previous = element; if (element->next == NULL) list->tail = new_element; - else element->next = new_element; + else element->next->previous = new_element; + + element->next = new_element; } list->size++; @@ -101,7 +103,7 @@ bool dlist_remove(DLinkedList *list, DLinkedElement *element, void **value) { // Remove the element from the list *value = element->value; - if (element == list->head) { + if (dlist_is_first(list, element)) { // The list become after deletion empty case list->head = element->next; if (list->head == NULL) @@ -110,7 +112,7 @@ bool dlist_remove(DLinkedList *list, DLinkedElement *element, void **value) { element->next->previous = NULL; } else { // The list does not become empty after deletion case - element->previous->next = element->previous; + element->previous->next = element->next; if (element->next == NULL) list->tail = element->previous; diff --git a/src/hash_utils.c b/src/hash_utils.c index d24708d..c0a613d 100644 --- a/src/hash_utils.c +++ b/src/hash_utils.c @@ -4,10 +4,10 @@ #include "hash_utils.h" bool cmp_int(const void *a, const void *b){ if(a ==NULL || b == NULL ) return false; - int* intA = (int*)a; - int* intB = (int*)b; + int intA = *((int*)a); + int intB = *((int*)b); - if (*intA == *intB) { + if (intA == intB) { return true; } else { return false; diff --git a/src/hashmap.c b/src/hashmap.c index a1de6b4..695a4ea 100644 --- a/src/hashmap.c +++ b/src/hashmap.c @@ -3,17 +3,83 @@ // #include "hashmap.h" +/** + * @brief Private method double like double linked list add + * @param map Map to put a new entry in + * @param last_entry Entry to add before + * @param new_entry Entry to be added + * @return true if the entry was added, false otherwise + */ +bool hashmap_push(HashMap *map, SimpleEntry *entry, SimpleEntry * new_entry) { + // Reject null hashtable except if list is empty + if (entry == NULL && hashmap_size(map) != 0) return false; + + + if (hashmap_size(map) == 0) { + // Empty list case + map->head = new_entry; + map->head->last = NULL; + map->head->next = NULL; + map->tail = new_entry; + } else { + // Non-empty list case + new_entry->next = entry->next; + new_entry->last = entry; + if (entry->next == NULL) map->tail = new_entry; + else entry->next->last = new_entry; + + entry->next = new_entry; + } + + map->size++; + return true; +} + +/** + * @brief Private method like double linked map remove + * @param map Hashmap to remove an entry + * @param entry Entry to be removed from the hashmap + * @param value Pointer on entry value + * @return true if the entry was removed from the hashmap, false otherwise + */ +bool hashmap_pop(HashMap *map, SimpleEntry *entry, void **value) { + // Do not authorize a null entry or in an empty map + if (hashmap_size(map) == 0 || entry == NULL) return false; + + // Remove the entry from the map + *value = entry->value; + if (entry == map->head) { + // The map become after deletion empty case + map->head = entry->next; + if (map->head == NULL) + map->tail = NULL; + else + entry->next->last = NULL; + } else { + // The map does not become empty after deletion case + entry->last->next = entry->next; + + if (entry->next == NULL) + map->tail = entry->last; + else entry->next->last = entry->last; + } + + free(entry); + + map->size--; + return true; +} + bool hashmap_create(HashMap *map, int containers, int (*hash)(const void *key), bool (*equals)(const void* key1, const void* key2), void(*destroy)(void *value)){ - int i; // Try To Allocate memory space for the linked hash table - + if(map == NULL) return false; + if((map->hashTable = (LinkedHashTable*) malloc(sizeof (LinkedHashTable)) )== NULL) return false; if(!lhtbl_create(map->hashTable, containers, hash, equals, destroy)) return false; - // Init the map map->size = 0; map->equals = equals; @@ -25,11 +91,18 @@ bool hashmap_create(HashMap *map, } void hashmap_destroy(HashMap *map){ + if(map == NULL) return; + SimpleEntry *current_entry; + void *temp; + for(current_entry= hashmap_first(map);current_entry!=NULL; current_entry= hashmap_next(current_entry)){ + if(!hashmap_removeEntry(map, current_entry, &temp)) return; + } lhtbl_destroy(map->hashTable); memset(map, 0, sizeof(HashMap)); } -bool hashmap_containsKey(const HashMap *map, void** value){ +bool hashmap_containsKey(HashMap *map, void** value){ + if(value == NULL || map == NULL) return false; LinkedElement *current_element; int current_container; @@ -40,7 +113,7 @@ bool hashmap_containsKey(const HashMap *map, void** value){ for(current_element= list_first(&map->hashTable->hashtable[current_container]); current_element != NULL; current_element= list_next(current_element) ){ SimpleEntry * current_entry = (SimpleEntry*)list_value(current_element); - if(map->hashTable->equals(*value, current_entry->key)){ + if(map->hashTable->equals(value, ¤t_entry->key)){ *value = list_value(current_element); return true; } @@ -52,10 +125,10 @@ bool hashmap_containsKey(const HashMap *map, void** value){ bool hashmap_put(HashMap *map, void *key, void *value){ bool result = false; - if(hashmap_containsKey((const HashMap *) map->hashTable, key)){ + if(hashmap_containsKey( map, &key)){ void* old_value = value; if(hashmap_replace(map,key, &old_value)){ - free(old_value); + map->destroy(old_value); return true; } }else{ @@ -69,10 +142,8 @@ bool hashmap_put(HashMap *map, void *key, void *value){ new_entry->value = value; // Add the current key value pair to the container if((result = list_add(&map->hashTable->hashtable[container], NULL, new_entry))){ - if (hashmap_size(map) == 0) map->tail = new_entry; - new_entry->next = map->head; - map->head = new_entry; - result = true; + map->hashTable->size++; + result = hashmap_push(map, hashmap_first(map), new_entry); } } @@ -82,11 +153,11 @@ bool hashmap_put(HashMap *map, void *key, void *value){ bool hashmap_addEntry(HashMap *map, SimpleEntry *entry){ bool result = false; - if(hashmap_containsKey((const HashMap *) map->hashTable, entry->key)){ + if(hashmap_containsKey(map, &entry->key)){ void* old_value = entry->value; if(hashmap_replace(map,entry->key, &old_value)){ - free(old_value); - return true; + map->destroy(old_value); + result = true; } }else{ int container; @@ -109,5 +180,82 @@ bool hashmap_addEntry(HashMap *map, SimpleEntry *entry){ } bool hashmap_putIfAbsent(HashMap *map, void *key, void *value){ + if(!hashmap_containsKey(map, &key)){ + if(hashmap_put(map, key, value)){ + return true; + } + } + return false; +} + +bool hashmap_replace(HashMap *map, void *key,void** value){ + bool result=false; + if(!hashmap_containsKey(map, &key)) return result; + int container; + + // Hash the given key with the user function + container = map->hashTable->hash(key) % map->hashTable->containers; + // Replace the current key value in the container + SimpleEntry *current_entry; + LinkedElement * current_element; + for(current_element= list_first(&map->hashTable->hashtable[container])->value;current_element!=NULL;current_element= list_next(current_element)) { + current_entry = (SimpleEntry *) current_element->value; + if (map->equals(current_entry->key, key)) { + void *temp = current_entry->value; + current_entry->value = *value; + value = temp; + map->destroy(temp); + result = true; + break; + } + } + return result; +} -} \ No newline at end of file +bool hashmap_remove(HashMap *map, void** value){ + if(map == NULL || map->size == 0) return false; + bool result=false; + void* temp = *value; + if(!hashmap_containsKey(map, value)) return result; + + LinkedElement *current_element,*last_element; + int current_container; + current_container = map->hashTable->hash(temp) % map->hashTable->containers; + + // Search for the value inside the current container + last_element = NULL; + + for(current_element= list_first(&map->hashTable->hashtable[current_container]); current_element != NULL; current_element = list_next(current_element)){ + // If the target value if equals to the current container element, then remove it + if( map->hashTable->equals(*value, &((SimpleEntry*)list_value(current_element))->key)){ + // Remove the value from the current container + if(list_remove(& map->hashTable->hashtable[current_container], last_element, *value)){ + map->hashTable->size--; + result= true; + break; + // Can't remove the data from the current container + }else{ + result= false; + break; + } + } + last_element = current_element; + } + if(result){ + SimpleEntry * current_entry= (SimpleEntry *) *value; + void* key_value; + result = hashmap_pop(map, current_entry, &key_value); + *value = key_value; + map->destroy(key_value); + } + return result; +} + +bool hashmap_removeEntry( HashMap *map, SimpleEntry *entry, void **value){ + bool result=false; + void* temp = entry->key; + if(!hashmap_containsKey(map, &temp)) return result; + result = hashmap_remove(map,temp); + value = temp; + return result; +} diff --git a/src/lhashtable.c b/src/lhtbl.c similarity index 97% rename from src/lhashtable.c rename to src/lhtbl.c index b3389f3..7665215 100644 --- a/src/lhashtable.c +++ b/src/lhtbl.c @@ -2,13 +2,14 @@ // Created by maxim on 28/02/2024. // -#include "lhashtable.h" +#include "lhtbl.h" bool lhtbl_create(LinkedHashTable *lhtbl, int containers, int (*hash)(const void *key), bool (*equals)(const void* key1, const void* key2), void(*destroy)(void *value)){ + if(hash == NULL || equals == NULL || destroy == NULL) return false; int i; diff --git a/tests/headers/HashMap_Test.h b/tests/headers/HashMap_Test.h new file mode 100644 index 0000000..932543b --- /dev/null +++ b/tests/headers/HashMap_Test.h @@ -0,0 +1,43 @@ +#include "gtest/gtest.h" +#include "hashmap.h" +#include "hash_utils.h" + +struct Chunk { + int data; +}; + +class HashMapTest : public testing::Test { +protected: + HashMap *map; + + void SetUp() override { + map = (HashMap *) malloc(sizeof(HashMap)); + hashmap_create(map, 16, hashref, cmp_int, free); + } + + void TearDown() override { + hashmap_destroy(map); + } +}; + +TEST_F(HashMapTest, BasicTest) { + Chunk *chunk1,*chunk2; + chunk1 = (Chunk *) malloc(sizeof(Chunk)); + chunk2 = (Chunk *) malloc(sizeof(Chunk)); + chunk1->data=1; + chunk2->data=2; + + ASSERT_TRUE(hashmap_put(map, reinterpret_cast(chunk1->data), (void*)chunk1)); + ASSERT_TRUE(hashmap_put(map, reinterpret_cast(chunk2->data), (void*)chunk2)); + + Chunk *value; + void* temp = reinterpret_cast(chunk1->data); + ASSERT_TRUE(hashmap_get(map, &temp)); + value = (Chunk *)temp; + ASSERT_EQ(value->data, 1); + temp = reinterpret_cast(chunk2->data); + ASSERT_TRUE(hashmap_remove(map, &temp)); + ASSERT_FALSE(hashmap_containsKey(map, reinterpret_cast(&chunk2->data))); + + ASSERT_EQ(hashmap_size(map), 1); +} \ No newline at end of file diff --git a/tests/main.cpp b/tests/main.cpp index 106959a..06a96e6 100644 --- a/tests/main.cpp +++ b/tests/main.cpp @@ -10,6 +10,7 @@ #include "EventBus_Test.h" #include "Exception_Test.h" #include "LinkedHashTable_Test.h" +#include "HashMap_Test.h" int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); From 3bb665d4de45edc3f3c5f360ddfe2b8f74a9667a Mon Sep 17 00:00:00 2001 From: nakira974 Date: Thu, 29 Feb 2024 20:50:27 +0100 Subject: [PATCH 15/27] Rename some functions, created Set_Test.h, fixed DLinkedList_Test.h and LinkedList_Test.h, fixed some LinkedList, DLinkedList and CLinkedList problems, fixed HashMap_Test.h and hashmap impl --- README.md | 4 +- headers/clist.h | 29 ++-- headers/dlist.h | 42 +++-- headers/event.h | 22 +-- headers/frame.h | 4 + headers/hash_utils.h | 12 +- headers/hashmap.h | 47 +++--- headers/lhtbl.h | 24 +-- headers/list.h | 39 +++-- headers/page.h | 5 +- headers/queue.h | 20 +-- headers/set.h | 28 ++-- headers/set_entry.h | 8 +- headers/sort.h | 23 +-- headers/stack.h | 16 +- src/clist.c | 2 +- src/dlist.c | 6 +- src/hash_utils.c | 33 ++-- src/hashmap.c | 121 ++++++++------- src/lhtbl.c | 40 ++--- src/list.c | 2 +- src/set.c | 37 ++--- tests/headers/CLinkedList_Test.h | 2 +- tests/headers/DLinkedList_Test.h | 35 +++-- tests/headers/HashMap_Test.h | 5 +- tests/headers/LinkedList_Test.h | 30 +--- tests/headers/Set_Test.h | 254 +++++++++++++++++++++++++++++++ tests/main.cpp | 1 + 28 files changed, 582 insertions(+), 309 deletions(-) create mode 100644 tests/headers/Set_Test.h diff --git a/README.md b/README.md index f8d8c54..930631d 100644 --- a/README.md +++ b/README.md @@ -8,9 +8,9 @@ hash maps, and array lists. It allows you to efficiently manage and manipulate c - [x] Linked list implementation for storing and traversing data in a dynamic manner. - [ ] (Not release yet) Hash map implementation for fast key-value lookups and storage. - [ ] (Not release yet) Array list implementation for efficient random access and dynamic resizing. -- [x] Binary trees implementations for organizing and efficiently searching data. +- [x] Binary trees implementations for organizing and efficiently searching data. - [x] Randomized set implementation for storing and traversing data in a dynamic manner. -- [x] Queues implementation for storing hashtable in the order they were added +- [x] Queues implementation for storing hashtable in the order they were added ## Usage diff --git a/headers/clist.h b/headers/clist.h index 15a89c7..19e9350 100644 --- a/headers/clist.h +++ b/headers/clist.h @@ -23,7 +23,6 @@ extern "C" { #endif - /** * @brief Data structure for circular linked list element */ @@ -55,7 +54,7 @@ typedef struct ClinkedList { * @param val2 Right value to compare * @return true if left is equals to right, false otherwise */ - int (*equals)(const void *val1, const void *val2); + bool (*equals)(const void *val1, const void *val2); /** * @brief Destroy handle @@ -115,7 +114,7 @@ bool clist_remove(CLinkedList *list, CLinkedElement *element, void **value); * @param random_element Reference to a random element * @return true if a random element has been returned, false otherwise */ -CLinkedElement * clist_get_random(CLinkedList *list); +CLinkedElement *clist_getRandom(CLinkedList *list); /** * @brief Replace a specified element from the given list with the specified value @@ -124,7 +123,7 @@ CLinkedElement * clist_get_random(CLinkedList *list); * @param value Value to replace * @return true if the given element's value was replaces, false otherwise */ -bool clist_replace(CLinkedList *list, CLinkedElement *element, void **value); +bool clist_replace(CLinkedList *list, CLinkedElement *element, void **value); /* ----- MACRO C++ COMPATIBILITY -----*/ #ifdef __cplusplus @@ -133,43 +132,43 @@ bool clist_replace(CLinkedList *list, CLinkedElement *element, void **value); * @return The current element count of the current list * @complexity O(1) */ -inline int clist_size(CLinkedList *list){ +inline int clist_size(CLinkedList *list) { return list->size; -}; +} ; /*** * Inline function that evaluates the first element of the specified list * @return The first element of the current list * @complexity O(1) */ -inline CLinkedElement* clist_first(CLinkedList * list){ +inline CLinkedElement *clist_first(CLinkedList *list) { return list->head; -}; +} ; /*** * Inline function that evaluates if the specified element is the first element of the specified list * @return true if the element is the first of the current list, false otherwise * @complexity O(1) */ -inline bool clist_is_first(CLinkedList * list, CLinkedElement *element){ +inline bool clist_isFirst(CLinkedList *list, CLinkedElement *element) { return (list)->head == element; -}; +} ; /*** * Inline function that evaluates the value of a list element * @return The value stored inside a list element * @complexity O(1) */ -inline void *clist_value(CLinkedElement *element){ +inline void *clist_value(CLinkedElement *element) { return ((element)->value); -}; +} ; /*** * Inline function that evaluates the next element of the current list element * @return The reference to the next element of the current list element * @complexity O(1) */ -inline CLinkedElement *clist_next(CLinkedElement *element){ +inline CLinkedElement *clist_next(CLinkedElement *element) { return (element)->next; } @@ -194,7 +193,7 @@ inline CLinkedElement *clist_next(CLinkedElement *element){ * @return true if the element is the first of the current list, false otherwise * @complexity O(1) */ -#define list_is_first(list, element) ((element) == (list)->head ? true : false ) +#define list_isFirst(list, element) ((element) == (list)->head ? true : false ) /** * @brief Macro that evaluates the value of a list element @@ -216,6 +215,4 @@ inline CLinkedElement *clist_next(CLinkedElement *element){ #endif - - #endif //COLLECTIONS_COMMONS_CLIST_H diff --git a/headers/dlist.h b/headers/dlist.h index 608dd00..c2ed57d 100644 --- a/headers/dlist.h +++ b/headers/dlist.h @@ -22,7 +22,6 @@ extern "C" { #endif - /** * @brief Data structure definition for a double chained linked list generic element */ @@ -55,7 +54,7 @@ typedef struct DLinkedList { * @param val2 Right value to compare * @return true if left is equals to right, false otherwise */ - int (*equals)(const void *val1, const void *val2); + bool (*equals)(const void *val1, const void *val2); /** * @brief Destroy handle @@ -115,7 +114,7 @@ bool dlist_add(DLinkedList *list, DLinkedElement *element, const void *value); * @return true if the element was added to the current list, false otherwise * */ -bool dlist_add_before(DLinkedList *list, DLinkedElement *element, const void *value); +bool dlist_addBefore(DLinkedList *list, DLinkedElement *element, const void *value); /** * @brief Remove a given entry from the current list, then returns a pointer on the value of the deleted entry @@ -133,7 +132,7 @@ bool dlist_remove(DLinkedList *list, DLinkedElement *entry, void **value); * @param value Reference to a random element * @return true if a random element has been returned, false otherwise */ -DLinkedElement * dlist_get_random(DLinkedList *list); +DLinkedElement *dlist_getRandom(DLinkedList *list); /** * @brief Replace a specified element from the given list with the specified value @@ -142,7 +141,7 @@ DLinkedElement * dlist_get_random(DLinkedList *list); * @param value Value to replace * @return true if the given element's value was replaces, false otherwise */ -bool dlist_replace(DLinkedList *list, DLinkedElement *element, void **value); +bool dlist_replace(DLinkedList *list, DLinkedElement *element, void **value); /* ----- MACRO C++ COMPATIBILITY -----*/ #ifdef __cplusplus @@ -151,61 +150,61 @@ bool dlist_replace(DLinkedList *list, DLinkedElement *element, void **value); * @return The current element count of the current list * @complexity O(1) */ -inline int dlist_size(DLinkedList *list){ +inline int dlist_size(DLinkedList *list) { return list->size; -}; +} ; /*** * @brief Inline function that evaluates the first element of the specified list * @return The first element of the current list * @complexity O(1) */ -inline DLinkedElement* dlist_first(DLinkedList * list){ +inline DLinkedElement *dlist_first(DLinkedList *list) { return list->head; -}; +} ; /*** * @brief Inline function that evaluates the last element of the specified list * @return The last element of the current list * @complexity O(1) */ -inline DLinkedElement *dlist_last(DLinkedList * list){ +inline DLinkedElement *dlist_last(DLinkedList *list) { return list->tail; -}; +} ; /*** * @brief Inline function that evaluates if the specified element is the first element of the specified list * @return true if the element is the first of the current list, false otherwise * @complexity O(1) */ -inline bool dlist_is_first(DLinkedList * list, DLinkedElement *element){ +inline bool dlist_isFirst(DLinkedList *list, DLinkedElement *element) { return (element)->previous == nullptr; -}; +} ; /*** * @brief Inline function that evaluates if the specified element is the last element of the specified list * @return true if the element is the last of the current list, false otherwise * @complexity O(1) */ -inline bool dlist_is_last(DLinkedList * list, DLinkedElement *element){ +inline bool dlist_isLast(DLinkedList *list, DLinkedElement *element) { return (element)->next == nullptr; -}; +} ; /*** * @brief Inline function that evaluates the value of a list element * @return The value stored inside a list element * @complexity O(1) */ -inline void *dlist_value(DLinkedElement *element){ +inline void *dlist_value(DLinkedElement *element) { return ((element)->value); -}; +} ; /*** * @brief Inline function that evaluates the next element of the current list element * @return The reference to the next element of the current list element * @complexity O(1) */ -inline DLinkedElement *dlist_next(DLinkedElement *element){ +inline DLinkedElement *dlist_next(DLinkedElement *element) { return (element)->next; } @@ -214,7 +213,7 @@ inline DLinkedElement *dlist_next(DLinkedElement *element){ * @return The reference to the next element of the current list element * @complexity O(1) */ -inline DLinkedElement *dlist_previous(DLinkedElement *element){ +inline DLinkedElement *dlist_previous(DLinkedElement *element) { return (element)->previous; } @@ -246,14 +245,14 @@ inline DLinkedElement *dlist_previous(DLinkedElement *element){ * @return true if the element is the first of the current list, false otherwise * @complexity O(1) */ -#define dlist_is_first(list, element) ((element)->previous == NULL ? true : false ) +#define dlist_isFirst(list, element) ((element)->previous == NULL ? true : false ) /*** * @brief Macro that evaluates if the specified element is the last element of the specified list * @return true if the element is the last of the current list, false otherwise * @complexity O(1) */ -#define dlist_is_last(list, element) ((element)->next == NULL ? true : false ) +#define dlist_isLast(list, element) ((element)->next == NULL ? true : false ) /*** * @brief Macro that evaluates the value of a list element @@ -283,5 +282,4 @@ inline DLinkedElement *dlist_previous(DLinkedElement *element){ #endif - #endif //COLLECTIONS_COMMONS_DLIST_H diff --git a/headers/event.h b/headers/event.h index 7abb406..adc1350 100644 --- a/headers/event.h +++ b/headers/event.h @@ -25,9 +25,9 @@ extern "C" { /** * @brief Data structure definition of an event */ -typedef struct Event{ +typedef struct Event { int eventType; - void* eventData; + void *eventData; } Event; /** @@ -36,15 +36,15 @@ typedef struct Event{ * @param event Event to save into the queue * @return true if the event was added in events, false otherwise */ - bool event_receive(Queue * events, const Event *event); - - /** - * @brief Interruption handle to process subscribed events - * @param events Events queue - * @param on_event_received User function to process the event - * @return true if the event was computed, false otherwise - */ - bool event_process(Queue *events, int(* on_event_received) (Event * event)); +bool event_receive(Queue *events, const Event *event); + +/** + * @brief Interruption handle to process subscribed events + * @param events Events queue + * @param on_event_received User function to process the event + * @return true if the event was computed, false otherwise + */ +bool event_process(Queue *events, int(*on_event_received)(Event *event)); #ifdef __cplusplus } diff --git a/headers/frame.h b/headers/frame.h index 2f519cf..3eba541 100644 --- a/headers/frame.h +++ b/headers/frame.h @@ -12,7 +12,9 @@ #include #include #else + #include + #endif #include "list.h" @@ -20,6 +22,7 @@ #ifdef __cplusplus extern "C" { #endif + /** * @brief Try to allocate a frame, then returns its index * @param frames @@ -34,6 +37,7 @@ int frame_alloc(LinkedList *frames); * @return true if the frame was destroy, false otherwise */ bool frame_destroy(LinkedList *frames, int frame_id); + #ifdef __cplusplus } #endif diff --git a/headers/hash_utils.h b/headers/hash_utils.h index 147ed72..c6011e3 100644 --- a/headers/hash_utils.h +++ b/headers/hash_utils.h @@ -22,7 +22,7 @@ extern "C" { * @author P.J. WEINBERGER * @see 'Compilers : Principles, Technics and Tools' from Alfred V. AHO */ -int hashpjw(const void* key); +int hashpjw(const void *key); /** * @brief Hashes the memory address of a reference and returns it as a uint64_t value @@ -32,6 +32,16 @@ int hashpjw(const void* key); */ int hashref(const void *ref); +/** + * @brief Takes an input integer and returns an integer hash value. + * + * @param integer The input integer for which the hash value needs to be calculated. + * @return The calculated hash value as an integer. + * @see https://stackoverflow.com/questions/664014/what-integer-hash-function-are-good-that-accepts-an-integer-hash-key + * @details The magic number used in the hash calculation was determined through a rigorous testing process. A special multi-threaded test program was employed, running for several hours. This program evaluated key factors such as the avalanche effect (the number of output bits that change if a single input bit is changed, which should be nearly 16 on average), independence of output bit changes (ensuring that output bits do not depend on each other), and the probability of a change in each output bit if any input bit is changed. The calculated values outperform the 32-bit finalizer used by MurmurHash and are almost as good as when using AES. Additionally, the use of the same constant twice provides a slight advantage, resulting in improved performance based on previous tests. However, it is important to note that the exact impact on performance may vary and further testing is recommended. + */ +int hashint(const void *integer); + /** * Inline assembly implementation of integer comparison. * @param a Pointer to the first value diff --git a/headers/hashmap.h b/headers/hashmap.h index d904aff..b207055 100644 --- a/headers/hashmap.h +++ b/headers/hashmap.h @@ -12,7 +12,6 @@ extern "C" { #endif #include "lhtbl.h" -#include "set.h" /** * @brief Hashmap Key-Value pair entry @@ -85,10 +84,10 @@ typedef struct HashMap { * @return true if the hashmap was created successfully, false otherwise */ bool hashmap_create(HashMap *map, - int containers, - int (*hash)(const void *key), - bool (*equals)(const void* key1, const void* key2), - void(*destroy)(void *value)); + int containers, + int (*hash)(const void *key), + bool (*equals)(const void *key1, const void *key2), + void(*destroy)(void *value)); /** * @brief Destroy the given hashmap and all its entries @@ -130,7 +129,7 @@ bool hashmap_putIfAbsent(HashMap *map, void *key, void *value); * @param old_value Pointer on the old key value * @return true if the replace occurs */ -bool hashmap_replace(HashMap *map, void *key,void** value); +bool hashmap_replace(HashMap *map, void *key, void **value); /** * @brief Remove a given entry from the current hashmap, then returns a pointer on the value of the deleted element @@ -138,7 +137,7 @@ bool hashmap_replace(HashMap *map, void *key,void** value); * @param value Double pointer of the key to delete, if deletion occurs returns pointer on the value of the deleted entry value * @return true if the element was correctly removed, false otherwise */ -bool hashmap_remove(HashMap *map, void** value); +bool hashmap_remove(HashMap *map, void **value); /** * @brief Remove a given entry from the current hashmap, then returns a pointer on the value of the deleted element @@ -147,7 +146,7 @@ bool hashmap_remove(HashMap *map, void** value); * @param value Output pointer on the value of the deleted entry value * @return true if the element was correctly removed, false otherwise */ -bool hashmap_removeEntry( HashMap *map, SimpleEntry *entry, void **value); +bool hashmap_removeEntry(HashMap *map, SimpleEntry *entry, void **value); /** * @brief Test if the given value is present in the hashmap, if a equals occurs value will contain the pointer on the equalsed value @@ -155,7 +154,7 @@ bool hashmap_removeEntry( HashMap *map, SimpleEntry *entry, void **value); * @param value Double pointer to remove the key in the given hashmap, if a delete occurs returns the pointer on it * @return true if the data table is present in the given hashmap, false otherwise */ -bool hashmap_containsKey(HashMap *map, void** value); +bool hashmap_containsKey(HashMap *map, void **value); #ifdef __cplusplus /** @@ -163,9 +162,9 @@ bool hashmap_containsKey(HashMap *map, void** value); * @return The current entry count of the current hashmap * @complexity O(1) */ -inline int hashmap_size(HashMap *hashmap){ +inline int hashmap_size(HashMap *hashmap) { return hashmap->size; -}; +} ; /** @@ -173,43 +172,43 @@ inline int hashmap_size(HashMap *hashmap){ * @return The first entry of the current hashmap * @complexity O(1) */ -inline SimpleEntry * hashmap_first(HashMap * hashmap){ +inline SimpleEntry *hashmap_first(HashMap *hashmap) { return hashmap->head; -}; +} ; /** * @brief Inline function that evaluates the last entry of the specified hashmap * @return The last entry of the current hashmap * @complexity O(1) */ -inline SimpleEntry * hashmap_last(HashMap * hashmap){ +inline SimpleEntry *hashmap_last(HashMap *hashmap) { return hashmap->tail; -}; +} ; /** * @brief Inline function that evaluates if the specified entry is the first entry of the specified hashmap * @return true if the entry is the first of the current hashmap, false otherwise * @complexity O(1) */ -inline bool hashmap_is_first(HashMap * hashmap, SimpleEntry *entry){ +inline bool hashmap_isFirst(HashMap *hashmap, SimpleEntry *entry) { return (hashmap)->head == entry; -}; +} ; /** * @brief Inline function that evaluates if the specified entry is the last entry of the specified hashmap * @return true if the entry is the last of the current hashmap, false otherwise * @complexity O(1) */ -inline bool hashmap_is_last(HashMap * hashmap, SimpleEntry *entry){ +inline bool hashmap_isLast(HashMap *hashmap, SimpleEntry *entry) { return (hashmap)->tail == entry; -}; +} ; /** * @brief Inline function that evaluates the next entry of the current hashmap entry * @return The reference to the next entry of the current hashmap entry * @complexity O(1) */ -inline SimpleEntry *hashmap_next(SimpleEntry *entry){ +inline SimpleEntry *hashmap_next(SimpleEntry *entry) { if (entry == nullptr) return nullptr; else return (entry)->next == nullptr ? nullptr : (entry)->next; } @@ -220,9 +219,9 @@ inline SimpleEntry *hashmap_next(SimpleEntry *entry){ * @param value Double pointer to remove the key in the given hashmap, if a equals occurs returns the pointer on it * @return true if the data table is present in the given hashmap, false otherwise */ -inline bool hashmap_get(HashMap *map, void** value){ +inline bool hashmap_get(HashMap *map, void **value) { return hashmap_containsKey(map, value); -}; +} ; #else /** * @brief Macro that evaluates the number of hashtable inside the specified hashmap @@ -250,14 +249,14 @@ inline bool hashmap_get(HashMap *map, void** value){ * @return true if the entry is the first of the current hashmap, false otherwise * @complexity O(1) */ -#define hashmap_is_first(hashmap, entry) ((entry) == (hashmap)->head ? true : false ) +#define hashmap_isFirst(hashmap, entry) ((entry) == (hashmap)->head ? true : false ) /** * @brief Macro that evaluates if the specified entry is the last entry of the specified hashmap * @return true if the entry is the last of the current hashmap, false otherwise * @complexity O(1) */ -#define hashmap_is_last(hashmap, entry) ((entry) == (hashmap)->tail ? true : false ) +#define hashmap_isLast(hashmap, entry) ((entry) == (hashmap)->tail ? true : false ) /** * @brief Macro that evaluates the value of a hashmap entry diff --git a/headers/lhtbl.h b/headers/lhtbl.h index ffbff17..e2eb684 100644 --- a/headers/lhtbl.h +++ b/headers/lhtbl.h @@ -26,7 +26,7 @@ extern "C" { /** * @brief Data structure definition for a linked hash table */ -typedef struct LinkedHashTable{ +typedef struct LinkedHashTable { /** * @brief Number of containers in the linked hash table */ @@ -45,13 +45,13 @@ typedef struct LinkedHashTable{ * @param key2 The second key to be compared * @return 0 if the keys equals, non-zero otherwise */ - bool (*equals)(const void* key1, const void* key2); + bool (*equals)(const void *key1, const void *key2); /** * @brief Pointer to the destroy function for hashtable * @param value The value to be destroyed */ - void(*destroy)(void *value); + void (*destroy)(void *value); /** * @brief Current element count of the hash table @@ -70,9 +70,9 @@ typedef struct LinkedHashTable{ * @return The current element count of the current list * @complexity O(1) */ -inline int lhtbl_size(LinkedHashTable *queue){ +inline int lhtbl_size(LinkedHashTable *queue) { return queue->size; -}; +} ; #else /*** @@ -93,10 +93,10 @@ inline int lhtbl_size(LinkedHashTable *queue){ * @return true if the hash table has been created successfully, false otherwise */ bool lhtbl_create(LinkedHashTable *lhtbl, - int containers, - int (*hash)(const void *key), - bool (*equals)(const void* key1, const void* key2), - void(*destroy)(void *value)); + int containers, + int (*hash)(const void *key), + bool (*equals)(const void *key1, const void *key2), + void(*destroy)(void *value)); /** * @brief Destroy a given data table @@ -110,7 +110,7 @@ void lhtbl_destroy(LinkedHashTable *lhtbl); * @param value Value to be put in the given data table * @return true if the value has been correctly inserted, false otherwise */ -bool lhtbl_put(LinkedHashTable *lhtbl, const void* value); +bool lhtbl_put(LinkedHashTable *lhtbl, const void *value); /** * @brief Remove a value from the data table, then if the operation has been compute value will contain the pointer on the destroyed value @@ -118,7 +118,7 @@ bool lhtbl_put(LinkedHashTable *lhtbl, const void* value); * @param value Double pointer on the value to be removed, then if it has been correctly removed the pointer on the removed value * @return true if the data table has been deleted from the data table, false otherwise */ -bool lhtbl_remove(LinkedHashTable *lhtbl, void** value); +bool lhtbl_remove(LinkedHashTable *lhtbl, void **value); /** * @brief Test if the given value is present in the hash table, if a equals occurs value will contain the pointer on the equalsed value @@ -126,7 +126,7 @@ bool lhtbl_remove(LinkedHashTable *lhtbl, void** value); * @param value Double pointer to lookup the value in the given data table, if a equals occurs returns the pointer on it * @return true if the data table is present in the given data table, false otherwise */ -bool lhtbl_containsKey(const LinkedHashTable *lhtbl, void** value); +bool lhtbl_containsKey(const LinkedHashTable *lhtbl, void **value); #ifdef __cplusplus } diff --git a/headers/list.h b/headers/list.h index c17337b..16604da 100644 --- a/headers/list.h +++ b/headers/list.h @@ -20,7 +20,6 @@ extern "C" { #endif - /** * @brief Data structure definition for a simple chained linked list generic element */ @@ -50,7 +49,7 @@ typedef struct LinkedList { * @param right Right value to compare * @return true if left is equals to right, false otherwise */ - int (*equals)(const void *left, const void *right); + bool (*equals)(const void *left, const void *right); /** * @brief Destroy handle @@ -107,7 +106,7 @@ bool list_add(LinkedList *list, LinkedElement *element, const void *value); * @complexity O(1) * @return true if the element was correctly removed, false otherwise */ -bool list_remove( LinkedList*list, LinkedElement *element, void **value); +bool list_remove(LinkedList *list, LinkedElement *element, void **value); /** * @brief Returns a random element from the given list @@ -115,7 +114,7 @@ bool list_remove( LinkedList*list, LinkedElement *element, void **value); * @param random_element Reference to a random element * @return true if a random element was returned, false otherwise */ -LinkedElement* list_get_random(LinkedList *list); +LinkedElement *list_getRandom(LinkedList *list); /** * @brief Replace a specified element from the given list with the specified value @@ -124,7 +123,7 @@ LinkedElement* list_get_random(LinkedList *list); * @param value Value to replace * @return true if the given element's value was replaces, false otherwise */ -bool list_replace(LinkedList *list, LinkedElement *element, void **value); +bool list_replace(LinkedList *list, LinkedElement *element, void **value); /* ----- MACRO C++ COMPATIBILITY -----*/ #ifdef __cplusplus @@ -133,9 +132,9 @@ bool list_replace(LinkedList *list, LinkedElement *element, void **value); * @return The current element count of the current list * @complexity O(1) */ -inline int list_size(LinkedList *list){ +inline int list_size(LinkedList *list) { return list->size; -}; +} ; /** @@ -143,52 +142,52 @@ inline int list_size(LinkedList *list){ * @return The first element of the current list * @complexity O(1) */ -inline LinkedElement* list_first(LinkedList * list){ +inline LinkedElement *list_first(LinkedList *list) { return list->head; -}; +} ; /** * @brief Inline function that evaluates the last element of the specified list * @return The last element of the current list * @complexity O(1) */ -inline LinkedElement * list_last(LinkedList * list){ +inline LinkedElement *list_last(LinkedList *list) { return list->tail; -}; +} ; /** * @brief Inline function that evaluates if the specified element is the first element of the specified list * @return true if the element is the first of the current list, false otherwise * @complexity O(1) */ -inline bool list_is_first(LinkedList * list, LinkedElement *element){ +inline bool list_isFirst(LinkedList *list, LinkedElement *element) { return (list)->head == element; -}; +} ; /** * @brief Inline function that evaluates if the specified element is the last element of the specified list * @return true if the element is the last of the current list, false otherwise * @complexity O(1) */ -inline bool list_is_last(LinkedList * list, LinkedElement *element){ +inline bool list_isLast(LinkedList *list, LinkedElement *element) { return (list)->tail == element; -}; +} ; /** * @brief Inline function that evaluates the value of a list element * @return The value stored inside a list element * @complexity O(1) */ -inline void *list_value(LinkedElement *element){ +inline void *list_value(LinkedElement *element) { return ((element)->value); -}; +} ; /** * @brief Inline function that evaluates the next element of the current list element * @return The reference to the next element of the current list element * @complexity O(1) */ -inline LinkedElement *list_next(LinkedElement *element){ +inline LinkedElement *list_next(LinkedElement *element) { if (element == nullptr) return nullptr; else return (element)->next == nullptr ? nullptr : (element)->next; } @@ -221,14 +220,14 @@ inline LinkedElement *list_next(LinkedElement *element){ * @return true if the element is the first of the current list, false otherwise * @complexity O(1) */ -#define list_is_first(list, element) ((element) == (list)->head ? true : false ) +#define list_isFirst(list, element) ((element) == (list)->head ? true : false ) /** * @brief Macro that evaluates if the specified element is the last element of the specified list * @return true if the element is the last of the current list, false otherwise * @complexity O(1) */ -#define list_is_last(list, element) ((element) == (list)->tail ? true : false ) +#define list_isLast(list, element) ((element) == (list)->tail ? true : false ) /** * @brief Macro that evaluates the value of a list element diff --git a/headers/page.h b/headers/page.h index 03d0159..36b8fa5 100644 --- a/headers/page.h +++ b/headers/page.h @@ -7,7 +7,9 @@ #ifndef COLLECTIONS_COMMONS_PAGE_H #define COLLECTIONS_COMMONS_PAGE_H + #include "clist.h" + /** * @brief Data structure of a Page */ @@ -20,7 +22,7 @@ typedef struct Page { * Page's state */ bool state; -}Page; +} Page; /** * @brief Use the second chance algorithm to loop in a circular list of Pages until it find one to replace @@ -28,4 +30,5 @@ typedef struct Page { * @return The id of the removed page */ int page_replace(CLinkedElement **current); + #endif //COLLECTIONS_COMMONS_PAGE_H diff --git a/headers/queue.h b/headers/queue.h index b14cd6d..34a4c60 100644 --- a/headers/queue.h +++ b/headers/queue.h @@ -32,7 +32,7 @@ typedef LinkedList Queue; * @complexity O(1) * @return */ -bool queue_enqueue(Queue *queue, const void* value); +bool queue_enqueue(Queue *queue, const void *value); /** * @brief Remove the first element of the specified queue @@ -41,7 +41,7 @@ bool queue_enqueue(Queue *queue, const void* value); * @complexity O(1) * @return A reference to the first queue's element */ -bool queue_dequeue(Queue * queue, void *value); +bool queue_dequeue(Queue *queue, void *value); #ifdef __cplusplus @@ -50,9 +50,9 @@ bool queue_dequeue(Queue * queue, void *value); * @return The current element count of the current list * @complexity O(1) */ -inline int queue_size(Queue *queue){ +inline int queue_size(Queue *queue) { return queue->size; -}; +} ; /** * @brief Inline function that peeks the first element of the queue without unstacking it @@ -60,7 +60,7 @@ inline int queue_size(Queue *queue){ * @return The current first element of the queue * @complexity O(1) */ -inline void * queue_peek(Queue * queue){ +inline void *queue_peek(Queue *queue) { return ((queue)->head == nullptr ? nullptr : (queue)->head->value); } @@ -70,7 +70,7 @@ inline void * queue_peek(Queue * queue){ * @param destroy Delegate user function for later destruction of a single element the current queue * @complexity O(1) */ -inline void queue_create(Queue * queue, void( *destroy)(void *value)){ +inline void queue_create(Queue *queue, void( *destroy)(void *value)) { list_create(queue, destroy); } @@ -80,15 +80,15 @@ inline void queue_create(Queue * queue, void( *destroy)(void *value)){ * @complexity O(n) where n is the number of hashtable in the current list */ -inline void queue_destroy(Queue * queue){ +inline void queue_destroy(Queue *queue) { list_destroy(queue); } /** * @brief Inline function that returns a random element from the queue */ -static inline LinkedElement *queue_peek_random(Queue* queue){ - return list_get_random(queue); +static inline LinkedElement *queue_peekRandom(Queue *queue) { + return list_getRandom(queue); } #else @@ -122,7 +122,7 @@ static inline LinkedElement *queue_peek_random(Queue* queue){ /** * @brief Macro that evaluates a random element from the queue and returns it */ -#define queue_peek_random(queue) list_get_random +#define queue_peekRandom(queue) list_getRandom #endif diff --git a/headers/set.h b/headers/set.h index d61d1e5..fb4ef6a 100644 --- a/headers/set.h +++ b/headers/set.h @@ -13,9 +13,9 @@ extern "C" { #endif - /** - * @brief Data structure definition for a generic dataset - */ +/** + * @brief Data structure definition for a generic dataset + */ typedef LinkedList Set; /** @@ -25,7 +25,7 @@ typedef LinkedList Set; * @param destroy User destroy function to clean set hashtable on remove * @complexity O(1) */ -void set_create(Set *set, int (*equals)(const void *left, const void *right), void (*destroy)(void *value)); +void set_create(Set *set, bool (*equals)(const void *left, const void *right), void (*destroy)(void *value)); /** * @biref Try to insert a value in the given set @@ -82,7 +82,7 @@ bool set_difference(Set *difference_result, const Set *left, const Set *right); * @return true if the element is in the set, false otherwise * @complexity O(n) where n is the number of hashtable inside the given Set to compare with the parameter value */ -bool set_is_member(const Set *set, const void *value); +bool set_isMember(const Set *set, const void *value); /** * @brief Test if the left operand is a subset of the right operand @@ -91,7 +91,7 @@ bool set_is_member(const Set *set, const void *value); * @return true if the left Set is a subset of the right Set, false otherwise * @complexity O(mn) where m and n are the number of hashtable in each operand */ -bool set_is_subset(const Set *left, const Set *right); +bool set_isSubset(const Set *left, const Set *right); /** * @brief Test if left and right Set operands are equal @@ -100,7 +100,7 @@ bool set_is_subset(const Set *left, const Set *right); * @return true if left and right are equal, false otherwise * @complexity O(n ^ 2 ) where n is the number of hashtable inside left AND right */ -bool set_is_equal(const Set *left, const Set *right); +bool set_equals(const Set *left, const Set *right); #ifdef __cplusplus /** @@ -109,24 +109,24 @@ bool set_is_equal(const Set *left, const Set *right); * @return The size of the current Set * @complexity O(1) */ -static inline int set_size(const Set * set){ - return list_size((LinkedList*)set); -}; +static inline int set_size(const Set *set) { + return list_size((LinkedList *) set); +} ; /** * @brief Inline function to destroy a set * @param set Set to destroy * @complexity O(n) where n is the number of hashtable inside the given Set to destroy */ -static inline void set_destroy(Set *set){ +static inline void set_destroy(Set *set) { list_destroy(set); } /** * @brief Inline function that returns a random element from the set */ -static inline LinkedElement * set_get_random(Set* set){ - return list_get_random(set); +static inline LinkedElement *set_getRandom(Set *set) { + return list_getRandom(set); } #else /** @@ -147,7 +147,7 @@ static inline LinkedElement * set_get_random(Set* set){ /** * @brief Macro that evaluates a random element from the set and returns it */ -#define set_get_random(set) list_get_random +#define set_get_random(set) list_getRandom #endif #ifdef __cplusplus diff --git a/headers/set_entry.h b/headers/set_entry.h index fd1bf87..a37bfe7 100644 --- a/headers/set_entry.h +++ b/headers/set_entry.h @@ -6,6 +6,7 @@ */ #ifndef COLLECTIONS_COMMONS_SET_ENTRY_H #define COLLECTIONS_COMMONS_SET_ENTRY_H + #include "set.h" @@ -16,10 +17,10 @@ extern "C" { /** * @brief Data structure for a set identify by a generic key */ -typedef struct KeySetEntry{ +typedef struct KeySetEntry { void *key; Set set; -}KeySetEntry; +} KeySetEntry; /** * @brief Determine if sets from hashtable to equals are covering ALL hashtable, if true return the best solution @@ -28,7 +29,8 @@ typedef struct KeySetEntry{ * @param equalsed_elements Shortest list of hashtable that equals ALL hashtable * @return True if hashtable to equals are covering ALL hashtable, false otherwise */ -bool set_equals_entries(Set *elements, Set* elements_to_equals, Set * equalsed_elements); +bool set_equals_entries(Set *elements, Set *elements_to_equals, Set *equalsed_elements); + #ifdef __cplusplus } #endif diff --git a/headers/sort.h b/headers/sort.h index 080bf2e..3612ecd 100644 --- a/headers/sort.h +++ b/headers/sort.h @@ -16,19 +16,24 @@ extern "C" { #include #include #else + #include #include #include + #endif - /** - * @brief Determine if a generic array is sorted or not - * @param value Array to determine if it's sorted or not - * @param element_count Number of hashtable inside the given array - * @param element_size The size of the enumerable - * @param compare User compare function - * @return true if the generic array is sorted, false otherwise - */ - bool array_is_sort(void * value, int element_count, size_t element_size, int (*compare)(const void *key1, const void *key2)); + +/** + * @brief Determine if a generic array is sorted or not + * @param value Array to determine if it's sorted or not + * @param element_count Number of hashtable inside the given array + * @param element_size The size of the enumerable + * @param compare User compare function + * @return true if the generic array is sorted, false otherwise + */ +bool +array_is_sort(void *value, int element_count, size_t element_size, int (*compare)(const void *key1, const void *key2)); + #ifdef __cplusplus } #endif diff --git a/headers/stack.h b/headers/stack.h index da7b4e8..22e87ad 100644 --- a/headers/stack.h +++ b/headers/stack.h @@ -49,14 +49,14 @@ bool stack_pop(Stack *stack, void **value); /** * @brief Peek the first element of the stack without unstacking it */ -inline void * stack_peek(Stack * stack){ +inline void *stack_peek(Stack *stack) { return ((stack)->head == nullptr ? nullptr : (stack)->head->value); } /** * @brief Return the current stack size */ -inline int stack_size(Stack *stack){ +inline int stack_size(Stack *stack) { return list_size(stack); } @@ -66,8 +66,8 @@ inline int stack_size(Stack *stack){ * @param destroy Delegate user function for later destruction of a single element the current stack * @complexity O(1) */ -inline void stack_create(Stack * stack, void( *destroy)(void *value)){ - list_create(stack,destroy); +inline void stack_create(Stack *stack, void( *destroy)(void *value)) { + list_create(stack, destroy); } /** @@ -76,15 +76,15 @@ inline void stack_create(Stack * stack, void( *destroy)(void *value)){ * @complexity O(n) where n is the number of hashtable in the current list */ -inline void stack_destory(Stack * stack){ +inline void stack_destory(Stack *stack) { list_destroy(stack); } /** * @brief Inline function that returns a random element from the stack */ -static inline LinkedElement * stack_peek_random(Stack * stack){ -return list_get_random(stack); +static inline LinkedElement *stack_peekRandom(Stack *stack) { + return list_getRandom(stack); } #else @@ -116,7 +116,7 @@ return list_get_random(stack); /** * @brief Macro that evaluates a random element from the queue and returns it */ -#define stack_peek_random(stack) list_get_random +#define stack_peek_random(stack) list_getRandom #endif #ifdef __cplusplus diff --git a/src/clist.c b/src/clist.c index 9baa56c..66d749f 100644 --- a/src/clist.c +++ b/src/clist.c @@ -62,7 +62,7 @@ bool clist_remove(CLinkedList *list, CLinkedElement *element, void **value) { return true; } -CLinkedElement *clist_get_random(CLinkedList *list) { +CLinkedElement *clist_getRandom(CLinkedList *list) { CLinkedElement *random_element; if (clist_size(list) == 0) return NULL; int rd_index = rand() % clist_size(list); diff --git a/src/dlist.c b/src/dlist.c index 56a1b4a..6faba75 100644 --- a/src/dlist.c +++ b/src/dlist.c @@ -56,7 +56,7 @@ bool dlist_add(DLinkedList *list, DLinkedElement *element, const void *value) { return true; } -bool dlist_add_before(DLinkedList *list, DLinkedElement *element, const void *value) { +bool dlist_addBefore(DLinkedList *list, DLinkedElement *element, const void *value) { DLinkedElement *new_element = NULL; // Reject null hashtable except if list is empty if (element == NULL && dlist_size(list) != 0) return false; @@ -103,7 +103,7 @@ bool dlist_remove(DLinkedList *list, DLinkedElement *element, void **value) { // Remove the element from the list *value = element->value; - if (dlist_is_first(list, element)) { + if (dlist_isFirst(list, element)) { // The list become after deletion empty case list->head = element->next; if (list->head == NULL) @@ -125,7 +125,7 @@ bool dlist_remove(DLinkedList *list, DLinkedElement *element, void **value) { return true; } -DLinkedElement *dlist_get_random(DLinkedList *list) { +DLinkedElement *dlist_getRandom(DLinkedList *list) { DLinkedElement *random_element; if (dlist_size(list) == 0) return NULL; // Génère un index aléatoire dans la plage des indices valides du tableau. diff --git a/src/hash_utils.c b/src/hash_utils.c index c0a613d..b030a8d 100644 --- a/src/hash_utils.c +++ b/src/hash_utils.c @@ -2,10 +2,11 @@ // Created by maxim on 28/02/2024. // #include "hash_utils.h" -bool cmp_int(const void *a, const void *b){ - if(a ==NULL || b == NULL ) return false; - int intA = *((int*)a); - int intB = *((int*)b); + +bool cmp_int(const void *a, const void *b) { + if (a == NULL || b == NULL) return false; + int intA = *((int *) a); + int intB = *((int *) b); if (intA == intB) { return true; @@ -18,11 +19,11 @@ int hashref(const void *ref) { const double phi = (sqrt(5) - 1) / 2; intptr_t address = (intptr_t) ref; - return ((int)( (int) address * phi)); + return ((int) ((int) address * phi)); } -int hashpjw(const void* key){ - const char * string; +int hashpjw(const void *key) { + const char *string; int value; // hash the key the bit to bit operations @@ -30,15 +31,23 @@ int hashpjw(const void* key){ value = 0; string = key; - while(*string != '\0'){ + while (*string != '\0') { int temp; - value = (value<<4) + (*string); - if(temp=(value & 0xf0000000)){ - value = value ^(temp >> 24); - value = value ^temp; + value = (value << 4) + (*string); + if (temp = (value & 0xf0000000)) { + value = value ^ (temp >> 24); + value = value ^ temp; } string++; } return (int) (value); } + +int hashint(const void *integer) { + int x = (int) integer; + x = ((x >> 16) ^ x) * 0x45d9f3b; + x = ((x >> 16) ^ x) * 0x45d9f3b; + x = (x >> 16) ^ x; + return x; +} \ No newline at end of file diff --git a/src/hashmap.c b/src/hashmap.c index 695a4ea..c69e515 100644 --- a/src/hashmap.c +++ b/src/hashmap.c @@ -10,7 +10,7 @@ * @param new_entry Entry to be added * @return true if the entry was added, false otherwise */ -bool hashmap_push(HashMap *map, SimpleEntry *entry, SimpleEntry * new_entry) { +bool hashmap_push(HashMap *map, SimpleEntry *entry, SimpleEntry *new_entry) { // Reject null hashtable except if list is empty if (entry == NULL && hashmap_size(map) != 0) return false; @@ -73,13 +73,13 @@ bool hashmap_pop(HashMap *map, SimpleEntry *entry, void **value) { bool hashmap_create(HashMap *map, int containers, int (*hash)(const void *key), - bool (*equals)(const void* key1, const void* key2), - void(*destroy)(void *value)){ + bool (*equals)(const void *key1, const void *key2), + void(*destroy)(void *value)) { // Try To Allocate memory space for the linked hash table - if(map == NULL) return false; - if((map->hashTable = (LinkedHashTable*) malloc(sizeof (LinkedHashTable)) )== NULL) return false; - if(!lhtbl_create(map->hashTable, containers, hash, equals, destroy)) return false; + if (map == NULL) return false; + if ((map->hashTable = (LinkedHashTable *) malloc(sizeof(LinkedHashTable))) == NULL) return false; + if (!lhtbl_create(map->hashTable, containers, hash, equals, destroy)) return false; // Init the map map->size = 0; map->equals = equals; @@ -90,19 +90,19 @@ bool hashmap_create(HashMap *map, return true; } -void hashmap_destroy(HashMap *map){ - if(map == NULL) return; +void hashmap_destroy(HashMap *map) { + if (map == NULL) return; SimpleEntry *current_entry; void *temp; - for(current_entry= hashmap_first(map);current_entry!=NULL; current_entry= hashmap_next(current_entry)){ - if(!hashmap_removeEntry(map, current_entry, &temp)) return; + for (current_entry = hashmap_first(map); current_entry != NULL; current_entry = hashmap_next(current_entry)) { + if (!hashmap_removeEntry(map, current_entry, &temp)) return; } lhtbl_destroy(map->hashTable); memset(map, 0, sizeof(HashMap)); } -bool hashmap_containsKey(HashMap *map, void** value){ - if(value == NULL || map == NULL) return false; +bool hashmap_containsKey(HashMap *map, void **value) { + if (value == NULL || map == NULL) return false; LinkedElement *current_element; int current_container; @@ -111,9 +111,10 @@ bool hashmap_containsKey(HashMap *map, void** value){ // Search the value inside the current container - for(current_element= list_first(&map->hashTable->hashtable[current_container]); current_element != NULL; current_element= list_next(current_element) ){ - SimpleEntry * current_entry = (SimpleEntry*)list_value(current_element); - if(map->hashTable->equals(value, ¤t_entry->key)){ + for (current_element = list_first(&map->hashTable->hashtable[current_container]); + current_element != NULL; current_element = list_next(current_element)) { + SimpleEntry *current_entry = (SimpleEntry *) list_value(current_element); + if (map->hashTable->equals(value, ¤t_entry->key)) { *value = list_value(current_element); return true; } @@ -122,26 +123,26 @@ bool hashmap_containsKey(HashMap *map, void** value){ return false; } -bool hashmap_put(HashMap *map, void *key, void *value){ +bool hashmap_put(HashMap *map, void *key, void *value) { bool result = false; - if(hashmap_containsKey( map, &key)){ - void* old_value = value; - if(hashmap_replace(map,key, &old_value)){ + if (hashmap_containsKey(map, &key)) { + void *old_value = value; + if (hashmap_replace(map, key, &old_value)) { map->destroy(old_value); return true; } - }else{ + } else { int container; // Hash the given key with the user function container = map->hashTable->hash(key) % map->hashTable->containers; - SimpleEntry * new_entry = (SimpleEntry*) malloc(sizeof(SimpleEntry)); + SimpleEntry *new_entry = (SimpleEntry *) malloc(sizeof(SimpleEntry)); new_entry->key = key; new_entry->value = value; // Add the current key value pair to the container - if((result = list_add(&map->hashTable->hashtable[container], NULL, new_entry))){ + if ((result = list_add(&map->hashTable->hashtable[container], NULL, new_entry))) { map->hashTable->size++; result = hashmap_push(map, hashmap_first(map), new_entry); } @@ -150,26 +151,26 @@ bool hashmap_put(HashMap *map, void *key, void *value){ return result; } -bool hashmap_addEntry(HashMap *map, SimpleEntry *entry){ +bool hashmap_addEntry(HashMap *map, SimpleEntry *entry) { bool result = false; - if(hashmap_containsKey(map, &entry->key)){ - void* old_value = entry->value; - if(hashmap_replace(map,entry->key, &old_value)){ + if (hashmap_containsKey(map, &entry->key)) { + void *old_value = entry->value; + if (hashmap_replace(map, entry->key, &old_value)) { map->destroy(old_value); result = true; } - }else{ + } else { int container; // Hash the given key with the user function container = map->hashTable->hash(entry->key) % map->hashTable->containers; - SimpleEntry * new_entry; - if((new_entry=(SimpleEntry*) malloc(sizeof(SimpleEntry))) == NULL) return false; + SimpleEntry *new_entry; + if ((new_entry = (SimpleEntry *) malloc(sizeof(SimpleEntry))) == NULL) return false; memcpy(new_entry, entry, sizeof(SimpleEntry)); // Add the current key value pair to the container - if((result = list_add(&map->hashTable->hashtable[container], NULL, new_entry))){ + if ((result = list_add(&map->hashTable->hashtable[container], NULL, new_entry))) { if (hashmap_size(map) == 0) map->tail = new_entry; new_entry->next = map->head; map->head = new_entry; @@ -179,26 +180,27 @@ bool hashmap_addEntry(HashMap *map, SimpleEntry *entry){ return result; } -bool hashmap_putIfAbsent(HashMap *map, void *key, void *value){ - if(!hashmap_containsKey(map, &key)){ - if(hashmap_put(map, key, value)){ +bool hashmap_putIfAbsent(HashMap *map, void *key, void *value) { + if (!hashmap_containsKey(map, &key)) { + if (hashmap_put(map, key, value)) { return true; } } return false; } -bool hashmap_replace(HashMap *map, void *key,void** value){ - bool result=false; - if(!hashmap_containsKey(map, &key)) return result; +bool hashmap_replace(HashMap *map, void *key, void **value) { + bool result = false; + if (!hashmap_containsKey(map, &key)) return result; int container; // Hash the given key with the user function container = map->hashTable->hash(key) % map->hashTable->containers; // Replace the current key value in the container SimpleEntry *current_entry; - LinkedElement * current_element; - for(current_element= list_first(&map->hashTable->hashtable[container])->value;current_element!=NULL;current_element= list_next(current_element)) { + LinkedElement *current_element; + for (current_element = list_first(&map->hashTable->hashtable[container])->value; + current_element != NULL; current_element = list_next(current_element)) { current_entry = (SimpleEntry *) current_element->value; if (map->equals(current_entry->key, key)) { void *temp = current_entry->value; @@ -212,38 +214,39 @@ bool hashmap_replace(HashMap *map, void *key,void** value){ return result; } -bool hashmap_remove(HashMap *map, void** value){ - if(map == NULL || map->size == 0) return false; - bool result=false; - void* temp = *value; - if(!hashmap_containsKey(map, value)) return result; +bool hashmap_remove(HashMap *map, void **value) { + if (map == NULL || map->size == 0) return false; + bool result = false; + void *temp = *value; + if (!hashmap_containsKey(map, value)) return result; - LinkedElement *current_element,*last_element; + LinkedElement *current_element, *last_element; int current_container; - current_container = map->hashTable->hash(temp) % map->hashTable->containers; + current_container = map->hashTable->hash(temp) % map->hashTable->containers; // Search for the value inside the current container last_element = NULL; - for(current_element= list_first(&map->hashTable->hashtable[current_container]); current_element != NULL; current_element = list_next(current_element)){ + for (current_element = list_first(&map->hashTable->hashtable[current_container]); + current_element != NULL; current_element = list_next(current_element)) { // If the target value if equals to the current container element, then remove it - if( map->hashTable->equals(*value, &((SimpleEntry*)list_value(current_element))->key)){ + if (map->hashTable->equals(*value, &((SimpleEntry *) list_value(current_element))->key)) { // Remove the value from the current container - if(list_remove(& map->hashTable->hashtable[current_container], last_element, *value)){ + if (list_remove(&map->hashTable->hashtable[current_container], last_element, *value)) { map->hashTable->size--; - result= true; + result = true; break; // Can't remove the data from the current container - }else{ - result= false; + } else { + result = false; break; } } last_element = current_element; } - if(result){ - SimpleEntry * current_entry= (SimpleEntry *) *value; - void* key_value; + if (result) { + SimpleEntry *current_entry = (SimpleEntry *) *value; + void *key_value; result = hashmap_pop(map, current_entry, &key_value); *value = key_value; map->destroy(key_value); @@ -251,11 +254,11 @@ bool hashmap_remove(HashMap *map, void** value){ return result; } -bool hashmap_removeEntry( HashMap *map, SimpleEntry *entry, void **value){ - bool result=false; - void* temp = entry->key; - if(!hashmap_containsKey(map, &temp)) return result; - result = hashmap_remove(map,temp); +bool hashmap_removeEntry(HashMap *map, SimpleEntry *entry, void **value) { + bool result = false; + void *temp = entry->key; + if (!hashmap_containsKey(map, &temp)) return result; + result = hashmap_remove(map, temp); value = temp; return result; } diff --git a/src/lhtbl.c b/src/lhtbl.c index 7665215..56a2437 100644 --- a/src/lhtbl.c +++ b/src/lhtbl.c @@ -7,20 +7,20 @@ bool lhtbl_create(LinkedHashTable *lhtbl, int containers, int (*hash)(const void *key), - bool (*equals)(const void* key1, const void* key2), - void(*destroy)(void *value)){ - if(hash == NULL || equals == NULL || destroy == NULL) return false; + bool (*equals)(const void *key1, const void *key2), + void(*destroy)(void *value)) { + if (hash == NULL || equals == NULL || destroy == NULL) return false; int i; // Allocate memory space for the linked hash table - if((lhtbl->hashtable = (LinkedList *) malloc(containers * sizeof(LinkedList))) == NULL) return false; + if ((lhtbl->hashtable = (LinkedList *) malloc(containers * sizeof(LinkedList))) == NULL) return false; // Creating containers lhtbl->containers = containers; - for(i = 0; i< lhtbl->containers;i++) + for (i = 0; i < lhtbl->containers; i++) list_create(&lhtbl->hashtable[i], destroy); lhtbl->hash = hash; @@ -31,10 +31,10 @@ bool lhtbl_create(LinkedHashTable *lhtbl, return true; } -void lhtbl_destroy(LinkedHashTable *lhtbl){ +void lhtbl_destroy(LinkedHashTable *lhtbl) { int i; - for(i=0;isize;i++) + for (i = 0; i < lhtbl->size; i++) list_destroy(&lhtbl->hashtable[i]); // Cleaning the memory location allocate to the internal hashtable @@ -45,42 +45,43 @@ void lhtbl_destroy(LinkedHashTable *lhtbl){ memset(lhtbl, 0, sizeof(LinkedHashTable)); } -bool lhtbl_put(LinkedHashTable *lhtbl, const void* value){ +bool lhtbl_put(LinkedHashTable *lhtbl, const void *value) { void *temp; int container; bool result = false; temp = (void *) value; // If the value is already in the table return false - if(lhtbl_containsKey(lhtbl, &temp)) return result; + if (lhtbl_containsKey(lhtbl, &temp)) return result; // Hash the given key with the user function container = lhtbl->hash(value) % lhtbl->containers; // Add the value inside the result container - if((result = list_add(&lhtbl->hashtable[container], NULL, value))) lhtbl->size++; + if ((result = list_add(&lhtbl->hashtable[container], NULL, value))) lhtbl->size++; return result; } -bool lhtbl_remove(LinkedHashTable *lhtbl, void** value){ - LinkedElement *current_element,*last_element; +bool lhtbl_remove(LinkedHashTable *lhtbl, void **value) { + LinkedElement *current_element, *last_element; int current_container; current_container = lhtbl->hash(*value) % lhtbl->containers; // Search for the value inside the current container last_element = NULL; - for(current_element= list_first(&lhtbl->hashtable[current_container]); current_element != NULL; current_element = list_next(current_element)){ + for (current_element = list_first(&lhtbl->hashtable[current_container]); + current_element != NULL; current_element = list_next(current_element)) { // If the target value if equals to the current container element, then remove it - if(lhtbl->equals(*value, list_value(current_element))){ + if (lhtbl->equals(*value, list_value(current_element))) { // Remove the value from the current container - if(list_remove(&lhtbl->hashtable[current_container], last_element, value)){ + if (list_remove(&lhtbl->hashtable[current_container], last_element, value)) { lhtbl->size--; return true; // Can't remove the data from the current container - }else return false; + } else return false; } last_element = current_element; } @@ -89,7 +90,7 @@ bool lhtbl_remove(LinkedHashTable *lhtbl, void** value){ return false; } -bool lhtbl_containsKey(const LinkedHashTable *lhtbl, void** value){ +bool lhtbl_containsKey(const LinkedHashTable *lhtbl, void **value) { LinkedElement *current_element; int current_container; @@ -98,8 +99,9 @@ bool lhtbl_containsKey(const LinkedHashTable *lhtbl, void** value){ // Search the value inside the current container - for(current_element= list_first(&lhtbl->hashtable[current_container]); current_element != NULL; current_element= list_next(current_element) ){ - if(lhtbl->equals(*value, list_value(current_element))){ + for (current_element = list_first(&lhtbl->hashtable[current_container]); + current_element != NULL; current_element = list_next(current_element)) { + if (lhtbl->equals(*value, list_value(current_element))) { *value = list_value(current_element); return true; } diff --git a/src/list.c b/src/list.c index f258020..9e8bb5d 100644 --- a/src/list.c +++ b/src/list.c @@ -83,7 +83,7 @@ bool list_remove(LinkedList *list, LinkedElement *element, void **value) { return true; } -LinkedElement *list_get_random(LinkedList *list) { +LinkedElement *list_getRandom(LinkedList *list) { LinkedElement *random_element; if (list_size(list) == 0) return NULL; // Génère un index aléatoire dans la plage des indices valides du tableau. diff --git a/src/set.c b/src/set.c index 36c7645..8fd6bc6 100644 --- a/src/set.c +++ b/src/set.c @@ -64,14 +64,14 @@ bool set_match_entries(Set *elements, Set *elements_to_match, Set *matched_eleme return true; } -void set_create(Set *set, int (*equals)(const void *left, const void *right), void (*destroy)(void *value)) { +void set_create(Set *set, bool (*equals)(const void *left, const void *right), void (*destroy)(void *value)) { list_create(set, destroy); set->equals = equals; } bool set_add(Set *set, const void *value) { // No duplicated values - if (set_is_member(set, value)) return false; + if (set_isMember(set, value)) return false; // Add the value at the end return list_add(set, list_last(set), value); } @@ -82,17 +82,18 @@ bool set_remove(Set *set, void **value) { // Search for a value to remove for (current_element = list_first(set); current_element != NULL; current_element = list_next(current_element)) { - if (set->equals(*value, list_value(current_element))) + if (set->equals(*value, list_value(current_element))) { + element_to_remove = current_element; break; - element_to_remove = current_element; + } } // Element not found case if (current_element == NULL) return false; - // Remove the last element - return list_remove(set, element_to_remove, value); + if (list_size(set) == 1) return list_remove(set, NULL, value); + else return list_remove(set, element_to_remove, value); } bool set_union(Set *union_result, const Set *left, const Set *right) { @@ -114,7 +115,7 @@ bool set_union(Set *union_result, const Set *left, const Set *right) { // Insertion of right set elements for (current_element = list_first(right); current_element != NULL; current_element = list_next(current_element)) { - if (set_is_member(left, list_value(current_element))) continue; + if (set_isMember(left, list_value(current_element))) continue; else { value = list_value(current_element); if (!list_add(union_result, list_last(union_result), value)) { @@ -138,7 +139,7 @@ bool set_intersection(Set *intersection_result, const Set *left, const Set *righ for (current_element = list_first(left); current_element != NULL; current_element = list_next(current_element)) { // If the current left element is in the right Set - if (set_is_member(right, list_value(current_element))) { + if (set_isMember(right, list_value(current_element))) { value = list_value(current_element); if (!list_add(intersection_result, list_last(intersection_result), value)) { set_destroy(intersection_result); @@ -159,7 +160,7 @@ bool set_difference(Set *difference_result, const Set *left, const Set *right) { // Insert elements of left non present in right for (current_element = list_first(left); current_element != NULL; current_element = list_next(current_element)) { // If the current left value is not in the right set - if (!set_is_member(right, list_value(current_element))) { + if (!set_isMember(right, list_value(current_element))) { value = list_value(current_element); if (!list_add(difference_result, list_last(difference_result), value)) { set_destroy(difference_result); @@ -170,19 +171,21 @@ bool set_difference(Set *difference_result, const Set *left, const Set *right) { return true; } -bool set_is_member(const Set *set, const void *value) { +bool set_isMember(const Set *set, const void *value) { LinkedElement *current_element; // Determine if the value is in set for (current_element = list_first(set); current_element != NULL; current_element = list_next(current_element)) { - // If any equals occurs, then return false - if (set->equals(value, list_value(current_element))) return false; + // If any equals occur, then return true + if (set->equals(value, list_value(current_element))) { + return true; + } } - return true; + return false; } -bool set_is_subset(const Set *left, const Set *right) { +bool set_isSubset(const Set *left, const Set *right) { LinkedElement *current_element; // Quick test to eliminate some usual cases @@ -190,12 +193,12 @@ bool set_is_subset(const Set *left, const Set *right) { // Determine if left is a subset of right for (current_element = list_first(left); current_element != NULL; current_element = list_next(current_element)) { // Validate one by one left elements in right set independently of their order - if (!set_is_member(right, list_value(current_element))) return false; + if (!set_isMember(right, list_value(current_element))) return false; } return true; } -bool set_is_equal(const Set *left, const Set *right) { +bool set_equals(const Set *left, const Set *right) { LinkedElement *current_element; // Quick test to eliminate usual cases @@ -204,7 +207,7 @@ bool set_is_equal(const Set *left, const Set *right) { // Determine if left and right sets are equal for (current_element = list_first(left); current_element != NULL; current_element = list_next(current_element)) { // If there is one element of left not present in right, sets are not equal - if (!set_is_member(right, list_value(current_element))) return false; + if (!set_isMember(right, list_value(current_element))) return false; } return true; diff --git a/tests/headers/CLinkedList_Test.h b/tests/headers/CLinkedList_Test.h index f119aa5..eba7377 100644 --- a/tests/headers/CLinkedList_Test.h +++ b/tests/headers/CLinkedList_Test.h @@ -62,7 +62,7 @@ TEST_F(CLinkedList_Test, PerformanceTest) { CLinkedElement *current_element; // Remove random element until the list is not empty - for(current_element= clist_get_random(obj); clist_size(obj) > 0;current_element= clist_next(current_element)){ + for(current_element= clist_getRandom(obj); clist_size(obj) > 0; current_element= clist_next(current_element)){ void *value = nullptr; clist_remove(obj,current_element , &value); delete static_cast(value); diff --git a/tests/headers/DLinkedList_Test.h b/tests/headers/DLinkedList_Test.h index b2dee18..60ba7d3 100644 --- a/tests/headers/DLinkedList_Test.h +++ b/tests/headers/DLinkedList_Test.h @@ -7,6 +7,7 @@ #include "dlist.h" #include + class DLinkedListTest : public testing::Test { protected: DLinkedList list; @@ -22,38 +23,36 @@ class DLinkedListTest : public testing::Test { TEST_F(DLinkedListTest, PerformanceTest) { // Insertion test - for (int i = 0; i < 1000000; ++i) { - int *value = (int *)malloc(sizeof(int)); - *value = i; - dlist_add(&list, nullptr, value); + + for (int i = 0; i < 100000; ++i) { + int *value = (int *) malloc(10* sizeof(int)); + for(int j =0;j<10;j++)value[j] = i+j; + dlist_add(&list, dlist_first(&list), value); } - EXPECT_EQ(dlist_size(&list), 1); + EXPECT_EQ(dlist_size(&list), 100000); // Deletion test - DLinkedElement *current_element; - - for(current_element= dlist_get_random(&list); current_element != nullptr;current_element= dlist_next(current_element)){ + while(dlist_size(&list) != 0){ void *value; - dlist_remove(&list, current_element, &value); + dlist_remove(&list, dlist_getRandom(&list), &value); delete static_cast(value); } + EXPECT_EQ(dlist_size(&list), 0); - for (int i = 0; i < 1000000; ++i) { - int *value = (int *)malloc(sizeof(int)); - *value = i; - dlist_add(&list, nullptr, value); + for (int i = 0; i < 100000; ++i) { + int *value = (int *) malloc(10* sizeof(int)); + for(int j =0;j<10;j++)value[j] = i+j; + dlist_add(&list, dlist_first(&list), value); } - current_element= dlist_first(&list); - while (current_element != nullptr) { + while(dlist_size(&list) != 0){ void *value; - dlist_remove(&list, current_element, &value); - free(value); - current_element = dlist_next(current_element); + dlist_remove(&list, dlist_getRandom(&list), &value); + delete static_cast(value); } EXPECT_EQ(dlist_size(&list), 0); diff --git a/tests/headers/HashMap_Test.h b/tests/headers/HashMap_Test.h index 932543b..06ac6ca 100644 --- a/tests/headers/HashMap_Test.h +++ b/tests/headers/HashMap_Test.h @@ -12,7 +12,8 @@ class HashMapTest : public testing::Test { void SetUp() override { map = (HashMap *) malloc(sizeof(HashMap)); - hashmap_create(map, 16, hashref, cmp_int, free); + // Creating 16 containers, because it works using an AVR ATmega328PB 8bit addressing blocks microprocessor + hashmap_create(map, 16, hashint, cmp_int, free); } void TearDown() override { @@ -40,4 +41,6 @@ TEST_F(HashMapTest, BasicTest) { ASSERT_FALSE(hashmap_containsKey(map, reinterpret_cast(&chunk2->data))); ASSERT_EQ(hashmap_size(map), 1); + ASSERT_TRUE(hashmap_remove(map, reinterpret_cast(&chunk1->data))); + ASSERT_EQ(hashmap_size(map), 0); } \ No newline at end of file diff --git a/tests/headers/LinkedList_Test.h b/tests/headers/LinkedList_Test.h index 143c9a3..4dbb863 100644 --- a/tests/headers/LinkedList_Test.h +++ b/tests/headers/LinkedList_Test.h @@ -23,41 +23,23 @@ class LinkedListTest : public testing::Test { TEST_F(LinkedListTest, PerformanceTest) { // Insertion test - for (int i = 0; i < 1000000; ++i) { - int *value = (int *) malloc(sizeof(int)); - *value = i; + for (int i = 0; i < 100000; ++i) { + int *value = (int *) malloc(10* sizeof(int)); + for(int j =0;j<10;j++)value[j] = i+j; list_add(&list, nullptr, value); } - EXPECT_EQ(list_size(&list), 1000000); + EXPECT_EQ(list_size(&list), 100000); // Deletion test - LinkedElement *current_element = list_first(&list); - for(current_element= list_get_random(&list); current_element != nullptr;current_element= list_next(current_element)){ + while(list_size(&list) != 0){ void *value; - list_remove(&list, current_element, &value); + list_remove(&list, nullptr, &value); delete static_cast(value); } EXPECT_EQ(list_size(&list), 0); - - for (int i = 0; i < 1000000; ++i) { - int *value = (int *) malloc(sizeof(int)); - *value = i; - list_add(&list, nullptr, value); - } - - current_element= list_first(&list); - - while (current_element != nullptr) { - void *value; - list_remove(&list, current_element, &value); - free(value); - current_element = list_next(current_element); - } - - EXPECT_EQ(list_size(&list), 0); } #endif //COLLECTIONS_COMMONS_LINKEDLIST_TEST_H diff --git a/tests/headers/Set_Test.h b/tests/headers/Set_Test.h new file mode 100644 index 0000000..fd47103 --- /dev/null +++ b/tests/headers/Set_Test.h @@ -0,0 +1,254 @@ +// +// Created by maxim on 29/02/2024. +// + +#include "gtest/gtest.h" +#include "set.h" + +#ifndef COLLECTIONS_COMMONS_SET_TEST_H +#define COLLECTIONS_COMMONS_SET_TEST_H + +typedef struct Block{ + Chunk* chunk; + int type; +}Block; + +bool cmp_block(const void* arg1,const void* arg2){ + if(arg1 == nullptr || arg2 == nullptr) return -1; + Block *b1 = ((Block*)arg1); + Block *b2 = ((Block*)arg2); + if(cmp_int(&b1->chunk->data, &b2->chunk->data) && cmp_int(&b1->type, &b2->type)){ + return true; + } + return false; +} +class SetTest : public testing::Test { +protected: + Set *set; + + void SetUp() override { + set = (Set *) malloc(sizeof(Set)); + // Creating 16 containers, because it works using an AVR ATmega328PB 8bit addressing blocks microprocessor + set_create(set,cmp_block,free); + } + + void TearDown() override { + set_destroy(set); + } +}; + + +TEST_F(SetTest, BasicTest) { + Chunk *chunk1,*chunk2; + Block *b1,*b2,*b3,*b4; + chunk1 = (Chunk *) malloc(sizeof(Chunk)); + chunk2 = (Chunk *) malloc(sizeof(Chunk)); + chunk1->data=1; + chunk2->data=2; + b1 = (Block*) malloc(sizeof(Block)); + b2 = (Block*) malloc(sizeof(Block)); + b3 = (Block*) malloc(sizeof(Block)); + b4 = (Block*) malloc(sizeof(Block)); + b1->type = 1; + b1->chunk = chunk1; + b2->type = 1; + b2->chunk = chunk2; + b3->type = 2; + b3->chunk = chunk1; + b4->type = 2; + b4->chunk = chunk1; + ASSERT_TRUE(set_add(set, b1)); + ASSERT_TRUE(set_add(set, b2)); + ASSERT_TRUE(set_add(set, b3)); + ASSERT_FALSE(set_add(set, b4)); + + // True because b3 represent that literal value evaluate by cmp_block function + ASSERT_TRUE(set_isMember(set, b4)); + ASSERT_TRUE(set_isMember(set, b1)); + ASSERT_EQ(set_size(set), 3); + free(b4); + free(chunk1); + free(chunk2); +} + +TEST_F(SetTest, UnionTest){ + Chunk *chunk1,*chunk2; + Block *b1,*b2,*b3,*b4; + Set * set1, *union_result; + set1 = (Set *)malloc(sizeof(Set)); + union_result = (Set *)malloc(sizeof(Set)); + set_create(set1, cmp_block, free); + chunk1 = (Chunk *) malloc(sizeof(Chunk)); + chunk2 = (Chunk *) malloc(sizeof(Chunk)); + chunk1->data=1; + chunk2->data=2; + b1 = (Block*) malloc(sizeof(Block)); + b2 = (Block*) malloc(sizeof(Block)); + b3 = (Block*) malloc(sizeof(Block)); + b4 = (Block*) malloc(sizeof(Block)); + b1->type = 1; + b1->chunk = chunk1; + b2->type = 1; + b2->chunk = chunk2; + b3->type = 2; + b3->chunk = chunk1; + b4->type = 2; + b4->chunk = chunk1; + set_add(set, b1); + set_add(set,b2); + set_add(set1,b3); + set_add(set1,b4); + ASSERT_TRUE(set_union(union_result, set, set1)); + + // 3 and not 4, Because b4 and b3 are equals one of them will be skipped + ASSERT_EQ(set_size(union_result), 3); + set_destroy(set1); + free(set1); +} + +TEST_F(SetTest, DifferenceTest) { + Set *difference_result, *left, *right; + Chunk *chunk1,*chunk2; + Block *b1,*b2,*b3,*b4,*b5; + chunk1 = (Chunk *) malloc(sizeof(Chunk)); + chunk2 = (Chunk *) malloc(sizeof(Chunk)); + chunk1->data=1; + chunk2->data=2; + b1 = (Block*) malloc(sizeof(Block)); + b2 = (Block*) malloc(sizeof(Block)); + b3 = (Block*) malloc(sizeof(Block)); + b4 = (Block*) malloc(sizeof(Block)); + b5 = (Block*) malloc(sizeof(Block)); + + b1->type = 1; + b1->chunk = chunk1; + b2->type = 1; + b2->chunk = chunk2; + b3->type = 2; + b3->chunk = chunk1; + b4->type = 2; + b4->chunk = chunk1; + b5->type = 3; + b5->chunk = chunk2; + + + difference_result = (Set *)malloc(sizeof(Set)); + left = (Set *)malloc(sizeof(Set)); + right = (Set *)malloc(sizeof(Set)); + + set_create(left, cmp_block, free); + set_create(right, cmp_block, free); + + + set_add(right,b1); + set_add(right,b2); + set_add(right,b3); + + set_add(left, b1); + set_add(left,b2); + set_add(left,b4); + set_add(left, b5); + + ASSERT_TRUE(set_difference(difference_result, left, right)); + + ASSERT_FALSE(set_equals(left, right)); + // Vérifier le résultat de la différence... + + ASSERT_EQ(set_size(difference_result), 1); + + void* delete_value = b1; + ASSERT_TRUE(set_remove(left, &delete_value)); + delete_value = b5; + ASSERT_TRUE(set_remove(difference_result, &delete_value)); + + set_destroy(difference_result); + set_destroy(left); + free(right); + + free(chunk1); + free(chunk2); +} + +TEST_F(SetTest, IntersectionTest) { + Set *intersection_result, *left, *right, *sub_set; + Chunk *chunk1,*chunk2; + Block *b1,*b2,*b3,*b4,*b5,*b1cp,*b2cp,*b4cp; + + // Creating chunks + chunk1 = (Chunk *) malloc(sizeof(Chunk)); + chunk2 = (Chunk *) malloc(sizeof(Chunk)); + chunk1->data=1; + chunk2->data=2; + + // Creating blocks + b1 = (Block*) malloc(sizeof(Block)); + b2 = (Block*) malloc(sizeof(Block)); + b3 = (Block*) malloc(sizeof(Block)); + b4 = (Block*) malloc(sizeof(Block)); + b5 = (Block*) malloc(sizeof(Block)); + b1cp = (Block*) malloc(sizeof(Block)); + b2cp = (Block*) malloc(sizeof(Block)); + b4cp = (Block*) malloc(sizeof(Block)); + b1->type = 1; + b1->chunk = chunk1; + b2->type = 1; + b2->chunk = chunk2; + b3->type = 2; + b3->chunk = chunk1; + b4->type = 2; + b4->chunk = chunk1; + b5->type = 3; + b5->chunk = chunk2; + + // Creating sets + intersection_result = (Set *)malloc(sizeof(Set)); + left = (Set *)malloc(sizeof(Set)); + right = (Set *)malloc(sizeof(Set)); + sub_set = (Set *)malloc(sizeof(Set)); + set_create(sub_set, cmp_block, free); + set_create(left, cmp_block, free); + set_create(right, cmp_block, free); + + // Creating right set + set_add(right,b1); + set_add(right,b2); + set_add(right,b3); + + // Creating left set + set_add(left, b1); + set_add(left,b2); + set_add(left,b4); + set_add(left, b5); + + // Create sub set, Add the copy of b1, b2 and b4 as subset, it's our expected intersection result + memcpy(b1cp ,b1,sizeof (Block)); + memcpy(b2cp ,b2,sizeof (Block)); + memcpy(b4cp ,b4,sizeof (Block)); + set_add(sub_set, b1cp); + set_add(sub_set, b2cp); + set_add(sub_set, b4cp); + + ASSERT_TRUE(set_intersection(intersection_result, left, right)); + + // verifier le résultat de l'intersection des deux ensembles + ASSERT_EQ(set_size(intersection_result), 3); + ASSERT_TRUE(set_isSubset(intersection_result, sub_set)); + + set_destroy(sub_set); + free(sub_set); + void* delete_value = b1; + ASSERT_TRUE(set_remove(left, &delete_value)); + delete_value = b5; + ASSERT_FALSE(set_remove(intersection_result, &delete_value)); + + set_destroy(intersection_result); + set_destroy(left); + free(right); + + free(chunk1); + free(chunk2); +} + + + +#endif //COLLECTIONS_COMMONS_SET_TEST_H diff --git a/tests/main.cpp b/tests/main.cpp index 06a96e6..652f428 100644 --- a/tests/main.cpp +++ b/tests/main.cpp @@ -11,6 +11,7 @@ #include "Exception_Test.h" #include "LinkedHashTable_Test.h" #include "HashMap_Test.h" +#include "Set_Test.h" int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); From 269d0298362d2e1e419160f595dd2a7fec67824c Mon Sep 17 00:00:00 2001 From: nakira974 Date: Thu, 29 Feb 2024 21:06:40 +0100 Subject: [PATCH 16/27] Add API definitions for hashset and correctly renamed CLinkedList --- headers/clist.h | 2 +- headers/hashset.h | 304 ++++++++++++++++++++++++++++++- tests/headers/CLinkedList_Test.h | 4 +- 3 files changed, 301 insertions(+), 9 deletions(-) diff --git a/headers/clist.h b/headers/clist.h index 19e9350..2a733a7 100644 --- a/headers/clist.h +++ b/headers/clist.h @@ -41,7 +41,7 @@ typedef struct CLinkedElement { * @brief Data structure for a circular linked list */ -typedef struct ClinkedList { +typedef struct CLinkedList { /** * @brief Current size of the list */ diff --git a/headers/hashset.h b/headers/hashset.h index 6a800cb..22da5a4 100644 --- a/headers/hashset.h +++ b/headers/hashset.h @@ -1,6 +1,6 @@ /** * @file sort.h - * @brief This file contains the API for hash tables + * @brief This file contains the API for hash sets * @author Maxime Loukhal * @date 27/02/2024 */ @@ -11,14 +11,306 @@ extern "C" { #endif +#include "lhtbl.h" + + +/** + * @brief Data structure to set a specific key with its associated value + */ +typedef struct HashSet { + + /** + * @brief Internal key hashtable + */ + LinkedHashTable *hashTable; + + /** + * @brief HashSet elements + */ + DLinkedList *elements; + /** + * @brief Hashmap current size + */ + int size; + + /** + * @brief Pointer to the User Keys equals function for hashset + * @param key1 The first key to be compared + * @param key2 The second key to be compared + * @return true if the keys equals, false otherwise + */ + bool (*equals)(const void *key1, const void *key2); + + /** + * @brief Pointer to the destroy function for hashset + * @param value The value to be destroyed + */ + void (*destroy)(void *value); +} HashSet; + +/** + * @brief Tries to allocate a new hashset + * @param set hashset to be created + * @param containers The number of containers in the internal hashtable of the hashset + * @param hash Key hash function + * @param equals Key equals function + * @param destroy Entry destroy function + * @return true if the hashset was created successfully, false otherwise + */ +bool hashset_create(HashSet *set, + int containers, + int (*hash)(const void *key), + bool (*equals)(const void *key1, const void *key2), + void(*destroy)(void *value)); + +/** + * @brief Destroy the given hashset and all its entries + * @param set The hashset to be destroyed + */ +void hashset_destroy(HashSet *set); + +/** + * @brief Associates the specified value to the specified key in the given hashset if the key isn't already present + * @param set Hashmap to add an entry in + * @param key Key to be added with the specified value in the given hashset + * @param value Value to be added with the specified key in the given hashset + * @return true if the given key value pair was added, false otherwise + */ +bool hashset_put(HashSet *set, void *key, void *value); + +/** + * @brief Puts an entry at the end of the given hashset + * @param set Hashmap to add an entry in + * @param entry Entry to be added in the given hashset + * @return true if the given entry was added, false otherwise + */ +bool hashset_addEntry(HashSet *set, DLinkedElement *entry); + +/** + * @brief Compute the put operation only if the target key isn't already in the given hashset + * @param set Hashmap to put a value if absent in + * @param key Key to put if absent in the given hashset + * @param value Value of the key to put if absent in the given hashset + * @return true if key value pair has been added to the given hashset, false otherwise + */ +bool hashset_putIfAbsent(HashSet *set, void *key, void *value); + +/** + * @brief Replace the value of a target key in a given hashset + * @param set Hashmap to replace a key value in + * @param key Key to replace the value + * @param new_value New value of the key + * @param old_value Pointer on the old key value + * @return true if the replace occurs + */ +bool hashset_replace(HashSet *set, void *key, void **value); + +/** + * @brief Remove a given entry from the current hashset, then returns a pointer on the value of the deleted element + * @param set Reference of the hashset to remove an element + * @param value Double pointer of the key to delete, if deletion occurs returns pointer on the value of the deleted entry value + * @return true if the element was correctly removed, false otherwise + */ +bool hashset_remove(HashSet *set, void **value); + +/** + * @brief Remove a given entry from the current hashset, then returns a pointer on the value of the deleted element + * @param set Reference of the hashset to remove an element + * @param element Entry of the hashset to be removed + * @param value Output pointer on the value of the deleted entry value + * @return true if the element was correctly removed, false otherwise + */ +bool hashset_removeEntry(HashSet *set, DLinkedElement *entry, void **value); + +/** + * @brief Test if the given value is present in the hashset, if a equals occurs value will contain the pointer on the equalsed value + * @param set Hashmap to lookup in + * @param value Double pointer to remove the key in the given hashset, if a delete occurs returns the pointer on it + * @return true if the data table is present in the given hashset, false otherwise + */ +bool hashset_containsKey(HashSet *set, void **value); + +/** + * @brief Build a HashSet resulting of the Union of left and right, left and right MUST stay accessible before result is destroy + * @param union_result Reference HashSet resulting of the union between left and right + * @param left Left HashSet to compare for union operation + * @param right Right HashSet to compare for union operation + * @return true if the union succeed, false otherwise + * @complexity O(mn) where m and n are the number of hashtable in each operand + */ +bool hashset_union(HashSet *union_result, const HashSet *left, const HashSet *right); + +/** + * @biref Build a HashSet resulting of the Intersection of left and right, left and right MUST stay accessible before result is destroy + * @param intersection_result Reference HashSet resulting of the intersection between left and right + * @param left Left HashSet to compare for intersection operation + * @param right Right HashSet to compare for intersection operation + * @return true if the intersection succeed, false otherwise + * @complexity O(mn) where m and n are the number of hashtable in each operand + */ +bool hashset_intersection(HashSet *intersection_result, const HashSet *left, const HashSet *right); + +/** + * @brief Build a HashSet resulting of the Difference of left and right, left and right MUST stay accessible before difference_result is destroy + * @param difference_result Reference HashSet resulting of the difference between left and right + * @param left Left HashSet to compare for difference operation + * @param right Right HashSet to compare for difference operation + * @return true if the difference succeed, false otherwise + * @complexity O(mn) where m and n are the number of hashtable in each operand + */ +bool hashset_difference(HashSet *difference_result, const HashSet *left, const HashSet *right); + +/** + * @brief Test if the value is in the given HashSet + * @param set HashSet to search in + * @param value Value to search in the set + * @return true if the element is in the set, false otherwise + * @complexity O(n) where n is the number of hashtable inside the given HashSet to compare with the parameter value + */ +bool hashset_isMember(const HashSet *set, const void *value); + +/** + * @brief Test if the left operand is a subset of the right operand + * @param left HashSet to determine if it's a subset of right operand + * @param right HashSet to be compared with left operand + * @return true if the left HashSet is a subset of the right HashSet, false otherwise + * @complexity O(mn) where m and n are the number of hashtable in each operand + */ +bool hashset_isSubset(const HashSet *left, const HashSet *right); + +/** + * @brief Test if left and right HashSet operands are equal + * @param left Left HashSet reference operand + * @param right Right HashSet reference operand + * @return true if left and right are equal, false otherwise + * @complexity O(n ^ 2 ) where n is the number of hashtable inside left AND right + */ +bool hashset_equals(const HashSet *left, const HashSet *right); #ifdef __cplusplus -#include +/** + * @brief Inline function that evaluates the number of hashtable inside the specified hashset + * @return The current entry count of the current hashset + * @complexity O(1) + */ +inline int hashset_size(HashSet *hashset) { + return hashset->size; +} ; + + +/** + * @brief Inline function that evaluates the first entry of the specified hashset + * @return The first entry of the current hashset + * @complexity O(1) + */ +inline DLinkedElement *hashset_first(HashSet *hashset) { + return hashset->elements->head; +} ; + +/** + * @brief Inline function that evaluates the last entry of the specified hashset + * @return The last entry of the current hashset + * @complexity O(1) + */ +inline DLinkedElement *hashset_last(HashSet *hashset) { + return hashset->elements->tail; +} ; + +/** + * @brief Inline function that evaluates if the specified entry is the first entry of the specified hashset + * @return true if the entry is the first of the current hashset, false otherwise + * @complexity O(1) + */ +inline bool hashset_isFirst(HashSet *hashset, DLinkedElement *entry) { + return (hashset)->elements->head == entry; +} ; + +/** + * @brief Inline function that evaluates if the specified entry is the last entry of the specified hashset + * @return true if the entry is the last of the current hashset, false otherwise + * @complexity O(1) + */ +inline bool hashset_isLast(HashSet *hashset, DLinkedElement *entry) { + return (hashset)->elements->tail == entry; +} ; + +/** + * @brief Inline function that evaluates the next entry of the current hashset entry + * @return The reference to the next entry of the current hashset entry + * @complexity O(1) + */ +inline DLinkedElement *hashset_next(DLinkedElement *entry) { + if (entry == nullptr) return nullptr; + else return (entry)->next == nullptr ? nullptr : (entry)->next; +} + +/** + * @brief Inline function that check if the given value is present in the hashset, if a equals occurs value will contain the pointer on the equalsed value + * @param set Hashmap to lookup in + * @param value Double pointer to remove the key in the given hashset, if a equals occurs returns the pointer on it + * @return true if the data table is present in the given hashset, false otherwise + */ +inline bool hashset_get(HashSet *set, void **value) { + return hashset_containsKey(set, value); +} ; #else -#include -#include -#endif -#include "lhtbl.h" +/** + * @brief Macro that evaluates the number of hashtable inside the specified hashset + * @return The current entry count of the current hashset + * @complexity O(1) + */ +#define hashset_size(hashset) ((hashset)->size) +/** + * @brief Macro that evaluates the first entry of the specified hashset + * @return The first entry of the current hashset + * @complexity O(1) + */ +#define hashset_first(hashset) ((hashset)->head) + +/** + * @brief Macro that evaluates the last entry of the specified hashset + * @return The last entry of the current hashset + * @complexity O(1) + */ +#define hashset_last(hashset) ((hashset)->tail) + +/** + * @brief Macro that evaluates if the specified entry is the first entry of the specified hashset + * @return true if the entry is the first of the current hashset, false otherwise + * @complexity O(1) + */ +#define hashset_isFirst(hashset, entry) ((entry) == (hashset)->head ? true : false ) + +/** + * @brief Macro that evaluates if the specified entry is the last entry of the specified hashset + * @return true if the entry is the last of the current hashset, false otherwise + * @complexity O(1) + */ +#define hashset_isLast(hashset, entry) ((entry) == (hashset)->tail ? true : false ) + +/** + * @brief Macro that evaluates the value of a hashset entry + * @return The value stored inside a hashset entry + * @complexity O(1) + */ +#define hashset_value(entry) ((entry)->value) + + +/** + * @brief Macro that evaluates the next entry of the current hashset entry + * @return The reference to the next entry of the current hashset entry + * @complexity O(1) + */ +#define hashset_next(entry) ((entry)->next) + +/** + * @brief Macro that evaluates if the given value is present in the hashset, if a equals occurs value will contain the pointer on the equalsed value + * @param set Hashmap to lookup in + * @param value Double pointer to remove the key in the given hashset, if a equals occurs returns the pointer on it + * @return true if the data table is present in the given hashset, false otherwise + */ +#define hashset_get(set,value) hashset_containsKey +#endif #ifdef __cplusplus } diff --git a/tests/headers/CLinkedList_Test.h b/tests/headers/CLinkedList_Test.h index eba7377..034ec71 100644 --- a/tests/headers/CLinkedList_Test.h +++ b/tests/headers/CLinkedList_Test.h @@ -16,14 +16,14 @@ class CLinkedList_Test : public ::testing::Test{ } Page; protected: - ClinkedList* obj; + CLinkedList* obj; static void destroy(void *value); int replace_page(CLinkedElement **current); void SetUp() override { // Code exécuté avant chaque test - obj = (ClinkedList *)malloc(sizeof(ClinkedList)); + obj = (CLinkedList *)malloc(sizeof(CLinkedList)); clist_create(obj, destroy); } From 0c26492285b3ed356162a23429cb5d62c5e91535 Mon Sep 17 00:00:00 2001 From: nakira974 Date: Thu, 29 Feb 2024 21:45:28 +0100 Subject: [PATCH 17/27] Add SCD operations for hashset, and create destroy implementations --- headers/hashmap.h | 4 +- headers/hashset.h | 43 ++----------- src/hashmap.c | 1 + src/hashset.c | 160 +++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 166 insertions(+), 42 deletions(-) diff --git a/headers/hashmap.h b/headers/hashmap.h index b207055..e0963bf 100644 --- a/headers/hashmap.h +++ b/headers/hashmap.h @@ -91,9 +91,9 @@ bool hashmap_create(HashMap *map, /** * @brief Destroy the given hashmap and all its entries - * @param map The hashmap to be destroyed + * @param set The hashmap to be destroyed */ -void hashmap_destroy(HashMap *map); +void hashmap_destroy(HashMap *set); /** * @brief Associates the specified value to the specified key in the given hashmap if the key isn't already present diff --git a/headers/hashset.h b/headers/hashset.h index 22da5a4..6596732 100644 --- a/headers/hashset.h +++ b/headers/hashset.h @@ -12,7 +12,7 @@ extern "C" { #endif #include "lhtbl.h" - +#include "dlist.h" /** * @brief Data structure to set a specific key with its associated value @@ -76,34 +76,8 @@ void hashset_destroy(HashSet *set); * @param value Value to be added with the specified key in the given hashset * @return true if the given key value pair was added, false otherwise */ -bool hashset_put(HashSet *set, void *key, void *value); - -/** - * @brief Puts an entry at the end of the given hashset - * @param set Hashmap to add an entry in - * @param entry Entry to be added in the given hashset - * @return true if the given entry was added, false otherwise - */ -bool hashset_addEntry(HashSet *set, DLinkedElement *entry); - -/** - * @brief Compute the put operation only if the target key isn't already in the given hashset - * @param set Hashmap to put a value if absent in - * @param key Key to put if absent in the given hashset - * @param value Value of the key to put if absent in the given hashset - * @return true if key value pair has been added to the given hashset, false otherwise - */ -bool hashset_putIfAbsent(HashSet *set, void *key, void *value); +bool hashset_add(HashSet *set, void *value); -/** - * @brief Replace the value of a target key in a given hashset - * @param set Hashmap to replace a key value in - * @param key Key to replace the value - * @param new_value New value of the key - * @param old_value Pointer on the old key value - * @return true if the replace occurs - */ -bool hashset_replace(HashSet *set, void *key, void **value); /** * @brief Remove a given entry from the current hashset, then returns a pointer on the value of the deleted element @@ -113,22 +87,13 @@ bool hashset_replace(HashSet *set, void *key, void **value); */ bool hashset_remove(HashSet *set, void **value); -/** - * @brief Remove a given entry from the current hashset, then returns a pointer on the value of the deleted element - * @param set Reference of the hashset to remove an element - * @param element Entry of the hashset to be removed - * @param value Output pointer on the value of the deleted entry value - * @return true if the element was correctly removed, false otherwise - */ -bool hashset_removeEntry(HashSet *set, DLinkedElement *entry, void **value); - /** * @brief Test if the given value is present in the hashset, if a equals occurs value will contain the pointer on the equalsed value * @param set Hashmap to lookup in * @param value Double pointer to remove the key in the given hashset, if a delete occurs returns the pointer on it * @return true if the data table is present in the given hashset, false otherwise */ -bool hashset_containsKey(HashSet *set, void **value); +bool hashset_contains(HashSet *set, void **value); /** * @brief Build a HashSet resulting of the Union of left and right, left and right MUST stay accessible before result is destroy @@ -250,7 +215,7 @@ inline DLinkedElement *hashset_next(DLinkedElement *entry) { * @return true if the data table is present in the given hashset, false otherwise */ inline bool hashset_get(HashSet *set, void **value) { - return hashset_containsKey(set, value); + return hashset_contains(set, value); } ; #else /** diff --git a/src/hashmap.c b/src/hashmap.c index c69e515..29d4064 100644 --- a/src/hashmap.c +++ b/src/hashmap.c @@ -244,6 +244,7 @@ bool hashmap_remove(HashMap *map, void **value) { } last_element = current_element; } + // If a removed operation occurred inside the hashtable, then compute deletion inside the entries collection if (result) { SimpleEntry *current_entry = (SimpleEntry *) *value; void *key_value; diff --git a/src/hashset.c b/src/hashset.c index c67b120..33015af 100644 --- a/src/hashset.c +++ b/src/hashset.c @@ -1,4 +1,162 @@ // // Created by maxim on 28/02/2024. // -#include "hashset.h" \ No newline at end of file +#include "hashset.h" + +/** + * @brief Private method to add an element with a preconfigured value before a list member + * @param list List to add a new element in + * @param element Element from the list to add before + * @param new_element Preconfigured element to add in the list + * @return true if the new element was added before the list element in the given list, false otherwise + */ +bool hashset_addBefore(DLinkedList *list, DLinkedElement *element, DLinkedElement *new_element) { + // Reject null hashtable except if list is empty + if (element == NULL && dlist_size(list) != 0) return false; + + // Allocate a new memory space for the element + if ((new_element = (DLinkedElement *) malloc(sizeof(DLinkedElement))) == NULL) + return false; + + if (dlist_size(list) > 0) { + // Empty list case + list->head = new_element; + list->head->previous = NULL; + list->head->next = NULL; + list->tail = new_element; + } else { + // Non-empty list case + + // The new element is just before the target element + new_element->next = element; + // The new element is inserted between the target and its current previous + new_element->previous = element->previous; + + // If we're on top of list then the new element become the head + if (element->previous == NULL) + list->head = new_element; + // else before replacing the previous element we need to update the current previous element next reference to the new created element + else element->previous->next = new_element; + + // finally replace the previous element + element->previous = new_element; + } + + list->size++; + + return true; +} + +bool hashset_create(HashSet *set, + int containers, + int (*hash)(const void *key), + bool (*equals)(const void *key1, const void *key2), + void(*destroy)(void *value)) { + + // Try To Allocate memory space for the linked hash table + if (set == NULL) return false; + if ((set->hashTable = (LinkedHashTable *) malloc(sizeof(LinkedHashTable))) == NULL) return false; + if (!lhtbl_create(set->hashTable, containers, hash, equals, destroy)) return false; + // Init the set + set->size = 0; + set->equals = equals; + set->destroy = destroy; + if((set->elements = (DLinkedList*) malloc(sizeof (DLinkedList)))== NULL){ + // Destroy the hashtable before leaving + lhtbl_destroy(set->hashTable); + return false; + } + + return true; +} + +void hashset_destroy(HashSet *set) { + if (set == NULL) return; + dlist_destroy(set->elements); + lhtbl_destroy(set->hashTable); + memset(set, 0, sizeof(HashSet)); +} + +bool hashset_contains(HashSet *set, void **value) { + if (value == NULL || set == NULL) return false; + LinkedElement *current_element; + int current_container; + + // Hash the given key value + current_container = set->hashTable->hash(*value) % set->hashTable->containers; + + // Search the value inside the current container + for (current_element = list_first(&set->hashTable->hashtable[current_container]); + current_element != NULL; current_element = list_next(current_element)) { + // If the target value if equals to the current container element, then remove it + DLinkedElement * current_setElement = ((DLinkedElement*)list_value(current_element)); + if (set->hashTable->equals(*value, current_setElement->value)) { + *value = dlist_value(current_setElement); + return true; + } + } + + return false; +} + +bool hashset_add(HashSet *set, void *value){ + bool result = false; + + if (hashset_contains(set, &value)) { + // The value is already in the set + return false; + } else { + int container; + + // Hash the given key with the user function + container = set->hashTable->hash(value) % set->hashTable->containers; + + DLinkedElement *new_element; + if((new_element=(DLinkedElement *) malloc(sizeof(DLinkedElement))) == NULL) return false; + new_element->value = value; + // Add the current key value pair to the container + if ((result = list_add(&set->hashTable->hashtable[container], NULL, new_element))) { + result = hashset_addBefore(set->elements, dlist_first(set->elements), new_element); + set->hashTable->size++; + set->size++; + } + + } + return result; +} + +bool hashset_remove(HashSet *set, void **value){ + if (set == NULL || set->size == 0) return false; + bool result = false; + void *temp = *value; + if (!hashset_contains(set, value)) return result; + + LinkedElement *current_element, *last_element; + int current_container; + current_container = set->hashTable->hash(temp) % set->hashTable->containers; + + // Search for the value inside the current container + last_element = NULL; + + for (current_element = list_first(&set->hashTable->hashtable[current_container]); + current_element != NULL; current_element = list_next(current_element)) { + // If the target value if equals to the current container element, then remove it + DLinkedElement * current_setElement = ((DLinkedElement*)list_value(current_element)); + if (set->hashTable->equals(*value, current_setElement->value)) { + // Remove the value from the current container + if (list_remove(&set->hashTable->hashtable[current_container], last_element, *value)) { + dlist_remove(set->elements, current_setElement, *value); + set->destroy(current_setElement); + set->hashTable->size--; + result = true; + break; + // Can't remove the data from the current container + } else { + result = false; + break; + } + } + last_element = current_element; + } + return result; +} \ No newline at end of file From 8e2105d275ffd343719766a6ada60eca16f8074b Mon Sep 17 00:00:00 2001 From: nakira974 Date: Thu, 29 Feb 2024 22:39:32 +0100 Subject: [PATCH 18/27] migrated to standard C 99 for universal support --- CMakeLists.txt | 2 +- headers/hash_utils.h | 2 ++ src/hash_utils.c | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2ca75d5..413cc7e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,7 +10,7 @@ endif () cmake_minimum_required(VERSION 3.27) project(collections_commons C) -set(CMAKE_C_STANDARD 23) +set(CMAKE_C_STANDARD 99) if (CMAKE_GENERATOR MATCHES "Visual Studio") set(CMAKE_ROOT_DIRECTORY ${CMAKE_SOURCE_DIR}) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/build/) diff --git a/headers/hash_utils.h b/headers/hash_utils.h index c6011e3..21e5f2f 100644 --- a/headers/hash_utils.h +++ b/headers/hash_utils.h @@ -10,9 +10,11 @@ extern "C" { #ifdef __cplusplus #include +#include #else #include #include +#include #endif /** * @brief PJW method to convert the given key into a permuted integer using consecutive XOR shifts diff --git a/src/hash_utils.c b/src/hash_utils.c index b030a8d..a0e3773 100644 --- a/src/hash_utils.c +++ b/src/hash_utils.c @@ -45,7 +45,7 @@ int hashpjw(const void *key) { } int hashint(const void *integer) { - int x = (int) integer; + int x = *((int*) integer); x = ((x >> 16) ^ x) * 0x45d9f3b; x = ((x >> 16) ^ x) * 0x45d9f3b; x = (x >> 16) ^ x; From af1195a60ef09ffdfba36d12065344bc5e497821 Mon Sep 17 00:00:00 2001 From: nakira974 Date: Sat, 2 Mar 2024 00:47:17 +0100 Subject: [PATCH 19/27] Add hashset union, difference and intersection impl, fixed hashint const void* cast --- headers/hashset.h | 28 +++---- src/hash_utils.c | 2 +- src/hashset.c | 207 +++++++++++++++++++++++++++++++++++++--------- 3 files changed, 181 insertions(+), 56 deletions(-) diff --git a/headers/hashset.h b/headers/hashset.h index 6596732..694bee0 100644 --- a/headers/hashset.h +++ b/headers/hashset.h @@ -217,6 +217,7 @@ inline DLinkedElement *hashset_next(DLinkedElement *entry) { inline bool hashset_get(HashSet *set, void **value) { return hashset_contains(set, value); } ; + #else /** * @brief Macro that evaluates the number of hashtable inside the specified hashset @@ -225,19 +226,6 @@ inline bool hashset_get(HashSet *set, void **value) { */ #define hashset_size(hashset) ((hashset)->size) -/** - * @brief Macro that evaluates the first entry of the specified hashset - * @return The first entry of the current hashset - * @complexity O(1) - */ -#define hashset_first(hashset) ((hashset)->head) - -/** - * @brief Macro that evaluates the last entry of the specified hashset - * @return The last entry of the current hashset - * @complexity O(1) - */ -#define hashset_last(hashset) ((hashset)->tail) /** * @brief Macro that evaluates if the specified entry is the first entry of the specified hashset @@ -274,7 +262,19 @@ inline bool hashset_get(HashSet *set, void **value) { * @param value Double pointer to remove the key in the given hashset, if a equals occurs returns the pointer on it * @return true if the data table is present in the given hashset, false otherwise */ -#define hashset_get(set,value) hashset_containsKey +#define hashset_get(set,value) hashset_contains + +/** + * @brief Macro that evaluates the first element of the given Hashset + * @param set HashSet to evaluate the first element in + */ +#define hashset_first(set) dlist_first(set->elements) + +/** + * @brief Macro that evaluates the last element of the given Hashset + * @param set HashSet to evaluate the first element in + */ +#define hashset_last(set) dlist_last(set->elements) #endif #ifdef __cplusplus diff --git a/src/hash_utils.c b/src/hash_utils.c index a0e3773..7213f15 100644 --- a/src/hash_utils.c +++ b/src/hash_utils.c @@ -45,7 +45,7 @@ int hashpjw(const void *key) { } int hashint(const void *integer) { - int x = *((int*) integer); + int x = ((int) integer); x = ((x >> 16) ^ x) * 0x45d9f3b; x = ((x >> 16) ^ x) * 0x45d9f3b; x = (x >> 16) ^ x; diff --git a/src/hashset.c b/src/hashset.c index 33015af..e3046d1 100644 --- a/src/hashset.c +++ b/src/hashset.c @@ -47,50 +47,50 @@ bool hashset_addBefore(DLinkedList *list, DLinkedElement *element, DLinkedElemen return true; } -bool hashset_create(HashSet *set, +bool hashset_create(HashSet *hashset, int containers, int (*hash)(const void *key), bool (*equals)(const void *key1, const void *key2), void(*destroy)(void *value)) { // Try To Allocate memory space for the linked hash table - if (set == NULL) return false; - if ((set->hashTable = (LinkedHashTable *) malloc(sizeof(LinkedHashTable))) == NULL) return false; - if (!lhtbl_create(set->hashTable, containers, hash, equals, destroy)) return false; - // Init the set - set->size = 0; - set->equals = equals; - set->destroy = destroy; - if((set->elements = (DLinkedList*) malloc(sizeof (DLinkedList)))== NULL){ + if (hashset == NULL) return false; + if ((hashset->hashTable = (LinkedHashTable *) malloc(sizeof(LinkedHashTable))) == NULL) return false; + if (!lhtbl_create(hashset->hashTable, containers, hash, equals, destroy)) return false; + // Init the hashset + hashset->size = 0; + hashset->equals = equals; + hashset->destroy = destroy; + if ((hashset->elements = (DLinkedList *) malloc(sizeof(DLinkedList))) == NULL) { // Destroy the hashtable before leaving - lhtbl_destroy(set->hashTable); + lhtbl_destroy(hashset->hashTable); return false; } return true; } -void hashset_destroy(HashSet *set) { - if (set == NULL) return; - dlist_destroy(set->elements); - lhtbl_destroy(set->hashTable); - memset(set, 0, sizeof(HashSet)); +void hashset_destroy(HashSet *hashset) { + if (hashset == NULL) return; + dlist_destroy(hashset->elements); + lhtbl_destroy(hashset->hashTable); + memset(hashset, 0, sizeof(HashSet)); } -bool hashset_contains(HashSet *set, void **value) { - if (value == NULL || set == NULL) return false; +bool hashset_contains(HashSet *hashset, void **value) { + if (value == NULL || hashset == NULL) return false; LinkedElement *current_element; int current_container; // Hash the given key value - current_container = set->hashTable->hash(*value) % set->hashTable->containers; + current_container = hashset->hashTable->hash(*value) % hashset->hashTable->containers; // Search the value inside the current container - for (current_element = list_first(&set->hashTable->hashtable[current_container]); + for (current_element = list_first(&hashset->hashTable->hashtable[current_container]); current_element != NULL; current_element = list_next(current_element)) { // If the target value if equals to the current container element, then remove it - DLinkedElement * current_setElement = ((DLinkedElement*)list_value(current_element)); - if (set->hashTable->equals(*value, current_setElement->value)) { + DLinkedElement *current_setElement = ((DLinkedElement *) list_value(current_element)); + if (hashset->hashTable->equals(*value, current_setElement->value)) { *value = dlist_value(current_setElement); return true; } @@ -99,55 +99,55 @@ bool hashset_contains(HashSet *set, void **value) { return false; } -bool hashset_add(HashSet *set, void *value){ +bool hashset_add(HashSet *hashset, void *value) { bool result = false; - if (hashset_contains(set, &value)) { - // The value is already in the set + if (hashset_contains(hashset, &value)) { + // The value is already in the hashset return false; } else { int container; // Hash the given key with the user function - container = set->hashTable->hash(value) % set->hashTable->containers; + container = hashset->hashTable->hash(value) % hashset->hashTable->containers; DLinkedElement *new_element; - if((new_element=(DLinkedElement *) malloc(sizeof(DLinkedElement))) == NULL) return false; + if ((new_element = (DLinkedElement *) malloc(sizeof(DLinkedElement))) == NULL) return false; new_element->value = value; // Add the current key value pair to the container - if ((result = list_add(&set->hashTable->hashtable[container], NULL, new_element))) { - result = hashset_addBefore(set->elements, dlist_first(set->elements), new_element); - set->hashTable->size++; - set->size++; + if ((result = list_add(&hashset->hashTable->hashtable[container], NULL, new_element))) { + result = hashset_addBefore(hashset->elements, dlist_first(hashset->elements), new_element); + hashset->hashTable->size++; + hashset->size++; } } return result; } -bool hashset_remove(HashSet *set, void **value){ - if (set == NULL || set->size == 0) return false; +bool hashset_remove(HashSet *hashset, void **value) { + if (hashset == NULL || hashset->size == 0) return false; bool result = false; void *temp = *value; - if (!hashset_contains(set, value)) return result; + if (!hashset_contains(hashset, value)) return result; LinkedElement *current_element, *last_element; int current_container; - current_container = set->hashTable->hash(temp) % set->hashTable->containers; + current_container = hashset->hashTable->hash(temp) % hashset->hashTable->containers; // Search for the value inside the current container last_element = NULL; - for (current_element = list_first(&set->hashTable->hashtable[current_container]); + for (current_element = list_first(&hashset->hashTable->hashtable[current_container]); current_element != NULL; current_element = list_next(current_element)) { // If the target value if equals to the current container element, then remove it - DLinkedElement * current_setElement = ((DLinkedElement*)list_value(current_element)); - if (set->hashTable->equals(*value, current_setElement->value)) { + DLinkedElement *current_setElement = ((DLinkedElement *) list_value(current_element)); + if (hashset->hashTable->equals(*value, current_setElement->value)) { // Remove the value from the current container - if (list_remove(&set->hashTable->hashtable[current_container], last_element, *value)) { - dlist_remove(set->elements, current_setElement, *value); - set->destroy(current_setElement); - set->hashTable->size--; + if (list_remove(&hashset->hashTable->hashtable[current_container], last_element, *value)) { + dlist_remove(hashset->elements, current_setElement, *value); + hashset->destroy(current_setElement); + hashset->hashTable->size--; result = true; break; // Can't remove the data from the current container @@ -159,4 +159,129 @@ bool hashset_remove(HashSet *set, void **value){ last_element = current_element; } return result; +} + +bool hashset_union(HashSet *union_result, const HashSet *left, const HashSet *right) { + DLinkedElement *current_element; + void *value; + + // Create the union hashset + hashset_create(union_result, left->hashTable->containers, left->hashTable->hash, left->equals, left->destroy); + + // Insertion of left hashset elements + for (current_element = hashset_first(left); + current_element != NULL; current_element = hashset_next(current_element)) { + value = list_value(current_element); + + if (!dlist_add(union_result->elements, hashset_last(union_result), value)) { + hashset_destroy(union_result); + return false; + } + } + + // Insertion of right hashset elements + for (current_element = hashset_first(right); + current_element != NULL; current_element = hashset_next(current_element)) { + if (hashset_isMember(left, list_value(current_element))) continue; + else { + value = list_value(current_element); + if (!dlist_add(union_result->elements, hashset_last(union_result), value)) { + hashset_destroy(union_result); + return false; + } + } + } + return true; +} + +bool hashset_intersection(HashSet *intersection_result, const HashSet *left, const HashSet *right) { + DLinkedElement *current_element; + void *value; + + // Create the intersection HashSet + + hashset_create(intersection_result, left->hashTable->containers, left->hashTable->hash, left->equals, + left->destroy); + + // intersection of elements in left and right hashset + + for (current_element = hashset_first(left); + current_element != NULL; current_element = hashset_next(current_element)) { + // If the current left element is in the right HashSet + if (hashset_isMember(right, list_value(current_element))) { + value = list_value(current_element); + if (!dlist_add(intersection_result->elements, hashset_last(intersection_result), value)) { + hashset_destroy(intersection_result); + return false; + } + } + } + return true; +} + +bool hashset_difference(HashSet *difference_result, const HashSet *left, const HashSet *right) { + DLinkedElement *current_element; + void *value; + + // Creation of the difference HashSet + hashset_create(difference_result, left->hashTable->containers, left->hashTable->hash, left->equals, left->destroy); + + // Insert elements of left non present in right + for (current_element = hashset_first(left); + current_element != NULL; current_element = hashset_next(current_element)) { + // If the current left value is not in the right hashset + if (!hashset_isMember(right, list_value(current_element))) { + value = list_value(current_element); + if (!dlist_add(difference_result->elements, hashset_last(difference_result), value)) { + hashset_destroy(difference_result); + return false; + } + } + } + return true; +} + +bool hashset_isMember(const HashSet *hashset, const void *value) { + DLinkedElement *current_element; + + // Determine if the value is in hashset + + for (current_element = hashset_first(hashset); + current_element != NULL; current_element = hashset_next(current_element)) { + // If any equals occur, then return true + if (hashset->equals(value, dlist_value(current_element))) { + return true; + } + } + return false; +} + +bool hashset_isSubset(const HashSet *left, const HashSet *right) { + DLinkedElement *current_element; + + // Quick test to eliminate some usual cases + if (hashset_size(left) > hashset_size(right)) return false; + // Determine if left is a subset of right + for (current_element = hashset_first(left); + current_element != NULL; current_element = hashset_next(current_element)) { + // Validate one by one left elements in right hashset independently of their order + if (!hashset_isMember(right, dlist_value(current_element))) return false; + } + return true; +} + +bool hashset_equals(const HashSet *left, const HashSet *right) { + DLinkedElement *current_element; + // Quick test to eliminate usual cases + + if (hashset_size(left) != hashset_size(right)) return false; + + // Determine if left and right sets are equal + for (current_element = hashset_first(left); + current_element != NULL; current_element = hashset_next(current_element)) { + // If there is one element of left not present in right, sets are not equal + if (!hashset_isMember(right, dlist_value(current_element))) return false; + } + + return true; } \ No newline at end of file From b4c9a95ef8bf39db77f8677269130dd53811e048 Mon Sep 17 00:00:00 2001 From: nakira974 Date: Sat, 2 Mar 2024 01:02:53 +0100 Subject: [PATCH 20/27] Removed bad impl in hashset --- headers/hashset.h | 10 +--------- src/hashset.c | 27 ++++++--------------------- 2 files changed, 7 insertions(+), 30 deletions(-) diff --git a/headers/hashset.h b/headers/hashset.h index 694bee0..58f560d 100644 --- a/headers/hashset.h +++ b/headers/hashset.h @@ -93,7 +93,7 @@ bool hashset_remove(HashSet *set, void **value); * @param value Double pointer to remove the key in the given hashset, if a delete occurs returns the pointer on it * @return true if the data table is present in the given hashset, false otherwise */ -bool hashset_contains(HashSet *set, void **value); +bool hashset_contains(const HashSet *set, void **value); /** * @brief Build a HashSet resulting of the Union of left and right, left and right MUST stay accessible before result is destroy @@ -125,14 +125,6 @@ bool hashset_intersection(HashSet *intersection_result, const HashSet *left, con */ bool hashset_difference(HashSet *difference_result, const HashSet *left, const HashSet *right); -/** - * @brief Test if the value is in the given HashSet - * @param set HashSet to search in - * @param value Value to search in the set - * @return true if the element is in the set, false otherwise - * @complexity O(n) where n is the number of hashtable inside the given HashSet to compare with the parameter value - */ -bool hashset_isMember(const HashSet *set, const void *value); /** * @brief Test if the left operand is a subset of the right operand diff --git a/src/hashset.c b/src/hashset.c index e3046d1..2c21f26 100644 --- a/src/hashset.c +++ b/src/hashset.c @@ -77,7 +77,7 @@ void hashset_destroy(HashSet *hashset) { memset(hashset, 0, sizeof(HashSet)); } -bool hashset_contains(HashSet *hashset, void **value) { +bool hashset_contains(const HashSet *hashset, void **value) { if (value == NULL || hashset == NULL) return false; LinkedElement *current_element; int current_container; @@ -182,7 +182,7 @@ bool hashset_union(HashSet *union_result, const HashSet *left, const HashSet *ri // Insertion of right hashset elements for (current_element = hashset_first(right); current_element != NULL; current_element = hashset_next(current_element)) { - if (hashset_isMember(left, list_value(current_element))) continue; + if (hashset_contains(left, list_value(current_element))) continue; else { value = list_value(current_element); if (!dlist_add(union_result->elements, hashset_last(union_result), value)) { @@ -208,7 +208,7 @@ bool hashset_intersection(HashSet *intersection_result, const HashSet *left, con for (current_element = hashset_first(left); current_element != NULL; current_element = hashset_next(current_element)) { // If the current left element is in the right HashSet - if (hashset_isMember(right, list_value(current_element))) { + if (hashset_contains(right, list_value(current_element))) { value = list_value(current_element); if (!dlist_add(intersection_result->elements, hashset_last(intersection_result), value)) { hashset_destroy(intersection_result); @@ -230,7 +230,7 @@ bool hashset_difference(HashSet *difference_result, const HashSet *left, const H for (current_element = hashset_first(left); current_element != NULL; current_element = hashset_next(current_element)) { // If the current left value is not in the right hashset - if (!hashset_isMember(right, list_value(current_element))) { + if (!hashset_contains(right, list_value(current_element))) { value = list_value(current_element); if (!dlist_add(difference_result->elements, hashset_last(difference_result), value)) { hashset_destroy(difference_result); @@ -241,21 +241,6 @@ bool hashset_difference(HashSet *difference_result, const HashSet *left, const H return true; } -bool hashset_isMember(const HashSet *hashset, const void *value) { - DLinkedElement *current_element; - - // Determine if the value is in hashset - - for (current_element = hashset_first(hashset); - current_element != NULL; current_element = hashset_next(current_element)) { - // If any equals occur, then return true - if (hashset->equals(value, dlist_value(current_element))) { - return true; - } - } - return false; -} - bool hashset_isSubset(const HashSet *left, const HashSet *right) { DLinkedElement *current_element; @@ -265,7 +250,7 @@ bool hashset_isSubset(const HashSet *left, const HashSet *right) { for (current_element = hashset_first(left); current_element != NULL; current_element = hashset_next(current_element)) { // Validate one by one left elements in right hashset independently of their order - if (!hashset_isMember(right, dlist_value(current_element))) return false; + if (!hashset_contains(right, dlist_value(current_element))) return false; } return true; } @@ -280,7 +265,7 @@ bool hashset_equals(const HashSet *left, const HashSet *right) { for (current_element = hashset_first(left); current_element != NULL; current_element = hashset_next(current_element)) { // If there is one element of left not present in right, sets are not equal - if (!hashset_isMember(right, dlist_value(current_element))) return false; + if (!hashset_contains(right, dlist_value(current_element))) return false; } return true; From 143d74dfad3f9ed25648f0aef0fd042750400b25 Mon Sep 17 00:00:00 2001 From: nakira974 Date: Sat, 2 Mar 2024 22:21:14 +0100 Subject: [PATCH 21/27] Fixed hashmap remove and pointers issues, add HashSet_Test.h --- src/hash_utils.c | 2 +- src/hashmap.c | 22 ++-- src/hashset.c | 20 +-- tests/headers/HashMap_Test.h | 24 ++-- tests/headers/HashSet_Test.h | 237 +++++++++++++++++++++++++++++++++++ tests/headers/Set_Test.h | 16 +-- tests/headers/block.h | 36 ++++++ tests/main.cpp | 2 +- 8 files changed, 311 insertions(+), 48 deletions(-) create mode 100644 tests/headers/HashSet_Test.h create mode 100644 tests/headers/block.h diff --git a/src/hash_utils.c b/src/hash_utils.c index 7213f15..a0e3773 100644 --- a/src/hash_utils.c +++ b/src/hash_utils.c @@ -45,7 +45,7 @@ int hashpjw(const void *key) { } int hashint(const void *integer) { - int x = ((int) integer); + int x = *((int*) integer); x = ((x >> 16) ^ x) * 0x45d9f3b; x = ((x >> 16) ^ x) * 0x45d9f3b; x = (x >> 16) ^ x; diff --git a/src/hashmap.c b/src/hashmap.c index 29d4064..675c0a2 100644 --- a/src/hashmap.c +++ b/src/hashmap.c @@ -48,7 +48,7 @@ bool hashmap_pop(HashMap *map, SimpleEntry *entry, void **value) { // Remove the entry from the map *value = entry->value; - if (entry == map->head) { + if (map->equals(entry->key, map->head->key)) { // The map become after deletion empty case map->head = entry->next; if (map->head == NULL) @@ -64,7 +64,7 @@ bool hashmap_pop(HashMap *map, SimpleEntry *entry, void **value) { else entry->next->last = entry->last; } - free(entry); + map->destroy(entry); map->size--; return true; @@ -114,8 +114,8 @@ bool hashmap_containsKey(HashMap *map, void **value) { for (current_element = list_first(&map->hashTable->hashtable[current_container]); current_element != NULL; current_element = list_next(current_element)) { SimpleEntry *current_entry = (SimpleEntry *) list_value(current_element); - if (map->hashTable->equals(value, ¤t_entry->key)) { - *value = list_value(current_element); + if (map->hashTable->equals(*value, current_entry->key)) { + *value = ((SimpleEntry*)list_value(current_element))->value; return true; } } @@ -218,21 +218,21 @@ bool hashmap_remove(HashMap *map, void **value) { if (map == NULL || map->size == 0) return false; bool result = false; void *temp = *value; - if (!hashmap_containsKey(map, value)) return result; + if (!hashmap_containsKey(map, &temp)) return result; LinkedElement *current_element, *last_element; int current_container; - current_container = map->hashTable->hash(temp) % map->hashTable->containers; + current_container = map->hashTable->hash(*value) % map->hashTable->containers; // Search for the value inside the current container last_element = NULL; - for (current_element = list_first(&map->hashTable->hashtable[current_container]); current_element != NULL; current_element = list_next(current_element)) { // If the target value if equals to the current container element, then remove it - if (map->hashTable->equals(*value, &((SimpleEntry *) list_value(current_element))->key)) { + SimpleEntry * current_entry = (SimpleEntry*) list_value(current_element); + if (map->hashTable->equals(*value, current_entry->key)) { // Remove the value from the current container - if (list_remove(&map->hashTable->hashtable[current_container], last_element, *value)) { + if (list_remove(&map->hashTable->hashtable[current_container], last_element, value)) { map->hashTable->size--; result = true; break; @@ -246,11 +246,9 @@ bool hashmap_remove(HashMap *map, void **value) { } // If a removed operation occurred inside the hashtable, then compute deletion inside the entries collection if (result) { - SimpleEntry *current_entry = (SimpleEntry *) *value; void *key_value; - result = hashmap_pop(map, current_entry, &key_value); + result = hashmap_pop(map, *value, &key_value); *value = key_value; - map->destroy(key_value); } return result; } diff --git a/src/hashset.c b/src/hashset.c index 2c21f26..a35fd4c 100644 --- a/src/hashset.c +++ b/src/hashset.c @@ -15,10 +15,7 @@ bool hashset_addBefore(DLinkedList *list, DLinkedElement *element, DLinkedElemen if (element == NULL && dlist_size(list) != 0) return false; // Allocate a new memory space for the element - if ((new_element = (DLinkedElement *) malloc(sizeof(DLinkedElement))) == NULL) - return false; - - if (dlist_size(list) > 0) { + if (dlist_size(list) == 0) { // Empty list case list->head = new_element; list->head->previous = NULL; @@ -65,15 +62,16 @@ bool hashset_create(HashSet *hashset, // Destroy the hashtable before leaving lhtbl_destroy(hashset->hashTable); return false; - } + }else dlist_create(hashset->elements, free); + return true; } void hashset_destroy(HashSet *hashset) { if (hashset == NULL) return; - dlist_destroy(hashset->elements); lhtbl_destroy(hashset->hashTable); + dlist_destroy(hashset->elements); memset(hashset, 0, sizeof(HashSet)); } @@ -109,16 +107,20 @@ bool hashset_add(HashSet *hashset, void *value) { int container; // Hash the given key with the user function - container = hashset->hashTable->hash(value) % hashset->hashTable->containers; + container = hashset->hashTable->hash(&value) % hashset->hashTable->containers; DLinkedElement *new_element; if ((new_element = (DLinkedElement *) malloc(sizeof(DLinkedElement))) == NULL) return false; new_element->value = value; + new_element->next = NULL; + new_element->previous = NULL; // Add the current key value pair to the container if ((result = list_add(&hashset->hashTable->hashtable[container], NULL, new_element))) { result = hashset_addBefore(hashset->elements, dlist_first(hashset->elements), new_element); - hashset->hashTable->size++; - hashset->size++; + if(result){ + hashset->hashTable->size++; + hashset->size++; + } } } diff --git a/tests/headers/HashMap_Test.h b/tests/headers/HashMap_Test.h index 06ac6ca..74b3187 100644 --- a/tests/headers/HashMap_Test.h +++ b/tests/headers/HashMap_Test.h @@ -1,10 +1,7 @@ #include "gtest/gtest.h" #include "hashmap.h" #include "hash_utils.h" - -struct Chunk { - int data; -}; +#include "block.h" class HashMapTest : public testing::Test { protected: @@ -28,19 +25,24 @@ TEST_F(HashMapTest, BasicTest) { chunk1->data=1; chunk2->data=2; - ASSERT_TRUE(hashmap_put(map, reinterpret_cast(chunk1->data), (void*)chunk1)); - ASSERT_TRUE(hashmap_put(map, reinterpret_cast(chunk2->data), (void*)chunk2)); + ASSERT_TRUE(hashmap_put(map, &chunk1->data, chunk1)); + ASSERT_TRUE(hashmap_put(map, &chunk2->data, chunk2)); Chunk *value; - void* temp = reinterpret_cast(chunk1->data); + void* temp = &chunk1->data; ASSERT_TRUE(hashmap_get(map, &temp)); - value = (Chunk *)temp; + value = (Chunk *) temp; ASSERT_EQ(value->data, 1); - temp = reinterpret_cast(chunk2->data); + temp = &chunk2->data; ASSERT_TRUE(hashmap_remove(map, &temp)); - ASSERT_FALSE(hashmap_containsKey(map, reinterpret_cast(&chunk2->data))); + ASSERT_EQ((Chunk*) temp, chunk2); + free(temp); + temp = &chunk2->data; + ASSERT_FALSE(hashmap_containsKey(map, &temp)); ASSERT_EQ(hashmap_size(map), 1); - ASSERT_TRUE(hashmap_remove(map, reinterpret_cast(&chunk1->data))); + temp = &chunk1->data; + ASSERT_TRUE(hashmap_remove(map, &temp)); + free(temp); ASSERT_EQ(hashmap_size(map), 0); } \ No newline at end of file diff --git a/tests/headers/HashSet_Test.h b/tests/headers/HashSet_Test.h new file mode 100644 index 0000000..62e7886 --- /dev/null +++ b/tests/headers/HashSet_Test.h @@ -0,0 +1,237 @@ +// +// Created by maxim on 2/03/2024. +// + +#ifndef COLLECTIONS_COMMONS_HASHSET_TEST_H +#define COLLECTIONS_COMMONS_HASHSET_TEST_H +#include "gtest/gtest.h" +#include "set.h" +#include "hashset.h" +#include "block.h" + +class HashSetTest : public testing::Test { +protected: + HashSet *set; + + void SetUp() override { + set = (HashSet *) malloc(sizeof(HashSet)); + // Creating 16 containers, because it works using an AVR ATmega328PB 8bit addressing blocks microprocessor + hashset_create(set, 16, hash_block, cmp_block, free); + } + + void TearDown() override { + hashset_destroy(set); + } +}; + + +TEST_F(HashSetTest, BasicTest) { + Chunk *chunk1,*chunk2; + Block *b1,*b2,*b3,*b4; + chunk1 = (Chunk *) malloc(sizeof(Chunk)); + chunk2 = (Chunk *) malloc(sizeof(Chunk)); + chunk1->data=1; + chunk2->data=2; + b1 = (Block*) malloc(sizeof(Block)); + b2 = (Block*) malloc(sizeof(Block)); + b3 = (Block*) malloc(sizeof(Block)); + b4 = (Block*) malloc(sizeof(Block)); + b1->type = 1; + b1->chunk = chunk1; + b2->type = 1; + b2->chunk = chunk2; + b3->type = 2; + b3->chunk = chunk1; + b4->type = 2; + b4->chunk = chunk1; + ASSERT_TRUE(hashset_add(set, b1)); + ASSERT_TRUE(hashset_add(set, b2)); + ASSERT_TRUE(hashset_add(set, b3)); + ASSERT_FALSE(hashset_add(set, b4)); + + // True because b3 represent that literal value evaluate by cmp_block function + ASSERT_TRUE(hashset_contains(set, reinterpret_cast(b4))); + ASSERT_TRUE(hashset_contains(set, reinterpret_cast(b1))); + ASSERT_EQ(hashset_size(set), 3); + free(b4); + free(chunk1); + free(chunk2); +} + +TEST_F(HashSetTest, UnionTest){ + Chunk *chunk1,*chunk2; + Block *b1,*b2,*b3,*b4; + HashSet * set1, *union_result; + set1 = (HashSet *)malloc(sizeof(HashSet)); + union_result = (HashSet *)malloc(sizeof(HashSet)); + hashset_create(set1, 16, hashref, cmp_block, free); + chunk1 = (Chunk *) malloc(sizeof(Chunk)); + chunk2 = (Chunk *) malloc(sizeof(Chunk)); + chunk1->data=1; + chunk2->data=2; + b1 = (Block*) malloc(sizeof(Block)); + b2 = (Block*) malloc(sizeof(Block)); + b3 = (Block*) malloc(sizeof(Block)); + b4 = (Block*) malloc(sizeof(Block)); + b1->type = 1; + b1->chunk = chunk1; + b2->type = 1; + b2->chunk = chunk2; + b3->type = 2; + b3->chunk = chunk1; + b4->type = 2; + b4->chunk = chunk1; + hashset_add(set, b1); + hashset_add(set,b2); + hashset_add(set1,b3); + hashset_add(set1,b4); + ASSERT_TRUE(hashset_union(union_result, set, set1)); + + // 3 and not 4, Because b4 and b3 are equals one of them will be skipped + ASSERT_EQ(hashset_size(union_result), 3); + hashset_destroy(set1); + free(set1); +} + +TEST_F(HashSetTest, HashSetDifferenceTest) { + HashSet *difference_result, *left, *right; + Chunk *chunk1,*chunk2; + Block *b1,*b2,*b3,*b4,*b5; + chunk1 = (Chunk *) malloc(sizeof(Chunk)); + chunk2 = (Chunk *) malloc(sizeof(Chunk)); + chunk1->data=1; + chunk2->data=2; + b1 = (Block*) malloc(sizeof(Block)); + b2 = (Block*) malloc(sizeof(Block)); + b3 = (Block*) malloc(sizeof(Block)); + b4 = (Block*) malloc(sizeof(Block)); + b5 = (Block*) malloc(sizeof(Block)); + + b1->type = 1; + b1->chunk = chunk1; + b2->type = 1; + b2->chunk = chunk2; + b3->type = 2; + b3->chunk = chunk1; + b4->type = 2; + b4->chunk = chunk1; + b5->type = 3; + b5->chunk = chunk2; + + + difference_result = (HashSet *)malloc(sizeof(HashSet)); + left = (HashSet *)malloc(sizeof(HashSet)); + right = (HashSet *)malloc(sizeof(HashSet)); + + hashset_create(left, 16, hashref, cmp_block, free); + hashset_create(right, 16, hashref, cmp_block, free); + + + hashset_add(right,b1); + hashset_add(right,b2); + hashset_add(right,b3); + + hashset_add(left, b1); + hashset_add(left,b2); + hashset_add(left,b4); + hashset_add(left, b5); + + ASSERT_TRUE(hashset_difference(difference_result, left, right)); + + ASSERT_FALSE(hashset_equals(left, right)); + // Vérifier le résultat de la différence... + + ASSERT_EQ(hashset_size(difference_result), 1); + + void* delete_value = b1; + ASSERT_TRUE(hashset_remove(left, &delete_value)); + delete_value = b5; + ASSERT_TRUE(hashset_remove(difference_result, &delete_value)); + + hashset_destroy(difference_result); + hashset_destroy(left); + free(right); + + free(chunk1); + free(chunk2); +} + +TEST_F(HashSetTest , IntersectionTest) { + HashSet *intersection_result, *left, *right, *sub_set; + Chunk *chunk1,*chunk2; + Block *b1,*b2,*b3,*b4,*b5,*b1cp,*b2cp,*b4cp; + + // Creating chunks + chunk1 = (Chunk *) malloc(sizeof(Chunk)); + chunk2 = (Chunk *) malloc(sizeof(Chunk)); + chunk1->data=1; + chunk2->data=2; + + // Creating blocks + b1 = (Block*) malloc(sizeof(Block)); + b2 = (Block*) malloc(sizeof(Block)); + b3 = (Block*) malloc(sizeof(Block)); + b4 = (Block*) malloc(sizeof(Block)); + b5 = (Block*) malloc(sizeof(Block)); + b1cp = (Block*) malloc(sizeof(Block)); + b2cp = (Block*) malloc(sizeof(Block)); + b4cp = (Block*) malloc(sizeof(Block)); + b1->type = 1; + b1->chunk = chunk1; + b2->type = 1; + b2->chunk = chunk2; + b3->type = 2; + b3->chunk = chunk1; + b4->type = 2; + b4->chunk = chunk1; + b5->type = 3; + b5->chunk = chunk2; + + // Creating sets + intersection_result = (HashSet *)malloc(sizeof(HashSet)); + left = (HashSet *)malloc(sizeof(HashSet)); + right = (HashSet *)malloc(sizeof(HashSet)); + sub_set = (HashSet *)malloc(sizeof(HashSet)); + hashset_create(sub_set, 16, hashref, cmp_block, free); + hashset_create(left, 16, hashref, cmp_block, free); + hashset_create(right, 16, hashref, cmp_block, free); + // Creating right set + hashset_add(right,b1); + hashset_add(right,b2); + hashset_add(right,b3); + + // Creating left set + hashset_add(left, b1); + hashset_add(left,b2); + hashset_add(left,b4); + hashset_add(left, b5); + + // Create sub set, Add the copy of b1, b2 and b4 as subset, it's our expected intersection result + memcpy(b1cp ,b1,sizeof (Block)); + memcpy(b2cp ,b2,sizeof (Block)); + memcpy(b4cp ,b4,sizeof (Block)); + hashset_add(sub_set, b1cp); + hashset_add(sub_set, b2cp); + hashset_add(sub_set, b4cp); + + ASSERT_TRUE(hashset_intersection(intersection_result, left, right)); + + // verifier le résultat de l'intersection des deux ensembles + ASSERT_EQ(hashset_size(intersection_result), 3); + ASSERT_TRUE(hashset_isSubset(intersection_result, sub_set)); + + hashset_destroy(sub_set); + free(sub_set); + void* delete_value = b1; + ASSERT_TRUE(hashset_remove(left, &delete_value)); + delete_value = b5; + ASSERT_FALSE(hashset_remove(intersection_result, &delete_value)); + + hashset_destroy(intersection_result); + hashset_destroy(left); + free(right); + + free(chunk1); + free(chunk2); +} +#endif //COLLECTIONS_COMMONS_HASHSET_TEST_H diff --git a/tests/headers/Set_Test.h b/tests/headers/Set_Test.h index fd47103..311adcc 100644 --- a/tests/headers/Set_Test.h +++ b/tests/headers/Set_Test.h @@ -4,24 +4,12 @@ #include "gtest/gtest.h" #include "set.h" +#include "block.h" #ifndef COLLECTIONS_COMMONS_SET_TEST_H #define COLLECTIONS_COMMONS_SET_TEST_H -typedef struct Block{ - Chunk* chunk; - int type; -}Block; - -bool cmp_block(const void* arg1,const void* arg2){ - if(arg1 == nullptr || arg2 == nullptr) return -1; - Block *b1 = ((Block*)arg1); - Block *b2 = ((Block*)arg2); - if(cmp_int(&b1->chunk->data, &b2->chunk->data) && cmp_int(&b1->type, &b2->type)){ - return true; - } - return false; -} + class SetTest : public testing::Test { protected: Set *set; diff --git a/tests/headers/block.h b/tests/headers/block.h new file mode 100644 index 0000000..5665dc2 --- /dev/null +++ b/tests/headers/block.h @@ -0,0 +1,36 @@ +// +// Created by maxim on 2/03/2024. +// + +#ifndef COLLECTIONS_COMMONS_BLOCK_H +#define COLLECTIONS_COMMONS_BLOCK_H + +#include +#include "hash_utils.h" + +struct Chunk { + int data; +} ; + +typedef struct Block{ + struct Chunk* chunk; + int type; +}Block; + +int hash_block(const void *block){ + Block *b1 = ((Block*)block); + + int id = b1->type + b1->chunk->data; + int result = hashint(&id); + return result; +} +bool cmp_block(const void* arg1,const void* arg2){ + if(arg1 == nullptr || arg2 == nullptr) return false; + Block *b1 = ((Block*)arg1); + Block *b2 = ((Block*)arg2); + if(cmp_int(&b1->chunk->data, &b2->chunk->data) && cmp_int(&b1->type, &b2->type)){ + return true; + } + return false; +} +#endif //COLLECTIONS_COMMONS_BLOCK_H diff --git a/tests/main.cpp b/tests/main.cpp index 652f428..a185bcc 100644 --- a/tests/main.cpp +++ b/tests/main.cpp @@ -12,7 +12,7 @@ #include "LinkedHashTable_Test.h" #include "HashMap_Test.h" #include "Set_Test.h" - +#include "HashSet_Test.h" int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); From 729e75d2a2315502fd41cc5b74b9ea9bfdb3f18f Mon Sep 17 00:00:00 2001 From: nakira974 Date: Sat, 2 Mar 2024 22:36:46 +0100 Subject: [PATCH 22/27] Fixed HashSet_Test.h basic test, and hashset hash handle pointer issue --- src/hashset.c | 2 +- tests/headers/HashSet_Test.h | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/hashset.c b/src/hashset.c index a35fd4c..d0bf414 100644 --- a/src/hashset.c +++ b/src/hashset.c @@ -107,7 +107,7 @@ bool hashset_add(HashSet *hashset, void *value) { int container; // Hash the given key with the user function - container = hashset->hashTable->hash(&value) % hashset->hashTable->containers; + container = hashset->hashTable->hash(value) % hashset->hashTable->containers; DLinkedElement *new_element; if ((new_element = (DLinkedElement *) malloc(sizeof(DLinkedElement))) == NULL) return false; diff --git a/tests/headers/HashSet_Test.h b/tests/headers/HashSet_Test.h index 62e7886..1fe4367 100644 --- a/tests/headers/HashSet_Test.h +++ b/tests/headers/HashSet_Test.h @@ -49,9 +49,14 @@ TEST_F(HashSetTest, BasicTest) { ASSERT_TRUE(hashset_add(set, b3)); ASSERT_FALSE(hashset_add(set, b4)); + void *temp = b4; // True because b3 represent that literal value evaluate by cmp_block function - ASSERT_TRUE(hashset_contains(set, reinterpret_cast(b4))); - ASSERT_TRUE(hashset_contains(set, reinterpret_cast(b1))); + ASSERT_TRUE(hashset_contains(set, &temp)); + // The returned value is b3 because b4 == b3 and b3 is the element in the set + ASSERT_EQ((Block*) temp,b3); + temp = b1; + ASSERT_TRUE(hashset_contains(set, &temp)); + ASSERT_EQ((Block*) temp,b1); ASSERT_EQ(hashset_size(set), 3); free(b4); free(chunk1); From f22d4e4caffb187c3f908883177d5778bf9feeca Mon Sep 17 00:00:00 2001 From: nakira974 Date: Sun, 3 Mar 2024 02:22:53 +0100 Subject: [PATCH 23/27] Fixed hashset impl and unit tests --- headers/hashset.h | 9 ++--- src/hashset.c | 34 +++++++++------- tests/headers/HashSet_Test.h | 76 ++++++++++++++++++++++-------------- 3 files changed, 69 insertions(+), 50 deletions(-) diff --git a/headers/hashset.h b/headers/hashset.h index 58f560d..cd4b230 100644 --- a/headers/hashset.h +++ b/headers/hashset.h @@ -160,7 +160,7 @@ inline int hashset_size(HashSet *hashset) { * @complexity O(1) */ inline DLinkedElement *hashset_first(HashSet *hashset) { - return hashset->elements->head; + return dlist_first(hashset->elements); } ; /** @@ -169,7 +169,7 @@ inline DLinkedElement *hashset_first(HashSet *hashset) { * @complexity O(1) */ inline DLinkedElement *hashset_last(HashSet *hashset) { - return hashset->elements->tail; + return dlist_last(hashset->elements); } ; /** @@ -196,8 +196,7 @@ inline bool hashset_isLast(HashSet *hashset, DLinkedElement *entry) { * @complexity O(1) */ inline DLinkedElement *hashset_next(DLinkedElement *entry) { - if (entry == nullptr) return nullptr; - else return (entry)->next == nullptr ? nullptr : (entry)->next; + return dlist_next(entry); } /** @@ -246,7 +245,7 @@ inline bool hashset_get(HashSet *set, void **value) { * @return The reference to the next entry of the current hashset entry * @complexity O(1) */ -#define hashset_next(entry) ((entry)->next) +#define hashset_next(entry) dlist_next(entry) /** * @brief Macro that evaluates if the given value is present in the hashset, if a equals occurs value will contain the pointer on the equalsed value diff --git a/src/hashset.c b/src/hashset.c index d0bf414..d4d8d5d 100644 --- a/src/hashset.c +++ b/src/hashset.c @@ -70,8 +70,10 @@ bool hashset_create(HashSet *hashset, void hashset_destroy(HashSet *hashset) { if (hashset == NULL) return; - lhtbl_destroy(hashset->hashTable); dlist_destroy(hashset->elements); + list_destroy(hashset->hashTable->hashtable); + hashset->hashTable->size = 0; + lhtbl_destroy(hashset->hashTable); memset(hashset, 0, sizeof(HashSet)); } @@ -146,10 +148,10 @@ bool hashset_remove(HashSet *hashset, void **value) { DLinkedElement *current_setElement = ((DLinkedElement *) list_value(current_element)); if (hashset->hashTable->equals(*value, current_setElement->value)) { // Remove the value from the current container - if (list_remove(&hashset->hashTable->hashtable[current_container], last_element, *value)) { - dlist_remove(hashset->elements, current_setElement, *value); - hashset->destroy(current_setElement); + if (list_remove(&hashset->hashTable->hashtable[current_container], last_element, value)) { + dlist_remove(hashset->elements, *value, value); hashset->hashTable->size--; + hashset->size--; result = true; break; // Can't remove the data from the current container @@ -173,9 +175,9 @@ bool hashset_union(HashSet *union_result, const HashSet *left, const HashSet *ri // Insertion of left hashset elements for (current_element = hashset_first(left); current_element != NULL; current_element = hashset_next(current_element)) { - value = list_value(current_element); + value = dlist_value(current_element); - if (!dlist_add(union_result->elements, hashset_last(union_result), value)) { + if (!hashset_add(union_result, value)) { hashset_destroy(union_result); return false; } @@ -184,10 +186,11 @@ bool hashset_union(HashSet *union_result, const HashSet *left, const HashSet *ri // Insertion of right hashset elements for (current_element = hashset_first(right); current_element != NULL; current_element = hashset_next(current_element)) { - if (hashset_contains(left, list_value(current_element))) continue; + void* currentRef = &((DLinkedElement *)list_value(current_element))->value; + if (hashset_contains(left, ¤tRef)) continue; else { value = list_value(current_element); - if (!dlist_add(union_result->elements, hashset_last(union_result), value)) { + if (!hashset_add(union_result, value)) { hashset_destroy(union_result); return false; } @@ -210,9 +213,9 @@ bool hashset_intersection(HashSet *intersection_result, const HashSet *left, con for (current_element = hashset_first(left); current_element != NULL; current_element = hashset_next(current_element)) { // If the current left element is in the right HashSet - if (hashset_contains(right, list_value(current_element))) { - value = list_value(current_element); - if (!dlist_add(intersection_result->elements, hashset_last(intersection_result), value)) { + value = dlist_value(current_element); + if (hashset_contains(right, &value)) { + if (!hashset_add(intersection_result, value)) { hashset_destroy(intersection_result); return false; } @@ -232,9 +235,9 @@ bool hashset_difference(HashSet *difference_result, const HashSet *left, const H for (current_element = hashset_first(left); current_element != NULL; current_element = hashset_next(current_element)) { // If the current left value is not in the right hashset - if (!hashset_contains(right, list_value(current_element))) { - value = list_value(current_element); - if (!dlist_add(difference_result->elements, hashset_last(difference_result), value)) { + value =dlist_value(current_element); + if (!hashset_contains(right, &value)) { + if (!hashset_add(difference_result, value)) { hashset_destroy(difference_result); return false; } @@ -252,7 +255,8 @@ bool hashset_isSubset(const HashSet *left, const HashSet *right) { for (current_element = hashset_first(left); current_element != NULL; current_element = hashset_next(current_element)) { // Validate one by one left elements in right hashset independently of their order - if (!hashset_contains(right, dlist_value(current_element))) return false; + void *value =dlist_value(current_element); + if (!hashset_contains(right, &value)) return false; } return true; } diff --git a/tests/headers/HashSet_Test.h b/tests/headers/HashSet_Test.h index 1fe4367..23c4fdd 100644 --- a/tests/headers/HashSet_Test.h +++ b/tests/headers/HashSet_Test.h @@ -58,9 +58,16 @@ TEST_F(HashSetTest, BasicTest) { ASSERT_TRUE(hashset_contains(set, &temp)); ASSERT_EQ((Block*) temp,b1); ASSERT_EQ(hashset_size(set), 3); - free(b4); - free(chunk1); - free(chunk2); + DLinkedElement *current_element=hashset_first(set); + while(current_element != nullptr){ + void *value = current_element->value; + current_element= hashset_next(current_element); + hashset_remove(set,&value); + free(value); + } + free(b4); + free(chunk1); + free(chunk2); } TEST_F(HashSetTest, UnionTest){ @@ -69,7 +76,7 @@ TEST_F(HashSetTest, UnionTest){ HashSet * set1, *union_result; set1 = (HashSet *)malloc(sizeof(HashSet)); union_result = (HashSet *)malloc(sizeof(HashSet)); - hashset_create(set1, 16, hashref, cmp_block, free); + hashset_create(set1, 16, hash_block, cmp_block, free); chunk1 = (Chunk *) malloc(sizeof(Chunk)); chunk2 = (Chunk *) malloc(sizeof(Chunk)); chunk1->data=1; @@ -78,36 +85,45 @@ TEST_F(HashSetTest, UnionTest){ b2 = (Block*) malloc(sizeof(Block)); b3 = (Block*) malloc(sizeof(Block)); b4 = (Block*) malloc(sizeof(Block)); + + b1->type = 1; - b1->chunk = chunk1; + b1->chunk = chunk2; b2->type = 1; b2->chunk = chunk2; b3->type = 2; b3->chunk = chunk1; - b4->type = 2; + b4->type = 3; b4->chunk = chunk1; hashset_add(set, b1); - hashset_add(set,b2); + hashset_add(set1,b2); hashset_add(set1,b3); - hashset_add(set1,b4); + hashset_add(set,b4); + hashset_add(set1,b2); + ASSERT_TRUE(hashset_union(union_result, set, set1)); // 3 and not 4, Because b4 and b3 are equals one of them will be skipped ASSERT_EQ(hashset_size(union_result), 3); hashset_destroy(set1); - free(set1); + free(union_result); + free(chunk1); + free(chunk2); + } TEST_F(HashSetTest, HashSetDifferenceTest) { HashSet *difference_result, *left, *right; Chunk *chunk1,*chunk2; - Block *b1,*b2,*b3,*b4,*b5; + Block *b1,*b2,*b3,*b4,*b5,*b2_1, *b2_2; chunk1 = (Chunk *) malloc(sizeof(Chunk)); chunk2 = (Chunk *) malloc(sizeof(Chunk)); chunk1->data=1; chunk2->data=2; b1 = (Block*) malloc(sizeof(Block)); + b2_1 = (Block*) malloc(sizeof(Block)); b2 = (Block*) malloc(sizeof(Block)); + b2_2 = (Block*) malloc(sizeof(Block)); b3 = (Block*) malloc(sizeof(Block)); b4 = (Block*) malloc(sizeof(Block)); b5 = (Block*) malloc(sizeof(Block)); @@ -128,16 +144,18 @@ TEST_F(HashSetTest, HashSetDifferenceTest) { left = (HashSet *)malloc(sizeof(HashSet)); right = (HashSet *)malloc(sizeof(HashSet)); - hashset_create(left, 16, hashref, cmp_block, free); - hashset_create(right, 16, hashref, cmp_block, free); + hashset_create(left, 16, hash_block, cmp_block, free); + hashset_create(right, 16, hash_block, cmp_block, free); hashset_add(right,b1); hashset_add(right,b2); hashset_add(right,b3); - hashset_add(left, b1); - hashset_add(left,b2); + memcpy(b2_1 ,b1,sizeof (Block)); + memcpy(b2_2 ,b2,sizeof (Block)); + hashset_add(left, b2_1); + hashset_add(left,b2_2); hashset_add(left,b4); hashset_add(left, b5); @@ -148,15 +166,9 @@ TEST_F(HashSetTest, HashSetDifferenceTest) { ASSERT_EQ(hashset_size(difference_result), 1); - void* delete_value = b1; - ASSERT_TRUE(hashset_remove(left, &delete_value)); - delete_value = b5; - ASSERT_TRUE(hashset_remove(difference_result, &delete_value)); - - hashset_destroy(difference_result); hashset_destroy(left); - free(right); - + hashset_destroy(right); + free(difference_result); free(chunk1); free(chunk2); } @@ -164,7 +176,7 @@ TEST_F(HashSetTest, HashSetDifferenceTest) { TEST_F(HashSetTest , IntersectionTest) { HashSet *intersection_result, *left, *right, *sub_set; Chunk *chunk1,*chunk2; - Block *b1,*b2,*b3,*b4,*b5,*b1cp,*b2cp,*b4cp; + Block *b1,*b2,*b3,*b4,*b5,*b1cp,*b2cp,*b4cp,*b1cp2,*b2cp2; // Creating chunks chunk1 = (Chunk *) malloc(sizeof(Chunk)); @@ -180,6 +192,8 @@ TEST_F(HashSetTest , IntersectionTest) { b5 = (Block*) malloc(sizeof(Block)); b1cp = (Block*) malloc(sizeof(Block)); b2cp = (Block*) malloc(sizeof(Block)); + b1cp2 = (Block*) malloc(sizeof(Block)); + b2cp2 = (Block*) malloc(sizeof(Block)); b4cp = (Block*) malloc(sizeof(Block)); b1->type = 1; b1->chunk = chunk1; @@ -197,17 +211,19 @@ TEST_F(HashSetTest , IntersectionTest) { left = (HashSet *)malloc(sizeof(HashSet)); right = (HashSet *)malloc(sizeof(HashSet)); sub_set = (HashSet *)malloc(sizeof(HashSet)); - hashset_create(sub_set, 16, hashref, cmp_block, free); - hashset_create(left, 16, hashref, cmp_block, free); - hashset_create(right, 16, hashref, cmp_block, free); + hashset_create(sub_set, 16, hash_block, cmp_block, free); + hashset_create(left, 16, hash_block, cmp_block, free); + hashset_create(right, 16, hash_block, cmp_block, free); // Creating right set hashset_add(right,b1); hashset_add(right,b2); hashset_add(right,b3); // Creating left set - hashset_add(left, b1); - hashset_add(left,b2); + memcpy(b1cp2 ,b1,sizeof (Block)); + memcpy(b2cp2 ,b2,sizeof (Block)); + hashset_add(left, b1cp2); + hashset_add(left,b2cp2); hashset_add(left,b4); hashset_add(left, b5); @@ -232,9 +248,9 @@ TEST_F(HashSetTest , IntersectionTest) { delete_value = b5; ASSERT_FALSE(hashset_remove(intersection_result, &delete_value)); - hashset_destroy(intersection_result); hashset_destroy(left); - free(right); + hashset_destroy(right); + free(intersection_result); free(chunk1); free(chunk2); From f0fcac9631c9ff85e8cf6a2b2a84fb2100eb5b5d Mon Sep 17 00:00:00 2001 From: nakira974 Date: Tue, 5 Mar 2024 21:51:44 +0100 Subject: [PATCH 24/27] Add ohtbl.h API --- headers/lhtbl.h | 12 ++- headers/ohtbl.h | 108 +++++++++++++++++++++++++++ src/lhtbl.c | 4 +- tests/headers/LinkedHashTable_Test.h | 2 +- 4 files changed, 116 insertions(+), 10 deletions(-) create mode 100644 headers/ohtbl.h diff --git a/headers/lhtbl.h b/headers/lhtbl.h index e2eb684..a42eb06 100644 --- a/headers/lhtbl.h +++ b/headers/lhtbl.h @@ -66,9 +66,8 @@ typedef struct LinkedHashTable { #ifdef __cplusplus /*** -* @brief Inline function that evaluates the number of hashtable inside the specified queue -* @return The current element count of the current list -* @complexity O(1) +* @brief Inline function that evaluates the number of elements inside the specified hash table +* @return The current element count of the current hash table */ inline int lhtbl_size(LinkedHashTable *queue) { return queue->size; @@ -76,9 +75,8 @@ inline int lhtbl_size(LinkedHashTable *queue) { #else /*** -* @brief Inline function that evaluates the number of hashtable inside the specified queue -* @return The current element count of the current chained hash table -* @complexity O(1) +* @brief Macro that evaluates the number of elements inside the specified hash table +* @return The current element count of the current hash table */ #define lhtbl_size(table) list_size; #endif @@ -126,7 +124,7 @@ bool lhtbl_remove(LinkedHashTable *lhtbl, void **value); * @param value Double pointer to lookup the value in the given data table, if a equals occurs returns the pointer on it * @return true if the data table is present in the given data table, false otherwise */ -bool lhtbl_containsKey(const LinkedHashTable *lhtbl, void **value); +bool lhtbl_contains(const LinkedHashTable *lhtbl, void **value); #ifdef __cplusplus } diff --git a/headers/ohtbl.h b/headers/ohtbl.h new file mode 100644 index 0000000..5f0c8c1 --- /dev/null +++ b/headers/ohtbl.h @@ -0,0 +1,108 @@ +/** + * @file ohtbl.h + * @brief This file contains the API for open addressing hash tables + * @author Maxime Loukhal + * @date 05/03/2024 + */ +#ifndef COLLECTIONS_COMMONS_OHTBL_H +#define COLLECTIONS_COMMONS_OHTBL_H + +#ifdef __cplusplus +#include +#include +#include +#else + #include +#include +#include +#endif + +#ifdef __cplusplus + extern "C" { +#endif +/** + * @brief Data structure for an Open Addressing Hash Table + */ +typedef struct OAHashTable{ + /** + * @brief Number of positions inside the hash table + */ + int positions; + /** + * @brief Vacant position inside the hash table + */ + void *vacant; + + int (*h1)(const void *key); + int (*h2) (const void *key); + int (*equals)(const void *key1, const void *key2); + void (*destroy)(void *value); + int size; + void **hashtable; +} OAHashTable; + +/** + * @brief Create a new Open Addressing hash table + * @param hashTable Hash table to be created + * @param postions Number of positions inside the hash table + * @param h1 Hash function n°1 + * @param h2 Hash function n°2 + * @param equals Values equals function + * @param destroy Values destroy function + * @return true if the hash table was created, false otherwise + */ +bool ohtbl_create(OAHashTable *hashTable, int postions, + int (*h1)(const void *key), + int (*h2) (const void *key), + int (*equals)(const void *key1, const void *key2), + void (*destroy)(void *value)); + +/** + * @brief Destroy the given Open Addressing hash table + * @param hashTable Hash table to be destroyed + */ +void ohtbl_destroy(OAHashTable *hashTable); + +/** + * @brief Try to add an element into the Open Addressing hash table + * @param hashTable Hash table to try to add an element in + * @param value Value to be added + * @return true if the value was inserted, false otherwise + */ +bool ohtbl_add(OAHashTable *hashTable, const void *value); + +/** + * @brief Remove an element from the given Open Addressing hash table + * @param hashTable Hash table to remove an element in + * @param value Pointer to the element to be destroyed and returned value + * @return true if the element was removed from the given Open Addressing hash table, false otherwise + */ +bool ohtbl_remove(OAHashTable * hashTable, void **value); + +/** + * @brief Determine if an element is present or not in the given hash table + * @param hashTable Hash table to determine if an element is present in + * @param value The value to determine if it's present or not in the given hash table + * @return true if the element is present in the given hash table, false otherwise + */ +bool ohtbl_contains(OAHashTable * hashTable, void **value); + +#ifdef __cplusplus +/*** +* @brief Inline function that evaluates the number of elements inside the specified hash table +* @return The current element count of the current hash table +*/ +static inline int ohtbl_size(OAHashTable *hashTable){ + return hashTable->size; +} +#else + /*** +* @brief Macro that evaluates the number of elements inside the specified hash table +* @return The current element count of the current hash table +*/ +#define ohtbl_size(hashTable) ((hashTable)->size) +#endif +#ifdef __cplusplus + } +#endif +#endif //COLLECTIONS_COMMONS_OHTBL_H diff --git a/src/lhtbl.c b/src/lhtbl.c index 56a2437..9652f53 100644 --- a/src/lhtbl.c +++ b/src/lhtbl.c @@ -52,7 +52,7 @@ bool lhtbl_put(LinkedHashTable *lhtbl, const void *value) { temp = (void *) value; // If the value is already in the table return false - if (lhtbl_containsKey(lhtbl, &temp)) return result; + if (lhtbl_contains(lhtbl, &temp)) return result; // Hash the given key with the user function container = lhtbl->hash(value) % lhtbl->containers; @@ -90,7 +90,7 @@ bool lhtbl_remove(LinkedHashTable *lhtbl, void **value) { return false; } -bool lhtbl_containsKey(const LinkedHashTable *lhtbl, void **value) { +bool lhtbl_contains(const LinkedHashTable *lhtbl, void **value) { LinkedElement *current_element; int current_container; diff --git a/tests/headers/LinkedHashTable_Test.h b/tests/headers/LinkedHashTable_Test.h index f395386..ec7887d 100644 --- a/tests/headers/LinkedHashTable_Test.h +++ b/tests/headers/LinkedHashTable_Test.h @@ -55,7 +55,7 @@ TEST_F(LinkedHashTableTest, TestLhtblPutAndGet) { ASSERT_TRUE(lhtbl_put(lhtbl, page)); void* value = page; - ASSERT_TRUE(lhtbl_containsKey(lhtbl, &value)); + ASSERT_TRUE(lhtbl_contains(lhtbl, &value)); Page* retrieved_page = (Page*)value; EXPECT_EQ(retrieved_page->numero, page->numero); EXPECT_EQ(retrieved_page->reference, page->reference); From 55651b54cd9eec9423034ff648dbb7004ba6dba7 Mon Sep 17 00:00:00 2001 From: nakira974 Date: Tue, 5 Mar 2024 23:47:07 +0100 Subject: [PATCH 25/27] Add ohtbl.c impl --- src/ohtbl.c | 104 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 src/ohtbl.c diff --git a/src/ohtbl.c b/src/ohtbl.c new file mode 100644 index 0000000..6b4561e --- /dev/null +++ b/src/ohtbl.c @@ -0,0 +1,104 @@ +// +// Created by maxim on 5/03/2024. +// +#include "ohtbl.h" +static char vacant; + +bool ohtbl_create(OAHashTable *hashTable, int postions, + int (*h1)(const void *key), + int (*h2) (const void *key), + int (*equals)(const void *key1, const void *key2), + void (*destroy)(void *value)){ + int i; + if((hashTable->hashtable = (void**) malloc(postions * sizeof (void*))) == NULL) return false; + + hashTable->positions = postions; + for(i =0; i< hashTable->positions;i++) hashTable->hashtable[i] = NULL; + hashTable->vacant = &vacant; + + hashTable->h1 = h1; + hashTable->h2 = h2; + hashTable->equals = equals; + hashTable->destroy = destroy; + hashTable->size = 0; + + return true; + +} + +void ohtbl_destroy(OAHashTable *hashTable){ + int i; + if(hashTable->destroy != NULL){ + for(i=0; i< hashTable->positions; i++){ + if(hashTable->hashtable[i] != NULL && hashTable->hashtable[i] != hashTable->vacant) + hashTable->destroy(hashTable->hashtable[i]); + } + } + + free(hashTable->hashtable); + memset(hashTable, 0, sizeof (OAHashTable)); +} + +bool ohtbl_add(OAHashTable *hashTable, const void *value){ + void *temp; + int position, i; + + if(hashTable->size == hashTable->positions) return false; + + temp = (void*)value; + if(ohtbl_contains(hashTable, &temp)) return false; + + // Double hashing for hash key + + for(i=0;ipositions;i++){ + position = (hashTable->h1(value) + (i * hashTable->h2(value))) % hashTable->positions; + + if(hashTable->hashtable[position] == NULL || hashTable->hashtable[position] == hashTable->vacant){ + // Insert the value inside the hash table + hashTable->hashtable[position] = (void*)value; + hashTable->size++; + return true; + } + } + + return false; +} + +bool ohtbl_remove(OAHashTable * hashTable, void **value){ + int position, i; + for(i = 0; i< hashTable->positions;i++){ + position = (hashTable->h1(*value) + (i * hashTable->h2(*value))) % hashTable->positions; + // If not value has matched + if(hashTable->hashtable[position] == NULL) return false; + + else if(hashTable->hashtable[position] == hashTable->vacant) continue; + else if(hashTable->equals(hashTable->hashtable[position], *value)){ + // Return the deleted value + *value = hashTable->hashtable[position]; + hashTable->hashtable[position] = hashTable->vacant; + hashTable->size--; + return true; + } + } + + return false; +} + +bool ohtbl_contains(OAHashTable * hashTable, void **value){ + int position, i; + + // Double hashing the key + + for(i = 0; i < hashTable->positions;i++){ + position = (hashTable->h1(*value) + (i * hashTable->h2(*value))) % hashTable->positions; + + // If no value is present at this position return false + if(hashTable->hashtable[position] == NULL) return false; + else if(hashTable->equals(hashTable->hashtable[position], *value)){ + // Return the deleted value + *value = hashTable->hashtable[position]; + return true; + } + } + return false; +} \ No newline at end of file From 99991240efbe5dc5729b5ab21b1ba121fa09f427 Mon Sep 17 00:00:00 2001 From: nakira974 Date: Wed, 6 Mar 2024 00:02:05 +0100 Subject: [PATCH 26/27] Add OAHashTable_Test.h and renamed some method #12 --- headers/lhtbl.h | 2 +- headers/ohtbl.h | 6 +-- src/ohtbl.c | 8 +++- tests/headers/OAHashTable_Test.h | 66 ++++++++++++++++++++++++++++++++ tests/main.cpp | 2 + 5 files changed, 78 insertions(+), 6 deletions(-) create mode 100644 tests/headers/OAHashTable_Test.h diff --git a/headers/lhtbl.h b/headers/lhtbl.h index a42eb06..7b58167 100644 --- a/headers/lhtbl.h +++ b/headers/lhtbl.h @@ -1,5 +1,5 @@ /** - * @file lhtbl.h + * @file ohtbl.h * @brief This file contains the API for linked hash tables * @author Maxime Loukhal * @date 27/02/2024 diff --git a/headers/ohtbl.h b/headers/ohtbl.h index 5f0c8c1..ff500ea 100644 --- a/headers/ohtbl.h +++ b/headers/ohtbl.h @@ -35,7 +35,7 @@ typedef struct OAHashTable{ int (*h1)(const void *key); int (*h2) (const void *key); - int (*equals)(const void *key1, const void *key2); + bool (*equals)(const void *key1, const void *key2); void (*destroy)(void *value); int size; void **hashtable; @@ -54,7 +54,7 @@ typedef struct OAHashTable{ bool ohtbl_create(OAHashTable *hashTable, int postions, int (*h1)(const void *key), int (*h2) (const void *key), - int (*equals)(const void *key1, const void *key2), + bool (*equals)(const void *key1, const void *key2), void (*destroy)(void *value)); /** @@ -69,7 +69,7 @@ void ohtbl_destroy(OAHashTable *hashTable); * @param value Value to be added * @return true if the value was inserted, false otherwise */ -bool ohtbl_add(OAHashTable *hashTable, const void *value); +bool ohtbl_put(OAHashTable *hashTable, const void *value); /** * @brief Remove an element from the given Open Addressing hash table diff --git a/src/ohtbl.c b/src/ohtbl.c index 6b4561e..a08836f 100644 --- a/src/ohtbl.c +++ b/src/ohtbl.c @@ -2,12 +2,16 @@ // Created by maxim on 5/03/2024. // #include "ohtbl.h" + +/** + * @brief Private memory address for vacant hash table elements + */ static char vacant; bool ohtbl_create(OAHashTable *hashTable, int postions, int (*h1)(const void *key), int (*h2) (const void *key), - int (*equals)(const void *key1, const void *key2), + bool (*equals)(const void *key1, const void *key2), void (*destroy)(void *value)){ int i; if((hashTable->hashtable = (void**) malloc(postions * sizeof (void*))) == NULL) return false; @@ -39,7 +43,7 @@ void ohtbl_destroy(OAHashTable *hashTable){ memset(hashTable, 0, sizeof (OAHashTable)); } -bool ohtbl_add(OAHashTable *hashTable, const void *value){ +bool ohtbl_put(OAHashTable *hashTable, const void *value){ void *temp; int position, i; diff --git a/tests/headers/OAHashTable_Test.h b/tests/headers/OAHashTable_Test.h new file mode 100644 index 0000000..795b303 --- /dev/null +++ b/tests/headers/OAHashTable_Test.h @@ -0,0 +1,66 @@ +// +// Created by maxim on 5/03/2024. +// + +#ifndef COLLECTIONS_COMMONS_OAHASHTABLE_TEST_H +#define COLLECTIONS_COMMONS_OAHASHTABLE_TEST_H +#include + +#include "ohtbl.h" +#include "hash_utils.h" +#include "exception.h" + +class OAHashTableTest : public ::testing::Test +{ +protected: + typedef struct Page { + int numero; + int reference; + } Page; + + OAHashTable *ohtbl; + + void SetUp() override { + ; + if((ohtbl = (OAHashTable*) malloc(sizeof (OAHashTable))) != nullptr){ + ohtbl_create(ohtbl, 10, hashref, hashref, cmp_int, free); + }else{ + throw_exception(); + } + + } + + void TearDown() override { + ohtbl_destroy(ohtbl); + } +}; + +TEST_F(OAHashTableTest, TestLhtblPutAndGet) { + Page* page = (Page*)malloc(sizeof(Page)); + page->numero = 1; + page->reference = 100; + + ASSERT_TRUE(ohtbl_put(ohtbl, page)); + + void* value = page; + ASSERT_TRUE(ohtbl_contains(ohtbl, &value)); + Page* retrieved_page = (Page*)value; + EXPECT_EQ(retrieved_page->numero, page->numero); + EXPECT_EQ(retrieved_page->reference, page->reference); +} + +TEST_F(OAHashTableTest, TestLhtblRemove) { + Page* page = (Page*)malloc(sizeof(Page)); + page->numero = 1; + page->reference = 100; + + ASSERT_TRUE(ohtbl_put(ohtbl, page)); + + void* value = (void*) page; + ASSERT_TRUE(ohtbl_remove(ohtbl, &value)); + + Page* removed_page = (Page*)value; + EXPECT_EQ(removed_page->numero, page->numero); + EXPECT_EQ(removed_page->reference, page->reference); +} +#endif //COLLECTIONS_COMMONS_OAHASHTABLE_TEST_H diff --git a/tests/main.cpp b/tests/main.cpp index a185bcc..237ddf0 100644 --- a/tests/main.cpp +++ b/tests/main.cpp @@ -13,6 +13,8 @@ #include "HashMap_Test.h" #include "Set_Test.h" #include "HashSet_Test.h" +#include "OAHashTable_Test.h" + int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); From a353ceb534fe1362ad1c48baf318312a6a78efbf Mon Sep 17 00:00:00 2001 From: nakira974 Date: Wed, 6 Mar 2024 00:10:02 +0100 Subject: [PATCH 27/27] Add stddef in hash_utils for liux build --- src/hash_utils.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hash_utils.c b/src/hash_utils.c index a0e3773..5e66200 100644 --- a/src/hash_utils.c +++ b/src/hash_utils.c @@ -2,6 +2,7 @@ // Created by maxim on 28/02/2024. // #include "hash_utils.h" +#include bool cmp_int(const void *a, const void *b) { if (a == NULL || b == NULL) return false;