From ebee25879d4d355e85c6487777f97d61c2863585 Mon Sep 17 00:00:00 2001 From: FArthur-cmd <613623@mail.ru> Date: Thu, 10 Nov 2022 13:17:56 +0300 Subject: [PATCH 1/7] start for hash table --- HashTable/.clang-format | 226 ++++++++++++++++++++++++++++++++ HashTable/CMakeLists.txt | 48 +++++++ HashTable/build_and_run_test | 45 +++++++ HashTable/include/HashTable.hpp | 19 +++ HashTable/include/HashUtils.hpp | 71 ++++++++++ HashTable/main.cpp | 1 + HashTable/test.cpp | 83 ++++++++++++ 7 files changed, 493 insertions(+) create mode 100644 HashTable/.clang-format create mode 100644 HashTable/CMakeLists.txt create mode 100755 HashTable/build_and_run_test create mode 100644 HashTable/include/HashTable.hpp create mode 100644 HashTable/include/HashUtils.hpp create mode 100644 HashTable/main.cpp create mode 100644 HashTable/test.cpp diff --git a/HashTable/.clang-format b/HashTable/.clang-format new file mode 100644 index 0000000..b1392af --- /dev/null +++ b/HashTable/.clang-format @@ -0,0 +1,226 @@ +--- +Language: Cpp +# BasedOnStyle: Google +AccessModifierOffset: -1 +AlignAfterOpenBracket: Align +AlignArrayOfStructures: None +AlignConsecutiveMacros: None +AlignConsecutiveAssignments: None +AlignConsecutiveBitFields: None +AlignConsecutiveDeclarations: None +AlignEscapedNewlines: Left +AlignOperands: Align +AlignTrailingComments: true +AllowAllArgumentsOnNextLine: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortEnumsOnASingleLine: true +AllowShortBlocksOnASingleLine: Never +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: All +AllowShortLambdasOnASingleLine: All +AllowShortIfStatementsOnASingleLine: WithoutElse +AllowShortLoopsOnASingleLine: true +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: true +AlwaysBreakTemplateDeclarations: Yes +AttributeMacros: + - __capability +BinPackArguments: true +BinPackParameters: true +BraceWrapping: + AfterCaseLabel: false + AfterClass: false + AfterControlStatement: Never + AfterEnum: false + AfterFunction: false + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + AfterExternBlock: false + BeforeCatch: false + BeforeElse: false + BeforeLambdaBody: false + BeforeWhile: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakBeforeBinaryOperators: None +BreakBeforeConceptDeclarations: true +BreakBeforeBraces: Attach +BreakBeforeInheritanceComma: false +BreakInheritanceList: BeforeColon +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: false +BreakConstructorInitializers: BeforeColon +BreakAfterJavaFieldAnnotations: false +BreakStringLiterals: true +ColumnLimit: 80 +CommentPragmas: '^ IWYU pragma:' +QualifierAlignment: Leave +CompactNamespaces: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DeriveLineEnding: true +DerivePointerAlignment: true +DisableFormat: false +EmptyLineAfterAccessModifier: Never +EmptyLineBeforeAccessModifier: LogicalBlock +ExperimentalAutoDetectBinPacking: false +PackConstructorInitializers: NextLine +BasedOnStyle: '' +ConstructorInitializerAllOnOneLineOrOnePerLine: false +AllowAllConstructorInitializersOnNextLine: true +FixNamespaceComments: true +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IfMacros: + - KJ_IF_MAYBE +IncludeBlocks: Regroup +IncludeCategories: + - Regex: '^' + Priority: 2 + SortPriority: 0 + CaseSensitive: false + - Regex: '^<.*\.h>' + Priority: 1 + SortPriority: 0 + CaseSensitive: false + - Regex: '^<.*' + Priority: 2 + SortPriority: 0 + CaseSensitive: false + - Regex: '.*' + Priority: 3 + SortPriority: 0 + CaseSensitive: false +IncludeIsMainRegex: '([-_](test|unittest))?$' +IncludeIsMainSourceRegex: '' +IndentAccessModifiers: false +IndentCaseLabels: true +IndentCaseBlocks: false +IndentGotoLabels: true +IndentPPDirectives: None +IndentExternBlock: AfterExternBlock +IndentRequires: false +IndentWidth: 2 +IndentWrappedFunctionNames: false +InsertTrailingCommas: None +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: false +LambdaBodyIndentation: Signature +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBinPackProtocolList: Never +ObjCBlockIndentWidth: 2 +ObjCBreakBeforeNestedBlockParam: true +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 1 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakOpenParenthesis: 0 +PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 200 +PenaltyIndentedWhitespace: 0 +PointerAlignment: Left +PPIndentWidth: -1 +RawStringFormats: + - Language: Cpp + Delimiters: + - cc + - CC + - cpp + - Cpp + - CPP + - 'c++' + - 'C++' + CanonicalDelimiter: '' + BasedOnStyle: google + - Language: TextProto + Delimiters: + - pb + - PB + - proto + - PROTO + EnclosingFunctions: + - EqualsProto + - EquivToProto + - PARSE_PARTIAL_TEXT_PROTO + - PARSE_TEST_PROTO + - PARSE_TEXT_PROTO + - ParseTextOrDie + - ParseTextProtoOrDie + - ParseTestProto + - ParsePartialTestProto + CanonicalDelimiter: pb + BasedOnStyle: google +ReferenceAlignment: Pointer +ReflowComments: true +RemoveBracesLLVM: false +SeparateDefinitionBlocks: Leave +ShortNamespaceLines: 1 +SortIncludes: CaseSensitive +SortJavaStaticImport: Before +SortUsingDeclarations: true +SpaceAfterCStyleCast: false +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: true +SpaceBeforeAssignmentOperators: true +SpaceBeforeCaseColon: false +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: ControlStatements +SpaceBeforeParensOptions: + AfterControlStatements: true + AfterForeachMacros: true + AfterFunctionDefinitionName: false + AfterFunctionDeclarationName: false + AfterIfMacros: true + AfterOverloadedOperator: false + BeforeNonEmptyParentheses: false +SpaceAroundPointerQualifiers: Default +SpaceBeforeRangeBasedForLoopColon: true +SpaceInEmptyBlock: false +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 2 +SpacesInAngles: Never +SpacesInConditionalStatement: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInLineCommentPrefix: + Minimum: 1 + Maximum: -1 +SpacesInParentheses: false +SpacesInSquareBrackets: false +SpaceBeforeSquareBrackets: false +BitFieldColonSpacing: Both +Standard: Auto +StatementAttributeLikeMacros: + - Q_EMIT +StatementMacros: + - Q_UNUSED + - QT_REQUIRE_VERSION +TabWidth: 8 +UseCRLF: false +UseTab: Never +WhitespaceSensitiveMacros: + - STRINGIZE + - PP_STRINGIZE + - BOOST_PP_STRINGIZE + - NS_SWIFT_NAME + - CF_SWIFT_NAME +... + diff --git a/HashTable/CMakeLists.txt b/HashTable/CMakeLists.txt new file mode 100644 index 0000000..dcda7d4 --- /dev/null +++ b/HashTable/CMakeLists.txt @@ -0,0 +1,48 @@ +cmake_minimum_required(VERSION 3.14) +project(test_programm) + +set(CMAKE_CXX_STANDARD 20) + +file(GLOB INCLUDE_SRC include/*.cpp include/*.c) +file(GLOB INCLUDE_HDR include/*.hpp include/*.h) + +if (ADDRESS) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address") + message(STATUS "Address sanitizer is enabled") +endif() + +if (UNDEFINED) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined") + message(STATUS "Undefined sanitizer is enabled") +endif() + +if (GDB) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O0") + message(STATUS "Debug is enabled") +endif() + +# Google tests +find_package(GTest) +enable_testing() + +add_executable( + test_programm + ${INCLUDE_SRC} + ${INCLUDE_HDR} + test.cpp +) + +target_link_libraries( + test_programm + GTest::gtest_main +) + +include(GoogleTest) +gtest_discover_tests(test_programm) + +add_executable( + main_programm + ${INCLUDE_SRC} + ${INCLUDE_HDR} + main.cpp +) \ No newline at end of file diff --git a/HashTable/build_and_run_test b/HashTable/build_and_run_test new file mode 100755 index 0000000..73744b3 --- /dev/null +++ b/HashTable/build_and_run_test @@ -0,0 +1,45 @@ +#!/usr/bin/env bash + +# format all files +for FILE in include/*.cpp +do + ../format $FILE +done + +for FILE in include/*.h +do + ../format $FILE +done + +for FILE in include/*.hpp +do + ../format $FILE +done + +../format main.cpp +../format test.cpp + +# create directory for building and tests. It will be ignored by git +if [ ! -d "./build" ] +then + mkdir build +fi +cd build + +# TODO: check input? +if [ -n "$1" ] +then + COMMAND="cmake" + for parameter in $@ + do + COMMAND="$COMMAND -D $parameter" + done + COMMAND="$COMMAND ../" + $COMMAND +else + cmake ../ +fi + +cmake --build . +./test_programm + diff --git a/HashTable/include/HashTable.hpp b/HashTable/include/HashTable.hpp new file mode 100644 index 0000000..f3a4fb2 --- /dev/null +++ b/HashTable/include/HashTable.hpp @@ -0,0 +1,19 @@ +#pragma once + +#include +#include +#include + +template +class HashTable { + public: + HashTable(size_t size); + + bool Insert(const Value& value); + + void Delete(const Value& value); + + bool Contains(const Value& value); + + private: +}; \ No newline at end of file diff --git a/HashTable/include/HashUtils.hpp b/HashTable/include/HashUtils.hpp new file mode 100644 index 0000000..e6ec6d9 --- /dev/null +++ b/HashTable/include/HashUtils.hpp @@ -0,0 +1,71 @@ +#pragma once +#include + +struct User { + size_t timestamp; + std::string name; + size_t id; + int64_t balance; +}; + +namespace Hash { + +template +class IntSimpleHash { + public: + bool operator()(T value) { return value % SIZE; } +}; + +template +class StringHash { + public: + bool operator()(std::string value) { + size_t result = 0; + for (char symbol : value) { + result = (result * alphabet_size_ + symbol - 'a') % SIZE; + } + return result; + } + + private: + size_t alphabet_size_ = 28; +}; + +template +class UserHash { + public: + bool operator()(const User& value) { + return (string_hash(value.name) + size_t_hash(value.id)) % SIZE; + } + + private: + StringHash string_hash; + IntSimpleHash size_t_hash; +}; + +} // namespace Hash + +namespace Equality { + +template +class SimpleEquality { + public: + bool operator()(const T& first, const T& second) { return first == second; } +}; + +class UserEquality { + public: + bool operator()(const User& first, const User& second) { + return first.name == second.name && first.id == second.id; + } +}; + +class UserEqualityWithTime { + public: + bool operator()(const User& first, const User& second) { + return first.name == second.name && first.id == second.id && + first.timestamp == second.timestamp; + } +}; + +} // namespace Equality \ No newline at end of file diff --git a/HashTable/main.cpp b/HashTable/main.cpp new file mode 100644 index 0000000..c3aeba4 --- /dev/null +++ b/HashTable/main.cpp @@ -0,0 +1 @@ +int main() { return 0; } \ No newline at end of file diff --git a/HashTable/test.cpp b/HashTable/test.cpp new file mode 100644 index 0000000..6bdd617 --- /dev/null +++ b/HashTable/test.cpp @@ -0,0 +1,83 @@ +#include + +#include +#include +#include + +#include "include/HashTable.hpp" +#include "include/HashUtils.hpp" + +TEST(Basic, INT) { + +} + +TEST(Basic, String) { + +} + +TEST(Basic, UserTest) { + HashTable, Equality::UserEquality> hash_table( + 1000); + + HashTable, Equality::UserEqualityWithTime> + hash_table_with_time(1000); + + User first_user{.name = "Test", .id = 5, .balance = 0, .timestamp = 0}; + User second_user{.name = "Other", .id = 2, .balance = 100, .timestamp = 1}; + hash_table.Insert(first_user); + hash_table_with_time.Insert(first_user); + hash_table.Insert(second_user); + hash_table_with_time.Insert(second_user); + + User modified_first = first_user; + modified_first.timestamp += 2; + + hash_table.Insert(modified_first); + hash_table_with_time.Insert(modified_first); + + ASSERT_EQ(true, hash_table.Contains(modified_first)); + /// TODO: add check for timestamp + ASSERT_EQ(true, hash_table.Contains(first_user)); + ASSERT_EQ(true, hash_table.Contains(second_user)); + + ASSERT_EQ(true, hash_table_with_time.Contains(modified_first)); + ASSERT_EQ(true, hash_table_with_time.Contains(first_user)); + ASSERT_EQ(true, hash_table_with_time.Contains(second_user)); +} + +TEST(Stress, INT) { + const size_t size = 100000; + HashTable, Equality::SimpleEquality > + hash_table(size); + std::unordered_set res; + std::random_device rand_dev; + std::mt19937 gen(rand_dev()); + std::uniform_int_distribution distrib( + 0, std::numeric_limits::max()); + int32_t generator_choice; + int32_t value; + + for (size_t i = 0; i < 100000; ++i) { + generator_choice = distrib(gen); + if (generator_choice % 3 == 0) { + value = distrib(gen); + hash_table.Insert(value); + res.insert(value); + } else if (generator_choice % 3 == 1) { + value = distrib(gen); + ASSERT_EQ(hash_table.Contains(value), res.contains(value)); + } else { + value = distrib(gen); + if (hash_table.Contains(value)) { + hash_table.Delete(value); + res.erase(value); + } + ASSERT_EQ(hash_table.Contains(value), res.contains(value)); + } + } +} + +int main(int argc, char** argv) { + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} From a4485efa4381f4e2097d8423816a4a65be4bf2f2 Mon Sep 17 00:00:00 2001 From: FArthur-cmd <613623@mail.ru> Date: Thu, 10 Nov 2022 13:21:10 +0300 Subject: [PATCH 2/7] solve --- HashTable/build_and_run_test | 2 ++ HashTable/include/HashTable.hpp | 50 +++++++++++++++++++++++++++++++-- HashTable/test.cpp | 39 +++++++++++++++++++++++-- 3 files changed, 87 insertions(+), 4 deletions(-) diff --git a/HashTable/build_and_run_test b/HashTable/build_and_run_test index 73744b3..cb09501 100755 --- a/HashTable/build_and_run_test +++ b/HashTable/build_and_run_test @@ -41,5 +41,7 @@ else fi cmake --build . + +# start google_tests ./test_programm diff --git a/HashTable/include/HashTable.hpp b/HashTable/include/HashTable.hpp index f3a4fb2..b6974b4 100644 --- a/HashTable/include/HashTable.hpp +++ b/HashTable/include/HashTable.hpp @@ -7,7 +7,7 @@ template class HashTable { public: - HashTable(size_t size); + HashTable(size_t size) : table_(size), size_(size) {} bool Insert(const Value& value); @@ -16,4 +16,50 @@ class HashTable { bool Contains(const Value& value); private: -}; \ No newline at end of file + using Container = std::vector >; + + Container table_; + Hash hash_; + EqualsTo equals_to_; + size_t size_; +}; + +template +bool HashTable::Insert(const Value& value) { + size_t position = hash_(value) % size_; + for (auto& element : table_[position]) { + if (equals_to_(element, value)) { + element = value; + return false; + } + } + + table_[position].push_back(value); + return true; +} + +template +void HashTable::Delete(const Value& value) { + size_t position = hash_(value) % size_; + auto it = table_[position].begin(); + auto erase_element = it; + while (it != table_[position].end()) { + if (equals_to_(*it, value)) { + erase_element = it; + ++it; + table_[position].erase(erase_element); + } + ++it; + } +} + +template +bool HashTable::Contains(const Value& value) { + size_t position = hash_(value) % size_; + for (const auto& element : table_[position]) { + if (equals_to_(element, value)) { + return true; + } + } + return false; +} \ No newline at end of file diff --git a/HashTable/test.cpp b/HashTable/test.cpp index 6bdd617..088f210 100644 --- a/HashTable/test.cpp +++ b/HashTable/test.cpp @@ -8,11 +8,46 @@ #include "include/HashUtils.hpp" TEST(Basic, INT) { - + std::unordered_set res; + HashTable, + Equality::SimpleEquality > + hash_table(1000); + + for (int32_t i = 0; i < 20; ++i) { + res.insert(i); + hash_table.Insert(i); + } + + for (auto element : res) { + ASSERT_EQ(true, hash_table.Contains(element)); + } + + for (int32_t i = 19; i >= 0; --i) { + hash_table.Delete(i); + ASSERT_EQ(false, hash_table.Contains(i)); + } } TEST(Basic, String) { - + std::unordered_set res; + HashTable, + Equality::SimpleEquality > + hash_table(1000); + + res.insert("abc"); + hash_table.Insert("abc"); + res.insert("def"); + hash_table.Insert("def"); + res.insert("hash"); + hash_table.Insert("hash"); + res.insert("a"); + hash_table.Insert("a"); + + for (auto element : res) { + ASSERT_EQ(true, hash_table.Contains(element)); + hash_table.Delete(element); + ASSERT_EQ(false, hash_table.Contains(element)); + } } TEST(Basic, UserTest) { From 27f24a464cfc46637b5d9bbe4a52bd1965c0fa18 Mon Sep 17 00:00:00 2001 From: FArthur-cmd <613623@mail.ru> Date: Thu, 10 Nov 2022 13:23:28 +0300 Subject: [PATCH 3/7] init LRU --- LRU/.clang-format | 226 +++++++++++++++++++++++++++++++++++++++++ LRU/CMakeLists.txt | 48 +++++++++ LRU/build_and_run_test | 46 +++++++++ LRU/include/LRU.hpp | 18 ++++ LRU/main.cpp | 1 + LRU/test.cpp | 84 +++++++++++++++ 6 files changed, 423 insertions(+) create mode 100644 LRU/.clang-format create mode 100644 LRU/CMakeLists.txt create mode 100755 LRU/build_and_run_test create mode 100644 LRU/include/LRU.hpp create mode 100644 LRU/main.cpp create mode 100644 LRU/test.cpp diff --git a/LRU/.clang-format b/LRU/.clang-format new file mode 100644 index 0000000..b1392af --- /dev/null +++ b/LRU/.clang-format @@ -0,0 +1,226 @@ +--- +Language: Cpp +# BasedOnStyle: Google +AccessModifierOffset: -1 +AlignAfterOpenBracket: Align +AlignArrayOfStructures: None +AlignConsecutiveMacros: None +AlignConsecutiveAssignments: None +AlignConsecutiveBitFields: None +AlignConsecutiveDeclarations: None +AlignEscapedNewlines: Left +AlignOperands: Align +AlignTrailingComments: true +AllowAllArgumentsOnNextLine: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortEnumsOnASingleLine: true +AllowShortBlocksOnASingleLine: Never +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: All +AllowShortLambdasOnASingleLine: All +AllowShortIfStatementsOnASingleLine: WithoutElse +AllowShortLoopsOnASingleLine: true +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: true +AlwaysBreakTemplateDeclarations: Yes +AttributeMacros: + - __capability +BinPackArguments: true +BinPackParameters: true +BraceWrapping: + AfterCaseLabel: false + AfterClass: false + AfterControlStatement: Never + AfterEnum: false + AfterFunction: false + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + AfterExternBlock: false + BeforeCatch: false + BeforeElse: false + BeforeLambdaBody: false + BeforeWhile: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakBeforeBinaryOperators: None +BreakBeforeConceptDeclarations: true +BreakBeforeBraces: Attach +BreakBeforeInheritanceComma: false +BreakInheritanceList: BeforeColon +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: false +BreakConstructorInitializers: BeforeColon +BreakAfterJavaFieldAnnotations: false +BreakStringLiterals: true +ColumnLimit: 80 +CommentPragmas: '^ IWYU pragma:' +QualifierAlignment: Leave +CompactNamespaces: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DeriveLineEnding: true +DerivePointerAlignment: true +DisableFormat: false +EmptyLineAfterAccessModifier: Never +EmptyLineBeforeAccessModifier: LogicalBlock +ExperimentalAutoDetectBinPacking: false +PackConstructorInitializers: NextLine +BasedOnStyle: '' +ConstructorInitializerAllOnOneLineOrOnePerLine: false +AllowAllConstructorInitializersOnNextLine: true +FixNamespaceComments: true +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IfMacros: + - KJ_IF_MAYBE +IncludeBlocks: Regroup +IncludeCategories: + - Regex: '^' + Priority: 2 + SortPriority: 0 + CaseSensitive: false + - Regex: '^<.*\.h>' + Priority: 1 + SortPriority: 0 + CaseSensitive: false + - Regex: '^<.*' + Priority: 2 + SortPriority: 0 + CaseSensitive: false + - Regex: '.*' + Priority: 3 + SortPriority: 0 + CaseSensitive: false +IncludeIsMainRegex: '([-_](test|unittest))?$' +IncludeIsMainSourceRegex: '' +IndentAccessModifiers: false +IndentCaseLabels: true +IndentCaseBlocks: false +IndentGotoLabels: true +IndentPPDirectives: None +IndentExternBlock: AfterExternBlock +IndentRequires: false +IndentWidth: 2 +IndentWrappedFunctionNames: false +InsertTrailingCommas: None +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: false +LambdaBodyIndentation: Signature +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBinPackProtocolList: Never +ObjCBlockIndentWidth: 2 +ObjCBreakBeforeNestedBlockParam: true +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 1 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakOpenParenthesis: 0 +PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 200 +PenaltyIndentedWhitespace: 0 +PointerAlignment: Left +PPIndentWidth: -1 +RawStringFormats: + - Language: Cpp + Delimiters: + - cc + - CC + - cpp + - Cpp + - CPP + - 'c++' + - 'C++' + CanonicalDelimiter: '' + BasedOnStyle: google + - Language: TextProto + Delimiters: + - pb + - PB + - proto + - PROTO + EnclosingFunctions: + - EqualsProto + - EquivToProto + - PARSE_PARTIAL_TEXT_PROTO + - PARSE_TEST_PROTO + - PARSE_TEXT_PROTO + - ParseTextOrDie + - ParseTextProtoOrDie + - ParseTestProto + - ParsePartialTestProto + CanonicalDelimiter: pb + BasedOnStyle: google +ReferenceAlignment: Pointer +ReflowComments: true +RemoveBracesLLVM: false +SeparateDefinitionBlocks: Leave +ShortNamespaceLines: 1 +SortIncludes: CaseSensitive +SortJavaStaticImport: Before +SortUsingDeclarations: true +SpaceAfterCStyleCast: false +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: true +SpaceBeforeAssignmentOperators: true +SpaceBeforeCaseColon: false +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: ControlStatements +SpaceBeforeParensOptions: + AfterControlStatements: true + AfterForeachMacros: true + AfterFunctionDefinitionName: false + AfterFunctionDeclarationName: false + AfterIfMacros: true + AfterOverloadedOperator: false + BeforeNonEmptyParentheses: false +SpaceAroundPointerQualifiers: Default +SpaceBeforeRangeBasedForLoopColon: true +SpaceInEmptyBlock: false +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 2 +SpacesInAngles: Never +SpacesInConditionalStatement: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInLineCommentPrefix: + Minimum: 1 + Maximum: -1 +SpacesInParentheses: false +SpacesInSquareBrackets: false +SpaceBeforeSquareBrackets: false +BitFieldColonSpacing: Both +Standard: Auto +StatementAttributeLikeMacros: + - Q_EMIT +StatementMacros: + - Q_UNUSED + - QT_REQUIRE_VERSION +TabWidth: 8 +UseCRLF: false +UseTab: Never +WhitespaceSensitiveMacros: + - STRINGIZE + - PP_STRINGIZE + - BOOST_PP_STRINGIZE + - NS_SWIFT_NAME + - CF_SWIFT_NAME +... + diff --git a/LRU/CMakeLists.txt b/LRU/CMakeLists.txt new file mode 100644 index 0000000..b58e7a1 --- /dev/null +++ b/LRU/CMakeLists.txt @@ -0,0 +1,48 @@ +cmake_minimum_required(VERSION 3.14) +project(test_programm) + +set(CMAKE_CXX_STANDARD 20) + +file(GLOB INCLUDE_SRC include/*.cpp include/*.c) +file(GLOB INCLUDE_HDR include/*.hpp include/*.h include/*.ipp) + +if (ADDRESS) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address") + message(STATUS "Address sanitizer is enabled") +endif() + +if (UNDEFINED) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined") + message(STATUS "Undefined sanitizer is enabled") +endif() + +if (GDB) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O0") + message(STATUS "Debug is enabled") +endif() + +# Google tests +find_package(GTest) +enable_testing() + +add_executable( + test_programm + ${INCLUDE_HDR} + ${INCLUDE_SRC} + test.cpp +) + +target_link_libraries( + test_programm + GTest::gtest_main +) + +include(GoogleTest) +gtest_discover_tests(test_programm) + +add_executable( + main_programm + ${INCLUDE_HDR} + ${INCLUDE_SRC} + main.cpp +) \ No newline at end of file diff --git a/LRU/build_and_run_test b/LRU/build_and_run_test new file mode 100755 index 0000000..fcf36ce --- /dev/null +++ b/LRU/build_and_run_test @@ -0,0 +1,46 @@ +#!/usr/bin/env bash + +# format all files +for FILE in include/*.cpp +do + ../format $FILE +done + +for FILE in include/*.h +do + ../format $FILE +done + +for FILE in include/*.hpp +do + ../format $FILE +done + +../format main.cpp +../format test.cpp + +# create directory for building and tests. It will be ignored by git +if [ ! -d "./build" ] +then + mkdir build +fi +cd build + +# TODO: check input? +if [ -n "$1" ] +then + COMMAND="cmake" + for parameter in $@ + do + COMMAND="$COMMAND -D $parameter" + done + COMMAND="$COMMAND ../" + $COMMAND +else + cmake ../ +fi + +cmake --build . + +# start google_tests +./test_programm diff --git a/LRU/include/LRU.hpp b/LRU/include/LRU.hpp new file mode 100644 index 0000000..71a8cdc --- /dev/null +++ b/LRU/include/LRU.hpp @@ -0,0 +1,18 @@ +#pragma once +#include +#include +#include +#include + +template +class LruCache { + public: + explicit LruCache(size_t size); + + std::optional GetValue(const Key& key); + /// GetValue(const Key& key, Value& return_value); + + void InsertValue(const Key& key, const Value& value); + + private: +}; diff --git a/LRU/main.cpp b/LRU/main.cpp new file mode 100644 index 0000000..c3aeba4 --- /dev/null +++ b/LRU/main.cpp @@ -0,0 +1 @@ +int main() { return 0; } \ No newline at end of file diff --git a/LRU/test.cpp b/LRU/test.cpp new file mode 100644 index 0000000..08b214f --- /dev/null +++ b/LRU/test.cpp @@ -0,0 +1,84 @@ +#include + +#include +#include + +#include "include/LRU.hpp" + +TEST(Basic, INSERT) { + LruCache cache(2); + cache.InsertValue(1, 2); + cache.InsertValue(2, 3); + cache.InsertValue(1, 3); + ASSERT_EQ(3, cache.GetValue(1)); + + cache.InsertValue(1, 2); + ASSERT_EQ(2, cache.GetValue(1).value()); + + cache.InsertValue(3, 2); + ASSERT_EQ(false, cache.GetValue(2).has_value()); +} + +TEST(Basic, EmptyCheck) { + LruCache cache(2); + ASSERT_EQ(false, cache.GetValue(2).has_value()); + ASSERT_EQ(false, cache.GetValue(3).has_value()); +} + +TEST(HeavyStructures, HugeCache) { + LruCache cache(10); + + cache.InsertValue("a", "1"); + cache.InsertValue("b", "2"); + cache.InsertValue("c", "3"); + + ASSERT_EQ(true, cache.GetValue("a").has_value()); + ASSERT_EQ("1", cache.GetValue("a")); + ASSERT_EQ("2", cache.GetValue("b")); + ASSERT_EQ("3", cache.GetValue("c")); + + ASSERT_EQ(false, cache.GetValue("d").has_value()); + + cache.InsertValue("c", "4"); + ASSERT_EQ("4", cache.GetValue("c")); +} + +TEST(HeavyStructures, SmallCache) { + LruCache cache(2); + + cache.InsertValue("b", "4"); + cache.InsertValue("c", "5"); + cache.InsertValue("b", "6"); + + cache.InsertValue("e", "7"); + ASSERT_EQ(false, cache.GetValue("c").has_value()); + ASSERT_EQ(true, cache.GetValue("b").has_value()); + ASSERT_EQ(true, cache.GetValue("e").has_value()); + + ASSERT_EQ(true, cache.GetValue("b").has_value()); + cache.InsertValue("f", "8"); + ASSERT_EQ(false, cache.GetValue("e").has_value()); + ASSERT_EQ(true, cache.GetValue("b").has_value()); + ASSERT_EQ(true, cache.GetValue("f").has_value()); +} + +TEST(STRESS, Strings) { + LruCache cache(100); + std::random_device rand_dev; + std::mt19937 gen(rand_dev()); + std::uniform_int_distribution distrib( + 0, std::numeric_limits::max()); + + for (size_t i = 0; i < 100000; ++i) { + if (distrib(gen) % 2 == 0) { + cache.InsertValue(distrib(gen) % 500, "foo"); + } else { + cache.GetValue(distrib(gen) % 500); + } + } +} + +int main(int argc, char** argv) { + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} From c6beabc8ebe0b9ffa47666c4cdbb779aa543eed4 Mon Sep 17 00:00:00 2001 From: FArthur-cmd <613623@mail.ru> Date: Thu, 10 Nov 2022 13:24:21 +0300 Subject: [PATCH 4/7] finish LRU --- LRU/include/LRU.hpp | 41 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/LRU/include/LRU.hpp b/LRU/include/LRU.hpp index 71a8cdc..5cc01de 100644 --- a/LRU/include/LRU.hpp +++ b/LRU/include/LRU.hpp @@ -7,7 +7,7 @@ template class LruCache { public: - explicit LruCache(size_t size); + explicit LruCache(size_t size) : size_(size) {} std::optional GetValue(const Key& key); /// GetValue(const Key& key, Value& return_value); @@ -15,4 +15,43 @@ class LruCache { void InsertValue(const Key& key, const Value& value); private: + using List = std::list >; + using HashMap = std::unordered_map; + + List cache_list_; + HashMap cache_hash_; + size_t size_; }; + +template +std::optional LruCache::GetValue(const Key& key) { + std::optional result; + if (cache_hash_.find(key) == cache_hash_.end()) { + return result; + } + + result.emplace(cache_hash_[key]->second); + + cache_list_.erase(cache_hash_[key]); + + // update reference + cache_list_.push_back({key, result.value()}); + cache_hash_[key] = --cache_list_.end(); + + return result; +} + +template +void LruCache::InsertValue(const Key& key, const Value& value) { + if (cache_hash_.find(key) != cache_hash_.end()) { + cache_list_.erase(cache_hash_[key]); + } + + cache_list_.push_back({key, value}); + cache_hash_[key] = --cache_list_.end(); + + if (cache_list_.size() > size_) { + cache_hash_.erase(cache_list_.begin()->first); + cache_list_.pop_front(); + } +} From 3e1b93df08a13434bdcb312989271f64c72cf4f3 Mon Sep 17 00:00:00 2001 From: FArthur-cmd <613623@mail.ru> Date: Thu, 10 Nov 2022 21:22:55 +0300 Subject: [PATCH 5/7] update description --- README.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 3ae190a..b288852 100644 --- a/README.md +++ b/README.md @@ -8,4 +8,9 @@ The code now contains errors to motivate students to correct them. * [Header](./Treap/TreapWithImplicitkey.hpp) * [Realization](./Treap/TreapWithImplicitkey.cpp) -* [Tests](./Treap/test.cpp) \ No newline at end of file +* [Tests](./Treap/test.cpp) + +## Hash + +* [Hash Table](./HashTable/include/HashTable.hpp) +* [LRU](./LRU/include/LRU.hpp) From e4d8c3fc6cdb23e17a50d44cfbb23fd25a48e99b Mon Sep 17 00:00:00 2001 From: FArthur-cmd <613623@mail.ru> Date: Wed, 16 Nov 2022 23:03:36 +0300 Subject: [PATCH 6/7] fix Treap --- Treap/CMakeLists.txt | 7 ++++++- Treap/{ => include}/TreapWithImplicitkey.cpp | 10 +++++++--- Treap/{ => include}/TreapWithImplicitkey.hpp | 6 ++---- Treap/main.cpp | 1 + Treap/test.cpp | 2 +- 5 files changed, 17 insertions(+), 9 deletions(-) rename Treap/{ => include}/TreapWithImplicitkey.cpp (95%) rename Treap/{ => include}/TreapWithImplicitkey.hpp (95%) create mode 100644 Treap/main.cpp diff --git a/Treap/CMakeLists.txt b/Treap/CMakeLists.txt index 5400d35..b48efae 100644 --- a/Treap/CMakeLists.txt +++ b/Treap/CMakeLists.txt @@ -4,13 +4,18 @@ project(test_programm) set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fsanitize=undefined -O1") +file(GLOB INCLUDE_SRC include/*.cpp include/*.c) +file(GLOB INCLUDE_HDR include/*.hpp include/*.h) + # Google tests find_package(GTest) enable_testing() add_executable( test_programm - TreapWithImplicitkey.hpp test.cpp TreapWithImplicitkey.cpp + ${INCLUDE_SRC} + ${INCLUDE_HDR} + test.cpp ) target_link_libraries( diff --git a/Treap/TreapWithImplicitkey.cpp b/Treap/include/TreapWithImplicitkey.cpp similarity index 95% rename from Treap/TreapWithImplicitkey.cpp rename to Treap/include/TreapWithImplicitkey.cpp index 3dc6d6e..8e78251 100644 --- a/Treap/TreapWithImplicitkey.cpp +++ b/Treap/include/TreapWithImplicitkey.cpp @@ -64,7 +64,7 @@ std::pair TreapWithImplicitkey::SplitNode(Node* current, UpdateChildren(current); return std::make_pair(left, current); } - if (current_pos > pos) { + if (current_pos < pos) { auto [left, right] = SplitNode(current->right, pos - current_pos - 1); current->right = left; UpdateChildren(current); @@ -97,6 +97,7 @@ void TreapWithImplicitkey::Insert(size_t pos, const int64_t& value) { void TreapWithImplicitkey::Remove(const size_t& pos) { auto [left, right_with_eq] = Split(pos); auto [equal, right] = SplitNode(right_with_eq, 1); + delete equal; root_ = MergeNodes(left, right); } @@ -106,11 +107,14 @@ int64_t TreapWithImplicitkey::Find(size_t pos) { while (current_pos != pos) { if (current_pos < pos) { pos -= current_pos; + --pos; current_ptr = current_ptr->right; current_pos = FindPos(current_ptr); - } else { + } else if (current_ptr->left != nullptr) { current_ptr = current_ptr->left; current_pos = FindPos(current_ptr); + } else { + return current_ptr->value; } } return current_ptr->value; @@ -118,4 +122,4 @@ int64_t TreapWithImplicitkey::Find(size_t pos) { TreapWithImplicitkey::~TreapWithImplicitkey() { delete root_; } -} // namespace Trees +} // namespace Trees \ No newline at end of file diff --git a/Treap/TreapWithImplicitkey.hpp b/Treap/include/TreapWithImplicitkey.hpp similarity index 95% rename from Treap/TreapWithImplicitkey.hpp rename to Treap/include/TreapWithImplicitkey.hpp index 7eb3a5b..80551bf 100644 --- a/Treap/TreapWithImplicitkey.hpp +++ b/Treap/include/TreapWithImplicitkey.hpp @@ -4,8 +4,6 @@ #include #include -/// THERE IS AN ERROR IN THIS CODE. TRY TO FIX IT :) - namespace Trees { struct Node { @@ -16,8 +14,8 @@ struct Node { size_t sum_of_children; size_t y; - Node* left; - Node* right; + Node* left = nullptr; + Node* right = nullptr; /// size_t sum_in_tree; int64_t value; diff --git a/Treap/main.cpp b/Treap/main.cpp new file mode 100644 index 0000000..c3aeba4 --- /dev/null +++ b/Treap/main.cpp @@ -0,0 +1 @@ +int main() { return 0; } \ No newline at end of file diff --git a/Treap/test.cpp b/Treap/test.cpp index 91b88a8..071817f 100644 --- a/Treap/test.cpp +++ b/Treap/test.cpp @@ -1,6 +1,6 @@ #include -#include "TreapWithImplicitkey.hpp" +#include "include/TreapWithImplicitkey.hpp" /// Only simple test cases are demonstrated, /// because it is easier to use them for people, From cbb86176a7425966745970161f50cbcdc1839873 Mon Sep 17 00:00:00 2001 From: FArthur-cmd <613623@mail.ru> Date: Thu, 17 Nov 2022 13:19:41 +0300 Subject: [PATCH 7/7] add some documentation --- README.md | 3 +++ docs/description.md | 19 ++++++++++++++ docs/testing.md | 61 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 83 insertions(+) create mode 100644 docs/description.md create mode 100644 docs/testing.md diff --git a/README.md b/README.md index b288852..1bbf28f 100644 --- a/README.md +++ b/README.md @@ -14,3 +14,6 @@ The code now contains errors to motivate students to correct them. * [Hash Table](./HashTable/include/HashTable.hpp) * [LRU](./LRU/include/LRU.hpp) + + +[How to work with project](./docs/description.md) \ No newline at end of file diff --git a/docs/description.md b/docs/description.md new file mode 100644 index 0000000..c018f8a --- /dev/null +++ b/docs/description.md @@ -0,0 +1,19 @@ +# How to work with project + +[generate_new_dir.sh](../generate_new_dir.sh) — generates copy of `TemplateForPrograms` directory (makes build easier). + +If you want to implement your own code, create a `include` folder. All files from this folder will be added to `main.cpp` and `test.cpp` during build. ([Read more about tests](./testing.md)) + +To build and test just run the script `build_and_run_test`. It will build programm and format all files. + +After running this script, the executable files `main_programm` and `test_programm` will lie in the `build` folder. `Main` is used to solve the problem you are facing. And the test is for checking the correctness of the implemented structure. + +Additional build parameters: +* `ADDRESS=1` — enables ASan +* `UNDEFINED=1` — enables UBSan + +These flags can be used together. + +__Example command to build with sanitizers__: + +`./build_and_run_test ADDRESS=1 UNDEFINED=1` \ No newline at end of file diff --git a/docs/testing.md b/docs/testing.md new file mode 100644 index 0000000..102df32 --- /dev/null +++ b/docs/testing.md @@ -0,0 +1,61 @@ +# More information about testing + +## Google tests + +All tests are written in `test.cpp`. More information about the tests themselves and how they can be written can be found in the google test documentation ([find link in main readme](../README.md)). This kind of testing will help you believe that part of the algorithm (the implemented function or structure) works correctly. Example tests can be found [in the template folder](../TemplateForPrograms/test.cpp) (and in each implementation) + +You can also run it manually with `./build/test_programm`. + +## Main test + +### Classic approach + +After writing the code in `main.cpp`, the build will create the file `main_programm`, which is the executable file of your program. Testing is fairly straightforward: +1) run the file with the command `./build/main_programm` (or `./main_programm` if you are already in build directory). Input data, compare with expected output. +2) Create a file, write the input data into it. Execute the command `cat path_to_created_file | ./build/main_programm` (redirect the output of the file to our program) + +### Other approach + +Add next script at the end of `build_and_run_test`. + +```sh +# create dir for test for main programm +if [ ! -d "./tests_results" ] +then + mkdir tests_results +fi + +for TEST in ../tests_for_main/test* +do + # no tests in directory + if [ ${TEST} == "../tests_for_main/test*" ] + then + break; + fi + + FILENAME=$(basename -- "$TEST") + NUMBER_OF_TEST="${FILENAME##*_}" + TEST_NAME="${FILENAME%_*}" + + # execute main + cat $TEST | ./main_programm > tests_results/${NUMBER_OF_TEST} + + # check result + if cmp -s tests_results/${NUMBER_OF_TEST} ../tests_for_main/res_${NUMBER_OF_TEST}; + then + STATUS="OK" + else + STATUS="ERROR" + fi + echo "Test name is $FILENAME. Status is ${STATUS}" + if [ ${STATUS} == "ERROR" ] + then + echo "Expected result" + cat ../tests_for_main/res_${NUMBER_OF_TEST} + echo "Program result is" + cat tests_results/${NUMBER_OF_TEST} + fi +done +``` + +Create directory `tests_for_main` near build script. Fill this directory with tests. Input data for tests should be put in file which name starts from `test_` and expected output should be in file with name which starts from `res_` (otherwise script will not work). \ No newline at end of file