From e1137f1a3a83259c363d4a8167381e4b416a3910 Mon Sep 17 00:00:00 2001 From: ilya-krivtsov <180809461+ilya-krivtsov@users.noreply.github.com> Date: Fri, 20 Dec 2024 16:59:13 +0300 Subject: [PATCH 1/2] Test 2.1 - task 2 --- test_2_1/CMakeLists.txt | 2 + test_2_1/task_2/CMakeLists.txt | 6 +++ test_2_1/task_2/hashset.c | 79 ++++++++++++++++++++++++++++++++++ test_2_1/task_2/hashset.h | 27 ++++++++++++ test_2_1/task_2/test.c | 78 +++++++++++++++++++++++++++++++++ 5 files changed, 192 insertions(+) create mode 100644 test_2_1/task_2/CMakeLists.txt create mode 100644 test_2_1/task_2/hashset.c create mode 100644 test_2_1/task_2/hashset.h create mode 100644 test_2_1/task_2/test.c diff --git a/test_2_1/CMakeLists.txt b/test_2_1/CMakeLists.txt index 14272d6..21702d2 100644 --- a/test_2_1/CMakeLists.txt +++ b/test_2_1/CMakeLists.txt @@ -1,3 +1,5 @@ project(test_2_1) set(testName "${PROJECT_NAME}") + +add_subdirectory(task_2) diff --git a/test_2_1/task_2/CMakeLists.txt b/test_2_1/task_2/CMakeLists.txt new file mode 100644 index 0000000..642cbb6 --- /dev/null +++ b/test_2_1/task_2/CMakeLists.txt @@ -0,0 +1,6 @@ +project("${testName}_task_2") + +add_library(hashset hashset.c) + +add_executable(${PROJECT_NAME}_test test.c) +target_link_libraries(${PROJECT_NAME}_test hashset) diff --git a/test_2_1/task_2/hashset.c b/test_2_1/task_2/hashset.c new file mode 100644 index 0000000..25196a1 --- /dev/null +++ b/test_2_1/task_2/hashset.c @@ -0,0 +1,79 @@ +#include "hashset.h" + +#include +#include + +typedef struct Hashset { + char *elements[HASHSET_SIZE]; +} Hashset; + +bool createHashset(Hashset **hashset) { + *hashset = malloc(sizeof(Hashset)); + if (*hashset == NULL) { + return false; + } + + for (int i = 0; i < HASHSET_SIZE; ++i) { + (*hashset)->elements[i] = NULL; + } + + return true; +} + +static unsigned int getStringHash(const char *string) { + unsigned int hash = 0; + for (int i = 0; string[i] != '\0'; ++i) { + hash = hash * 57 + string[i]; + } + return hash; +} + +bool addToHashset(Hashset *hashset, const char *string) { + if (string == NULL) { + return false; + } + + unsigned int elementIndex = getStringHash(string) % HASHSET_SIZE; + + int counter = 0; + while (hashset->elements[elementIndex] != NULL) { + elementIndex = (elementIndex + 1) % HASHSET_SIZE; + ++counter; + if (counter >= HASHSET_SIZE) { + return false; + } + } + + char *stringCopy = strdup(string); + if (stringCopy == NULL) { + return false; + } + + hashset->elements[elementIndex] = stringCopy; +} + +bool containedInHashset(Hashset *hashset, const char *string) { + unsigned int elementIndex = getStringHash(string) % HASHSET_SIZE; + + if (hashset->elements[elementIndex] == NULL) { + return false; + } + + int counter = 0; + while (strcmp(hashset->elements[elementIndex], string) != 0) { + elementIndex = (elementIndex + 1) % HASHSET_SIZE; + ++counter; + if (counter >= HASHSET_SIZE) { + return false; + } + } + + return true; +} + +void disposeHashset(Hashset *hashset) { + for (int i = 0; i < HASHSET_SIZE; ++i) { + free(hashset->elements[i]); + } + free(hashset); +} diff --git a/test_2_1/task_2/hashset.h b/test_2_1/task_2/hashset.h new file mode 100644 index 0000000..af7ba01 --- /dev/null +++ b/test_2_1/task_2/hashset.h @@ -0,0 +1,27 @@ +#pragma once + +#define HASHSET_SIZE 256 + +/// @brief Hashset of strings +typedef struct Hashset Hashset; + +/// @brief Creates new hashset +/// @param hashset Pointer to store new hashset to +/// @return `true` if created successfully, `false` otherwise (allocation failed) +bool createHashset(Hashset **hashset); + +/// @brief Adds string to hashtable +/// @param hashset Hashset to add string to +/// @param string String to add +/// @return `true` if added successfully, `false` otherwise (no space for new entries left) +bool addToHashset(Hashset *hashset, const char *string); + +/// @brief Searchs for specified string +/// @param hashset Hashset to search string in +/// @param string String to search +/// @return `true` if found, `false` otherwise +bool containedInHashset(Hashset *hashset, const char *string); + +/// @brief Disposes hashtable +/// @param hashset Hashtable to dispose +void disposeHashset(Hashset *hashset); diff --git a/test_2_1/task_2/test.c b/test_2_1/task_2/test.c new file mode 100644 index 0000000..5170a17 --- /dev/null +++ b/test_2_1/task_2/test.c @@ -0,0 +1,78 @@ +#define CTEST_MAIN +#define CTEST_SEGFAULT +#include "../../ctest/ctest.h" + +#include + +#include "hashset.h" + +int main(int argc, const char *argv[]) { + return ctest_main(argc, argv); +} + +Hashset *createNewHashset(void) { + Hashset *hashset = NULL; + ASSERT_TRUE(createHashset(&hashset)); + return hashset; +} + +CTEST(hashsetTests, createTest) { + Hashset *hashset = createNewHashset(); + disposeHashset(hashset); +} + +CTEST(hashsetTests, singleElemenTest) { + Hashset *hashset = createNewHashset(); + + ASSERT_FALSE(containedInHashset(hashset, "element")); + ASSERT_TRUE(addToHashset(hashset, "element")); + ASSERT_TRUE(containedInHashset(hashset, "element")); + ASSERT_FALSE(containedInHashset(hashset, "not_element")); + + disposeHashset(hashset); +} + +CTEST(hashsetTests, randomElementsTest) { + char *elements[HASHSET_SIZE] = { 0 }; + + const char *elementTemplate = "key_000"; + const int elementOffset = strlen("key_"); + const int digitsCount = strlen(elementTemplate) - elementOffset; + + for (int i = 0; i < HASHSET_SIZE; ++i) { + char *element = strdup(elementTemplate); + + ASSERT_NOT_NULL(element); + + elements[i] = element; + + int number = i; + for (int j = digitsCount - 1; j >= 0; --j) { + char digit = (number % 10) + '0'; + element[elementOffset + j] = digit; + number /= 10; + } + } + + Hashset *hashset = createNewHashset(); + + srand(453563458); + for (int i = 0; i < HASHSET_SIZE; ++i) { + int index = (rand() % (HASHSET_SIZE - i)) + i; + + ASSERT_TRUE(addToHashset(hashset, elements[i])); + } + + for (int i = 0; i < HASHSET_SIZE; ++i) { + ASSERT_TRUE(containedInHashset(hashset, elements[i])); + } + + ASSERT_FALSE(containedInHashset(hashset, "random_element")); + ASSERT_FALSE(containedInHashset(hashset, "does_not_exist")); + + for (int i = 0; i < HASHSET_SIZE; ++i) { + free(elements[i]); + } + + disposeHashset(hashset); +} From 81a0993e0025170c795a904871f7dbf9f9d89b70 Mon Sep 17 00:00:00 2001 From: ilya-krivtsov <180809461+ilya-krivtsov@users.noreply.github.com> Date: Fri, 20 Dec 2024 17:02:44 +0300 Subject: [PATCH 2/2] Fixed return and added more comments (test2.1 task 2) --- test_2_1/task_2/hashset.c | 2 ++ test_2_1/task_2/hashset.h | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/test_2_1/task_2/hashset.c b/test_2_1/task_2/hashset.c index 25196a1..eff1ac8 100644 --- a/test_2_1/task_2/hashset.c +++ b/test_2_1/task_2/hashset.c @@ -50,6 +50,8 @@ bool addToHashset(Hashset *hashset, const char *string) { } hashset->elements[elementIndex] = stringCopy; + + return true; } bool containedInHashset(Hashset *hashset, const char *string) { diff --git a/test_2_1/task_2/hashset.h b/test_2_1/task_2/hashset.h index af7ba01..b679eea 100644 --- a/test_2_1/task_2/hashset.h +++ b/test_2_1/task_2/hashset.h @@ -13,7 +13,7 @@ bool createHashset(Hashset **hashset); /// @brief Adds string to hashtable /// @param hashset Hashset to add string to /// @param string String to add -/// @return `true` if added successfully, `false` otherwise (no space for new entries left) +/// @return `true` if added successfully, `false` otherwise (string was `NULL`, allocation failed, no space for new entries left) bool addToHashset(Hashset *hashset, const char *string); /// @brief Searchs for specified string