diff --git a/exam-sample_02/Makefile b/exam-sample_02/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..9cca8cc1f703b3fbe69d9367e0fbdffacc6f60b7 --- /dev/null +++ b/exam-sample_02/Makefile @@ -0,0 +1,19 @@ +CFLAGS += -Wall -Wextra -std=c11 -pedantic +CFLAGS += -g +CFLAGS += -I./include +LDFLAGS += -L./lib +LDLIBS += -lupoalglib -lm + + +.PHONY: all clean + +all: test/bst_subtree_count_even test/ht_sepchain_odelete + +test/bst_subtree_count_even: test/bst_subtree_count_even.o exam.o + +test/ht_sepchain_odelete: test/ht_sepchain_odelete.o exam.o + +clean: + $(RM) test/bst_subtree_count_even + $(RM) test/ht_sepchain_odelete + $(RM) *.o test/*.o diff --git a/exam-sample_02/exam.c b/exam-sample_02/exam.c new file mode 100644 index 0000000000000000000000000000000000000000..3b30e3245ec941c06ff4edf49409d2f415e6572a --- /dev/null +++ b/exam-sample_02/exam.c @@ -0,0 +1,111 @@ +/* vim: set tabstop=4 expandtab shiftwidth=4 softtabstop=4: */ + + +/******************************************************************************/ +/*** NOME: ***/ +/*** COGNOME: ***/ +/*** MATRICOLA: ***/ +/******************************************************************************/ + + +#include <assert.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <upo/bst.h> +#include <upo/hashtable.h> + + +/**** BEGIN of EXERCISE #1 ****/ + +size_t upo_bst_subtree_count_skip_2_impl(upo_bst_node_t *node) +{ + if (!node) { return 0; } + size_t count = 1; + if (node->left) { + count += upo_bst_subtree_count_skip_2_impl(node->left->left) + + upo_bst_subtree_count_skip_2_impl(node->left->right); + } + if (node->right) { + count += upo_bst_subtree_count_skip_2_impl(node->right->left) + + upo_bst_subtree_count_skip_2_impl(node->right->right); + } + return count; +} + +size_t upo_bst_subtree_count_even(const upo_bst_t bst, const void *key) +{ + if (!bst) { + return 0; + } + if (upo_bst_is_empty(bst)) { + return 0; + } + + upo_bst_node_t *node = bst->root; + upo_bst_comparator_t cmp = upo_bst_get_comparator(bst); + int res; + int even = 1; + while (node && (res = cmp(key, node->key)) != 0) + { + node = res < 0 ? node->left : node->right; + even = !even; + } + if (!node) + { + return 0; + } + if (even) + { + return upo_bst_subtree_count_skip_2_impl(node); + } + + size_t count = 0; + if (node->left) { + count += upo_bst_subtree_count_skip_2_impl(node->left); + } + if (node->right) { + count += upo_bst_subtree_count_skip_2_impl(node->right); + } + return count; +} + +/**** END of EXERCISE #1 ****/ + + +/**** BEGIN of EXERCISE #2 ****/ + +void upo_ht_sepchain_odelete(upo_ht_sepchain_t ht, const void *key, int destroy_data) +{ + if (!ht) + { + perror("Uninitialized hash table"); + return; + } + upo_ht_hasher_t h = upo_ht_sepchain_get_hasher(ht); + size_t i = h(key, upo_ht_sepchain_capacity(ht)); + if (ht->slots[i].head) + { + upo_ht_comparator_t cmp = upo_ht_sepchain_get_comparator(ht); + upo_ht_sepchain_list_node_t **before = &ht->slots[i].head; + while (*before && cmp((*before)->key, key) != 0) + { + before = &(*before)->next; + } + if (*before) + { + upo_ht_sepchain_list_node_t *next = (*before)->next; + if (destroy_data) + { + free((*before)->key); + free((*before)->value); + } + free(*before); + *before = next; + --ht->size; + } + } +} + +/**** END of EXERCISE #2 ****/ diff --git a/exam-sample_02/exam.pdf b/exam-sample_02/exam.pdf new file mode 100644 index 0000000000000000000000000000000000000000..ee9c491104f983b847614d4bad4b03c06c73c7ec Binary files /dev/null and b/exam-sample_02/exam.pdf differ diff --git a/exam-sample_02/include/upo/bst.h b/exam-sample_02/include/upo/bst.h new file mode 100644 index 0000000000000000000000000000000000000000..53919e27714e1935b704afb845969b8a862935a8 --- /dev/null +++ b/exam-sample_02/include/upo/bst.h @@ -0,0 +1,161 @@ +/* vim: set tabstop=4 expandtab shiftwidth=4 softtabstop=4: */ + +/** + * \file upo/bst.h + * + * \brief The Binary Search Tree (BST) abstract data type. + * + * Trees are nonlinear containers where data is structured according to + * hierarchical organization. + * Trees are made of nodes that are connected to each other according to a + * parent-child relationship. + * Binary Search Trees are Binary Trees where: + * - Each node has a key and an associated value (possibly, the + * key itself), + * - The key in node v is greater than the keys in all nodes in the + * left subtree of v, and + * - The key in node v is less than the keys in all nodes in the right + * subtree of v. + * . + * + * \author Marco Guazzone (marco.guazzone@uniupo.it) + * + * \copyright 2015 University of Piemonte Orientale, Computer Science Institute + * + * This file is part of UPOalglib. + * + * UPOalglib is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * UPOalglib is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with UPOalglib. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef UPO_BST_H +#define UPO_BST_H + + +#include <stddef.h> + + +/** + * \brief The type for key comparison functions. + * + * Declares the type for key comparison functions that are used to compare keys + * stored in the binary search tree. + * A comparison function takes two parameters: + * - The first parameter is a pointer to the first key to compare. + * - The second parameter is a pointer to the second key to compare. + * A comparison function returns a number less than, equal to, or greater than + * zero if the first key (first argument) is less than, equal to, or greater + * than the second key (second argument), respectively. + */ +typedef int (*upo_bst_comparator_t)(const void*, const void*); + +/** \brief Alias for binary search tree node type. */ +typedef struct upo_bst_node_s upo_bst_node_t; + +/** \brief Type for nodes of a binary search tree. */ +struct upo_bst_node_s +{ + void* key; /**< Pointer to user-provided key. */ + void* value; /**< Pointer to user-provided value. */ + upo_bst_node_t* left; /**< Pointer to the left child node. */ + upo_bst_node_t* right; /**< Pointer to the right child node. */ +}; + +/** \brief Defines a binary tree. */ +struct upo_bst_s +{ + upo_bst_node_t* root; /**< The root of the binary tree. */ + upo_bst_comparator_t key_cmp; /**< Pointer to the key comparison function. */ +}; + +/** \brief Declares the Binary Search Tree type. */ +typedef struct upo_bst_s* upo_bst_t; + + +/** + * \brief Creates a new empty binary search tree. + * + * \param key_cmp A pointer to the function used to compare keys. + * \return An empty binary search tree. + * + * Worst-case complexity: constant, `O(1)`. + */ +upo_bst_t upo_bst_create(upo_bst_comparator_t key_cmp); + +/** + * \brief Destroys the given binary search tree together with data stored on it. + * + * \param tree The binary search tree to destroy. + * \param destroy_data Tells whether the previously allocated memory for keys + * and values stored in this binary search tree must be freed (value `1`) or + * not (value `0`). + * + * Memory deallocation (if requested) is performed by means of the `free()` + * standard C function. + * + * Worst-case complexity: linear in the number `n` of elements, `O(n)`. + */ +void upo_bst_destroy(upo_bst_t tree, int destroy_data); + +/** + * \brief Removes all elements from the given binary search tree and destroys + * all data stored on it. + * + * \param tree The binary search tree to clear. + * \param destroy_data Tells whether the previously allocated memory for keys + * and values stored in this binary search tree must be freed (value `1`) or + * not (value `0`). + * + * Memory deallocation (if requested) is performed by means of the `free()` + * standard C function. + * + * Worst-case complexity: linear in the number `n` of elements, `O(n)`. + */ +void upo_bst_clear(upo_bst_t tree, int destroy_data); + +/** + * \brief Returns the comparison function stored in the binary search tree. + * + * \param tree The binary search tree. + * \return The comparison function. + */ +upo_bst_comparator_t upo_bst_get_comparator(const upo_bst_t tree); + +/** + * \brief Tells if the given binary search tree is empty. + * + * \param tree The binary search tree. + * \return `1` if the binary search tree is empty or `0` otherwise. + * + * A binary search tree is empty if it doesn't contain any node. + * + * Worst-case complexity: constant, `O(1)`. + */ +int upo_bst_is_empty(const upo_bst_t tree); + +/** + * \brief Counts the number of nodes of the subtree rooted at the node of the + * binary search tree containing the given key and that are located at an + * even depth. + * + * \param tree The binary search tree. + * \param key The key for which this function must return the number of nodes of + * the subtree rooted at the associated node and located at an even depth. + * \return The number of nodes of the subtree rooted at the node containing the + * given key and located at an even depth, or `0` if the tree is empty or if + * the given key does not belong to the tree. + */ +size_t upo_bst_subtree_count_even(const upo_bst_t tree, const void* key); + + +#endif /* UPO_BST_H */ diff --git a/exam-sample_02/include/upo/hashtable.h b/exam-sample_02/include/upo/hashtable.h new file mode 100644 index 0000000000000000000000000000000000000000..0d95aa44b138cad424d3138ffe3c39d323c6ae5e --- /dev/null +++ b/exam-sample_02/include/upo/hashtable.h @@ -0,0 +1,353 @@ +/* vim: set tabstop=4 expandtab shiftwidth=4 softtabstop=4: */ + +/** + * \file upo/hashtable.h + * + * \brief The Hash Table (HT) abstract data type. + * + * Hash Tables are containers composed of unique keys (containing at most one of + * each key value) that associates values of another type with the keys. + * + * \author Marco Guazzone (marco.guazzone@uniupo.it) + * + * \copyright 2015 University of Piemonte Orientale, Computer Science Institute + * + * This file is part of UPOalglib. + * + * UPOalglib is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * UPOalglib is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with UPOalglib. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef UPO_HASHTABLE_H +#define UPO_HASHTABLE_H + + +#include <stddef.h> + + +/*** BEGIN of COMMON TYPES ***/ + + +/** \brief The type for hash functions. + * + * Declares the type for key hash functions that are used to map key + * space into the index space to use for indexing the hash table. + * A hash function takes two parameters: + * - The first parameter is a pointer to the key to hash. + * - The second parameter is the capacity of the hash table. + * A hash function returns a nonnegative number which represents a position + * (index) in the hash table. + */ +typedef size_t (*upo_ht_hasher_t)(const void*, size_t); + +/** + * \brief The type for key comparison functions. + * + * Declares the type for key comparison functions that are used to compare keys + * stored in the hash table. + * A comparison function takes two parameters: + * - The first parameter is a pointer to the first key to compare. + * - The second parameter is a pointer to the second key to compare. + * A comparison function returns a number less than, equal to, or greater than + * zero if the first key (first argument) is less than, equal to, or greater + * than the second key (second argument), respectively. + */ +typedef int (*upo_ht_comparator_t)(const void*, const void*); + + +/*** END of COMMON TYPES ***/ + + +/*** BEGIN of HASH TABLE with SEPARATE CHAINING ***/ + + +/** \brief Default capacity of hash tables with separate chaining. */ +#define UPO_HT_SEPCHAIN_DEFAULT_CAPACITY 997U + + +/** \brief Type for nodes of the list of collisions. */ +struct upo_ht_sepchain_list_node_s +{ + void *key; /**< Pointer to the user-provided key. */ + void *value; /**< Pointer to the value associated to the key. */ + struct upo_ht_sepchain_list_node_s *next; /**< Pointer to the next node in the list. */ +}; +/** \brief Alias for the type for nodes of the list of collisions. */ +typedef struct upo_ht_sepchain_list_node_s upo_ht_sepchain_list_node_t; + +/** \brief Type for slots of hash tables with separate chaining. */ +struct upo_ht_sepchain_slot_s +{ + upo_ht_sepchain_list_node_t *head; /**< Pointer to the head of the list of collisions. */ +}; +/** \brief Alias for the type for slots of hash tables with separate chaining. */ +typedef struct upo_ht_sepchain_slot_s upo_ht_sepchain_slot_t; + +/** \brief Type for hash tables with separate chaining. */ +struct upo_ht_sepchain_s +{ + upo_ht_sepchain_slot_t *slots; /**< The hash table as array of slots. */ + size_t capacity; /**< The capacity of the hash table. */ + size_t size; /**< The number of elements stored in the hash table. */ + upo_ht_hasher_t key_hash; /**< The key hash function. */ + upo_ht_comparator_t key_cmp; /**< The key comparison function. */ +}; + +/** \brief Type for hash tables with separate chaining. */ +typedef struct upo_ht_sepchain_s* upo_ht_sepchain_t; + + +/** + * \brief Creates a new empty hash table. + * + * \param m The initial capacity of the hash table. + * \param key_hash A pointer to the function used to hash keys. + * \param key_cmp A pointer to the function used to compare keys. + * \return An empty hash table. + * + * Worst-case complexity: linear in the capacity `m` of the hash table, `O(m)`. + */ +upo_ht_sepchain_t upo_ht_sepchain_create(size_t m, upo_ht_hasher_t key_hash, upo_ht_comparator_t key_cmp); + +/** + * \brief Destroys the given hash table. + * + * \param ht The hash table to destroy. + * \param destroy_data Tells whether the previously allocated memory for data + * stored in the hash table must be freed (value `1`) or not (value `0`). + * + * Memory deallocation (if requested) is performed by means of the `free()` + * standard C function. + * + * Worst-case complexity: linear in the capacity `m` of the hash table, `O(m)`. + */ +void upo_ht_sepchain_destroy(upo_ht_sepchain_t ht, int destroy_data); + +/** + * \brief Removes all key-value pairs from the given hash table. + * + * \param ht The hash table to clear. + * \param destroy_data Tells whether the previously allocated memory for data + * stored in the hash table must be freed (value `1`) or not (value `0`). + * + * Memory deallocation (if requested) is performed by means of the `free()` + * standard C function. + * + * Worst-case complexity: linear in the capacity `m` of the hash table, `O(m)`. + */ +void upo_ht_sepchain_clear(upo_ht_sepchain_t ht, int destroy_data); + +/** + * \brief Tells if the given hash table is empty. + * + * \param ht The hash table. + * \return `1` if the hash table is empty or `0` otherwise. + * + * A hash table is empty if it doesn't contain any node. + * + * Worst-case complexity: constant, `O(1)`. + */ +int upo_ht_sepchain_is_empty(const upo_ht_sepchain_t ht); + +/** + * \brief Returns the capacity of the hash table. + * + * \param ht The hash table. + * \return The total number of slots of the hash tables. + * + * Worst-case complexity: constant, `O(1)`. + */ +size_t upo_ht_sepchain_capacity(const upo_ht_sepchain_t ht); + +/** + * \brief Returns the size of the hash table. + * + * \param ht The hash table. + * \return The number of keys stored in the hash tables. + * + * Worst-case complexity: linear in the capacity `m` of the hash table, `O(m)`. + */ +size_t upo_ht_sepchain_size(const upo_ht_sepchain_t ht); + +/** + * \brief Returns the load factor of the hash table. + * + * \param ht The hash table. + * \return The load factor which is defined as the ratio between the number of + * stored keys (i.e., the keys) and the number of slots (i.e., the capacity). + * + * Worst-case complexity: constant, `O(1)`. + */ +double upo_ht_sepchain_load_factor(const upo_ht_sepchain_t ht); + +/** + * \brief Returns the key comparator function. + * + * \param ht The hash table. + * \return The key comparator function. + */ +upo_ht_comparator_t upo_ht_sepchain_get_comparator(const upo_ht_sepchain_t ht); + +/** + * \brief Returns the key hasher function. + * + * \param ht The hash table. + * \return The key hasher function. + */ +upo_ht_hasher_t upo_ht_sepchain_get_hasher(const upo_ht_sepchain_t ht); + +/** + * \brief Removes the value identified by the provided key in the given + * hash table. + * + * \param ht The hash table. + * \param key The key. + * \param destroy_data Tells whether the previously allocated memory for data, + * that is to be removed, must be freed (value `1`) or not (value `0`). + * + * Memory deallocation (if requested) is performed by means of the `free()` + * standard C function. + * + * Worst-case complexity: linear in the number `n` of elements, `O(n)`. + */ +void upo_ht_sepchain_odelete(upo_ht_sepchain_t ht, const void *key, int destroy_data); + + +/*** END of HASH TABLE with SEPARATE CHAINING ***/ + + +/*** BEGIN of HASH FUNCTIONS ***/ + + +/** + * \brief Hash function for integers that uses the division method. + * + * \param x The integer to be hashed. + * \param m The number of possible hash values. + * \return The hash value which is an integer number in \f$\{0,\ldots,m-1\}\f$. + * + * The division method is defined as: + * \f[ + * h(x) = x \bmod m + * \f] + * where: + * - \f$y \bmod z\f$ means the remainder of the division \f$y / z\f$. + * . + */ +size_t upo_ht_hash_int_div(const void *x, size_t m); + +/** + * \brief Hash function for integers that uses the multiplication method. + * + * \param x The integer to be hashed. + * \param a A multiplicative constant in the range of (0,1). + * \param m The number of possible hash values. + * \return The hash value which is an integer number in \f$\{0,\ldots,m-1\}\f$. + * + * The multiplication method is defined as: + * \f[ + * h(x) = m \lfloor a x \bmod 1 \rfloor + * \f] + * where: + * - \f$\lfloor y \rfloor\f$ means the floor of \f$y\f$, that is the greatest + * integer less than or equal to \f$y\f$. + * - \f$y \bmod z\f$ means the remainder of the division \f$y / z\f$. + * - \f$y \bmod 1\f$ is the fractional part of \f$y\f$, that is + * the result of \f$y - \lfloor y \rfloor\f$. + * . + */ +size_t upo_ht_hash_int_mult(const void *x, double a, size_t m); + +/** + * \brief Hash function for integers that uses the multiplication method and + * the value of the multiplicative constant as proposed by Knuth. + * + * \param x The integer to be hashed. + * \param m The number of possible hash values. + * \return The hash value which is an integer number in \f$\{0,\ldots,m-1\}\f$. + */ +size_t upo_ht_hash_int_mult_knuth(const void *x, size_t m); + +/** + * \brief Hash function for strings. + * + * \param s The string to be hashed. + * \param h0 The initial value for the hash value that is usually chosen + * randomly from a universal family mapping integer domain + * \f$\{0,\ldots,p-1\} \mapsto \{0,\ldots,m-1\}\f$. + * \param a A multiplicative factor such that \f$a \in \{0,\ldots,p-1\}\f$ which + * is usually uniformly random. + * \param m The number of possible hash values. + * \return The hash value which is an integer number in \f$\{0,\ldots,m-1\}\f$. + * + * The implemented hash function is the following: + * \f[ + * h(k) = h_0 \left( \big(\sum_{i=0}^{\ell-1} k_i\cdot a^i \big) \bmod m \right), + * \f] + * where: + * - \f$k=(k_0,\ldots,k_{\ell-1})\f$ is an array of characters of size \$\ell\$ + */ +size_t upo_ht_hash_str(const void *s, size_t h0, size_t a, size_t m); + +/** + * \brief The Bernstein's hash function `djb2`. + * + * This hash function was first reported by Daniel J. Bernstein in comp.lang.c on 1991. + * + * See: + * - https://groups.google.com/forum/#!msg/comp.lang.c/lSKWXiuNOAk/zstZ3SRhCjgJ + * - http://www.cse.yorku.ca/~oz/hash.html + * . + */ +size_t upo_ht_hash_str_djb2(const void *s, size_t m); + +/** + * \brief The Bernstein's hash function `djb2a`. + * + * This hash function is an alternative to the 'djb2' hash function that was + * first reported by Daniel J. Bernstein in comp.lang.c on 1991. + * Instead of using the sum operator it uses the XOR operator. + * + * See: + * - https://groups.google.com/forum/#!msg/comp.lang.c/lSKWXiuNOAk/zstZ3SRhCjgJ + * - http://www.cse.yorku.ca/~oz/hash.html + * . + */ +size_t upo_ht_hash_str_djb2a(const void *s, size_t m); + +/** + * \brief The Java's hash function `hashCode`. + * + * See: + * - https://docs.oracle.com/javase/8/docs/api/java/lang/String.html#hashCode-- + * . + */ +size_t upo_ht_hash_str_java(const void *s, size_t m); + +/** + * \brief The Kernighan and Ritchie's hash function proposed in the second + * edition of their C book. + */ +size_t upo_ht_hash_str_kr2e(const void *s, size_t m); + +/** + * \brief The SGI STL's hash function `hash_fun`. + * + */ +size_t upo_ht_hash_str_sgistl(const void *s, size_t m); + + +/*** END of HASH FUNCTIONS ***/ + + +#endif /* UPO_HASHTABLE_H */ diff --git a/exam-sample_02/include/upo/test.h b/exam-sample_02/include/upo/test.h new file mode 100644 index 0000000000000000000000000000000000000000..f373ab96266cd4d23f5530e2a916d187cc26039f --- /dev/null +++ b/exam-sample_02/include/upo/test.h @@ -0,0 +1,43 @@ +/* vim: set tabstop=4 expandtab shiftwidth=4 softtabstop=4: */ + +/** + * \file upo/test/utility.h + * + * \brief Collection of useful functions for testing. + * + * \author Marco Guazzone (marco.guazzone@uniupo.it) + * + * \copyright 2015 University of Piemonte Orientale, Computer Science Institute + * + * This file is part of UPOalglib. + * + * UPOalglib is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * UPOalglib is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with UPOalglib. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef UPO_TEST_H +#define UPO_TEST_H + + +int upo_test_int_cmp(const void* a, const void* b); + +int upo_test_str_cmp(const void* a, const void* b); + +char* upo_test_int_to_string(const void *pval); + +char* upo_test_str_to_string(const void *pval); + +char* upo_test_array_to_string(const void *base, size_t nelem, size_t elem_sz, char* (*to_string)(const void*)); + + +#endif /* UPO_TEST_H */ diff --git a/exam-sample_02/lib/libupoalglib.a b/exam-sample_02/lib/libupoalglib.a new file mode 100644 index 0000000000000000000000000000000000000000..44a6ea57f9cd514063d4c67ef153a4bcd9e0ef85 Binary files /dev/null and b/exam-sample_02/lib/libupoalglib.a differ diff --git a/exam-sample_02/lib/libupoalglib.a-fedora b/exam-sample_02/lib/libupoalglib.a-fedora new file mode 100644 index 0000000000000000000000000000000000000000..44a6ea57f9cd514063d4c67ef153a4bcd9e0ef85 Binary files /dev/null and b/exam-sample_02/lib/libupoalglib.a-fedora differ diff --git a/exam-sample_02/lib/libupoalglib.a-ubuntu b/exam-sample_02/lib/libupoalglib.a-ubuntu new file mode 100644 index 0000000000000000000000000000000000000000..7855963573abce868e6c5349e28c73726e6d98be Binary files /dev/null and b/exam-sample_02/lib/libupoalglib.a-ubuntu differ diff --git a/exam-sample_02/test/bst_subtree_count_even.c b/exam-sample_02/test/bst_subtree_count_even.c new file mode 100644 index 0000000000000000000000000000000000000000..4a4e58f287e28bc9f34a9b03dc9cc11a34b7ef3a --- /dev/null +++ b/exam-sample_02/test/bst_subtree_count_even.c @@ -0,0 +1,361 @@ +/* vim: set tabstop=4 expandtab shiftwidth=4 softtabstop=4: */ + +/* + * Copyright 2016 University of Piemonte Orientale, Computer Science Institute + * + * This file is part of UPOalglib. + * + * UPOalglib is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * UPOalglib is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with UPOalglib. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <assert.h> +#include <limits.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <upo/bst.h> +#include <upo/test.h> + + +#define TEST_OK 1 +#define TEST_FAIL 0 + + +static int test_bst1(); +static int test_bst2(); +static int test_bst3(); +static int test_bst4(); +static int test_bst5(); +static int test_empty_bst(); +static int test_int_bst(int *keys, int *values, size_t n, int *no_keys, size_t m); +static int test_str_bst(char **keys, int *values, size_t n, char **no_keys, size_t m); +static int test_bst(void *keys, size_t key_sz, void *values, size_t value_sz, size_t n, void *no_keys, size_t m, upo_bst_comparator_t key_cmp, char* (*key_to_string)(const void*), char* (*value_to_string)(const void*)); +extern size_t upo_bst_check(const upo_bst_t x, const void *y); +extern void upo_bst_dump(const upo_bst_t, FILE *, char* (*)(const void*), int, char* (*)(const void*), int); +extern void* upo_bst_put(upo_bst_t, void*, void*); + + +int main() +{ + size_t n = 5; + size_t i = 0; + int ret = 0; + + printf("*** [DISCLAIMER] ***************************************************************\n"); + printf("The following tests are provided as is, to allow you to quickly test your code.\n"); + printf("However, passing these tests is a necessary but not sufficient condition,\n"); + printf("meaning that they do not guarantee that your code is correct.\n"); + printf("In fact, your code may be wrong even it passes all these tests\n"); + printf("********************************************************************************\n\n"); + + for (i = 1; i <= n; ++i) + { + switch (i) + { + case 1: + ret = test_bst1(); + break; + case 2: + ret = test_bst2(); + break; + case 3: + ret = test_bst3(); + break; + case 4: + ret = test_bst4(); + break; + case 5: + ret = test_bst5(); + break; + default: + fprintf(stderr, "ERROR: Unexpected test case number"); + abort(); + } + printf("Test BST #%lu => %s\n", i, (ret == TEST_OK) ? "[OK]" : "[FAIL]"); + } + + ret = test_empty_bst(); + printf("Test Empty BST => %s\n", (ret == TEST_OK) ? "[OK]" : "[FAIL]"); + + return 0; +} + + +int test_bst1() +{ + /* + * BST: + * 8 + * / \ + * 3 10 + * / \ \ + * 1 6 14 + * / \ / + * 4 7 13 + */ + + int keys[] = {8, 3, 1, 6, 4, 7, 10, 14, 13}; + int values[] = {0, 1, 2, 3, 4, 5, 6, 7, 8}; + int no_keys[] = {0, 2, 5, 9, 11, 16}; + size_t n = sizeof keys/sizeof keys[0]; + size_t m = sizeof no_keys/sizeof no_keys[0]; + + assert( n == sizeof keys/sizeof keys[0] ); + assert( n == sizeof values/sizeof values[0] ); + assert( m == sizeof no_keys/sizeof no_keys[0] ); + + return test_int_bst(keys, values, n, no_keys, m); +} + +int test_bst2() +{ + /* + * BST: + * 11 + * / \ + * 3 13 + * / \ \ + * 1 9 19 + * / / + * 7 15 + * / \ + * 5 17 + */ + + int keys[] = {11, 3, 1, 9, 7, 5, 13, 19, 15, 17}; + int values[] = {-11, -3, -1, -9, -7, -5, -13, -19, -15, -17}; + int no_keys[] = {0, 6, 10, 12, 14, 20}; + size_t n = sizeof keys/sizeof keys[0]; + size_t m = sizeof no_keys/sizeof no_keys[0]; + + assert( n == sizeof keys/sizeof keys[0] ); + assert( n == sizeof values/sizeof values[0] ); + assert( m == sizeof no_keys/sizeof no_keys[0] ); + + return test_int_bst(keys, values, n, no_keys, m); +} + +int test_bst3() +{ + /* + * BST: + * 11 + * / + * 9 + * / + * 7 + * / + * 5 + * / + * 3 + * / + * 1 + */ + + int keys[] = {11, 9, 7, 5, 3, 1}; + int values[] = {0, 1, 2, 3, 4, 5}; + int no_keys[] = {0, 2, 4, 6, 8, 10, 12}; + size_t n = sizeof keys/sizeof keys[0]; + size_t m = sizeof no_keys/sizeof no_keys[0]; + + assert( n == sizeof keys/sizeof keys[0] ); + assert( n == sizeof values/sizeof values[0] ); + assert( m == sizeof no_keys/sizeof no_keys[0] ); + + return test_int_bst(keys, values, n, no_keys, m); +} + +int test_bst4() +{ + /* + * BST: + * 1 + * \ + * 3 + * \ + * 5 + * \ + * 7 + * \ + * 9 + * \ + * 11 + */ + + int keys[] = {1, 3, 5, 7, 9, 11}; + int values[] = {0, 1, 2, 3, 4, 5}; + int no_keys[] = {0, 2, 4, 6, 8, 10, 12}; + size_t n = sizeof keys/sizeof keys[0]; + size_t m = sizeof no_keys/sizeof no_keys[0]; + + assert( n == sizeof keys/sizeof keys[0] ); + assert( n == sizeof values/sizeof values[0] ); + assert( m == sizeof no_keys/sizeof no_keys[0] ); + + return test_int_bst(keys, values, n, no_keys, m); +} + +int test_bst5() +{ + /* + * BST: + * "aae" + * / \ + * "aac" "aaj" + * / \ \ + * "aaa" "aad" "aak" + */ + + char *keys[] = {"aae", "aaj", "aac", "aad", "aaa", "aak"}; + int values[] = {-5, -10, -3, -4, -1, -11}; + char *no_keys[] = {"AAA", "xyz", "aaf"}; + size_t n = sizeof keys/sizeof keys[0]; + size_t m = sizeof no_keys/sizeof no_keys[0]; + + assert( n == sizeof keys/sizeof keys[0] ); + assert( n == sizeof values/sizeof values[0] ); + assert( m == sizeof no_keys/sizeof no_keys[0] ); + + return test_str_bst(keys, values, n, no_keys, m); +} + +int test_empty_bst() +{ + return test_int_bst(NULL, NULL, 0, NULL, 0); +} + +int test_int_bst(int *keys, int *values, size_t n, int *no_keys, size_t m) +{ + return test_bst(keys, sizeof keys[0], values, sizeof values[0], n, no_keys, m, upo_test_int_cmp, upo_test_int_to_string, upo_test_int_to_string); +} + +int test_str_bst(char **keys, int *values, size_t n, char **no_keys, size_t m) +{ + return test_bst(keys, sizeof keys[0], values, sizeof values[0], n, no_keys, m, upo_test_str_cmp, upo_test_str_to_string, upo_test_int_to_string); +} + +int test_bst(void *keys, size_t key_sz, void *values, size_t value_sz, size_t n, void *no_keys, size_t m, upo_bst_comparator_t key_cmp, char* (*key_to_string)(const void*), char* (*value_to_string)(const void*)) +{ + upo_bst_t bst = NULL; + unsigned char *pck = keys; + unsigned char *pcv = values; + unsigned char *pcnk = no_keys; + int ret = TEST_OK; + + /* Creates BST */ + + bst = upo_bst_create(key_cmp); + + assert( bst != NULL ); + + if (n > 0) + { + // Non-empty BST + + for (size_t i = 0; i < n; ++i) + { + upo_bst_put(bst, pck + i*key_sz, pcv + i*value_sz); + } + + // Keys + for (size_t i = 0; i < n && ret == TEST_OK; ++i) + { + void *pkey = NULL; + size_t count = 0; + size_t count_check = 0; + + pkey = malloc(key_sz); + if (pkey == NULL) + { + perror("[ERROR] Unable to allocate memory for key"); + abort(); + } + + memcpy(pkey, pck + i*key_sz, key_sz); + + count = upo_bst_subtree_count_even(bst, pkey); + + count_check = upo_bst_check(bst, pkey); + + if (count != count_check) + { + char *key_str = key_to_string(pkey); + fprintf(stderr, "[file: %s, line: %d] ERROR: Key: '%s' -> Expected count %lu, got %lu.\n", __FILE__, __LINE__, key_str, count_check, count); + free(key_str); + fprintf(stderr, "[file: %s, line: %d] <BST>:\n", __FILE__, __LINE__); + upo_bst_dump(bst, stderr, key_to_string, 1, value_to_string, 1); + fprintf(stderr, "[file: %s, line: %d] </BST>:\n", __FILE__, __LINE__); + ret = TEST_FAIL; + } + + free(pkey); + } + + // No keys + for (size_t i = 0; i < m && ret == TEST_OK; ++i) + { + void *pkey = NULL; + size_t count = 0; + size_t count_check = 0; + + pkey = malloc(key_sz); + if (pkey == NULL) + { + perror("[ERROR] Unable to allocate memory for key"); + abort(); + } + + memcpy(pkey, pcnk + i*key_sz, key_sz); + + count = upo_bst_subtree_count_even(bst, pkey); + + count_check = upo_bst_check(bst, pkey); + + if (count != count_check) + { + char *key_str = key_to_string(pkey); + fprintf(stderr, "[file: %s, line: %d] ERROR: Key: '%s' -> Expected count '%lu', got %lu.\n", __FILE__, __LINE__, key_str, count_check, count); + free(key_str); + fprintf(stderr, "[file: %s, line: %d] <BST>:\n", __FILE__, __LINE__); + upo_bst_dump(bst, stderr, key_to_string, 1, value_to_string, 1); + fprintf(stderr, "[file: %s, line: %d] </BST>:\n", __FILE__, __LINE__); + ret = TEST_FAIL; + } + + free(pkey); + } + } + else + { + // Empty BST + + int dummy_key = 0; + size_t count = 0; + + count = upo_bst_subtree_count_even(bst, &dummy_key); + + if (count != 0) + { + fprintf(stderr, "[file: %s, line: %d] ERROR: Empty BST -> Expected count 0, got %lu.\n", __FILE__, __LINE__, count); + ret = TEST_FAIL; + } + } + + /* Destroy */ + + upo_bst_destroy(bst, 0); + + return ret; +} diff --git a/exam-sample_02/test/ht_sepchain_odelete.c b/exam-sample_02/test/ht_sepchain_odelete.c new file mode 100644 index 0000000000000000000000000000000000000000..d3762046627ffe19c12efb028c876c0bc267055f --- /dev/null +++ b/exam-sample_02/test/ht_sepchain_odelete.c @@ -0,0 +1,506 @@ +/* vim: set tabstop=4 expandtab shiftwidth=4 softtabstop=4: */ + +/* + * Copyright 2015 University of Piemonte Orientale, Computer Science Institute + * + * This file is part of UPOalglib. + * + * UPOalglib is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * UPOalglib is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with UPOalglib. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <assert.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <upo/hashtable.h> +#include <upo/test.h> + + +#define TEST_OK 1 +#define TEST_FAIL 0 + + +static int test_ht1(); +static int test_ht2(); +static int test_ht3(); +static int test_ht4(); +static int test_ht5(); +static int test_ht6(); +static int test_empty_ht(); +static int test_int_ht(int *keys, int *values, size_t n, int *no_keys, size_t m); +static int test_str_ht(char **keys, int *values, size_t n, char **no_keys, size_t m); +static int test_ht(void *keys, size_t key_sz, void *values, size_t value_sz, size_t n, void *no_keys, size_t m, upo_ht_hasher_t key_hasher, upo_ht_comparator_t key_cmp, char* (*key_to_string)(const void*), char* (*value_to_string)(const void*)); +extern upo_ht_sepchain_list_node_t* upo_ht_sepchain_check_order(const upo_ht_sepchain_t ht); +extern int upo_ht_sepchain_contains(const upo_ht_sepchain_t ht, const void *key); +extern void upo_ht_sepchain_dump(const upo_ht_sepchain_t, FILE *, char* (*)(const void*), int, char* (*)(const void*), int); +extern void* upo_ht_sepchain_put(upo_ht_sepchain_t ht, void *key, void *value); + + +int main() +{ + size_t n = 6; + size_t i = 0; + int ret = 0; + + printf("*** [DISCLAIMER] ***************************************************************\n"); + printf("The following tests are provided as is, to allow you to quickly test your code.\n"); + printf("However, passing these tests is a necessary but not sufficient condition,\n"); + printf("meaning that they do not guarantee that your code is correct.\n"); + printf("In fact, your code may be wrong even it passes all these tests\n"); + printf("********************************************************************************\n\n"); + + for (i = 1; i <= n; ++i) + { + switch (i) + { + case 1: + ret = test_ht1(); + break; + case 2: + ret = test_ht2(); + break; + case 3: + ret = test_ht3(); + break; + case 4: + ret = test_ht4(); + break; + case 5: + ret = test_ht5(); + break; + case 6: + ret = test_ht6(); + break; + default: + fprintf(stderr, "ERROR: Unexpected test case number"); + abort(); + } + printf("Test HT #%zu => %s\n", i, (ret == TEST_OK) ? "[OK]" : "[FAIL]"); + } + + ret = test_empty_ht(); + printf("Test Empty HT => %s\n", (ret == TEST_OK) ? "[OK]" : "[FAIL]"); + + return 0; +} + + +int test_ht1() +{ + int keys[] = {0,1,2,3,4,5,6,7,8,9,1000,2000,3000,4000,5000,6000,7000,8000,9000}; + int values[] = {0,1,2,3,4,5,6,7,8,9,1000,2000,3000,4000,5000,6000,7000,8000,9000}; + int no_keys[] = {10,11,12,13,14,15,16,19,1010,2010,3010,4010,5010}; + size_t n = sizeof keys/sizeof keys[0]; + size_t m = sizeof no_keys/sizeof no_keys[0]; + + assert( n == (sizeof keys/sizeof keys[0]) ); + assert( n == (sizeof values/sizeof values[0]) ); + assert( m == (sizeof no_keys/sizeof no_keys[0]) ); + + return test_int_ht(keys, values, n, no_keys, m); +} + +int test_ht2() +{ + int keys[] = {0,10,20,30,40,50,60,70,80,90,100,200,300,400,500,600,700,800,900}; + int values[] = {0,1,2,3,4,5,6,7,8,9,1000,2000,3000,4000,5000,6000,7000,8000,9000}; + int no_keys[] = {1,11,21,31,41,51,61,71,81,91,101,201,301,401,501,601,701,801,901,1001,1101,1201,1301,1401,1501}; + size_t n = sizeof keys/sizeof keys[0]; + size_t m = sizeof no_keys/sizeof no_keys[0]; + + assert( n == (sizeof keys/sizeof keys[0]) ); + assert( n == (sizeof values/sizeof values[0]) ); + assert( m == (sizeof no_keys/sizeof no_keys[0]) ); + + return test_int_ht(keys, values, n, no_keys, m); +} + +int test_ht3() +{ + int keys[] = {0,1,2,3,4,10,11,12,13,14,1000,2000,3000,4000,5000,6000,7000,8000,9000}; + int values[] = {0,1,2,3,4,5,6,7,8,9,1000,2000,3000,4000,5000,6000,7000,8000,9000}; + int no_keys[] = {5,6,7,8,9,15,16,17,18,19,1500,1600,1700,1800,1900}; + size_t n = sizeof keys/sizeof keys[0]; + size_t m = sizeof no_keys/sizeof no_keys[0]; + + assert( n == (sizeof keys/sizeof keys[0]) ); + assert( n == (sizeof values/sizeof values[0]) ); + assert( m == (sizeof no_keys/sizeof no_keys[0]) ); + + return test_int_ht(keys, values, n, no_keys, m); +} + +int test_ht4() +{ + char *keys[] = {"AA","AB","AQ","Aa","Aq","Ba","Ca","Da","Ea","Fa","AAA", "Ab"}; + int values[] = {0,1,2,3,4,5,6,7,8,9,10,11}; + char *no_keys[] = {"xAA","xAB","xAQ","xAa","xAq","xBa","xCa","xDa","xEa","xFa","xAAA", "xAb", "yAA", "yAB"}; + size_t n = sizeof keys/sizeof keys[0]; + size_t m = sizeof no_keys/sizeof no_keys[0]; + + assert( n == (sizeof keys/sizeof keys[0]) ); + assert( n == (sizeof values/sizeof values[0]) ); + assert( m == (sizeof no_keys/sizeof no_keys[0]) ); + + return test_str_ht(keys, values, n, no_keys, m); +} + +int test_ht5() +{ + char *keys[] = {"aaa","aba","aca","ada","aea","afa","aga","aha","aia","aja"}; + int values[] = {0,1,2,3,4,5,6,7,8,9}; + char *no_keys[] = {"a1a","a2a","a3a","a4a","a5a","a6a","a7a","a9a","a9a","a10a"}; + size_t n = sizeof keys/sizeof keys[0]; + size_t m = sizeof no_keys/sizeof no_keys[0]; + + assert( n == (sizeof keys/sizeof keys[0]) ); + assert( n == (sizeof values/sizeof values[0]) ); + assert( m == (sizeof no_keys/sizeof no_keys[0]) ); + + return test_str_ht(keys, values, n, no_keys, m); +} + +int test_ht6() +{ + char *keys[] = {"aaa","aab","aac","aad","aba","abb","abc","abd","abe","abf"}; + int values[] = {0,1,2,3,4,5,6,7,8,9}; + char *no_keys[] = {"aax","abx","acx","adx","aex","afx"}; + size_t n = sizeof keys/sizeof keys[0]; + size_t m = sizeof no_keys/sizeof no_keys[0]; + + assert( n == (sizeof keys/sizeof keys[0]) ); + assert( n == (sizeof values/sizeof values[0]) ); + assert( m == (sizeof no_keys/sizeof no_keys[0]) ); + + return test_str_ht(keys, values, n, no_keys, m); +} + +int test_empty_ht() +{ + int dummy1 = 0; + int dummy2 = 1; + + return test_int_ht(&dummy1, &dummy1, 0, &dummy2, 0); +} + +int test_int_ht(int *keys, int *values, size_t n, int *no_keys, size_t m) +{ + assert( keys ); + assert( values ); + assert( no_keys ); + + return test_ht(keys, sizeof keys[0], values, sizeof values[0], n, no_keys, m, upo_ht_hash_int_div, upo_test_int_cmp, upo_test_int_to_string, upo_test_int_to_string); +} + +int test_str_ht(char **keys, int *values, size_t n, char **no_keys, size_t m) +{ + assert( keys ); + assert( values ); + assert( no_keys ); + + return test_ht(keys, sizeof keys[0], values, sizeof values[0], n, no_keys, m, upo_ht_hash_str_kr2e, upo_test_str_cmp, upo_test_str_to_string, upo_test_int_to_string); +} + +int test_ht(void *keys, size_t key_sz, void *values, size_t value_sz, size_t n, void *no_keys, size_t m, upo_ht_hasher_t key_hasher, upo_ht_comparator_t key_cmp, char* (*key_to_string)(const void*), char* (*value_to_string)(const void*)) +{ + upo_ht_sepchain_t ht = NULL; + size_t base_cap = 3; + size_t caps[4]; + size_t nc; + unsigned char *pck = keys; + unsigned char *pcv = values; + unsigned char *pcnk = no_keys; + int ret = TEST_OK; + +/* + caps[0] = 2*n+UPO_HT_SEPCHAIN_DEFAULT_CAPACITY; + caps[1] = n*UPO_HT_SEPCHAIN_DEFAULT_CAPACITY; + caps[2] = UPO_HT_SEPCHAIN_DEFAULT_CAPACITY; +*/ + caps[0] = 3*n+base_cap; + caps[1] = 2*n+base_cap; + caps[2] = n*base_cap; + caps[3] = base_cap; + nc = sizeof caps/sizeof caps[0]; + + for (size_t k = 0; k < nc && ret == TEST_OK; ++k) + { + ht = upo_ht_sepchain_create(caps[k], key_hasher, key_cmp); + + assert( ht != NULL ); + + if (n > 0) + { + // Non-empty HT + + // Populate the HT + for (size_t i = 0; i < n; ++i) + { + upo_ht_sepchain_put(ht, pck + i*key_sz, pcv + i*value_sz); + } + + // Remove from HT + for (size_t i = 0; i < n && ret == TEST_OK; ++i) + { + size_t old_size = 0; + size_t new_size = 0; + int found = 0; + + void *key = NULL; + + key = malloc(key_sz); + if (key == NULL) + { + perror("Unable to allocate memory for key"); + abort(); + } + + memcpy(key, pck + i*key_sz, key_sz); + + old_size = upo_ht_sepchain_size(ht); + + upo_ht_sepchain_odelete(ht, key, 0); + + new_size = upo_ht_sepchain_size(ht); + + found = upo_ht_sepchain_contains(ht, key); + + if (found == 1) + { + char *key_str = key_to_string(key); + fprintf(stderr, "[file: %s, line: %d] ERROR: HT Alternative #: %lu, Key: '%s' -> Found key after its deletion.\n", __FILE__, __LINE__, k, key_str); + fprintf(stderr, "[file: %s, line: %d]: <HT>\n", __FILE__, __LINE__); + upo_ht_sepchain_dump(ht, stderr, key_to_string, 1, value_to_string, 1); + fprintf(stderr, "[file: %s, line: %d]: </HT>\n", __FILE__, __LINE__); + fflush(stderr); + free(key_str); + ret = TEST_FAIL; + } + else if (new_size != (old_size-1)) + { + char *key_str = key_to_string(key); + fprintf(stderr, "[file: %s, line: %d] ERROR: HT Alternative #: %lu, Key: '%s' -> Expected size: %lu, got %lu.\n", __FILE__, __LINE__, k, key_str, (old_size-1), new_size); + fprintf(stderr, "[file: %s, line: %d]: <HT>\n", __FILE__, __LINE__); + upo_ht_sepchain_dump(ht, stderr, key_to_string, 1, value_to_string, 1); + fprintf(stderr, "[file: %s, line: %d]: </HT>\n", __FILE__, __LINE__); + fflush(stderr); + free(key_str); + ret = TEST_FAIL; + } + + free(key); + + // Check order of stored values + + upo_ht_sepchain_list_node_t *node = upo_ht_sepchain_check_order(ht); + if (node != NULL) + { + char *key_str1 = key_to_string(node->key); + char *key_str2 = key_to_string(node->next->key); + fprintf(stderr, "[file: %s, line: %d] ERROR: HT Alternative #: %zu, Keys: '%s' and '%s' are out of order.\n", __FILE__, __LINE__, k, key_str1, key_str2); + free(key_str1); + free(key_str2); + fprintf(stderr, "[file: %s, line: %d]: <HT>\n", __FILE__, __LINE__); + upo_ht_sepchain_dump(ht, stderr, key_to_string, 1, value_to_string, 1); + fprintf(stderr, "[file: %s, line: %d]: </HT>\n", __FILE__, __LINE__); + fflush(stderr); + ret = TEST_FAIL; + } + } + + upo_ht_sepchain_clear(ht, 0); + + // Now for each key to be removed, fill the HT with all keys, remove the given key and then check that the other keys are still present in the HT + + for (size_t j = 0; j < n && ret == TEST_OK; ++j) + { + // Populate the HT + for (size_t i = 0; i < n && ret == TEST_OK; ++i) + { + upo_ht_sepchain_put(ht, pck + i*key_sz, pcv + i*value_sz); + } + + // Remove from the HT + + void *key = NULL; + + key = malloc(key_sz); + if (key == NULL) + { + perror("Unable to allocate memory for key"); + abort(); + } + + memcpy(key, pck + j*key_sz, key_sz); + + size_t old_size = 0; + size_t new_size = 0; + int found = 0; + + old_size = upo_ht_sepchain_size(ht); + + upo_ht_sepchain_odelete(ht, key, 0); + + new_size = upo_ht_sepchain_size(ht); + + found = upo_ht_sepchain_contains(ht, key); + + if (found == 1) + { + char *key_str = key_to_string(key); + fprintf(stderr, "[file: %s, line: %d] ERROR: HT Alternative #: %lu, Key: '%s' -> Found key after its deletion.\n", __FILE__, __LINE__, k, key_str); + fprintf(stderr, "[file: %s, line: %d]: <HT>\n", __FILE__, __LINE__); + upo_ht_sepchain_dump(ht, stderr, key_to_string, 1, value_to_string, 1); + fprintf(stderr, "[file: %s, line: %d]: </HT>\n", __FILE__, __LINE__); + fflush(stderr); + free(key_str); + ret = TEST_FAIL; + } + else if (new_size != (old_size-1)) + { + char *key_str = key_to_string(key); + fprintf(stderr, "[file: %s, line: %d] ERROR: HT Alternative #: %lu, Key: '%s' -> Expected size: %lu, got %lu.\n", __FILE__, __LINE__, k, key_str, (old_size-1), new_size); + fprintf(stderr, "[file: %s, line: %d]: <HT>\n", __FILE__, __LINE__); + upo_ht_sepchain_dump(ht, stderr, key_to_string, 1, value_to_string, 1); + fprintf(stderr, "[file: %s, line: %d]: </HT>\n", __FILE__, __LINE__); + fflush(stderr); + free(key_str); + ret = TEST_FAIL; + } + + for (size_t i = 0; i < n && ret == TEST_OK; ++i) + { + if (i == j) + { + // Skip the remove key + continue; + } + + found = upo_ht_sepchain_contains(ht, pck + i*key_sz); + + if (found == 0) + { + ret = TEST_FAIL; + char *key_str = key_to_string(key); + char *key2_str = key_to_string(pck + i*key_sz); + fprintf(stderr, "[file: %s, line: %d] ERROR: HT Alternative #: %lu, Key: '%s' -> Key '%s' not found after the deletion of another key.\n", __FILE__, __LINE__, k, key_str, key2_str); + fprintf(stderr, "[file: %s, line: %d]: <HT>\n", __FILE__, __LINE__); + upo_ht_sepchain_dump(ht, stderr, key_to_string, 1, value_to_string, 1); + fprintf(stderr, "[file: %s, line: %d]: </HT>\n", __FILE__, __LINE__); + fflush(stderr); + free(key_str); + free(key2_str); + ret = TEST_FAIL; + } + } + + /* Clean-up */ + free(key); + + // Clear the HT + upo_ht_sepchain_clear(ht, 0); + } + + // Now populate again the HT and try to remove a key not stored in it. + + // Populate the HT + for (size_t i = 0; i < n; ++i) + { + upo_ht_sepchain_put(ht, pck + i*key_sz, pcv + i*value_sz); + } + + // Remove from HT + for (size_t i = 0; i < m && ret == TEST_OK; ++i) + { + size_t old_size = 0; + size_t new_size = 0; + int found = 0; + + // Use a different pointer for key to catch comparison-by-pointers issues + + void *key = NULL; + + key = malloc(key_sz); + if (key == NULL) + { + perror("Unable to allocate memory for key"); + abort(); + } + + memcpy(key, pcnk + i*key_sz, key_sz); + + old_size = upo_ht_sepchain_size(ht); + + upo_ht_sepchain_odelete(ht, key, 0); + + new_size = upo_ht_sepchain_size(ht); + + found = upo_ht_sepchain_contains(ht, key); + + if (found == 1) + { + char *key_str = key_to_string(key); + fprintf(stderr, "[file: %s, line: %d] ERROR: HT Alternative #: %lu, Key: '%s' -> Found key not belonging to the HT.\n", __FILE__, __LINE__, k, key_str); + fprintf(stderr, "[file: %s, line: %d]: <HT>\n", __FILE__, __LINE__); + upo_ht_sepchain_dump(ht, stderr, key_to_string, 1, value_to_string, 1); + fprintf(stderr, "[file: %s, line: %d]: </HT>\n", __FILE__, __LINE__); + fflush(stderr); + free(key_str); + ret = TEST_FAIL; + } + else if (new_size != old_size) + { + char *key_str = key_to_string(key); + fprintf(stderr, "[file: %s, line: %d] ERROR: HT Alternative #: %lu, Key: '%s' -> Expected size: %lu, got %lu.\n", __FILE__, __LINE__, k, key_str, old_size, new_size); + fprintf(stderr, "[file: %s, line: %d]: <HT>\n", __FILE__, __LINE__); + upo_ht_sepchain_dump(ht, stderr, key_to_string, 1, value_to_string, 1); + fprintf(stderr, "[file: %s, line: %d]: </HT>\n", __FILE__, __LINE__); + fflush(stderr); + free(key_str); + ret = TEST_FAIL; + } + + free(key); + + // Check order of stored values + + upo_ht_sepchain_list_node_t *node = upo_ht_sepchain_check_order(ht); + if (node != NULL) + { + char *key_str1 = key_to_string(node->key); + char *key_str2 = key_to_string(node->next->key); + fprintf(stderr, "[file: %s, line: %d] ERROR: HT Alternative #: %zu, Keys: '%s' and '%s' are out of order.\n", __FILE__, __LINE__, k, key_str1, key_str2); + free(key_str1); + free(key_str2); + fprintf(stderr, "[file: %s, line: %d]: <HT>\n", __FILE__, __LINE__); + upo_ht_sepchain_dump(ht, stderr, key_to_string, 1, value_to_string, 1); + fprintf(stderr, "[file: %s, line: %d]: </HT>\n", __FILE__, __LINE__); + fflush(stderr); + ret = TEST_FAIL; + } + } + + upo_ht_sepchain_clear(ht, 0); + } + else + { + // Empty HT: no test + } + + upo_ht_sepchain_destroy(ht, 0); + } + + return ret; +}