From b2b63d32c1d1c92c4a81306ff52506cfe8578700 Mon Sep 17 00:00:00 2001 From: Katrina Owen Date: Thu, 2 Mar 2023 17:53:45 +0100 Subject: [PATCH 001/309] Sync gigasecond docs with problem-specifications (#565) The gigasecond exercise has been overhauled as part of a project to make practice exercises more consistent and friendly. For more context, please see the discussion in the forum, as well as the pull request that updated the exercise in the problem-specifications repository: - https://forum.exercism.org/t/new-project-making-practice-exercises-more-consistent-and-human-across-exercism/3943 - https://github.com/exercism/problem-specifications/pull/2206 --- .../practice/gigasecond/.docs/instructions.md | 8 ++++--- .../practice/gigasecond/.docs/introduction.md | 24 +++++++++++++++++++ 2 files changed, 29 insertions(+), 3 deletions(-) create mode 100644 exercises/practice/gigasecond/.docs/introduction.md diff --git a/exercises/practice/gigasecond/.docs/instructions.md b/exercises/practice/gigasecond/.docs/instructions.md index 680870f3..1e20f002 100644 --- a/exercises/practice/gigasecond/.docs/instructions.md +++ b/exercises/practice/gigasecond/.docs/instructions.md @@ -1,6 +1,8 @@ # Instructions -Given a moment, determine the moment that would be after a gigasecond -has passed. +Your task is to determine the date and time one gigasecond after a certain date. -A gigasecond is 10^9 (1,000,000,000) seconds. +A gigasecond is one thousand million seconds. +That is a one with nine zeros after it. + +If you were born on _January 24th, 2015 at 22:00 (10:00:00pm)_, then you would be a gigasecond old on _October 2nd, 2046 at 23:46:40 (11:46:40pm)_. diff --git a/exercises/practice/gigasecond/.docs/introduction.md b/exercises/practice/gigasecond/.docs/introduction.md new file mode 100644 index 00000000..74afaa99 --- /dev/null +++ b/exercises/practice/gigasecond/.docs/introduction.md @@ -0,0 +1,24 @@ +# Introduction + +The way we measure time is kind of messy. +We have 60 seconds in a minute, and 60 minutes in an hour. +This comes from ancient Babylon, where they used 60 as the basis for their number system. +We have 24 hours in a day, 7 days in a week, and how many days in a month? +Well, for days in a month it depends not only on which month it is, but also on what type of calendar is used in the country you live in. + +What if, instead, we only use seconds to express time intervals? +Then we can use metric system prefixes for writing large numbers of seconds in more easily comprehensible quantities. + +- A food recipe might explain that you need to let the brownies cook in the oven for two kiloseconds (that's two thousand seconds). +- Perhaps you and your family would travel to somewhere exotic for two megaseconds (that's two million seconds). +- And if you and your spouse were married for _a thousand million_ seconds, you would celebrate your one gigasecond anniversary. + +```exercism/note +If we ever colonize Mars or some other planet, measuring time is going to get even messier. +If someone says "year" do they mean a year on Earth or a year on Mars? + +The idea for this exercise came from the science fiction novel ["A Deepness in the Sky"][vinge-novel] by author Vernor Vinge. +In it the author uses the metric system as the basis for time measurements. + +[vinge-novel]: https://www.tor.com/2017/08/03/science-fiction-with-something-for-everyone-a-deepness-in-the-sky-by-vernor-vinge/ +``` From 509caeb9eb916f285227f5718193fbf9be3e63a4 Mon Sep 17 00:00:00 2001 From: Bob Hoeppner <32035397+bobahop@users.noreply.github.com> Date: Fri, 3 Mar 2023 01:36:05 -0600 Subject: [PATCH 002/309] Sieve approach (#569) Add approaches for `sieve`. --- .../practice/sieve/.approaches/config.json | 15 +++++ .../sieve/.approaches/introduction.md | 48 ++++++++++++++++ .../.approaches/vector-of-bools/content.md | 56 +++++++++++++++++++ .../.approaches/vector-of-bools/snippet.txt | 8 +++ 4 files changed, 127 insertions(+) create mode 100644 exercises/practice/sieve/.approaches/config.json create mode 100644 exercises/practice/sieve/.approaches/introduction.md create mode 100644 exercises/practice/sieve/.approaches/vector-of-bools/content.md create mode 100644 exercises/practice/sieve/.approaches/vector-of-bools/snippet.txt diff --git a/exercises/practice/sieve/.approaches/config.json b/exercises/practice/sieve/.approaches/config.json new file mode 100644 index 00000000..45d19c65 --- /dev/null +++ b/exercises/practice/sieve/.approaches/config.json @@ -0,0 +1,15 @@ +{ + "introduction": { + "authors": ["bobahop"], + "contributors": [] + }, + "approaches": [ + { + "uuid": "49609966-f2d7-42e6-89f5-3e567cc20713", + "slug": "vector-of-bools", + "title": "Vector of bools", + "blurb": "Use a vector of bools to keep track of composite numbers.", + "authors": ["bobahop"] + } + ] +} diff --git a/exercises/practice/sieve/.approaches/introduction.md b/exercises/practice/sieve/.approaches/introduction.md new file mode 100644 index 00000000..8c4c0205 --- /dev/null +++ b/exercises/practice/sieve/.approaches/introduction.md @@ -0,0 +1,48 @@ +# Introduction + +There are several variants of a general approach for solving Sieve. +A general approach is to keep track of composite numbers with a `vector` of `bool` values. + +## General guidance + +Something to consider is to keep the number of allocations and iterations at a minimum to get the best performance. + +## Approach: `vector` of `bool`s + +**sieve.h** +```cpp +#if !defined(SIEVE_H) +#define SIEVE_H +#include +namespace sieve { + std::vector primes(int); +} // namespace sieve +#endif // SIEVE_H +``` + +**sieve.cpp** +```cpp +#include "sieve.h" + +namespace sieve { + + std::vector primes(int limit) { + std::vector composite(limit + 1, false); + std::vector primes; + primes.reserve(limit / 2); + + for (int number = 2; number <= limit; number++) { + if (!composite[number]) { + primes.emplace_back(number); + for(int idx = number * number; idx <= limit; idx +=number) + composite[idx] = true; + } + } + return primes; + } +} // namespace sieve +``` + +For more information, check the [`vector` of `bool`s approach][approach-vector-of-bools]. + +[approach-vector-of-bools]: https://exercism.org/tracks/cpp/exercises/sieve/approaches/vector-of-bools diff --git a/exercises/practice/sieve/.approaches/vector-of-bools/content.md b/exercises/practice/sieve/.approaches/vector-of-bools/content.md new file mode 100644 index 00000000..17949fee --- /dev/null +++ b/exercises/practice/sieve/.approaches/vector-of-bools/content.md @@ -0,0 +1,56 @@ +# `vector` of `bool`s + +**sieve.h** +```cpp +#if !defined(SIEVE_H) +#define SIEVE_H +#include +namespace sieve { + std::vector primes(int); +} // namespace sieve +#endif // SIEVE_H +``` + +**sieve.cpp** +```cpp +#include "sieve.h" + +namespace sieve { + + std::vector primes(int limit) { + std::vector composite(limit + 1, false); + std::vector primes; + primes.reserve(limit / 2); + + for (int number = 2; number <= limit; number++) { + if (!composite[number]) { + primes.emplace_back(number); + for(int idx = number * number; idx <= limit; idx +=number) + composite[idx] = true; + } + } + return primes; + } +} // namespace sieve +``` + +This approach starts by defining a [`vector`][vector] to keep track of the composite numbers, with the elements initialized to `false`. +The output `vector` is also defined, and then the [`reserve`][reserve] method is used to set its capacity to half of the limit, since +at least half of the numbers will be even and so not prime. + +Since values less than `2` are not prime, the iteration of the outer [`for` loop][for] begins at `2`. +If the number being iterated is not a composite number, then the [`emplace_back`][emplace-back] method is used to append the number being iterated +to the output `vector`. + +Since any number evenly divisible by that prime is not prime, the inner `for` loop iterates from the prime times itself, setting each of the +elements at that index to `true` for being a composite number. + +After the outer loop is done, the `vector` of primes is returned. + +[size]: https://en.cppreference.com/w/cpp/container/vector/size +[vector]: https://en.cppreference.com/w/cpp/container/vector +[reserve]: https://en.cppreference.com/w/cpp/container/vector/reserve +[emplace-back]: https://en.cppreference.com/w/cpp/container/vector/emplace_back +[for]: https://en.cppreference.com/w/cpp/language/for +[if]: https://en.cppreference.com/w/cpp/language/if +[domain-error]: https://en.cppreference.com/w/cpp/error/domain_error diff --git a/exercises/practice/sieve/.approaches/vector-of-bools/snippet.txt b/exercises/practice/sieve/.approaches/vector-of-bools/snippet.txt new file mode 100644 index 00000000..886554d8 --- /dev/null +++ b/exercises/practice/sieve/.approaches/vector-of-bools/snippet.txt @@ -0,0 +1,8 @@ +for (int number = 2; number <= limit; number++) { + if (!composite[number]) { + primes.emplace_back(number); + for(int idx = number * number; idx <= limit; idx +=number) + composite[idx] = true; + } +} +return primes; From 29220bfbaa18bad450a8c3a42f2a7523c6e33e4a Mon Sep 17 00:00:00 2001 From: Bob Hoeppner <32035397+bobahop@users.noreply.github.com> Date: Fri, 3 Mar 2023 01:36:30 -0600 Subject: [PATCH 003/309] Binary Search approach (#568) Add approaches to `binary-search`. --- .../binary-search/.approaches/config.json | 15 ++++ .../binary-search/.approaches/introduction.md | 42 +++++++++++ .../while-with-if-statements/content.md | 74 +++++++++++++++++++ .../while-with-if-statements/snippet.txt | 8 ++ 4 files changed, 139 insertions(+) create mode 100644 exercises/practice/binary-search/.approaches/config.json create mode 100644 exercises/practice/binary-search/.approaches/introduction.md create mode 100644 exercises/practice/binary-search/.approaches/while-with-if-statements/content.md create mode 100644 exercises/practice/binary-search/.approaches/while-with-if-statements/snippet.txt diff --git a/exercises/practice/binary-search/.approaches/config.json b/exercises/practice/binary-search/.approaches/config.json new file mode 100644 index 00000000..e913d9cf --- /dev/null +++ b/exercises/practice/binary-search/.approaches/config.json @@ -0,0 +1,15 @@ +{ + "introduction": { + "authors": ["bobahop"], + "contributors": [] + }, + "approaches": [ + { + "uuid": "68a494d9-964c-4b2f-a31b-5063dfe0ffe7", + "slug": "while-with-if-statements", + "title": "While with if statements", + "blurb": "Use a while loop with if statements to return the answer.", + "authors": ["bobahop"] + } + ] +} diff --git a/exercises/practice/binary-search/.approaches/introduction.md b/exercises/practice/binary-search/.approaches/introduction.md new file mode 100644 index 00000000..e2aef794 --- /dev/null +++ b/exercises/practice/binary-search/.approaches/introduction.md @@ -0,0 +1,42 @@ +# Introduction + +There are many ways to solve Binary Search. +One approach can use a `while` loop with `if` statements. + +## Approach: `while` loop with `if` statements + +**binary_search.h** +```cpp +#if !defined(BINARY_SEARCH_H) +#define BINARY_SEARCH_H +#include +#include +namespace binary_search { + std::size_t find (const std::vector& data, int value); +} // namespace binary_search +#endif // BINARY_SEARCH_H +``` + +**binary_search.cpp** +```cpp +#include "binary_search.h" +#include + +namespace binary_search { + std::size_t find (const std::vector& data, int value) { + std::size_t left = 0, right = data.size(); + while (left < right) { + std::size_t mid = left + ((right - left) / 2); + int look = data[mid]; + if (look == value) return mid; + if (look < value) left = mid + 1; + else right = mid; + } + throw std::domain_error("Value not found. No soup for you!"); + } +} // namespace binary_search +``` + +For more information, check the [`while` loop with `if` statements approach][approach-while-with-if-statements]. + +[approach-while-with-if-statements]: https://exercism.org/tracks/cpp/exercises/binary-search/approaches/while-with-if-statements diff --git a/exercises/practice/binary-search/.approaches/while-with-if-statements/content.md b/exercises/practice/binary-search/.approaches/while-with-if-statements/content.md new file mode 100644 index 00000000..eadf9099 --- /dev/null +++ b/exercises/practice/binary-search/.approaches/while-with-if-statements/content.md @@ -0,0 +1,74 @@ +# +## Approach: `while` loop with `if` statements + +**binary_search.h** +```cpp +#if !defined(BINARY_SEARCH_H) +#define BINARY_SEARCH_H +#include +#include +namespace binary_search { + std::size_t find (const std::vector& data, int value); +} // namespace binary_search +#endif // BINARY_SEARCH_H +``` + +**binary_search.cpp** +```cpp +#include "binary_search.h" +#include + +namespace binary_search { + std::size_t find (const std::vector& data, int value) { + std::size_t left = 0, right = data.size(); + while (left < right) { + std::size_t mid = left + ((right - left) / 2); + int look = data[mid]; + if (look == value) return mid; + if (look < value) left = mid + 1; + else right = mid; + } + throw std::domain_error("Value not found. No soup for you!"); + } +} // namespace binary_search +``` + +The `find` function starts by defining the variables that control iterating to the answer. +The `left` is initialized to `0` and the `right` is initialized to the [size][size] of the [`vector`][vector] of `int`s passed in. +The middle value is initialized to `0`. + +The [`while` loop][while] iterates while `left` is less than `right`. + +Inside the loop, the middle value is set by `left` plus ((`right` - `left`) divided by `2`). +The reason for not doing (`left` + `right`) divided by `2` is to prevent overflow for very large sizes of the input `vector`, as explained [here][mid-bug]. +For example, if `left` is `0` and `right` is `10`, then the middle is calculated to `5`. +if `left` is `6` and `right` is `10`, then the middle is calculated to `8`. + +An [`if` statement][if] is used to check the value of the element whose index in the `vector` of `int`s is the middle value. +If the element at the index of the middle value matches the value being searched for, then the middle value is returned. + +If the first `if` statement does not return, then another `if` statement is used to check the element. + +```exercism/note +Note that if an `if` statement can return, it does not need to be followed by an `else if ` or an `else`. +If the statement returns, then control flow will leave the function. +If the statement does not return, control will fall through to the next statement anyway. +``` + +If the element at the index of the middle value is less than the value being searched for, then `left` is set to the middle value +plus one so that the next iteration will look for higher numbers. + +Otherwise, the value being searched for must be less than the element at the index of the middle value, so `right` is set to the middle value +so that the next iteration will look at lower numbers. + +If `left` and `right` are changed during the iterations so that `left` is no longer less than `right`, +then the value being searched for is not in the `vector` of `int`s. +The loop exits and a [std::domain_error][domain-error] is returned from the function. + +[size]: https://en.cppreference.com/w/cpp/container/vector/size +[vector]: https://en.cppreference.com/w/cpp/container/vector +[while]: https://en.cppreference.com/w/cpp/language/while +[if]: https://en.cppreference.com/w/cpp/language/if +[domain-error]: https://en.cppreference.com/w/cpp/error/domain_error +[mid-bug]: https://ai.googleblog.com/2006/06/extra-extra-read-all-about-it-nearly.html + diff --git a/exercises/practice/binary-search/.approaches/while-with-if-statements/snippet.txt b/exercises/practice/binary-search/.approaches/while-with-if-statements/snippet.txt new file mode 100644 index 00000000..1020f34d --- /dev/null +++ b/exercises/practice/binary-search/.approaches/while-with-if-statements/snippet.txt @@ -0,0 +1,8 @@ +while (left < right) { + std::size_t mid = left + ((right - left) / 2); + int look = data[mid]; + if (look == value) return mid; + if (look < value) left = mid + 1; + else right = mid; +} +throw std::domain_error("Value not found."); From ac62d95844226ce9be7b97d2f674dd6ee9684fbf Mon Sep 17 00:00:00 2001 From: Bob Hoeppner <32035397+bobahop@users.noreply.github.com> Date: Mon, 6 Mar 2023 07:46:58 -0600 Subject: [PATCH 004/309] Secret Handshake approaches (#571) * Added approach for "if-statements-with-reverse" method * Added approach for "iterate-once" method --- .../secret-handshake/.approaches/config.json | 22 ++++ .../if-statements-with-reverse/content.md | 78 +++++++++++++ .../if-statements-with-reverse/snippet.txt | 8 ++ .../.approaches/introduction.md | 98 ++++++++++++++++ .../.approaches/iterate-once/content.md | 106 ++++++++++++++++++ .../.approaches/iterate-once/snippet.txt | 7 ++ 6 files changed, 319 insertions(+) create mode 100644 exercises/practice/secret-handshake/.approaches/config.json create mode 100644 exercises/practice/secret-handshake/.approaches/if-statements-with-reverse/content.md create mode 100644 exercises/practice/secret-handshake/.approaches/if-statements-with-reverse/snippet.txt create mode 100644 exercises/practice/secret-handshake/.approaches/introduction.md create mode 100644 exercises/practice/secret-handshake/.approaches/iterate-once/content.md create mode 100644 exercises/practice/secret-handshake/.approaches/iterate-once/snippet.txt diff --git a/exercises/practice/secret-handshake/.approaches/config.json b/exercises/practice/secret-handshake/.approaches/config.json new file mode 100644 index 00000000..c8fa235a --- /dev/null +++ b/exercises/practice/secret-handshake/.approaches/config.json @@ -0,0 +1,22 @@ +{ + "introduction": { + "authors": ["bobahop"], + "contributors": [] + }, + "approaches": [ + { + "uuid": "d0cfe906-5844-4bcc-b30a-08341057deb4", + "slug": "if-statements-with-reverse", + "title": "if statements with reverse", + "blurb": "Use if statements with reverse if needed.", + "authors": ["bobahop"] + }, + { + "uuid": "616c4db1-392f-4033-a37d-e0c9af4d995f", + "slug": "iterate-once", + "title": "Iterate once", + "blurb": "Iterate once even if reverse is needed.", + "authors": ["bobahop"] + } + ] +} diff --git a/exercises/practice/secret-handshake/.approaches/if-statements-with-reverse/content.md b/exercises/practice/secret-handshake/.approaches/if-statements-with-reverse/content.md new file mode 100644 index 00000000..057d661f --- /dev/null +++ b/exercises/practice/secret-handshake/.approaches/if-statements-with-reverse/content.md @@ -0,0 +1,78 @@ +# `if` statements with `reverse()` + +**secret_handshake.h** +```cpp +#if !defined(SECRET_HANDSHAKE_H) +#define SECRET_HANDSHAKE_H +#include +#include + +namespace secret_handshake { + std::vector commands (unsigned int signal); +} // namespace secret_handshake + +#endif // SECRET_HANDSHAKE_H +``` + +**secret_handshake.cpp** +```cpp +#include "secret_handshake.h" +#include + +namespace secret_handshake { + +std::vector commands(unsigned int signal) +{ + std::vector result; + if (signal & 0b00001) result.emplace_back("wink"); + if (signal & 0b00010) result.emplace_back("double blink"); + if (signal & 0b00100) result.emplace_back("close your eyes"); + if (signal & 0b01000) result.emplace_back("jump"); + if (signal & 0b10000) std::reverse(begin(result), end(result)); + return result; +} +} // namespace secret_handshake +``` + +The `commands` function starts by defining the `vector` to hold the returned actions. + +It then has a series of `if` statements, each of which uses the [bitwise AND operator][bitwise-operators] to check if the input signal contains a particular action. +Each action is represented by a binary literal, but could just as well be represented by its decimal value + +```cpp + if (signal & 1) result.emplace_back("wink"); + if (signal & 2) result.emplace_back("double blink"); + if (signal & 4) result.emplace_back("close your eyes"); + if (signal & 8) result.emplace_back("jump"); + if (signal & 16) std::reverse(begin(result), end(result)); +``` + +or its hexadecimal value + +```cpp + if (signal & 0x01) result.emplace_back("wink"); + if (signal & 0x02) result.emplace_back("double blink"); + if (signal & 0x04) result.emplace_back("close your eyes"); + if (signal & 0x08) result.emplace_back("jump"); + if (signal & 0x010) std::reverse(begin(result), end(result)); +``` + +The [`emplace_back()`][emplace-back] function is used to add the action to the result `vector` if the action's value is contained in the input signal. + +If the reverse value is contained in the input signal, then the [`reverse()`][reverse] function is used to reverse the elements in the result `vector`. + +The [`begin()`][begin] and [`end()`][end] member functions could be called as free functions like so + +```cpp +if (signal & 0x010) std::reverse(result.begin(), result.end()); +``` + +The result will be the same (at least in this exercise.) + +When all of the if statements are gone through, the function returns the result `vector`. + +[bitwise-operators]: https://www.geeksforgeeks.org/bitwise-operators-in-c-cpp/ +[emplace-back]: https://en.cppreference.com/w/cpp/container/vector/emplace_back +[reverse]: https://en.cppreference.com/w/cpp/algorithm/reverse +[begin]: https://en.cppreference.com/w/cpp/iterator/begin +[end]: https://en.cppreference.com/w/cpp/iterator/end diff --git a/exercises/practice/secret-handshake/.approaches/if-statements-with-reverse/snippet.txt b/exercises/practice/secret-handshake/.approaches/if-statements-with-reverse/snippet.txt new file mode 100644 index 00000000..14683079 --- /dev/null +++ b/exercises/practice/secret-handshake/.approaches/if-statements-with-reverse/snippet.txt @@ -0,0 +1,8 @@ + std::vector result; + + if (signal & 0b00001) result.emplace_back("wink"); + if (signal & 0b00010) result.emplace_back("double blink"); + if (signal & 0b00100) result.emplace_back("close your eyes"); + if (signal & 0b01000) result.emplace_back("jump"); + if (signal & 0b10000) std::reverse(begin(result), end(result)); + return result; diff --git a/exercises/practice/secret-handshake/.approaches/introduction.md b/exercises/practice/secret-handshake/.approaches/introduction.md new file mode 100644 index 00000000..b6f8044f --- /dev/null +++ b/exercises/practice/secret-handshake/.approaches/introduction.md @@ -0,0 +1,98 @@ +# Introduction + +There are many ways to solve Secret Handshake. +One general approach is to go through a series of `if` statements and then use [`reverse()`][reverse] if needed. +Another general approach is to iterate once even if the actions are meant to be reversed. + +## Approach: `if` statements with `reverse()` + +**secret_handshake.h** +```cpp +#if !defined(SECRET_HANDSHAKE_H) +#define SECRET_HANDSHAKE_H +#include +#include + +namespace secret_handshake { + std::vector commands (unsigned int signal); +} // namespace secret_handshake + +#endif // SECRET_HANDSHAKE_H +``` + +**secret_handshake.cpp** +```cpp +#include "secret_handshake.h" +#include + +namespace secret_handshake { + +std::vector commands(unsigned int signal) +{ + std::vector result; + if (signal & 0b00001) result.emplace_back("wink"); + if (signal & 0b00010) result.emplace_back("double blink"); + if (signal & 0b00100) result.emplace_back("close your eyes"); + if (signal & 0b01000) result.emplace_back("jump"); + if (signal & 0b10000) std::reverse(begin(result), end(result)); + return result; +} +} // namespace secret_handshake +``` + +For more information, check the [`if` statements with `reverse()` approach][approach-if-statements-with-reverse]. + +## Approach: Iterate once + +**secret_handshake.h** +```cpp +#if !defined(SECRET_HANDSHAKE_H) +#define SECRET_HANDSHAKE_H +#include +#include + +namespace secret_handshake { + std::vector commands (unsigned int signal); +} // namespace secret_handshake + +#endif // SECRET_HANDSHAKE_H +``` + +**secret_handshake.cpp** +```cpp +#include "secret_handshake.h" + +namespace { + const std::vector actions = { + "wink", + "double blink", + "close your eyes", + "jump", + }; + const unsigned int REVERSE = 16; +} + +namespace secret_handshake { + std::vector commands (unsigned int signal) { + std::vector output; + int action = 0, action_incr = 1, end = actions.size(); + if (signal & REVERSE) {action = actions.size() - 1; action_incr = -1; end = -1;} + + for (; action != end; action+=action_incr) + if (signal & (1 << action)) + output.emplace_back(actions[action]); + return output; + } +} // namespace secret_handshake +``` + +For more information, check the [Iterate once approach][approach-iterate-once]. + +## Which approach to use? + +Since benchmarking is currrently outside the scope of this document, which to use is pretty much a matter of personal preference, +but the `if` statements with `reverse()` may be considered to be more idiomatic as well as more readable. + +[reverse]: https://en.cppreference.com/w/cpp/algorithm/reverse +[approach-if-statements-with-reverse]: https://exercism.org/tracks/cpp/exercises/secret-handshake/approaches/if-statements-with-reverse +[approach-iterate-once]: https://exercism.org/tracks/cpp/exercises/secret-handshake/approaches/iterate-once diff --git a/exercises/practice/secret-handshake/.approaches/iterate-once/content.md b/exercises/practice/secret-handshake/.approaches/iterate-once/content.md new file mode 100644 index 00000000..fc0958a8 --- /dev/null +++ b/exercises/practice/secret-handshake/.approaches/iterate-once/content.md @@ -0,0 +1,106 @@ +# Iterate once + +**secret_handshake.h** +```cpp +#if !defined(SECRET_HANDSHAKE_H) +#define SECRET_HANDSHAKE_H +#include +#include + +namespace secret_handshake { + std::vector commands (unsigned int signal); +} // namespace secret_handshake + +#endif // SECRET_HANDSHAKE_H +``` + +**secret_handshake.cpp** +```cpp +#include "secret_handshake.h" + +namespace { + const std::vector actions = { + "wink", + "double blink", + "close your eyes", + "jump", + }; + const unsigned int reverse = 16; +} + +namespace secret_handshake { + std::vector commands (unsigned int signal) { + std::vector output; + int action = 0, action_incr = 1, end = actions.size(); + if (signal & reverse) {action = actions.size() - 1; action_incr = -1; end = -1;} + + for (; action != end; action += action_incr) + if (signal & (1 << action)) + output.emplace_back(actions[action]); + return output; + } +} // namespace secret_handshake +``` + +This approach starts by defining a [`const`][const] `vector` to hold the action values in their normal order. +The value of `16` is defined as a `const` with a meaningful name so it won't be used as a [magic number][magic-number]. +The values are defined within an unnamed namespace. +The `static` keyword used to be used for this, but it was deprecated for this purpose in former versions (and then was later undeprecated.) +Many coders still prefer using the unnamed namespace. + +The output `vector` is defined, and then variables are defined that control iterating through the actions `vector`, setting their values to iterate in the normal order. + +The [bitwise AND operator][bitwise-operators] is used to check if the input signal contains the action for reversing the order of the other actions. + +For example, if the number passed in is `19`, which is `10011` in binary, then it is ANDed with `16`, which is `10000` in binary. +The `1` in `10000` is also at the same position in `10011`, so the two values ANDed will not be `0`. +- `10011` AND +- `10000` = +- `10000` + +If the number passed in is `3`, which is `00011` in binary, then it is ANDed with `16`, which is `10000` in binary. +The `1` in `10000` is not at the same position in `00011`, so the two values ANDed will be `0`. +- `00011` AND +- `10000` = +- `00000` + +If the signal passed in contains the action for reverse, then the iteration variables are set to iterate backwards through the `vector` of actions. + +The `for` loop begins. + +Normal iteration will start at index `0`. +Reverse iteration will start at index `3`. + +Normal iteration will terminate when the index equals `4`. +Reverse iteration will terminate when the index equals `-1`. + +Normal iteration will increase the index by `1` for each iteration. +Reverse iteration will decrease the index by `1` for each iteration. + +For each iteration of the `for` loop, the AND operator is used to check if the number passed in contains `1` shifted left (`<<`) for the number of positions as the value being iterated. +It uses the falsiness of `0` and the truthiness of any value other than `0`. + +```cpp +for (; action != end; action += action_incr) + if (signal & (1 << action)) + output.emplace_back(actions[action]); +``` + +For example, if the number being iterated is `0`, then `1` is shifted left `0` times (so not shifted at all), and the signal passed in is ANDed with `00001`. +If the signal passed in is `3`, which is `00011` in binary, then it is ANDed with `00001`. +`00011` ANDed with `00001` is not equal to `0` (so not `false`), so the action at the index of the `vector` of actions is added to the output `vector`. +The index used is the number being iterated, which is `0`, so the element at index `0` (`"wink"`) would be added to the output `vector` using the [emplace_back][emplace-back] function. + +If the number being iterated is `1`, then `1` is shifted left `1` time, and the signal passed in is ANDed with `00010`. +If the signal passed in is `3`, which is `00011` in binary, then it is ANDed with `00010`. +`00011` ANDed with `00010` is not equal to `0` (so not `false`), so the action at the index of the `vector` of actions is added to the output `vector`. +The index used is the number being iterated, which is `1`, so the element at index `1` (`"double blink"`) would be added to the output `vector`. + +If the signal passed in ANDed with the number being iterated is equal to `0`, then the `action` in the `vector` for that index is not added to the output `vector`. + +After iterating through the `vector` of actions is done, the output `vector` is returned from the function. + +[const]: https://en.cppreference.com/w/cpp/language/cv +[magic-number]: https://en.wikipedia.org/wiki/Magic_number_(programming) +[bitwise-operators]: https://www.geeksforgeeks.org/bitwise-operators-in-c-cpp/ +[emplace-back]: https://en.cppreference.com/w/cpp/container/vector/emplace_back diff --git a/exercises/practice/secret-handshake/.approaches/iterate-once/snippet.txt b/exercises/practice/secret-handshake/.approaches/iterate-once/snippet.txt new file mode 100644 index 00000000..2bc0e37f --- /dev/null +++ b/exercises/practice/secret-handshake/.approaches/iterate-once/snippet.txt @@ -0,0 +1,7 @@ +int action = 0, action_incr = 1, end = signals.size(); +if (signal & REVERSE) {action = actions.size() - 1; action_incr = -1; end = -1;} + +for (; action != end; action+=action_incr) + if (signal & (1 << action)) + output.emplace_back(signals[action]); +return output; From 1b7fac3badd77a6ab8c3c927ef05e9ada5910a75 Mon Sep 17 00:00:00 2001 From: Katrina Owen Date: Tue, 7 Mar 2023 10:24:24 +0100 Subject: [PATCH 005/309] Sync two-fer docs with problem-specifications (#572) The two-fer exercise has been overhauled as part of a project to make practice exercises more consistent and friendly. For more context, please see the discussion in the forum, as well as the pull request that updated the exercise in the problem-specifications repository: - https://forum.exercism.org/t/new-project-making-practice-exercises-more-consistent-and-human-across-exercism/3943 - https://github.com/exercism/problem-specifications/pull/2204 --- exercises/practice/two-fer/.docs/instructions.md | 15 +++++++-------- exercises/practice/two-fer/.docs/introduction.md | 8 ++++++++ 2 files changed, 15 insertions(+), 8 deletions(-) create mode 100644 exercises/practice/two-fer/.docs/introduction.md diff --git a/exercises/practice/two-fer/.docs/instructions.md b/exercises/practice/two-fer/.docs/instructions.md index f4853c54..a9bb4a3c 100644 --- a/exercises/practice/two-fer/.docs/instructions.md +++ b/exercises/practice/two-fer/.docs/instructions.md @@ -1,16 +1,15 @@ # Instructions -`Two-fer` or `2-fer` is short for two for one. One for you and one for me. +Your task is to determine what you will say as you give away the extra cookie. -Given a name, return a string with the message: +If your friend likes cookies, and is named Do-yun, then you will say: ```text -One for name, one for me. +One for Do-yun, one for me. ``` -Where "name" is the given name. - -However, if the name is missing, return the string: +If your friend doesn't like cookies, you give the cookie to the next person in line at the bakery. +Since you don't know their name, you will say _you_ instead. ```text One for you, one for me. @@ -18,9 +17,9 @@ One for you, one for me. Here are some examples: -|Name |String to return +|Name |Dialogue |:-------|:------------------ |Alice |One for Alice, one for me. -|Bob |One for Bob, one for me. +|Bohdan |One for Bohdan, one for me. | |One for you, one for me. |Zaphod |One for Zaphod, one for me. diff --git a/exercises/practice/two-fer/.docs/introduction.md b/exercises/practice/two-fer/.docs/introduction.md new file mode 100644 index 00000000..8c124394 --- /dev/null +++ b/exercises/practice/two-fer/.docs/introduction.md @@ -0,0 +1,8 @@ +# Introduction + +In some English accents, when you say "two for" quickly, it sounds like "two fer". +Two-for-one is a way of saying that if you buy one, you also get one for free. +So the phrase "two-fer" often implies a two-for-one offer. + +Imagine a bakery that has a holiday offer where you can buy two cookies for the price of one ("two-fer one!"). +You go for the offer and (very generously) decide to give the extra cookie to a friend. From 4a83ba2c1a085d55e8ac5448565f64b38fd81f42 Mon Sep 17 00:00:00 2001 From: Katrina Owen Date: Tue, 7 Mar 2023 10:26:14 +0100 Subject: [PATCH 006/309] Sync binary-search docs with problem-specifications (#576) The binary-search exercise has been overhauled as part of a project to make practice exercises more consistent and friendly. For more context, please see the discussion in the forum, as well as the pull request that updated the exercise in the problem-specifications repository: - https://forum.exercism.org/t/new-project-making-practice-exercises-more-consistent-and-human-across-exercism/3943 - https://github.com/exercism/problem-specifications/pull/2220 ---- If you approve this pull request, I will eventually merge it. However, if you are happy with this change **please merge the pull request**, as it will get the changes into the hands of the students much more quickly. --- .../binary-search/.docs/instructions.md | 45 ++++++++----------- .../binary-search/.docs/introduction.md | 9 ++++ 2 files changed, 28 insertions(+), 26 deletions(-) create mode 100644 exercises/practice/binary-search/.docs/introduction.md diff --git a/exercises/practice/binary-search/.docs/instructions.md b/exercises/practice/binary-search/.docs/instructions.md index 4dcaba72..175c4c4b 100644 --- a/exercises/practice/binary-search/.docs/instructions.md +++ b/exercises/practice/binary-search/.docs/instructions.md @@ -1,35 +1,28 @@ # Instructions -Implement a binary search algorithm. +Your task is to implement a binary search algorithm. -Searching a sorted collection is a common task. A dictionary is a sorted -list of word definitions. Given a word, one can find its definition. A -telephone book is a sorted list of people's names, addresses, and -telephone numbers. Knowing someone's name allows one to quickly find -their telephone number and address. +A binary search algorithm finds an item in a list by repeatedly splitting it in half, only keeping the half which contains the item we're looking for. +It allows us to quickly narrow down the possible locations of our item until we find it, or until we've eliminated all possible locations. -If the list to be searched contains more than a few items (a dozen, say) -a binary search will require far fewer comparisons than a linear search, -but it imposes the requirement that the list be sorted. +```exercism/caution +Binary search only works when a list has been sorted. +``` -In computer science, a binary search or half-interval search algorithm -finds the position of a specified input value (the search "key") within -an array sorted by key value. +The algorithm looks like this: -In each step, the algorithm compares the search key value with the key -value of the middle element of the array. +- Divide the sorted list in half and compare the middle element with the item we're looking for. +- If the middle element is our item, then we're done. +- If the middle element is greater than our item, we can eliminate that number and all the numbers **after** it. +- If the middle element is less than our item, we can eliminate that number and all the numbers **before** it. +- Repeat the process on the part of the list that we kept. -If the keys match, then a matching element has been found and its index, -or position, is returned. +Here's an example: -Otherwise, if the search key is less than the middle element's key, then -the algorithm repeats its action on the sub-array to the left of the -middle element or, if the search key is greater, on the sub-array to the -right. +Let's say we're looking for the number 23 in the following sorted list: `[4, 8, 12, 16, 23, 28, 32]`. -If the remaining array to be searched is empty, then the key cannot be -found in the array and a special "not found" indication is returned. - -A binary search halves the number of items to check with each iteration, -so locating an item (or determining its absence) takes logarithmic time. -A binary search is a dichotomic divide and conquer search algorithm. +- We start by comparing 23 with the middle element, 16. +- Since 23 is greater than 16, we can eliminate the left half of the list, leaving us with `[23, 28, 32]`. +- We then compare 23 with the new middle element, 28. +- Since 23 is less than 28, we can eliminate the right half of the list: `[23]`. +- We've found our item. diff --git a/exercises/practice/binary-search/.docs/introduction.md b/exercises/practice/binary-search/.docs/introduction.md new file mode 100644 index 00000000..66c4b8a4 --- /dev/null +++ b/exercises/practice/binary-search/.docs/introduction.md @@ -0,0 +1,9 @@ +# Introduction + +You have stumbled upon a group of mathematicians who are also singer-songwriters. +They have written a song for each of their favorite numbers, and, as you can imagine, they have a lot of favorite numbers. + +You are curious to hear the song for your favorite number, but with so many songs to wade through, finding the right song could take a while. +Fortunately, they have organized their songs in a playlist sorted by the title — which is simply the number that the song is about. + +You realize that you can use a binary search algorithm to quickly find a song given the title. From ff70dd5eb8b2395fb38c6e5878004afd4e42379f Mon Sep 17 00:00:00 2001 From: Katrina Owen Date: Tue, 7 Mar 2023 10:27:56 +0100 Subject: [PATCH 007/309] Sync pangram docs with problem-specifications (#575) The pangram exercise has been overhauled as part of a project to make practice exercises more consistent and friendly. For more context, please see the discussion in the forum, as well as the pull request that updated the exercise in the problem-specifications repository: - https://forum.exercism.org/t/new-project-making-practice-exercises-more-consistent-and-human-across-exercism/3943 - https://github.com/exercism/problem-specifications/pull/2215 ---- If you approve this pull request, I will eventually merge it. However, if you are happy with this change **please merge the pull request**, as it will get the changes into the hands of the students much more quickly. --- exercises/practice/pangram/.docs/instructions.md | 11 +++++------ exercises/practice/pangram/.docs/introduction.md | 16 ++++++++++++++++ 2 files changed, 21 insertions(+), 6 deletions(-) create mode 100644 exercises/practice/pangram/.docs/introduction.md diff --git a/exercises/practice/pangram/.docs/instructions.md b/exercises/practice/pangram/.docs/instructions.md index dbba4f64..d5698bc2 100644 --- a/exercises/practice/pangram/.docs/instructions.md +++ b/exercises/practice/pangram/.docs/instructions.md @@ -1,9 +1,8 @@ # Instructions -Determine if a sentence is a pangram. A pangram (Greek: παν γράμμα, pan gramma, -"every letter") is a sentence using every letter of the alphabet at least once. -The best known English pangram is: -> The quick brown fox jumps over the lazy dog. +Your task is to figure out if a sentence is a pangram. -The alphabet used consists of ASCII letters `a` to `z`, inclusive, and is case -insensitive. Input will not contain non-ASCII symbols. +A pangram is a sentence using every letter of the alphabet at least once. +It is case insensitive, so it doesn't matter if a letter is lower-case (e.g. `k`) or upper-case (e.g. `K`). + +For this exercise we only use the basic letters used in the English alphabet: `a` to `z`. diff --git a/exercises/practice/pangram/.docs/introduction.md b/exercises/practice/pangram/.docs/introduction.md new file mode 100644 index 00000000..d38fa341 --- /dev/null +++ b/exercises/practice/pangram/.docs/introduction.md @@ -0,0 +1,16 @@ +# Introduction + +You work for a company that sells fonts through their website. +They'd like to show a different sentence each time someone views a font on their website. +To give a comprehensive sense of the font, the random sentences should use **all** the letters in the English alphabet. + +They're running a competition to get suggestions for sentences that they can use. +You're in charge of checking the submissions to see if they are valid. + +```exercism/note +Pangram comes from Greek, παν γράμμα, pan gramma, which means "every letter". + +The best known English pangram is: + +> The quick brown fox jumps over the lazy dog. +``` From 6d6a80c654abef7f12dec5c01aded14027476912 Mon Sep 17 00:00:00 2001 From: Christian Willner <34183939+vaeng@users.noreply.github.com> Date: Tue, 7 Mar 2023 15:19:49 +0100 Subject: [PATCH 008/309] Add simple-linked-list exercise (#570) * Add simple-linked-list as a practice exercise --- config.json | 15 + .../.docs/instructions.append.md | 14 + .../simple-linked-list/.docs/instructions.md | 15 + .../simple-linked-list/.meta/config.json | 21 + .../simple-linked-list/.meta/example.cpp | 46 + .../simple-linked-list/.meta/example.h | 37 + .../simple-linked-list/CMakeLists.txt | 64 + .../simple-linked-list/simple_linked_list.cpp | 32 + .../simple-linked-list/simple_linked_list.h | 40 + .../simple_linked_list_test.cpp | 127 + .../simple-linked-list/test/catch.hpp | 17937 ++++++++++++++++ .../simple-linked-list/test/tests-main.cpp | 2 + 12 files changed, 18350 insertions(+) create mode 100644 exercises/practice/simple-linked-list/.docs/instructions.append.md create mode 100644 exercises/practice/simple-linked-list/.docs/instructions.md create mode 100644 exercises/practice/simple-linked-list/.meta/config.json create mode 100644 exercises/practice/simple-linked-list/.meta/example.cpp create mode 100644 exercises/practice/simple-linked-list/.meta/example.h create mode 100644 exercises/practice/simple-linked-list/CMakeLists.txt create mode 100644 exercises/practice/simple-linked-list/simple_linked_list.cpp create mode 100644 exercises/practice/simple-linked-list/simple_linked_list.h create mode 100644 exercises/practice/simple-linked-list/simple_linked_list_test.cpp create mode 100644 exercises/practice/simple-linked-list/test/catch.hpp create mode 100644 exercises/practice/simple-linked-list/test/tests-main.cpp diff --git a/config.json b/config.json index d958b211..9cdc24d7 100644 --- a/config.json +++ b/config.json @@ -779,6 +779,21 @@ "loops", "strings" ] + }, + { + "slug": "simple-linked-list", + "name": "Simple linked list", + "uuid": "ffccabe9-9779-4914-9cff-c6f5696c8afe", + "practices": ["pointers"], + "prerequisites":[], + "difficulty": 4, + "status": "beta", + "topics": [ + "classes", + "conditionals", + "loops", + "pointers" + ] } ], "foregone": [ diff --git a/exercises/practice/simple-linked-list/.docs/instructions.append.md b/exercises/practice/simple-linked-list/.docs/instructions.append.md new file mode 100644 index 00000000..21467079 --- /dev/null +++ b/exercises/practice/simple-linked-list/.docs/instructions.append.md @@ -0,0 +1,14 @@ +# Implementation Hints + +We have provided the general structure of a `List` class for you. +It has the private variables `head` of type `Element*` and `current_size` of type `size_t` that you can use. + +The `Element` class was given as well, it has two public variables: `data` of type `int` and `next` of type `Element*`. + +You can see the details in `simple_linked_list.h`. You do not have to change that file, but you can if it fits your needs. + +The tests use the functions as they are supplied in `simple_linked_list.cpp`, don't change their signature. You can add more functions and members if you want to. + +## Can I use smart pointers? + +Although the header-file includes raw pointers, you are free to chose a different implementation. diff --git a/exercises/practice/simple-linked-list/.docs/instructions.md b/exercises/practice/simple-linked-list/.docs/instructions.md new file mode 100644 index 00000000..9ec958d4 --- /dev/null +++ b/exercises/practice/simple-linked-list/.docs/instructions.md @@ -0,0 +1,15 @@ +# Instructions + +Write a simple linked list implementation that uses Elements and a List. + +The linked list is a fundamental data structure in computer science, often used in the implementation of other data structures. +They're pervasive in functional programming languages, such as Clojure, Erlang, or Haskell, but far less common in imperative languages such as Ruby or Python. + +The simplest kind of linked list is a singly linked list. +Each element in the list contains data and a "next" field pointing to the next element in the list of elements. + +This variant of linked lists is often used to represent sequences or push-down stacks (also called a LIFO stack; Last In, First Out). + +As a first take, lets create a singly linked list to contain integers, and provide functions to reverse a linked list. + +When implementing this in a language with built-in linked lists, implement your own abstract data type. diff --git a/exercises/practice/simple-linked-list/.meta/config.json b/exercises/practice/simple-linked-list/.meta/config.json new file mode 100644 index 00000000..585f86ec --- /dev/null +++ b/exercises/practice/simple-linked-list/.meta/config.json @@ -0,0 +1,21 @@ +{ + "authors": [ + "vaeng" + ], + "files": { + "solution": [ + "simple_linked_list.cpp", + "simple_linked_list.h" + ], + "test": [ + "simple_linked_list_test.cpp" + ], + "example": [ + ".meta/example.cpp", + ".meta/example.h" + ] + }, + "blurb": "Write a simple linked list implementation that uses Elements and a List.", + "source": "Inspired by 'Data Structures and Algorithms with Object-Oriented Design Patterns in Ruby', singly linked-lists.", + "source_url": "https://web.archive.org/web/20160731005714/http://brpreiss.com/books/opus8/html/page96.html" +} diff --git a/exercises/practice/simple-linked-list/.meta/example.cpp b/exercises/practice/simple-linked-list/.meta/example.cpp new file mode 100644 index 00000000..1b821e42 --- /dev/null +++ b/exercises/practice/simple-linked-list/.meta/example.cpp @@ -0,0 +1,46 @@ +#include "simple_linked_list.h" + +#include + +namespace simple_linked_list { +List::~List() { + while (head != nullptr) { + Element* next = head->next; + delete head; + head = next; + } +} + +size_t List::size() { return current_size; } + +void List::push(int entry) { + auto element = new Element{entry}; + element->next = head; + head = element; + current_size++; +} + +int List::pop() { + if (head == nullptr) { + throw std::runtime_error("Cannot pop from empty list."); + } else { + auto element = head; + head = head->next; + int data = element->data; + delete element; + current_size--; + return data; + } +} + +void List::reverse() { + Element* new_head = nullptr; + while (head != nullptr) { + auto temp = new_head; + new_head = head; + head = head->next; + new_head->next = temp; + } + head = new_head; +} +} // namespace simple_linked_list diff --git a/exercises/practice/simple-linked-list/.meta/example.h b/exercises/practice/simple-linked-list/.meta/example.h new file mode 100644 index 00000000..bdb3dfcc --- /dev/null +++ b/exercises/practice/simple-linked-list/.meta/example.h @@ -0,0 +1,37 @@ +#if !defined(SIMPLE_LINKED_LIST_H) +#define SIMPLE_LINKED_LIST_H + +#include + +namespace simple_linked_list { + +class Element { + public: + Element(int data) : data{data} {}; + int data{}; + Element* next{nullptr}; +}; + +class List { + public: + List() = default; + ~List(); + + List(const List&) = delete; + List& operator=(const List&) = delete; + List(const List&&) = delete; + List& operator=(const List&&) = delete; + + size_t size(); + void push(int enty); + int pop(); + void reverse(); + + private: + Element* head{nullptr}; + size_t current_size{0}; +}; + +} // namespace simple_linked_list + +#endif diff --git a/exercises/practice/simple-linked-list/CMakeLists.txt b/exercises/practice/simple-linked-list/CMakeLists.txt new file mode 100644 index 00000000..3b0589fd --- /dev/null +++ b/exercises/practice/simple-linked-list/CMakeLists.txt @@ -0,0 +1,64 @@ +# Get the exercise name from the current directory +get_filename_component(exercise ${CMAKE_CURRENT_SOURCE_DIR} NAME) + +# Basic CMake project +cmake_minimum_required(VERSION 3.5.1) + +# Name the project after the exercise +project(${exercise} CXX) + +# Get a source filename from the exercise name by replacing -'s with _'s +string(REPLACE "-" "_" file ${exercise}) + +# Implementation could be only a header +if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${file}.cpp) + set(exercise_cpp ${file}.cpp) +else() + set(exercise_cpp "") +endif() + +# Use the common Catch library? +if(EXERCISM_COMMON_CATCH) + # For Exercism track development only + add_executable(${exercise} ${file}_test.cpp ${exercise_cpp} ${file}.h $) +elseif(EXERCISM_TEST_SUITE) + # The Exercism test suite is being run, the Docker image already + # includes a pre-built version of Catch. + find_package(Catch2 REQUIRED) + add_executable(${exercise} ${file}_test.cpp ${exercise_cpp} ${file}.h) + target_link_libraries(${exercise} PRIVATE Catch2::Catch2WithMain) + # When Catch is installed system wide we need to include a different + # header, we need this define to use the correct one. + target_compile_definitions(${exercise} PRIVATE EXERCISM_TEST_SUITE) +else() + # Build executable from sources and headers + add_executable(${exercise} ${file}_test.cpp ${exercise_cpp} ${file}.h test/tests-main.cpp) +endif() + +set_target_properties(${exercise} PROPERTIES + CXX_STANDARD 17 + CXX_STANDARD_REQUIRED OFF + CXX_EXTENSIONS OFF +) + +set(CMAKE_BUILD_TYPE Debug) + +if("${CMAKE_CXX_COMPILER_ID}" MATCHES "(GNU|Clang)") + set_target_properties(${exercise} PROPERTIES + COMPILE_FLAGS "-Wall -Wextra -Wpedantic -Werror" + ) +endif() + +# Configure to run all the tests? +if(${EXERCISM_RUN_ALL_TESTS}) + target_compile_definitions(${exercise} PRIVATE EXERCISM_RUN_ALL_TESTS) +endif() + +# Tell MSVC not to warn us about unchecked iterators in debug builds +if(${MSVC}) + set_target_properties(${exercise} PROPERTIES + COMPILE_DEFINITIONS_DEBUG _SCL_SECURE_NO_WARNINGS) +endif() + +# Run the tests on every build +add_custom_target(test_${exercise} ALL DEPENDS ${exercise} COMMAND ${exercise}) diff --git a/exercises/practice/simple-linked-list/simple_linked_list.cpp b/exercises/practice/simple-linked-list/simple_linked_list.cpp new file mode 100644 index 00000000..b5566fa0 --- /dev/null +++ b/exercises/practice/simple-linked-list/simple_linked_list.cpp @@ -0,0 +1,32 @@ +#include "simple_linked_list.h" + +#include + +namespace simple_linked_list { + +size_t List::size() { + // TODO: Return the correct size of the list. + return 0; +} + +void List::push(int entry) { + // TODO: Implement a function that pushes an Element with `entry` as data to + // the front of the list. +} + +int List::pop() { + // TODO: Implement a function that returns the data value of the first + // element in the list then discard that element. + return 0; +} + +void List::reverse() { + // TODO: Implement a function to reverse the order of the elements in the + // list. +} + +List::~List() { + // TODO: Ensure that all resources are freed on destruction +} + +} // namespace simple_linked_list diff --git a/exercises/practice/simple-linked-list/simple_linked_list.h b/exercises/practice/simple-linked-list/simple_linked_list.h new file mode 100644 index 00000000..0867e936 --- /dev/null +++ b/exercises/practice/simple-linked-list/simple_linked_list.h @@ -0,0 +1,40 @@ +#if !defined(SIMPLE_LINKED_LIST_H) +#define SIMPLE_LINKED_LIST_H + +#include + +namespace simple_linked_list { + +class Element { + public: + Element(int data) : data{data} {}; + int data{}; + Element* next{nullptr}; +}; + +class List { + public: + List() = default; + ~List(); + + // Moving and copying is not needed to solve the exercise. + // If you want to change these, make sure to correctly + // free / move / copy the allocated resources. + List(const List&) = delete; + List& operator=(const List&) = delete; + List(const List&&) = delete; + List& operator=(const List&&) = delete; + + size_t size(); + void push(int enty); + int pop(); + void reverse(); + + private: + Element* head{nullptr}; + size_t current_size{0}; +}; + +} // namespace simple_linked_list + +#endif diff --git a/exercises/practice/simple-linked-list/simple_linked_list_test.cpp b/exercises/practice/simple-linked-list/simple_linked_list_test.cpp new file mode 100644 index 00000000..f10edae8 --- /dev/null +++ b/exercises/practice/simple-linked-list/simple_linked_list_test.cpp @@ -0,0 +1,127 @@ +// Include the header file with the definitions of the functions you create. +#include "simple_linked_list.h" + +// Include the test framework. +#ifdef EXERCISM_TEST_SUITE +#include +#else +#include "test/catch.hpp" +#endif + +// Declares a single test. +TEST_CASE("EmptyListHasSizeZero") +{ + simple_linked_list::List empty{}; + REQUIRE(empty.size() == 0); +} + +#ifdef EXERCISM_RUN_ALL_TESTS + +TEST_CASE("SingletonListHasSizeOne") +{ + simple_linked_list::List list{}; + list.push(44); + REQUIRE(list.size() == 1); +} + +TEST_CASE("NonEmptyListHasCorrectSize") +{ + simple_linked_list::List list{}; + list.push(44); + list.push(42); + list.push(47); + list.push(-11); + REQUIRE(list.size() == 4); +} + +TEST_CASE("ListHasCorrectSizeAfterPop") +{ + simple_linked_list::List list{}; + list.push(24); + list.push(2); + list.push(17); + list.pop(); + REQUIRE(list.size() == 2); +} + +TEST_CASE("ListHasCorrectSizeAfterPopAndPush") +{ + simple_linked_list::List list{}; + list.push(242); + list.push(21); + list.push(-17); + list.pop(); + list.push(34); + REQUIRE(list.size() == 3); + +} + +TEST_CASE("PopFromSize1") +{ + simple_linked_list::List list{}; + auto desired = 142; + list.push(desired); + auto actual = list.pop(); + REQUIRE(actual == desired); +} + +TEST_CASE("PopFromSizeTwo") +{ + simple_linked_list::List list{}; + auto desired_top = 112; + auto desired_bottom = 221; + list.push(desired_bottom); + list.push(desired_top); + auto actual_top = list.pop(); + REQUIRE(actual_top == desired_top); + auto actual_bottom = list.pop(); + REQUIRE(actual_bottom == desired_bottom); +} + +TEST_CASE("PopAndPushList") +{ + simple_linked_list::List list{}; + + list.push(1); + list.push(2); + list.push(3); + auto third = list.pop(); + list.push(4); + list.push(5); + auto fifth = list.pop(); + auto forth = list.pop(); + auto second = list.pop(); + list.push(6); + auto sixth = list.pop(); + auto first = list.pop(); + REQUIRE(first == 1); + REQUIRE(second == 2); + REQUIRE(third == 3); + REQUIRE(forth == 4); + REQUIRE(fifth == 5); + REQUIRE(sixth == 6); +} + + +TEST_CASE("ReverseEmptyList") +{ + simple_linked_list::List empty{}; + empty.reverse(); + REQUIRE(empty.size() == 0); + +} + +TEST_CASE("ReverseNonEmptyList") +{ + simple_linked_list::List list{}; + for(int i = 0; i < 5; i++) { + list.push(i); + } + + list.reverse(); + + for(int i = 0; i < 5; i++) { + REQUIRE(list.pop() == i); + } +} +#endif diff --git a/exercises/practice/simple-linked-list/test/catch.hpp b/exercises/practice/simple-linked-list/test/catch.hpp new file mode 100644 index 00000000..36eaeb27 --- /dev/null +++ b/exercises/practice/simple-linked-list/test/catch.hpp @@ -0,0 +1,17937 @@ +/* + * Catch v2.13.6 + * Generated: 2021-04-16 18:23:38.044268 + * ---------------------------------------------------------- + * This file has been merged from multiple headers. Please don't edit it directly + * Copyright (c) 2021 Two Blue Cubes Ltd. All rights reserved. + * + * Distributed under the Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + */ +#ifndef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED +#define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED +// start catch.hpp + + +#define CATCH_VERSION_MAJOR 2 +#define CATCH_VERSION_MINOR 13 +#define CATCH_VERSION_PATCH 6 + +#ifdef __clang__ +# pragma clang system_header +#elif defined __GNUC__ +# pragma GCC system_header +#endif + +// start catch_suppress_warnings.h + +#ifdef __clang__ +# ifdef __ICC // icpc defines the __clang__ macro +# pragma warning(push) +# pragma warning(disable: 161 1682) +# else // __ICC +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wpadded" +# pragma clang diagnostic ignored "-Wswitch-enum" +# pragma clang diagnostic ignored "-Wcovered-switch-default" +# endif +#elif defined __GNUC__ + // Because REQUIREs trigger GCC's -Wparentheses, and because still + // supported version of g++ have only buggy support for _Pragmas, + // Wparentheses have to be suppressed globally. +# pragma GCC diagnostic ignored "-Wparentheses" // See #674 for details + +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wunused-variable" +# pragma GCC diagnostic ignored "-Wpadded" +#endif +// end catch_suppress_warnings.h +#if defined(CATCH_CONFIG_MAIN) || defined(CATCH_CONFIG_RUNNER) +# define CATCH_IMPL +# define CATCH_CONFIG_ALL_PARTS +#endif + +// In the impl file, we want to have access to all parts of the headers +// Can also be used to sanely support PCHs +#if defined(CATCH_CONFIG_ALL_PARTS) +# define CATCH_CONFIG_EXTERNAL_INTERFACES +# if defined(CATCH_CONFIG_DISABLE_MATCHERS) +# undef CATCH_CONFIG_DISABLE_MATCHERS +# endif +# if !defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER) +# define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER +# endif +#endif + +#if !defined(CATCH_CONFIG_IMPL_ONLY) +// start catch_platform.h + +// See e.g.: +// https://opensource.apple.com/source/CarbonHeaders/CarbonHeaders-18.1/TargetConditionals.h.auto.html +#ifdef __APPLE__ +# include +# if (defined(TARGET_OS_OSX) && TARGET_OS_OSX == 1) || \ + (defined(TARGET_OS_MAC) && TARGET_OS_MAC == 1) +# define CATCH_PLATFORM_MAC +# elif (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE == 1) +# define CATCH_PLATFORM_IPHONE +# endif + +#elif defined(linux) || defined(__linux) || defined(__linux__) +# define CATCH_PLATFORM_LINUX + +#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) || defined(__MINGW32__) +# define CATCH_PLATFORM_WINDOWS +#endif + +// end catch_platform.h + +#ifdef CATCH_IMPL +# ifndef CLARA_CONFIG_MAIN +# define CLARA_CONFIG_MAIN_NOT_DEFINED +# define CLARA_CONFIG_MAIN +# endif +#endif + +// start catch_user_interfaces.h + +namespace Catch { + unsigned int rngSeed(); +} + +// end catch_user_interfaces.h +// start catch_tag_alias_autoregistrar.h + +// start catch_common.h + +// start catch_compiler_capabilities.h + +// Detect a number of compiler features - by compiler +// The following features are defined: +// +// CATCH_CONFIG_COUNTER : is the __COUNTER__ macro supported? +// CATCH_CONFIG_WINDOWS_SEH : is Windows SEH supported? +// CATCH_CONFIG_POSIX_SIGNALS : are POSIX signals supported? +// CATCH_CONFIG_DISABLE_EXCEPTIONS : Are exceptions enabled? +// **************** +// Note to maintainers: if new toggles are added please document them +// in configuration.md, too +// **************** + +// In general each macro has a _NO_ form +// (e.g. CATCH_CONFIG_NO_POSIX_SIGNALS) which disables the feature. +// Many features, at point of detection, define an _INTERNAL_ macro, so they +// can be combined, en-mass, with the _NO_ forms later. + +#ifdef __cplusplus + +# if (__cplusplus >= 201402L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201402L) +# define CATCH_CPP14_OR_GREATER +# endif + +# if (__cplusplus >= 201703L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) +# define CATCH_CPP17_OR_GREATER +# endif + +#endif + +// Only GCC compiler should be used in this block, so other compilers trying to +// mask themselves as GCC should be ignored. +#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) && !defined(__CUDACC__) && !defined(__LCC__) +# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic push" ) +# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic pop" ) + +# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__) + +#endif + +#if defined(__clang__) + +# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic push" ) +# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic pop" ) + +// As of this writing, IBM XL's implementation of __builtin_constant_p has a bug +// which results in calls to destructors being emitted for each temporary, +// without a matching initialization. In practice, this can result in something +// like `std::string::~string` being called on an uninitialized value. +// +// For example, this code will likely segfault under IBM XL: +// ``` +// REQUIRE(std::string("12") + "34" == "1234") +// ``` +// +// Therefore, `CATCH_INTERNAL_IGNORE_BUT_WARN` is not implemented. +# if !defined(__ibmxl__) && !defined(__CUDACC__) +# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__) /* NOLINT(cppcoreguidelines-pro-type-vararg, hicpp-vararg) */ +# endif + +# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" ) \ + _Pragma( "clang diagnostic ignored \"-Wglobal-constructors\"") + +# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wparentheses\"" ) + +# define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wunused-variable\"" ) + +# define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wgnu-zero-variadic-macro-arguments\"" ) + +# define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wunused-template\"" ) + +#endif // __clang__ + +//////////////////////////////////////////////////////////////////////////////// +// Assume that non-Windows platforms support posix signals by default +#if !defined(CATCH_PLATFORM_WINDOWS) + #define CATCH_INTERNAL_CONFIG_POSIX_SIGNALS +#endif + +//////////////////////////////////////////////////////////////////////////////// +// We know some environments not to support full POSIX signals +#if defined(__CYGWIN__) || defined(__QNX__) || defined(__EMSCRIPTEN__) || defined(__DJGPP__) + #define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS +#endif + +#ifdef __OS400__ +# define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS +# define CATCH_CONFIG_COLOUR_NONE +#endif + +//////////////////////////////////////////////////////////////////////////////// +// Android somehow still does not support std::to_string +#if defined(__ANDROID__) +# define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING +# define CATCH_INTERNAL_CONFIG_ANDROID_LOGWRITE +#endif + +//////////////////////////////////////////////////////////////////////////////// +// Not all Windows environments support SEH properly +#if defined(__MINGW32__) +# define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH +#endif + +//////////////////////////////////////////////////////////////////////////////// +// PS4 +#if defined(__ORBIS__) +# define CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE +#endif + +//////////////////////////////////////////////////////////////////////////////// +// Cygwin +#ifdef __CYGWIN__ + +// Required for some versions of Cygwin to declare gettimeofday +// see: http://stackoverflow.com/questions/36901803/gettimeofday-not-declared-in-this-scope-cygwin +# define _BSD_SOURCE +// some versions of cygwin (most) do not support std::to_string. Use the libstd check. +// https://gcc.gnu.org/onlinedocs/gcc-4.8.2/libstdc++/api/a01053_source.html line 2812-2813 +# if !((__cplusplus >= 201103L) && defined(_GLIBCXX_USE_C99) \ + && !defined(_GLIBCXX_HAVE_BROKEN_VSWPRINTF)) + +# define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING + +# endif +#endif // __CYGWIN__ + +//////////////////////////////////////////////////////////////////////////////// +// Visual C++ +#if defined(_MSC_VER) + +# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION __pragma( warning(push) ) +# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION __pragma( warning(pop) ) + +// Universal Windows platform does not support SEH +// Or console colours (or console at all...) +# if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) +# define CATCH_CONFIG_COLOUR_NONE +# else +# define CATCH_INTERNAL_CONFIG_WINDOWS_SEH +# endif + +// MSVC traditional preprocessor needs some workaround for __VA_ARGS__ +// _MSVC_TRADITIONAL == 0 means new conformant preprocessor +// _MSVC_TRADITIONAL == 1 means old traditional non-conformant preprocessor +# if !defined(__clang__) // Handle Clang masquerading for msvc +# if !defined(_MSVC_TRADITIONAL) || (defined(_MSVC_TRADITIONAL) && _MSVC_TRADITIONAL) +# define CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +# endif // MSVC_TRADITIONAL +# endif // __clang__ + +#endif // _MSC_VER + +#if defined(_REENTRANT) || defined(_MSC_VER) +// Enable async processing, as -pthread is specified or no additional linking is required +# define CATCH_INTERNAL_CONFIG_USE_ASYNC +#endif // _MSC_VER + +//////////////////////////////////////////////////////////////////////////////// +// Check if we are compiled with -fno-exceptions or equivalent +#if defined(__EXCEPTIONS) || defined(__cpp_exceptions) || defined(_CPPUNWIND) +# define CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED +#endif + +//////////////////////////////////////////////////////////////////////////////// +// DJGPP +#ifdef __DJGPP__ +# define CATCH_INTERNAL_CONFIG_NO_WCHAR +#endif // __DJGPP__ + +//////////////////////////////////////////////////////////////////////////////// +// Embarcadero C++Build +#if defined(__BORLANDC__) + #define CATCH_INTERNAL_CONFIG_POLYFILL_ISNAN +#endif + +//////////////////////////////////////////////////////////////////////////////// + +// Use of __COUNTER__ is suppressed during code analysis in +// CLion/AppCode 2017.2.x and former, because __COUNTER__ is not properly +// handled by it. +// Otherwise all supported compilers support COUNTER macro, +// but user still might want to turn it off +#if ( !defined(__JETBRAINS_IDE__) || __JETBRAINS_IDE__ >= 20170300L ) + #define CATCH_INTERNAL_CONFIG_COUNTER +#endif + +//////////////////////////////////////////////////////////////////////////////// + +// RTX is a special version of Windows that is real time. +// This means that it is detected as Windows, but does not provide +// the same set of capabilities as real Windows does. +#if defined(UNDER_RTSS) || defined(RTX64_BUILD) + #define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH + #define CATCH_INTERNAL_CONFIG_NO_ASYNC + #define CATCH_CONFIG_COLOUR_NONE +#endif + +#if !defined(_GLIBCXX_USE_C99_MATH_TR1) +#define CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER +#endif + +// Various stdlib support checks that require __has_include +#if defined(__has_include) + // Check if string_view is available and usable + #if __has_include() && defined(CATCH_CPP17_OR_GREATER) + # define CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW + #endif + + // Check if optional is available and usable + # if __has_include() && defined(CATCH_CPP17_OR_GREATER) + # define CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL + # endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) + + // Check if byte is available and usable + # if __has_include() && defined(CATCH_CPP17_OR_GREATER) + # include + # if __cpp_lib_byte > 0 + # define CATCH_INTERNAL_CONFIG_CPP17_BYTE + # endif + # endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) + + // Check if variant is available and usable + # if __has_include() && defined(CATCH_CPP17_OR_GREATER) + # if defined(__clang__) && (__clang_major__ < 8) + // work around clang bug with libstdc++ https://bugs.llvm.org/show_bug.cgi?id=31852 + // fix should be in clang 8, workaround in libstdc++ 8.2 + # include + # if defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9) + # define CATCH_CONFIG_NO_CPP17_VARIANT + # else + # define CATCH_INTERNAL_CONFIG_CPP17_VARIANT + # endif // defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9) + # else + # define CATCH_INTERNAL_CONFIG_CPP17_VARIANT + # endif // defined(__clang__) && (__clang_major__ < 8) + # endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) +#endif // defined(__has_include) + +#if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER) +# define CATCH_CONFIG_COUNTER +#endif +#if defined(CATCH_INTERNAL_CONFIG_WINDOWS_SEH) && !defined(CATCH_CONFIG_NO_WINDOWS_SEH) && !defined(CATCH_CONFIG_WINDOWS_SEH) && !defined(CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH) +# define CATCH_CONFIG_WINDOWS_SEH +#endif +// This is set by default, because we assume that unix compilers are posix-signal-compatible by default. +#if defined(CATCH_INTERNAL_CONFIG_POSIX_SIGNALS) && !defined(CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_POSIX_SIGNALS) +# define CATCH_CONFIG_POSIX_SIGNALS +#endif +// This is set by default, because we assume that compilers with no wchar_t support are just rare exceptions. +#if !defined(CATCH_INTERNAL_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_WCHAR) +# define CATCH_CONFIG_WCHAR +#endif + +#if !defined(CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_CPP11_TO_STRING) +# define CATCH_CONFIG_CPP11_TO_STRING +#endif + +#if defined(CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_NO_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_CPP17_OPTIONAL) +# define CATCH_CONFIG_CPP17_OPTIONAL +#endif + +#if defined(CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_NO_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_CPP17_STRING_VIEW) +# define CATCH_CONFIG_CPP17_STRING_VIEW +#endif + +#if defined(CATCH_INTERNAL_CONFIG_CPP17_VARIANT) && !defined(CATCH_CONFIG_NO_CPP17_VARIANT) && !defined(CATCH_CONFIG_CPP17_VARIANT) +# define CATCH_CONFIG_CPP17_VARIANT +#endif + +#if defined(CATCH_INTERNAL_CONFIG_CPP17_BYTE) && !defined(CATCH_CONFIG_NO_CPP17_BYTE) && !defined(CATCH_CONFIG_CPP17_BYTE) +# define CATCH_CONFIG_CPP17_BYTE +#endif + +#if defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT) +# define CATCH_INTERNAL_CONFIG_NEW_CAPTURE +#endif + +#if defined(CATCH_INTERNAL_CONFIG_NEW_CAPTURE) && !defined(CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE) && !defined(CATCH_CONFIG_NO_NEW_CAPTURE) && !defined(CATCH_CONFIG_NEW_CAPTURE) +# define CATCH_CONFIG_NEW_CAPTURE +#endif + +#if !defined(CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED) && !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) +# define CATCH_CONFIG_DISABLE_EXCEPTIONS +#endif + +#if defined(CATCH_INTERNAL_CONFIG_POLYFILL_ISNAN) && !defined(CATCH_CONFIG_NO_POLYFILL_ISNAN) && !defined(CATCH_CONFIG_POLYFILL_ISNAN) +# define CATCH_CONFIG_POLYFILL_ISNAN +#endif + +#if defined(CATCH_INTERNAL_CONFIG_USE_ASYNC) && !defined(CATCH_INTERNAL_CONFIG_NO_ASYNC) && !defined(CATCH_CONFIG_NO_USE_ASYNC) && !defined(CATCH_CONFIG_USE_ASYNC) +# define CATCH_CONFIG_USE_ASYNC +#endif + +#if defined(CATCH_INTERNAL_CONFIG_ANDROID_LOGWRITE) && !defined(CATCH_CONFIG_NO_ANDROID_LOGWRITE) && !defined(CATCH_CONFIG_ANDROID_LOGWRITE) +# define CATCH_CONFIG_ANDROID_LOGWRITE +#endif + +#if defined(CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER) && !defined(CATCH_CONFIG_NO_GLOBAL_NEXTAFTER) && !defined(CATCH_CONFIG_GLOBAL_NEXTAFTER) +# define CATCH_CONFIG_GLOBAL_NEXTAFTER +#endif + +// Even if we do not think the compiler has that warning, we still have +// to provide a macro that can be used by the code. +#if !defined(CATCH_INTERNAL_START_WARNINGS_SUPPRESSION) +# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION +#endif +#if !defined(CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION) +# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION +#endif +#if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS +#endif +#if !defined(CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS +#endif +#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS +#endif +#if !defined(CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS +#endif + +// The goal of this macro is to avoid evaluation of the arguments, but +// still have the compiler warn on problems inside... +#if !defined(CATCH_INTERNAL_IGNORE_BUT_WARN) +# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) +#endif + +#if defined(__APPLE__) && defined(__apple_build_version__) && (__clang_major__ < 10) +# undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS +#elif defined(__clang__) && (__clang_major__ < 5) +# undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS +#endif + +#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS +#endif + +#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) +#define CATCH_TRY if ((true)) +#define CATCH_CATCH_ALL if ((false)) +#define CATCH_CATCH_ANON(type) if ((false)) +#else +#define CATCH_TRY try +#define CATCH_CATCH_ALL catch (...) +#define CATCH_CATCH_ANON(type) catch (type) +#endif + +#if defined(CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR) && !defined(CATCH_CONFIG_NO_TRADITIONAL_MSVC_PREPROCESSOR) && !defined(CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR) +#define CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +#endif + +// end catch_compiler_capabilities.h +#define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line +#define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) +#ifdef CATCH_CONFIG_COUNTER +# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __COUNTER__ ) +#else +# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ ) +#endif + +#include +#include +#include + +// We need a dummy global operator<< so we can bring it into Catch namespace later +struct Catch_global_namespace_dummy {}; +std::ostream& operator<<(std::ostream&, Catch_global_namespace_dummy); + +namespace Catch { + + struct CaseSensitive { enum Choice { + Yes, + No + }; }; + + class NonCopyable { + NonCopyable( NonCopyable const& ) = delete; + NonCopyable( NonCopyable && ) = delete; + NonCopyable& operator = ( NonCopyable const& ) = delete; + NonCopyable& operator = ( NonCopyable && ) = delete; + + protected: + NonCopyable(); + virtual ~NonCopyable(); + }; + + struct SourceLineInfo { + + SourceLineInfo() = delete; + SourceLineInfo( char const* _file, std::size_t _line ) noexcept + : file( _file ), + line( _line ) + {} + + SourceLineInfo( SourceLineInfo const& other ) = default; + SourceLineInfo& operator = ( SourceLineInfo const& ) = default; + SourceLineInfo( SourceLineInfo&& ) noexcept = default; + SourceLineInfo& operator = ( SourceLineInfo&& ) noexcept = default; + + bool empty() const noexcept { return file[0] == '\0'; } + bool operator == ( SourceLineInfo const& other ) const noexcept; + bool operator < ( SourceLineInfo const& other ) const noexcept; + + char const* file; + std::size_t line; + }; + + std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ); + + // Bring in operator<< from global namespace into Catch namespace + // This is necessary because the overload of operator<< above makes + // lookup stop at namespace Catch + using ::operator<<; + + // Use this in variadic streaming macros to allow + // >> +StreamEndStop + // as well as + // >> stuff +StreamEndStop + struct StreamEndStop { + std::string operator+() const; + }; + template + T const& operator + ( T const& value, StreamEndStop ) { + return value; + } +} + +#define CATCH_INTERNAL_LINEINFO \ + ::Catch::SourceLineInfo( __FILE__, static_cast( __LINE__ ) ) + +// end catch_common.h +namespace Catch { + + struct RegistrarForTagAliases { + RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); + }; + +} // end namespace Catch + +#define CATCH_REGISTER_TAG_ALIAS( alias, spec ) \ + CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } \ + CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION + +// end catch_tag_alias_autoregistrar.h +// start catch_test_registry.h + +// start catch_interfaces_testcase.h + +#include + +namespace Catch { + + class TestSpec; + + struct ITestInvoker { + virtual void invoke () const = 0; + virtual ~ITestInvoker(); + }; + + class TestCase; + struct IConfig; + + struct ITestCaseRegistry { + virtual ~ITestCaseRegistry(); + virtual std::vector const& getAllTests() const = 0; + virtual std::vector const& getAllTestsSorted( IConfig const& config ) const = 0; + }; + + bool isThrowSafe( TestCase const& testCase, IConfig const& config ); + bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ); + std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ); + std::vector const& getAllTestCasesSorted( IConfig const& config ); + +} + +// end catch_interfaces_testcase.h +// start catch_stringref.h + +#include +#include +#include +#include + +namespace Catch { + + /// A non-owning string class (similar to the forthcoming std::string_view) + /// Note that, because a StringRef may be a substring of another string, + /// it may not be null terminated. + class StringRef { + public: + using size_type = std::size_t; + using const_iterator = const char*; + + private: + static constexpr char const* const s_empty = ""; + + char const* m_start = s_empty; + size_type m_size = 0; + + public: // construction + constexpr StringRef() noexcept = default; + + StringRef( char const* rawChars ) noexcept; + + constexpr StringRef( char const* rawChars, size_type size ) noexcept + : m_start( rawChars ), + m_size( size ) + {} + + StringRef( std::string const& stdString ) noexcept + : m_start( stdString.c_str() ), + m_size( stdString.size() ) + {} + + explicit operator std::string() const { + return std::string(m_start, m_size); + } + + public: // operators + auto operator == ( StringRef const& other ) const noexcept -> bool; + auto operator != (StringRef const& other) const noexcept -> bool { + return !(*this == other); + } + + auto operator[] ( size_type index ) const noexcept -> char { + assert(index < m_size); + return m_start[index]; + } + + public: // named queries + constexpr auto empty() const noexcept -> bool { + return m_size == 0; + } + constexpr auto size() const noexcept -> size_type { + return m_size; + } + + // Returns the current start pointer. If the StringRef is not + // null-terminated, throws std::domain_exception + auto c_str() const -> char const*; + + public: // substrings and searches + // Returns a substring of [start, start + length). + // If start + length > size(), then the substring is [start, size()). + // If start > size(), then the substring is empty. + auto substr( size_type start, size_type length ) const noexcept -> StringRef; + + // Returns the current start pointer. May not be null-terminated. + auto data() const noexcept -> char const*; + + constexpr auto isNullTerminated() const noexcept -> bool { + return m_start[m_size] == '\0'; + } + + public: // iterators + constexpr const_iterator begin() const { return m_start; } + constexpr const_iterator end() const { return m_start + m_size; } + }; + + auto operator += ( std::string& lhs, StringRef const& sr ) -> std::string&; + auto operator << ( std::ostream& os, StringRef const& sr ) -> std::ostream&; + + constexpr auto operator "" _sr( char const* rawChars, std::size_t size ) noexcept -> StringRef { + return StringRef( rawChars, size ); + } +} // namespace Catch + +constexpr auto operator "" _catch_sr( char const* rawChars, std::size_t size ) noexcept -> Catch::StringRef { + return Catch::StringRef( rawChars, size ); +} + +// end catch_stringref.h +// start catch_preprocessor.hpp + + +#define CATCH_RECURSION_LEVEL0(...) __VA_ARGS__ +#define CATCH_RECURSION_LEVEL1(...) CATCH_RECURSION_LEVEL0(CATCH_RECURSION_LEVEL0(CATCH_RECURSION_LEVEL0(__VA_ARGS__))) +#define CATCH_RECURSION_LEVEL2(...) CATCH_RECURSION_LEVEL1(CATCH_RECURSION_LEVEL1(CATCH_RECURSION_LEVEL1(__VA_ARGS__))) +#define CATCH_RECURSION_LEVEL3(...) CATCH_RECURSION_LEVEL2(CATCH_RECURSION_LEVEL2(CATCH_RECURSION_LEVEL2(__VA_ARGS__))) +#define CATCH_RECURSION_LEVEL4(...) CATCH_RECURSION_LEVEL3(CATCH_RECURSION_LEVEL3(CATCH_RECURSION_LEVEL3(__VA_ARGS__))) +#define CATCH_RECURSION_LEVEL5(...) CATCH_RECURSION_LEVEL4(CATCH_RECURSION_LEVEL4(CATCH_RECURSION_LEVEL4(__VA_ARGS__))) + +#ifdef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +#define INTERNAL_CATCH_EXPAND_VARGS(...) __VA_ARGS__ +// MSVC needs more evaluations +#define CATCH_RECURSION_LEVEL6(...) CATCH_RECURSION_LEVEL5(CATCH_RECURSION_LEVEL5(CATCH_RECURSION_LEVEL5(__VA_ARGS__))) +#define CATCH_RECURSE(...) CATCH_RECURSION_LEVEL6(CATCH_RECURSION_LEVEL6(__VA_ARGS__)) +#else +#define CATCH_RECURSE(...) CATCH_RECURSION_LEVEL5(__VA_ARGS__) +#endif + +#define CATCH_REC_END(...) +#define CATCH_REC_OUT + +#define CATCH_EMPTY() +#define CATCH_DEFER(id) id CATCH_EMPTY() + +#define CATCH_REC_GET_END2() 0, CATCH_REC_END +#define CATCH_REC_GET_END1(...) CATCH_REC_GET_END2 +#define CATCH_REC_GET_END(...) CATCH_REC_GET_END1 +#define CATCH_REC_NEXT0(test, next, ...) next CATCH_REC_OUT +#define CATCH_REC_NEXT1(test, next) CATCH_DEFER ( CATCH_REC_NEXT0 ) ( test, next, 0) +#define CATCH_REC_NEXT(test, next) CATCH_REC_NEXT1(CATCH_REC_GET_END test, next) + +#define CATCH_REC_LIST0(f, x, peek, ...) , f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1) ) ( f, peek, __VA_ARGS__ ) +#define CATCH_REC_LIST1(f, x, peek, ...) , f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST0) ) ( f, peek, __VA_ARGS__ ) +#define CATCH_REC_LIST2(f, x, peek, ...) f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1) ) ( f, peek, __VA_ARGS__ ) + +#define CATCH_REC_LIST0_UD(f, userdata, x, peek, ...) , f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1_UD) ) ( f, userdata, peek, __VA_ARGS__ ) +#define CATCH_REC_LIST1_UD(f, userdata, x, peek, ...) , f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST0_UD) ) ( f, userdata, peek, __VA_ARGS__ ) +#define CATCH_REC_LIST2_UD(f, userdata, x, peek, ...) f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1_UD) ) ( f, userdata, peek, __VA_ARGS__ ) + +// Applies the function macro `f` to each of the remaining parameters, inserts commas between the results, +// and passes userdata as the first parameter to each invocation, +// e.g. CATCH_REC_LIST_UD(f, x, a, b, c) evaluates to f(x, a), f(x, b), f(x, c) +#define CATCH_REC_LIST_UD(f, userdata, ...) CATCH_RECURSE(CATCH_REC_LIST2_UD(f, userdata, __VA_ARGS__, ()()(), ()()(), ()()(), 0)) + +#define CATCH_REC_LIST(f, ...) CATCH_RECURSE(CATCH_REC_LIST2(f, __VA_ARGS__, ()()(), ()()(), ()()(), 0)) + +#define INTERNAL_CATCH_EXPAND1(param) INTERNAL_CATCH_EXPAND2(param) +#define INTERNAL_CATCH_EXPAND2(...) INTERNAL_CATCH_NO## __VA_ARGS__ +#define INTERNAL_CATCH_DEF(...) INTERNAL_CATCH_DEF __VA_ARGS__ +#define INTERNAL_CATCH_NOINTERNAL_CATCH_DEF +#define INTERNAL_CATCH_STRINGIZE(...) INTERNAL_CATCH_STRINGIZE2(__VA_ARGS__) +#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +#define INTERNAL_CATCH_STRINGIZE2(...) #__VA_ARGS__ +#define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param)) +#else +// MSVC is adding extra space and needs another indirection to expand INTERNAL_CATCH_NOINTERNAL_CATCH_DEF +#define INTERNAL_CATCH_STRINGIZE2(...) INTERNAL_CATCH_STRINGIZE3(__VA_ARGS__) +#define INTERNAL_CATCH_STRINGIZE3(...) #__VA_ARGS__ +#define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) (INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param)) + 1) +#endif + +#define INTERNAL_CATCH_MAKE_NAMESPACE2(...) ns_##__VA_ARGS__ +#define INTERNAL_CATCH_MAKE_NAMESPACE(name) INTERNAL_CATCH_MAKE_NAMESPACE2(name) + +#define INTERNAL_CATCH_REMOVE_PARENS(...) INTERNAL_CATCH_EXPAND1(INTERNAL_CATCH_DEF __VA_ARGS__) + +#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +#define INTERNAL_CATCH_MAKE_TYPE_LIST2(...) decltype(get_wrapper()) +#define INTERNAL_CATCH_MAKE_TYPE_LIST(...) INTERNAL_CATCH_MAKE_TYPE_LIST2(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__)) +#else +#define INTERNAL_CATCH_MAKE_TYPE_LIST2(...) INTERNAL_CATCH_EXPAND_VARGS(decltype(get_wrapper())) +#define INTERNAL_CATCH_MAKE_TYPE_LIST(...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_MAKE_TYPE_LIST2(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__))) +#endif + +#define INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(...)\ + CATCH_REC_LIST(INTERNAL_CATCH_MAKE_TYPE_LIST,__VA_ARGS__) + +#define INTERNAL_CATCH_REMOVE_PARENS_1_ARG(_0) INTERNAL_CATCH_REMOVE_PARENS(_0) +#define INTERNAL_CATCH_REMOVE_PARENS_2_ARG(_0, _1) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_1_ARG(_1) +#define INTERNAL_CATCH_REMOVE_PARENS_3_ARG(_0, _1, _2) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_2_ARG(_1, _2) +#define INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_0, _1, _2, _3) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_3_ARG(_1, _2, _3) +#define INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_0, _1, _2, _3, _4) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_1, _2, _3, _4) +#define INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_0, _1, _2, _3, _4, _5) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_1, _2, _3, _4, _5) +#define INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_0, _1, _2, _3, _4, _5, _6) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_1, _2, _3, _4, _5, _6) +#define INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_0, _1, _2, _3, _4, _5, _6, _7) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_1, _2, _3, _4, _5, _6, _7) +#define INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_1, _2, _3, _4, _5, _6, _7, _8) +#define INTERNAL_CATCH_REMOVE_PARENS_10_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9) +#define INTERNAL_CATCH_REMOVE_PARENS_11_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_10_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10) + +#define INTERNAL_CATCH_VA_NARGS_IMPL(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N + +#define INTERNAL_CATCH_TYPE_GEN\ + template struct TypeList {};\ + template\ + constexpr auto get_wrapper() noexcept -> TypeList { return {}; }\ + template class...> struct TemplateTypeList{};\ + template class...Cs>\ + constexpr auto get_wrapper() noexcept -> TemplateTypeList { return {}; }\ + template\ + struct append;\ + template\ + struct rewrap;\ + template class, typename...>\ + struct create;\ + template class, typename>\ + struct convert;\ + \ + template \ + struct append { using type = T; };\ + template< template class L1, typename...E1, template class L2, typename...E2, typename...Rest>\ + struct append, L2, Rest...> { using type = typename append, Rest...>::type; };\ + template< template class L1, typename...E1, typename...Rest>\ + struct append, TypeList, Rest...> { using type = L1; };\ + \ + template< template class Container, template class List, typename...elems>\ + struct rewrap, List> { using type = TypeList>; };\ + template< template class Container, template class List, class...Elems, typename...Elements>\ + struct rewrap, List, Elements...> { using type = typename append>, typename rewrap, Elements...>::type>::type; };\ + \ + template