From bceb256a0cca344ab43f1013274ab63e89e23457 Mon Sep 17 00:00:00 2001 From: Omar Boukli-Hacene Date: Fri, 16 Jun 2023 23:39:04 +0200 Subject: [PATCH] Restructure code and files Isolate tests from algorithm code files --- .editorconfig | 2 +- src/fizzbuzz.hpp | 45 ++++++ .../main.cpp => lc-lru-cache.hpp} | 132 +---------------- src/palindrome.hpp | 36 +++++ src/palindromic-number.hpp | 31 ++++ ...main.cpp => p0001-multiples-of-3-or-5.hpp} | 38 +---- src/sonar.hpp | 97 ++++++++++++ src/fizzbuzz/main.cpp => test/fizzbuzz.cpp | 34 +---- test/lc-lru-cache.cpp | 138 ++++++++++++++++++ .../main.cpp => test/palindrome.cpp | 26 +--- .../main.cpp => test/palindromic-number.cpp | 20 +-- .../p0001-multiples-of-3-or-5.cpp | 43 ++++++ src/sonar/main.cpp => test/sonar.cpp | 95 +----------- 13 files changed, 408 insertions(+), 329 deletions(-) create mode 100644 src/fizzbuzz.hpp rename src/{lc-lru-cache/main.cpp => lc-lru-cache.hpp} (66%) create mode 100644 src/palindrome.hpp create mode 100644 src/palindromic-number.hpp rename src/project-euler/{p0001-multiples-of-3-or-5/main.cpp => p0001-multiples-of-3-or-5.hpp} (59%) create mode 100644 src/sonar.hpp rename src/fizzbuzz/main.cpp => test/fizzbuzz.cpp (57%) create mode 100644 test/lc-lru-cache.cpp rename src/palindrome/main.cpp => test/palindrome.cpp (65%) rename src/palindromic-number/main.cpp => test/palindromic-number.cpp (81%) create mode 100644 test/project-euler/p0001-multiples-of-3-or-5.cpp rename src/sonar/main.cpp => test/sonar.cpp (59%) diff --git a/.editorconfig b/.editorconfig index 65d5eb6..ac0dca5 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,6 +1,6 @@ root = true -[*.{c,cpp,h}] +[*.{c,cpp,h,hpp}] charset = utf-8 end_of_line = lf indent_size = 4 diff --git a/src/fizzbuzz.hpp b/src/fizzbuzz.hpp new file mode 100644 index 0000000..3a57f40 --- /dev/null +++ b/src/fizzbuzz.hpp @@ -0,0 +1,45 @@ +// Copyright (c) Omar Boukli-Hacene. All rights reserved. +// Distributed under an MIT-style license that can be +// found in the LICENSE file. + +// SPDX-License-Identifier: MIT + +/// Problem source: +/// https://imranontech.com/2007/01/24/using-fizzbuzz-to-find-developers-who-grok-coding/ +/// +/// Original problem text: +/// Write a program that prints the numbers from 1 to 100. But for multiples of +/// three print "Fizz" instead of the number and for the multiples of five +/// print "Buzz". For numbers which are multiples of both three and five print +/// "FizzBuzz". + +#ifndef FIZZBUZZ_HPP_ +#define FIZZBUZZ_HPP_ + +#include +#include + +std::string fizzbuzz(int const n) noexcept { + std::ostringstream buffer; + for (int i{1}; i <= n; ++i) { + bool f{true}; + + if (i % 3 == 0) { + buffer << "Fizz"; + f = false; + } + + if (i % 5 == 0) { + buffer << "Buzz"; + continue; + } + + if (f) { + buffer << i; + } + } + + return buffer.str(); +} + +#endif // FIZZBUZZ_HPP_ diff --git a/src/lc-lru-cache/main.cpp b/src/lc-lru-cache.hpp similarity index 66% rename from src/lc-lru-cache/main.cpp rename to src/lc-lru-cache.hpp index 96113bf..804adf4 100644 --- a/src/lc-lru-cache/main.cpp +++ b/src/lc-lru-cache.hpp @@ -2,6 +2,9 @@ /// https://simontoth.substack.com/p/daily-bite-of-c-lru-cache /// https://leetcode.com/problems/lru-cache/ +#ifndef LC_LRU_CACHE_HPP_ +#define LC_LRU_CACHE_HPP_ + #include #include #include @@ -175,131 +178,4 @@ class LRUCache final : public LRUCacheBase { } // namespace forfun::lrucache -template -std::enable_if_t, void> -test() { - int volatile val{}; - - { - T cache{2}; - - cache.put(1, 1); // Cache is {{1, 1}}. - - cache.put(2, 2); // Cache is {{1, 1, {2, 2}}. - - val = cache.get(1); - assert(val == 1); - - cache.put( - 3, 3); // LRU key was 2. Evicts key 2. Cache is {{1, 1}, {3, 3}}. - - val = cache.get(2); // Returns -1 (key not found). - assert(val == -1); - - cache.put( - 4, 4); // LRU key was 1; evicts key 1, cache is {{4, 4}, {3, 3}}. - - val = cache.get(1); - assert(val == -1); // Returns -1 (key not found). - - val = cache.get(3); - assert(val == 3); - - val = cache.get(4); - assert(val == 4); - } - - { - T cache(2); - - cache.put(1, 1); - - val = cache.get(1); - assert(val == 1); - - cache.put(2, 2); - - val = cache.get(2); - assert(val == 2); - - cache.put(3, 3); // Evicts key 1. - - val = cache.get(1); - assert(val == -1); - - cache.put(2, 4); - - val = cache.get(2); - assert(val == 4); - - cache.put(4, 4); // Evicts key 3. - - val = cache.get(3); - assert(val == -1); - - val = cache.get(5); - assert(val == -1); - } - - { - T cache(1); - - cache.put(1, 1); - - val = cache.get(1); - assert(val == 1); - - cache.put(2, 2); // Evicts key 1. - - val = cache.get(1); - assert(val == -1); - - val = cache.get(2); - assert(val == 2); - - cache.put(2, 3); - - val = cache.get(2); - assert(val == 3); - } - - { - T cache(3); - - cache.put(1, 1); - cache.put(2, 2); - cache.put(3, 3); - - val = cache.get(1); - assert(val == 1); - - val = cache.get(2); - assert(val == 2); - - val = cache.get(3); - assert(val == 3); - - cache.put(4, 4); // Evicts key 1. - - val = cache.get(1); - assert(val == -1); - - val = cache.get(4); - assert(val == 4); - - val = cache.get(2); - assert(val == 2); - - cache.put(5, 5); // Evicts key 3, as key 2 was accessed recently. - - val = cache.get(3); - assert(val == -1); - } -} - -int main() { - test(); - test(); - - return 0; -} +#endif // LC_LRU_CACHE_HPP_ diff --git a/src/palindrome.hpp b/src/palindrome.hpp new file mode 100644 index 0000000..2acfc7a --- /dev/null +++ b/src/palindrome.hpp @@ -0,0 +1,36 @@ +// Copyright (c) Omar Boukli-Hacene. All rights reserved. +// Distributed under an MIT-style license that can be +// found in the LICENSE file. + +// SPDX-License-Identifier: MIT + +// Problem source: +// https://en.wikipedia.org/wiki/Palindrome + +#ifndef PALINDROME_HPP_ +#define PALINDROME_HPP_ + +#include +#include +#include + +template +[[nodiscard]] bool is_palindrome(T const& s) noexcept { + Tsize const len = (s.length()) / Tsize{2}; + auto begin = s.cbegin(); + auto end = --(s.cend()); + + for (Tsize i{0}; i < len; ++i) { + if (std::tolower(static_cast(*begin)) + != std::tolower(static_cast(*end))) { + return false; + } + + ++begin; + --end; + } + + return true; +} + +#endif // PALINDROME_HPP_ diff --git a/src/palindromic-number.hpp b/src/palindromic-number.hpp new file mode 100644 index 0000000..57805da --- /dev/null +++ b/src/palindromic-number.hpp @@ -0,0 +1,31 @@ +// Copyright (c) Omar Boukli-Hacene. All rights reserved. +// Distributed under an MIT-style license that can be +// found in the LICENSE file. + +// SPDX-License-Identifier: MIT + +// Problem source: +// https://en.wikipedia.org/wiki/Palindromic_number + +#ifndef PALINDROMIC_NUMBER_HPP_ +#define PALINDROMIC_NUMBER_HPP_ + +#include + +[[nodiscard]] bool is_palindrome(int const n) noexcept { + if (n < 0) { + return false; + } + + int nn{0}; + std::div_t d{.quot = n, .rem = 0}; + while (d.quot > 0) { + nn *= 10; + d = std::div(d.quot, 10); + nn += d.rem; + } + + return n == nn; +} + +#endif // PALINDROMIC_NUMBER_HPP_ diff --git a/src/project-euler/p0001-multiples-of-3-or-5/main.cpp b/src/project-euler/p0001-multiples-of-3-or-5.hpp similarity index 59% rename from src/project-euler/p0001-multiples-of-3-or-5/main.cpp rename to src/project-euler/p0001-multiples-of-3-or-5.hpp index d86344c..f8ca28d 100644 --- a/src/project-euler/p0001-multiples-of-3-or-5/main.cpp +++ b/src/project-euler/p0001-multiples-of-3-or-5.hpp @@ -13,8 +13,10 @@ /// /// Find the sum of all the multiples of 3 or 5 below 1000. +#ifndef PROJECT_EULER_P0001_MULTIPLES_OF_3_OR_5_HPP_ +#define PROJECT_EULER_P0001_MULTIPLES_OF_3_OR_5_HPP_ + #include -#include namespace { [[nodiscard]] inline constexpr int sum_2x(int const n, int const q) noexcept { @@ -30,36 +32,4 @@ namespace { return (sum_2x(n, 3) + sum_2x(n, 5) - sum_2x(n, 15)) / 2; } -int main() { - { - int const s{find_sum_mult_three_five(1)}; - assert(s == 0); - } - - { - int const s{find_sum_mult_three_five(4)}; - assert(s == 3); - } - - { - int s{find_sum_mult_three_five(6)}; - assert(s == 8); - } - - { - int const s{find_sum_mult_three_five(10)}; - assert(s == 23); - } - - { - int const s{find_sum_mult_three_five(11)}; - assert(s == 33); - } - - { - int s{find_sum_mult_three_five(1000)}; - assert(s == 233168); - } - - return 0; -} +#endif // PROJECT_EULER_P0001_MULTIPLES_OF_3_OR_5_HPP_ diff --git a/src/sonar.hpp b/src/sonar.hpp new file mode 100644 index 0000000..8233ffc --- /dev/null +++ b/src/sonar.hpp @@ -0,0 +1,97 @@ +/// Problem sources: +/// https://simontoth.substack.com/p/daily-bite-of-c-sonar +/// https://compiler-explorer.com/z/v4TdoqKc1 + +#ifndef SONAR_HPP_ +#define SONAR_HPP_ + +#include +#include +#include + +struct Area { + int top; + int bottom; + int left; + int right; +}; + +struct Sonar { + struct Coord { + int x; + int y; + }; + + std::vector coords; + bool ping(Area area) const; +}; + +/// Problem: +/// +/// You are given access to a ping method on a sonar system. +/// +/// As quickly as possible, determine the number of ships in the given +/// area using this method. The method only returns information about +/// presence (whether any ships are in the given area). +/// +/// The area includes the borders. + +int count_ships(Sonar const& sonar, const Area area) { + if (!sonar.ping(area)) { + return 0; + } + + int const width{std::abs(area.right - area.left)}; + int const height{std::abs(area.bottom - area.top)}; + + if ((width + height) == 0) { + return 1; + } + + int const mw0{area.left + (width / 2)}; + int const mw1{mw0 + 1}; + int const mh0{area.top + (height / 2)}; + int const mh1{mh0 + 1}; + + return count_ships( + sonar, + { + area.top, + mh0, + area.left, + mw0, + }) + + count_ships( + sonar, + { + area.top, + mh0, + mw1, + area.right, + }) + + count_ships( + sonar, + { + mh1, + area.bottom, + area.left, + mw0, + }) + + count_ships( + sonar, + { + mh1, + area.bottom, + mw1, + area.right, + }); +} + +bool Sonar::ping(Area area) const { + return std::ranges::any_of(coords, [&area](Coord const& coord) { + return coord.x >= area.top && coord.x <= area.bottom + && coord.y >= area.left && coord.y <= area.right; + }); +} + +#endif // SONAR_HPP_ diff --git a/src/fizzbuzz/main.cpp b/test/fizzbuzz.cpp similarity index 57% rename from src/fizzbuzz/main.cpp rename to test/fizzbuzz.cpp index 20e257c..8c5e746 100644 --- a/src/fizzbuzz/main.cpp +++ b/test/fizzbuzz.cpp @@ -4,41 +4,9 @@ // SPDX-License-Identifier: MIT -/// Problem source: -/// https://imranontech.com/2007/01/24/using-fizzbuzz-to-find-developers-who-grok-coding/ -/// -/// Original problem text: -/// Write a program that prints the numbers from 1 to 100. But for multiples of -/// three print "Fizz" instead of the number and for the multiples of five -/// print "Buzz". For numbers which are multiples of both three and five print -/// "FizzBuzz". +#include "fizzbuzz.hpp" #include -#include -#include - -std::string fizzbuzz(int const n) noexcept { - std::ostringstream buffer; - for (int i{1}; i <= n; ++i) { - bool f{true}; - - if (i % 3 == 0) { - buffer << "Fizz"; - f = false; - } - - if (i % 5 == 0) { - buffer << "Buzz"; - continue; - } - - if (f) { - buffer << i; - } - } - - return buffer.str(); -} int main() { { diff --git a/test/lc-lru-cache.cpp b/test/lc-lru-cache.cpp new file mode 100644 index 0000000..c283a90 --- /dev/null +++ b/test/lc-lru-cache.cpp @@ -0,0 +1,138 @@ +// Copyright (c) Omar Boukli-Hacene. All rights reserved. +// Distributed under an MIT-style license that can be +// found in the LICENSE file. + +// SPDX-License-Identifier: MIT + +#include "lc-lru-cache.hpp" + +#include + +template +std::enable_if_t, void> +test() { + int volatile val{}; + + { + T cache{2}; + + cache.put(1, 1); // Cache is {{1, 1}}. + + cache.put(2, 2); // Cache is {{1, 1, {2, 2}}. + + val = cache.get(1); + assert(val == 1); + + cache.put( + 3, 3); // LRU key was 2. Evicts key 2. Cache is {{1, 1}, {3, 3}}. + + val = cache.get(2); // Returns -1 (key not found). + assert(val == -1); + + cache.put( + 4, 4); // LRU key was 1; evicts key 1, cache is {{4, 4}, {3, 3}}. + + val = cache.get(1); + assert(val == -1); // Returns -1 (key not found). + + val = cache.get(3); + assert(val == 3); + + val = cache.get(4); + assert(val == 4); + } + + { + T cache(2); + + cache.put(1, 1); + + val = cache.get(1); + assert(val == 1); + + cache.put(2, 2); + + val = cache.get(2); + assert(val == 2); + + cache.put(3, 3); // Evicts key 1. + + val = cache.get(1); + assert(val == -1); + + cache.put(2, 4); + + val = cache.get(2); + assert(val == 4); + + cache.put(4, 4); // Evicts key 3. + + val = cache.get(3); + assert(val == -1); + + val = cache.get(5); + assert(val == -1); + } + + { + T cache(1); + + cache.put(1, 1); + + val = cache.get(1); + assert(val == 1); + + cache.put(2, 2); // Evicts key 1. + + val = cache.get(1); + assert(val == -1); + + val = cache.get(2); + assert(val == 2); + + cache.put(2, 3); + + val = cache.get(2); + assert(val == 3); + } + + { + T cache(3); + + cache.put(1, 1); + cache.put(2, 2); + cache.put(3, 3); + + val = cache.get(1); + assert(val == 1); + + val = cache.get(2); + assert(val == 2); + + val = cache.get(3); + assert(val == 3); + + cache.put(4, 4); // Evicts key 1. + + val = cache.get(1); + assert(val == -1); + + val = cache.get(4); + assert(val == 4); + + val = cache.get(2); + assert(val == 2); + + cache.put(5, 5); // Evicts key 3, as key 2 was accessed recently. + + val = cache.get(3); + assert(val == -1); + } +} + +int main() { + test(); + test(); + + return 0; +} diff --git a/src/palindrome/main.cpp b/test/palindrome.cpp similarity index 65% rename from src/palindrome/main.cpp rename to test/palindrome.cpp index d72d22a..aa67650 100644 --- a/src/palindrome/main.cpp +++ b/test/palindrome.cpp @@ -4,31 +4,9 @@ // SPDX-License-Identifier: MIT -// Problem source: -// https://en.wikipedia.org/wiki/Palindrome +#include "palindrome.hpp" -#include -#include -#include - -template -[[nodiscard]] bool is_palindrome(T const& s) noexcept { - Tsize const len = (s.length()) / Tsize{2}; - auto begin = s.cbegin(); - auto end = --(s.cend()); - - for (Tsize i{0}; i < len; ++i) { - if (std::tolower(static_cast(*begin)) - != std::tolower(static_cast(*end))) { - return false; - } - - ++begin; - --end; - } - - return true; -} +#include int main() { using namespace std::string_literals; diff --git a/src/palindromic-number/main.cpp b/test/palindromic-number.cpp similarity index 81% rename from src/palindromic-number/main.cpp rename to test/palindromic-number.cpp index 4babc1a..9fd0538 100644 --- a/src/palindromic-number/main.cpp +++ b/test/palindromic-number.cpp @@ -4,27 +4,9 @@ // SPDX-License-Identifier: MIT -// Problem source: -// https://en.wikipedia.org/wiki/Palindromic_number +#include "palindromic-number.hpp" #include -#include - -[[nodiscard]] bool is_palindrome(int const n) noexcept { - if (n < 0) { - return false; - } - - int nn{0}; - std::div_t d{.quot = n, .rem = 0}; - while (d.quot > 0) { - nn *= 10; - d = std::div(d.quot, 10); - nn += d.rem; - } - - return n == nn; -} int main() { { diff --git a/test/project-euler/p0001-multiples-of-3-or-5.cpp b/test/project-euler/p0001-multiples-of-3-or-5.cpp new file mode 100644 index 0000000..6e55a6e --- /dev/null +++ b/test/project-euler/p0001-multiples-of-3-or-5.cpp @@ -0,0 +1,43 @@ +// Copyright (c) Omar Boukli-Hacene. All rights reserved. +// Distributed under an MIT-style license that can be +// found in the LICENSE file. + +// SPDX-License-Identifier: MIT + +#include "project-euler/p0001-multiples-of-3-or-5.hpp" + +#include + +int main() { + { + int const s{find_sum_mult_three_five(1)}; + assert(s == 0); + } + + { + int const s{find_sum_mult_three_five(4)}; + assert(s == 3); + } + + { + int s{find_sum_mult_three_five(6)}; + assert(s == 8); + } + + { + int const s{find_sum_mult_three_five(10)}; + assert(s == 23); + } + + { + int const s{find_sum_mult_three_five(11)}; + assert(s == 33); + } + + { + int s{find_sum_mult_three_five(1000)}; + assert(s == 233168); + } + + return 0; +} diff --git a/src/sonar/main.cpp b/test/sonar.cpp similarity index 59% rename from src/sonar/main.cpp rename to test/sonar.cpp index f1dc540..801647a 100644 --- a/src/sonar/main.cpp +++ b/test/sonar.cpp @@ -1,89 +1,11 @@ -/// Problem sources: -/// https://simontoth.substack.com/p/daily-bite-of-c-sonar -/// https://compiler-explorer.com/z/v4TdoqKc1 - -#include -#include - -struct Area { - int top; - int bottom; - int left; - int right; -}; - -struct Sonar { - struct Coord { - int x; - int y; - }; - - std::vector coords; - bool ping(Area area) const; -}; - -/// Problem: -/// -/// You are given access to a ping method on a sonar system. -/// -/// As quickly as possible, determine the number of ships in the given -/// area using this method. The method only returns information about -/// presence (whether any ships are in the given area). -/// -/// The area includes the borders. - -int count_ships(Sonar const& sonar, const Area area) { - if (!sonar.ping(area)) { - return 0; - } - - int const width{std::abs(area.right - area.left)}; - int const height{std::abs(area.bottom - area.top)}; +// Copyright (c) Omar Boukli-Hacene. All rights reserved. +// Distributed under an MIT-style license that can be +// found in the LICENSE file. - if ((width + height) == 0) { - return 1; - } +// SPDX-License-Identifier: MIT - int const mw0{area.left + (width / 2)}; - int const mw1{mw0 + 1}; - int const mh0{area.top + (height / 2)}; - int const mh1{mh0 + 1}; - - return count_ships( - sonar, - { - area.top, - mh0, - area.left, - mw0, - }) - + count_ships( - sonar, - { - area.top, - mh0, - mw1, - area.right, - }) - + count_ships( - sonar, - { - mh1, - area.bottom, - area.left, - mw0, - }) - + count_ships( - sonar, - { - mh1, - area.bottom, - mw1, - area.right, - }); -} +#include "sonar.hpp" -#include #include #include @@ -164,10 +86,3 @@ int main() { assert(num_ships == 99); } } - -bool Sonar::ping(Area area) const { - return std::ranges::any_of(coords, [&area](Coord const& coord) { - return coord.x >= area.top && coord.x <= area.bottom - && coord.y >= area.left && coord.y <= area.right; - }); -}