diff --git a/.clang-format b/.clang-format index 9a9cbf817..ed9165255 100644 --- a/.clang-format +++ b/.clang-format @@ -3,4 +3,4 @@ BasedOnStyle: Google # Customize with larger indents IndentWidth: 4 -ObjCBlockIndentWidth: 4 \ No newline at end of file +ObjCBlockIndentWidth: 4 diff --git a/.github/dependabot.yml b/.github/dependabot.yml index ed8f4a432..234b07e76 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -6,4 +6,4 @@ updates: - package-ecosystem: 'github-actions' directory: '/' schedule: - interval: 'daily' + interval: 'monthly' diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ac7ce1bf9..867639527 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,16 +11,16 @@ on: jobs: linux-min: name: Linux Min Config - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 strategy: matrix: - compiler: [clang++-6.0, g++-10] + compiler: [clang++-15, g++-12] steps: - - uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 - name: Install Dependencies # Boost must be installed only because the CMake version (3.12) can't # detect the installed Boost version (1.69) - run: sudo apt-get update && sudo apt-get -y install ninja-build libboost-date-time-dev clang-6.0 g++-10 g++-multilib + run: sudo apt-get update && sudo apt-get -y install ninja-build libboost-date-time-dev g++-multilib - name: Run tests with common Catch run: | cmake -G Ninja . @@ -32,12 +32,12 @@ jobs: linux-latest: name: Linux Latest Config needs: [linux-min] - runs-on: ubuntu-22.04 + runs-on: ubuntu-26.04 strategy: matrix: compiler: [clang++, g++] steps: - - uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 - name: Install Dependencies # Boost must be installed only because the CMake version (3.12) can't # detect the installed Boost version (1.69) @@ -64,7 +64,7 @@ jobs: needs: [linux-min] runs-on: windows-2022 steps: - - uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 - name: Run Tests shell: powershell # Delete the exercises that require Boost to avoid issues with Windows setup. @@ -80,7 +80,7 @@ jobs: needs: [linux-min] runs-on: macOS-latest steps: - - uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 - name: Install Boost run: brew install boost - name: Run Tests @@ -88,4 +88,3 @@ jobs: cmake . cmake --build . -- test_hello-world cmake --build . - diff --git a/.github/workflows/format-code.yml b/.github/workflows/format-code.yml index 2270dffea..5fac99bbc 100644 --- a/.github/workflows/format-code.yml +++ b/.github/workflows/format-code.yml @@ -7,7 +7,7 @@ on: jobs: format: name: "Format C++ code" - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 if: github.event.issue.pull_request != '' && (contains(github.event.comment.body, '/format') || contains(github.event.comment.body, '/clang-format')) steps: - name: "Checkout code" diff --git a/.github/workflows/hello-world.yml b/.github/workflows/hello-world.yml index 02f152080..e75d287e1 100644 --- a/.github/workflows/hello-world.yml +++ b/.github/workflows/hello-world.yml @@ -19,10 +19,10 @@ on: jobs: hello-world-fails: name: Hello World Fails - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 - name: Check Hello World Fails run: bin/check-hello-world.sh env: - CXX: ${{ matrix.compiler }} \ No newline at end of file + CXX: ${{ matrix.compiler }} diff --git a/.github/workflows/ping-cross-track-maintainers-team.yml b/.github/workflows/ping-cross-track-maintainers-team.yml new file mode 100644 index 000000000..b6ec9c566 --- /dev/null +++ b/.github/workflows/ping-cross-track-maintainers-team.yml @@ -0,0 +1,16 @@ +name: Ping cross-track maintainers team + +on: + pull_request_target: + types: + - opened + +permissions: + pull-requests: write + +jobs: + ping: + if: github.repository_owner == 'exercism' # Stops this job from running on forks + uses: exercism/github-actions/.github/workflows/ping-cross-track-maintainers-team.yml@main + secrets: + github_membership_token: ${{ secrets.COMMUNITY_CONTRIBUTIONS_WORKFLOW_TOKEN }} diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml new file mode 100644 index 000000000..777d3396c --- /dev/null +++ b/.github/workflows/pre-commit.yml @@ -0,0 +1,24 @@ +name: Pre-commit checks + +on: + # Run workflow for PRs. + pull_request: + + # Whenever we have a new commit on main, run the workflow for that. + push: + branches: [main] + +jobs: + pre-commit: + name: Pre-commit checks + runs-on: ubuntu-26.04 + steps: + - name: Checkout code + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 + with: + ref: ${{github.event.pull_request.head.sha}} + repository: ${{github.event.pull_request.head.repo.full_name}} + - name: Set up Python + uses: actions/setup-python@v7 + - name: Run pre-commit checks on PR + uses: pre-commit/action@v3.0.1 diff --git a/.github/workflows/run-configlet-sync.yml b/.github/workflows/run-configlet-sync.yml new file mode 100644 index 000000000..c175036c1 --- /dev/null +++ b/.github/workflows/run-configlet-sync.yml @@ -0,0 +1,10 @@ +name: Run Configlet Sync + +on: + workflow_dispatch: + schedule: + - cron: '0 0 15 * *' + +jobs: + configlet-sync: + uses: exercism/github-actions/.github/workflows/configlet-sync.yml@main diff --git a/.github/workflows/verify-code-formatting.yml b/.github/workflows/verify-code-formatting.yml deleted file mode 100644 index f336277e4..000000000 --- a/.github/workflows/verify-code-formatting.yml +++ /dev/null @@ -1,38 +0,0 @@ -name: "Verify C++ code formatting" - -on: - push: - paths: - - "**/*.cpp" - - "**/*.h" - - "**/*.hpp" - - ".clang-format" - - "!**/catch.hpp" - pull_request: - paths: - - "**/*.cpp" - - "**/*.h" - - "**/*.hpp" - - ".clang-format" - - "!**/catch.hpp" - -jobs: - verify-code-formatting: - runs-on: [ubuntu-22.04] - steps: - - name: "Checkout code" - uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b - - - name: "Verify formatting of all files" - if: github.ref == 'refs/heads/master' - run: | - find . -type f \( -iname '*.cpp' -o -iname '*.h' -o -iname '*.hpp' \) -a ! -iname "catch.hpp" | \ - xargs bin/check-formatting.sh - - - name: "Verify formatting of the PR's files" - if: github.ref != 'refs/heads/master' && github.event.pull_request.url - run: | - PULL_REQUEST_URL=$(jq -r ".pull_request.url" "$GITHUB_EVENT_PATH") - curl --url $"${PULL_REQUEST_URL}/files" --header 'authorization: Bearer ${{ secrets.GITHUB_TOKEN }}' | \ - jq -c '.[] | select(.status == "added" or .status == "modified") | select(.filename | match("(?&2 @@ -69,16 +70,16 @@ main() { curl "${curlopts[@]}" --output "${output_path}" "${download_url}" case "${ext}" in - *zip) unzip "${output_path}" -d "${output_dir}" ;; - *) tar xzf "${output_path}" -C "${output_dir}" ;; + zip) unzip "${output_path}" -d "${output_dir}" ;; + *) tar xzf "${output_path}" -C "${output_dir}" ;; esac rm -f "${output_path}" local executable_ext case "${os}" in - windows*) executable_ext='.exe' ;; - *) executable_ext='' ;; + windows) executable_ext='.exe' ;; + *) executable_ext='' ;; esac local configlet_path="${output_dir}/configlet${executable_ext}" diff --git a/bin/make-stub-files.sh b/bin/make-stub-files.sh index e38ddc880..76eab0b27 100755 --- a/bin/make-stub-files.sh +++ b/bin/make-stub-files.sh @@ -21,10 +21,8 @@ for exercise_dir in "${exercises_dir}"/*; do header="$exercise_name.h" source="$exercise_name.cpp" if ! test -f "$header"; then - printf "#if !defined(${exercise_name^^}_H)\n" >> $header - printf "#define ${exercise_name^^}_H\n" >> $header + printf "#pragma once\n" >> $header printf "\nnamespace $exercise_name {\n\n} // namespace $exercise_name\n" >> $header - printf "\n#endif // ${exercise_name^^}_H" >> $header git add $header fi if ! test -f "$source"; then diff --git a/concepts/auto/links.json b/concepts/auto/links.json index 9c85e3634..87f0bf23d 100644 --- a/concepts/auto/links.json +++ b/concepts/auto/links.json @@ -7,4 +7,4 @@ "url": "https://www.learncpp.com/cpp-tutorial/type-deduction-for-objects-using-the-auto-keyword/", "description": "Learn C++ overview on the auto keyword and its usage" } -] \ No newline at end of file +] diff --git a/concepts/basics/about.md b/concepts/basics/about.md index 1a3ddc396..764b6b3e8 100644 --- a/concepts/basics/about.md +++ b/concepts/basics/about.md @@ -6,7 +6,7 @@ To set off the C++ journey we are starting with variables, function calls, and c Comments come in two flavors: single- and multi-line. Everything that comes after `//` on the same line is ignored by the compiler. -Multi-line comments are also known as C-style comments. +Multi-line comments are also known as C-style comments. They are surrounded by `/*` and `*/`. Anything that comes between these will be ignored as well. @@ -40,7 +40,7 @@ It cannot be stressed enough: avoid undefined behavior at all cost. ## Arithmetic Operations -Arithmetic operators like `*`, `+`, or `-` can be part of an expression like `3 * 2` or `tomatoes + potatoes`. +Arithmetic operators like `*`, `+`, or `-` can be part of an expression like `3 * 2` or `tomatoes + potatoes`. ## Updating Variables @@ -84,7 +84,7 @@ int total_fee(int vips, int adults, int kids) { */ int standard_fee{30}; int kids_discount{15}; - + int kids_total_fee = kids * (standard_fee - kids_discount); int vips_total_fee = vips * vip_fee(standard_fee); int adult_total_fee = adults * standard_fee; diff --git a/concepts/basics/introduction.md b/concepts/basics/introduction.md index 7e6a49ef6..c2512452f 100644 --- a/concepts/basics/introduction.md +++ b/concepts/basics/introduction.md @@ -6,7 +6,7 @@ To set off the C++ journey we are starting with variables, function calls, and c Comments come in two flavors: single- and multi-line. Everything that comes after `//` on the same line is ignored by the compiler. -Multi-line comments are also known as C-style comments. +Multi-line comments are also known as C-style comments. They are surrounded by `/*` and `*/`. Anything that comes between these will be ignored as well. @@ -40,7 +40,7 @@ It cannot be stressed enough: avoid undefined behavior at all cost. ## Arithmetic Operations -Arithmetic operators like `*`, `+`, or `-` can be part of an expression like `3 * 2` or `tomatoes + potatoes`. +Arithmetic operators like `*`, `+`, or `-` can be part of an expression like `3 * 2` or `tomatoes + potatoes`. ## Updating Variables @@ -84,7 +84,7 @@ int total_fee(int vips, int adults, int kids) { */ int standard_fee{30}; int kids_discount{15}; - + int kids_total_fee = kids * (standard_fee - kids_discount); int vips_total_fee = vips * vip_fee(standard_fee); int adult_total_fee = adults * standard_fee; diff --git a/concepts/basics/links.json b/concepts/basics/links.json index ab2f7aa15..690b9bc3d 100644 --- a/concepts/basics/links.json +++ b/concepts/basics/links.json @@ -11,4 +11,4 @@ "url": "https://isocpp.org/faq", "description": "C++ Super-FAQ" } -] \ No newline at end of file +] diff --git a/concepts/booleans/introduction.md b/concepts/booleans/introduction.md index 267063973..ad0ee9e12 100644 --- a/concepts/booleans/introduction.md +++ b/concepts/booleans/introduction.md @@ -35,4 +35,4 @@ If you use a number in a Boolean operation, everything except `0` is treated as !true && 0.0 // => false true + true + false // => 2 ``` -~~~~ \ No newline at end of file +~~~~ diff --git a/concepts/booleans/links.json b/concepts/booleans/links.json index 0df565316..3368e317b 100644 --- a/concepts/booleans/links.json +++ b/concepts/booleans/links.json @@ -3,4 +3,4 @@ "url": "https://en.cppreference.com/w/cpp/language/operator_logical", "description": "C++ reference on Logical operators" } -] \ No newline at end of file +] diff --git a/concepts/classes/about.md b/concepts/classes/about.md index d8c64f19f..bb94b0334 100644 --- a/concepts/classes/about.md +++ b/concepts/classes/about.md @@ -52,7 +52,7 @@ silverhand.cast_spell(); silverhand.name = "Laeral"; // damage is private: -silverhand.damage = 500; +silverhand.damage = 500; // => Compilation error ``` diff --git a/concepts/classes/introduction.md b/concepts/classes/introduction.md index b851e444e..e9a957bc5 100644 --- a/concepts/classes/introduction.md +++ b/concepts/classes/introduction.md @@ -51,7 +51,7 @@ silverhand.cast_spell(); silverhand.name = "Laeral"; // damage is private: -silverhand.damage = 500; +silverhand.damage = 500; // => Compilation error ``` @@ -102,4 +102,4 @@ Conventionally, the `struct` keyword is often used for **data-only structures**. The `class` keyword is preferred for objects that need to ensure certain properties. Such an invariant could be that the `damage` of your `Wizzard` `class` cannot turn negative. The `damage` variable is private and any function that changes the damage would ensure the invariant is preserved. -~~~~ \ No newline at end of file +~~~~ diff --git a/concepts/classes/links.json b/concepts/classes/links.json index 5afd99559..cd994028c 100644 --- a/concepts/classes/links.json +++ b/concepts/classes/links.json @@ -3,4 +3,4 @@ "url": "https://en.cppreference.com/w/cpp/language/classes", "description": "C++ reference on for classes" } -] \ No newline at end of file +] diff --git a/concepts/comparisons/about.md b/concepts/comparisons/about.md index 95803ef9b..ec34ac14f 100644 --- a/concepts/comparisons/about.md +++ b/concepts/comparisons/about.md @@ -27,7 +27,7 @@ Here are some common examples: ```cpp bool eq3 = 2 == 3; // false, integer comparison -bool eq4 = 2.1 != 2.2; // true, float comparison +bool eq4 = 2.1 != 2.2; // true, float comparison bool eq5 = "hello" == "hello"; // true, string comparison ``` diff --git a/concepts/comparisons/introduction.md b/concepts/comparisons/introduction.md index 103cf6b4e..f16a5b0d0 100644 --- a/concepts/comparisons/introduction.md +++ b/concepts/comparisons/introduction.md @@ -27,7 +27,7 @@ Here are some common examples: ```cpp bool eq3 = 2 == 3; // false, integer comparison -bool eq4 = 2.1 != 2.2; // true, float comparison +bool eq4 = 2.1 != 2.2; // true, float comparison bool eq5 = "hello" == "hello"; // true, string comparison ``` diff --git a/concepts/comparisons/links.json b/concepts/comparisons/links.json index 8be8cc9ab..be11e8132 100644 --- a/concepts/comparisons/links.json +++ b/concepts/comparisons/links.json @@ -3,4 +3,4 @@ "url": "https://en.cppreference.com/w/cpp/language/operator_comparison", "description": "C++ reference on comparison operators" } -] \ No newline at end of file +] diff --git a/concepts/enums/about.md b/concepts/enums/about.md index 809f97914..e0f1c4627 100644 --- a/concepts/enums/about.md +++ b/concepts/enums/about.md @@ -46,7 +46,7 @@ enum class WheelMaterial { plastic }; ``` -Although the wheels and the deck can both be made of _plastic_, the two cannot be confused. +Although the wheels and the deck can both be made of _plastic_, the two cannot be confused. They are different _types_: `DeckMaterial` plastic and `WheelMaterial` plastic. Each `enumeration` will have its `enumerators` in its own scope - its own `namespace`. This is the reason they are called `scoped enumerations`. @@ -57,7 +57,7 @@ You might be thinking that with a name like `scoped`, there would also be _`uns `Unscoped enumerations` are becoming less popular because they all share the same global namespace. Because of the sharing, you could not have two `unscoped enumerations` with the same `enumerators` like _plastic_ in the example above. -Also, `unscoped enumerations` implicitly convert to integers. +Also, `unscoped enumerations` implicitly convert to integers. Look at the example below for a surprising result: ```cpp @@ -84,4 +84,4 @@ If you want to convert `scoped enumerations` to integers you can use `static_cas -[magic numbers]: https://en.wikipedia.org/wiki/Magic_number_(programming) \ No newline at end of file +[magic numbers]: https://en.wikipedia.org/wiki/Magic_number_(programming) diff --git a/concepts/enums/introduction.md b/concepts/enums/introduction.md index a9b0f41be..ad4e4e4c9 100644 --- a/concepts/enums/introduction.md +++ b/concepts/enums/introduction.md @@ -46,7 +46,7 @@ enum class WheelMaterial { plastic }; ``` -Although the wheels and the deck can both be made of _plastic_, the two cannot be confused. +Although the wheels and the deck can both be made of _plastic_, the two cannot be confused. They are different _types_: `DeckMaterial` plastic and `WheelMaterial` plastic. Each `enumeration` will have its `enumerators` in its own scope - its own `namespace`. This is the reason they are called `scoped enumerations`. @@ -57,7 +57,7 @@ You might be thinking that with the name `scoped`, there would also be be `unsco `Unscoped enumerations` are becoming less popular because they all share the same global namespace. Because of the sharing, you could not have two `unscoped enumerations` with the same `enumerators` like _plastic_ in the example above. -Also, `unscoped enumerations` implicitly convert to integers. +Also, `unscoped enumerations` implicitly convert to integers. Look at the example below for a surprising result: ```cpp @@ -84,4 +84,4 @@ If you want to convert `scoped enumerations` to integers you can use `static_cas -[magic numbers]: https://en.wikipedia.org/wiki/Magic_number_(programming) \ No newline at end of file +[magic numbers]: https://en.wikipedia.org/wiki/Magic_number_(programming) diff --git a/concepts/enums/links.json b/concepts/enums/links.json index ca711b76f..30bc05dcd 100644 --- a/concepts/enums/links.json +++ b/concepts/enums/links.json @@ -3,4 +3,4 @@ "url": "https://en.cppreference.com/w/cpp/language/enum", "description": "C++ reference on enumerations" } -] \ No newline at end of file +] diff --git a/concepts/functions/about.md b/concepts/functions/about.md index e2f12ed33..89748088a 100644 --- a/concepts/functions/about.md +++ b/concepts/functions/about.md @@ -66,7 +66,7 @@ class Stubborn { response = reply; } string answer(const string& question) const { - if (question.lenghth() == 0) { return "";} + if (question.length() == 0) { return "";} return response; } private: diff --git a/concepts/functions/introduction.md b/concepts/functions/introduction.md index b832a0a5a..3a173b9bd 100644 --- a/concepts/functions/introduction.md +++ b/concepts/functions/introduction.md @@ -66,7 +66,7 @@ class Stubborn { response = reply; } string answer(const string& question) const { - if (question.lenghth() == 0) { return "";} + if (question.length() == 0) { return ""; } return response; } private: diff --git a/concepts/functions/links.json b/concepts/functions/links.json index c08cc662b..6d5b65a78 100644 --- a/concepts/functions/links.json +++ b/concepts/functions/links.json @@ -15,4 +15,4 @@ "url": "https://en.cppreference.com/w/cpp/language/default_arguments", "description": "C++ reference on default arguments" } -] \ No newline at end of file +] diff --git a/concepts/headers/about.md b/concepts/headers/about.md index b6a57a709..5983cd3ce 100644 --- a/concepts/headers/about.md +++ b/concepts/headers/about.md @@ -10,7 +10,7 @@ The header file will tell you _what_ a codebase has to offer without going into The most common file extension for header files is `.h`. Some projects use `.hpp` or skip the extension completely. -The definitions are located in a separate `.cpp` file. +The definitions are located in a separate `.cpp` file. To reunite the parts, the source file starts by _including_ the respective header file. If you want to write a library called "quick_math" that offers a function "super_root" that you want to use often, the files would look like this: @@ -18,17 +18,24 @@ If you want to write a library called "quick_math" that offers a function "super ```cpp // A file named quick_math.h #pragma once + namespace quick_math { - double super_root(double x, int n); + +double super_root(double x, int n); + } ``` ```cpp // A file named quick_math.cpp -#include "quick_math.h" #include + +#include "quick_math.h" + double quick_math::super_root(double x, int n) { - while(n) { x = std::sqrt(x), --n;} + while (n) { + x = std::sqrt(x), --n; + } return x; } ``` @@ -51,57 +58,81 @@ One possible layout is to keep all the implementation details in the source file // A file named robot_flower.h #if !defined(ROBOT_FLOWER_H) #define ROBOT_FLOWER_H + #include + namespace robots { - class Flower { - private: - bool needs_water{}; - int size{}; - std::string name{}; - public: - Flower(std::string name, int size = 0); - void give_water(); - std::string get_name(); - int get_size(); - void start_next_day(); - }; -} + +class Flower { + private: + bool needs_water{}; + int size{}; + std::string name{}; + + public: + Flower(std::string name, int size = 0); + void give_water(); + std::string get_name(); + int get_size(); + void start_next_day(); +}; +} // namespace robots #endif ``` ```cpp // A file named robot_flower.cpp #include "robot_flower.h" -robots::Flower::Flower(std::string name, int size) {this->name = "Robotica " + name; this->size = size;} -void robots::Flower::start_next_day() {if (!needs_water) ++size; needs_water = true;} -std::string robots::Flower::get_name() {return name;} -int robots::Flower::get_size() {return size;} + +robots::Flower::Flower(std::string name, int size) { + this->name = "Robotica " + name; + this->size = size; +} + +void robots::Flower::start_next_day() { + if (!needs_water) ++size; + needs_water = true; +} + +std::string robots::Flower::get_name() { return name; } + +int robots::Flower::get_size() { return size; } ``` When the header is used as an API overview, that is where a person would look for information like default values. The `size` parameter's default of the constructor is therefore handled in the header and not in the implementation. The definitions in the source file are prefixed with the namespace `robots` and the class type `Flower`. - + Another layout option is a _header only_ library, that does not have a `.cpp` file at all: ```cpp // A file named robot_flower.h #pragma once + #include + namespace robots { - class Flower { - private: - bool needs_water{}; - int size{}; - std::string name{}; - public: - Flower(std::string name, int size = 0) {this->name = "Robotica " + name; this->size = size;} - void give_water() {needs_water = false;} - std::string get_name() {return name;} - int get_size() {return size;} - void start_next_day() {if (!needs_water) ++size; needs_water = true;} - }; -} + +class Flower { + private: + bool needs_water{}; + int size{}; + std::string name{}; + + public: + Flower(std::string name, int size = 0) { + this->name = "Robotica " + name; + this->size = size; + } + void give_water() { needs_water = false; } + std::string get_name() { return name; } + int get_size() { return size; } + void start_next_day() { + if (!needs_water) ++size; + needs_water = true; + } +}; +} // namespace robots ``` Projects might use combinations of these layouts and there is a lot of discussion as to what might be the best fit for each use case. @@ -129,9 +160,7 @@ int myFunction(int n) { } } -int myOtherFunction(int m) { - return myFunction(m / 2); -} +int myOtherFunction(int m) { return myFunction(m / 2); } ``` When `myFunction` is defined, the compiler does not know about `myOtherFunction` yet. @@ -142,8 +171,8 @@ The compiler assumes that the definition will follow at some later point after t The next example shows how a forward declaration is used for functions. ```cpp -int myFunction(int n); // Forward declaration of myFunction -int myOtherFunction(int m); // Forward declaration of myOtherFunction +int myFunction(int n); // Forward declaration of myFunction +int myOtherFunction(int m); // Forward declaration of myOtherFunction // Definition of myFunction int myFunction(int n) { @@ -155,16 +184,14 @@ int myFunction(int n) { } // Definition of myOtherFunction -int myOtherFunction(int m) { - return myFunction(m / 2); -} +int myOtherFunction(int m) { return myFunction(m / 2); } ``` ## Include Guards via ifndef It does not matter if the same file is included multiple times within a project. Header files should not contain definitions. -The complete project cannot have the same definition more than once. +The complete project cannot have the same definition more than once. This is called the "One definition rule". It will be enforced by the compiler. @@ -178,10 +205,12 @@ The syntax can be seen below with `MY_HEADER_FILE_H` as a variable. ```cpp #ifndef MY_HEADER_FILE_H /* any name uniquely mapped to file name */ #define MY_HEADER_FILE_H + // file content + #endif ``` The problem with `#pragma once` is, that pragmas are not an official part of the C++ language and the implementation differs from compiler to compiler. Many big projects have switched to the simpler pragma method, but a few are still cautious. -~~~~ \ No newline at end of file +~~~~ diff --git a/concepts/headers/introduction.md b/concepts/headers/introduction.md index c8d9c68ff..978b94c63 100644 --- a/concepts/headers/introduction.md +++ b/concepts/headers/introduction.md @@ -10,7 +10,7 @@ The header file will tell you _what_ a codebase has to offer without going into The most common file extension for header files is `.h`. Some projects use `.hpp` or skip the extension completely. -The definitions are located in a separate `.cpp` file. +The definitions are located in a separate `.cpp` file. To reunite the parts, the source file starts by _including_ the respective header file. If you want to write a library called "quick_math" that offers a function "super_root" that you want to use often, the files would look like this: @@ -18,17 +18,24 @@ If you want to write a library called "quick_math" that offers a function "super ```cpp // A file named quick_math.h #pragma once + namespace quick_math { - double super_root(double x, int n); -} + +double super_root(double x, int n); + +} // namespace quick_math ``` ```cpp // A file named quick_math.cpp -#include "quick_math.h" #include + +#include "quick_math.h" + double quick_math::super_root(double x, int n) { - while(n) { x = std::sqrt(x), --n;} + while (n) { + x = std::sqrt(x), --n; + } return x; } ``` @@ -51,57 +58,88 @@ One possible layout is to keep all the implementation details in the source file // A file named robot_flower.h #if !defined(ROBOT_FLOWER_H) #define ROBOT_FLOWER_H + #include + namespace robots { - class Flower { - private: - bool needs_water{}; - int size{}; - std::string name{}; - public: - Flower(std::string name, int size = 0); - void give_water(); - std::string get_name(); - int get_size(); - void start_next_day(); - }; -} + +class Flower { + private: + bool needs_water{}; + int size{}; + std::string name{}; + + public: + Flower(std::string name, int size = 0); + void give_water(); + std::string get_name(); + int get_size(); + void start_next_day(); +}; + +} // namespace robots + #endif ``` ```cpp // A file named robot_flower.cpp #include "robot_flower.h" -robots::Flower::Flower(std::string name, int size) {this->name = "Robotica " + name; this->size = size;} -void robots::Flower::start_next_day() {if (!needs_water) ++size; needs_water = true;} -std::string robots::Flower::get_name() {return name;} -int robots::Flower::get_size() {return size;} + +robots::Flower::Flower(std::string name, int size) { + this->name = "Robotica " + name; + this->size = size; +} + +void robots::Flower::start_next_day() { + if (!needs_water) { + ++size; + } + needs_water = true; +} + +std::string robots::Flower::get_name() { return name; } + +int robots::Flower::get_size() { return size; } ``` When the header is used as an API overview, that is where a person would look for information like default values. The `size` parameter's default of the constructor is therefore handled in the header and not in the implementation. The definitions in the source file are prefixed with the namespace `robots` and the class type `Flower`. - + Another layout option is a _header only_ library, that does not have a `.cpp` file at all: ```cpp // A file named robot_flower.h #pragma once + #include + namespace robots { - class Flower { - private: - bool needs_water{}; - int size{}; - std::string name{}; - public: - Flower(std::string name, int size = 0) {this->name = "Robotica " + name; this->size = size;} - void give_water() {needs_water = false;} - std::string get_name() {return name;} - int get_size() {return size;} - void start_next_day() {if (!needs_water) ++size; needs_water = true;} - }; -} + +class Flower { + private: + bool needs_water{}; + int size{}; + std::string name{}; + + public: + Flower(std::string name, int size = 0) { + this->name = "Robotica " + name; + this->size = size; + } + void give_water() { needs_water = false; } + std::string get_name() { return name; } + int get_size() { return size; } + void start_next_day() { + if (!needs_water) { + ++size; + } + needs_water = true; + } +}; + +} // namespace robots ``` Projects might use combinations of these layouts and there is a lot of discussion as to what might be the best fit for each use case. diff --git a/concepts/headers/links.json b/concepts/headers/links.json index 5dcf350be..fa81042f8 100644 --- a/concepts/headers/links.json +++ b/concepts/headers/links.json @@ -7,4 +7,4 @@ "url": "https://www.learncpp.com/cpp-tutorial/classes-and-header-files/", "description": "More information about classes in header files" } -] \ No newline at end of file +] diff --git a/concepts/if-statements/about.md b/concepts/if-statements/about.md index 0473b4a8d..f2921bd27 100644 --- a/concepts/if-statements/about.md +++ b/concepts/if-statements/about.md @@ -41,4 +41,4 @@ if (int v{2 * num}; v > 10) { // => 14 ``` -> Note: any variables created in the initialization cannot be accesed after the end of the if statement. \ No newline at end of file +> Note: any variables created in the initialization cannot be accesed after the end of the if statement. diff --git a/concepts/if-statements/introduction.md b/concepts/if-statements/introduction.md index 48f930d49..ae4bb9344 100644 --- a/concepts/if-statements/introduction.md +++ b/concepts/if-statements/introduction.md @@ -41,4 +41,4 @@ if (int v{2 * num}; v > 10) { // => 14 ``` -> Note: any variables created in the initialization cannot be accesed after the end of the if statement. \ No newline at end of file +> Note: any variables created in the initialization cannot be accesed after the end of the if statement. diff --git a/concepts/if-statements/links.json b/concepts/if-statements/links.json index 0a9484653..7f0c14f80 100644 --- a/concepts/if-statements/links.json +++ b/concepts/if-statements/links.json @@ -3,4 +3,4 @@ "url": "https://en.cppreference.com/w/cpp/language/if", "description": "C++ reference on if statements" } -] \ No newline at end of file +] diff --git a/concepts/includes/about.md b/concepts/includes/about.md index 93fc9ed00..d9399b1e5 100644 --- a/concepts/includes/about.md +++ b/concepts/includes/about.md @@ -8,7 +8,7 @@ During compilation, the line with the directive is replaced by the content of th Namespaces are kept as they are in the original file after includes. ## The Standard Library - + The standard library offers many common functions, algorithms, and data structures. The standard library uses the `std` namespace. diff --git a/concepts/includes/introduction.md b/concepts/includes/introduction.md index 87cc4f3ca..581ef7cd1 100644 --- a/concepts/includes/introduction.md +++ b/concepts/includes/introduction.md @@ -11,7 +11,7 @@ During compilation, the line with the directive is replaced by the content of th Namespaces are kept as they are in the original file after includes. ## The Standard Library - + The standard library offers many common functions, algorithms, and data structures. The standard library uses the `std` namespace. diff --git a/concepts/includes/links.json b/concepts/includes/links.json index 2887e9531..41b93f13f 100644 --- a/concepts/includes/links.json +++ b/concepts/includes/links.json @@ -3,4 +3,4 @@ "url": "https://en.cppreference.com/w/cpp/preprocessor/include", "description": "C++ reference on Source File Inclusion" } -] \ No newline at end of file +] diff --git a/concepts/literals/about.md b/concepts/literals/about.md index c32446754..420b44433 100644 --- a/concepts/literals/about.md +++ b/concepts/literals/about.md @@ -36,7 +36,7 @@ This is a good default case and use-cases with the narrower `float` type are les ```cpp auto light_year_in_m{9.46073e+15f}; // well in the range of float auto earth_to_edge_comoving_distance_in_nm{4.32355e+32}; // needs double type for magnitude -auto eulers_number{2.718281828459045d}; // needs double type for precision +auto eulers_number{2.718281828459045}; // needs double type for precision ``` ~~~~exercism/advanced @@ -68,8 +68,9 @@ auto il_nam{"보는 것이 하는 것보다 더 재미있을 수가 없지"sv}; A _string_view_ can be seen as a reference to a const string. +[ascii-code]: https://www.ascii-code.com/ + ~~~~ [numbers-concept]: https://exercism.org/tracks/cpp/concepts/numbers [in-depth-integers]: https://www.learncpp.com/cpp-tutorial/fixed-width-integers-and-size-t/ -[ascii-code]: https://www.ascii-code.com/ diff --git a/concepts/literals/introduction.md b/concepts/literals/introduction.md index e89c7b112..99f433b19 100644 --- a/concepts/literals/introduction.md +++ b/concepts/literals/introduction.md @@ -33,10 +33,19 @@ auto net_worth_carlisle_cullen{46'000'000'000LL}; // int and uint are not enough Floating-point numbers usually resolve to `double` during compilation. This is a good default case and use-cases with the narrower `float` type are less frequent than the unsigned example above. +~~~~exercism/advanced +The [C++23 standard][cpp23-literals] introduces more fine grained control with literals like `f128` or `F16`. +Some compilers allow their own literals. +GCC permits the usage of `d` as a literal, but this is not foreseen in the standard and can hinder cross-platform compatibility. + +[cpp23-literals]: https://en.cppreference.com/w/cpp/language/floating_literal + +~~~~ + ```cpp auto light_year_in_m{9.46073e+15f}; // well in the range of float auto earth_to_edge_comoving_distance_in_nm{4.32355e+32}; // needs double type for magnitude -auto eulers_number{2.718281828459045d}; // needs double type for precision +auto eulers_number{2.718281828459045}; // needs double type for precision ``` ~~~~exercism/advanced @@ -68,8 +77,9 @@ auto il_nam{"보는 것이 하는 것보다 더 재미있을 수가 없지"sv}; A _string_view_ can be seen as a reference to a const string. +[ascii-code]: https://www.ascii-code.com/ + ~~~~ [numbers-concept]: https://exercism.org/tracks/cpp/concepts/numbers [in-depth-integers]: https://www.learncpp.com/cpp-tutorial/fixed-width-integers-and-size-t/ -[ascii-code]: https://www.ascii-code.com/ diff --git a/concepts/literals/links.json b/concepts/literals/links.json index 1b9edf60d..9f98210d0 100644 --- a/concepts/literals/links.json +++ b/concepts/literals/links.json @@ -3,4 +3,4 @@ "url": "https://www.learncpp.com/cpp-tutorial/literals/", "description": "Learn C++ overview on literals" } -] \ No newline at end of file +] diff --git a/concepts/loops/about.md b/concepts/loops/about.md index 10c335d34..b1fcd0f73 100644 --- a/concepts/loops/about.md +++ b/concepts/loops/about.md @@ -63,7 +63,7 @@ for (int i{1}; i < 10; ++i) { } ``` -This loop will sum the numbers from `1` to `9` (including `9`). +This loop will sum the numbers from `1` to `9` (including `9`). ## Break and Continue diff --git a/concepts/loops/introduction.md b/concepts/loops/introduction.md index 690d8e88f..521154ee2 100644 --- a/concepts/loops/introduction.md +++ b/concepts/loops/introduction.md @@ -63,7 +63,7 @@ for (int i{1}; i < 10; ++i) { } ``` -This loop will sum the numbers from `1` to `9` (including `9`). +This loop will sum the numbers from `1` to `9` (including `9`). ## Break and Continue @@ -84,7 +84,7 @@ In contrast, the keyword `continue` only stops the execution of the current iter ```cpp int equal_sum{0}; for (int i{1}; i < 7; ++i) { - if (n%2 == 1) { + if (i%2 == 1) { continue; } equal_sum += i; diff --git a/concepts/loops/links.json b/concepts/loops/links.json index c814151ca..458f3a2d1 100644 --- a/concepts/loops/links.json +++ b/concepts/loops/links.json @@ -7,4 +7,4 @@ "url": "https://en.cppreference.com/w/cpp/language/while", "description": "C++ reference on while loops" } -] \ No newline at end of file +] diff --git a/concepts/namespaces/about.md b/concepts/namespaces/about.md index a2220d0cf..8c281986e 100644 --- a/concepts/namespaces/about.md +++ b/concepts/namespaces/about.md @@ -44,4 +44,4 @@ namespace o = my_other_ns; int also_my_result{m::foo() + o::foo() * m::my_inner_ns::baz()}; ``` -~~~~ \ No newline at end of file +~~~~ diff --git a/concepts/namespaces/links.json b/concepts/namespaces/links.json index 06397a0ec..9cb677f95 100644 --- a/concepts/namespaces/links.json +++ b/concepts/namespaces/links.json @@ -3,4 +3,4 @@ "url": "https://en.cppreference.com/w/cpp/language/namespace", "description": "C++ reference on namespaces" } -] \ No newline at end of file +] diff --git a/concepts/numbers/.meta/config.json b/concepts/numbers/.meta/config.json index 6c515a485..afae10271 100644 --- a/concepts/numbers/.meta/config.json +++ b/concepts/numbers/.meta/config.json @@ -6,4 +6,4 @@ "contributors": [ "tesarect" ] -} \ No newline at end of file +} diff --git a/concepts/numbers/about.md b/concepts/numbers/about.md index 8ef58f28f..223f35eb9 100644 --- a/concepts/numbers/about.md +++ b/concepts/numbers/about.md @@ -4,7 +4,7 @@ Integers are whole numbers like `0`, `691`, or `-2`. Floating point numbers are numbers with a decimal point like `6.02214076`, `0.1`, or `-1.616`. ## Integers -The following example shows the declaration and initialization of four different variables +The following example shows the declaration and initialization of four different variables ```cpp int m_morales{9241}; // base 10: 0-9 @@ -29,7 +29,7 @@ You can use an apostrophe to separate digits for easier readability. ## Floating-Point Numbers -The floating-point literals come in two flavors. +The floating-point literals come in two flavors. In addition to the intuitive `0.0024` it is possible to use its scientific notation `2.4e-3`. The most common floating-point type is `double`. @@ -60,15 +60,15 @@ Consider also that we are only assigning the value of `width` to `length` at the Therefore, if the value of `width` changes at a later moment, it will not affect the value taken by `length`. Assignment operator can be combined with the other operators(arithmetic & bitwise) known as `compound assignment` operators `+=`, `-=`, `*=`, `/=`, `%=`. -These operators modifies the current value of a variable by performing an operation on it. +These operators modify the current value of a variable by performing an operation on it. ```cpp // we start with 0 people int people{}; // we need 0 eggs -int eggs{}; +int eggs{}; // two people joined: -people += 2; +people += 2; // people is now 2 // let's add 3 eggs per person eggs += 3 * people; diff --git a/concepts/numbers/introduction.md b/concepts/numbers/introduction.md index a97f047d8..30c7fe2e5 100644 --- a/concepts/numbers/introduction.md +++ b/concepts/numbers/introduction.md @@ -4,7 +4,7 @@ Integers are whole numbers like `0`, `691`, or `-2`. Floating point numbers are numbers with a decimal point like `6.02214076`, `0.1`, or `-1.616`. ## Integers -The following example shows the declaration and initialization of four different variables +The following example shows the declaration and initialization of four different variables ```cpp int m_morales{9241}; // base 10: 0-9 @@ -29,7 +29,7 @@ You can use an apostrophe to separate digits for easier readability. ## Floating-Point Numbers -The floating-point literals come in two flavors. +The floating-point literals come in two flavors. In addition to the intuitive `0.0024` it is possible to use its scientific notation `2.4e-3`. The most common floating-point type is `double`. @@ -60,15 +60,15 @@ Consider also that we are only assigning the value of `width` to `length` at the Therefore, if the value of `width` changes at a later moment, it will not affect the value taken by `length`. Assignment operator can be combined with the other operators(arithmetic & bitwise) known as `compound assignment` operators `+=`, `-=`, `*=`, `/=`, `%=`. -These operators modifies the current value of a variable by performing an operation on it. +These operators modify the current value of a variable by performing an operation on it. ```cpp // we start with 0 people int people{}; // we need 0 eggs -int eggs{}; +int eggs{}; // two people joined: -people += 2; +people += 2; // people is now 2 // let's add 3 eggs per person eggs += 3 * people; diff --git a/concepts/numbers/links.json b/concepts/numbers/links.json index f11210b04..894269e31 100644 --- a/concepts/numbers/links.json +++ b/concepts/numbers/links.json @@ -11,4 +11,4 @@ "url": "https://en.wikipedia.org/wiki/Double-precision_floating-point_format", "description": "Explanation on the floating point format" } - ] \ No newline at end of file + ] diff --git a/concepts/pointers/.meta/config.json b/concepts/pointers/.meta/config.json new file mode 100644 index 000000000..c0d7cc03c --- /dev/null +++ b/concepts/pointers/.meta/config.json @@ -0,0 +1,6 @@ +{ + "blurb": "In C++, pointers are variables that store object addresses. They allow you to directly manipulate memory and access to data structures like arrays and objects.", + "authors": [ + "vaeng" + ] +} diff --git a/concepts/pointers/about.md b/concepts/pointers/about.md new file mode 100644 index 000000000..c5348a211 --- /dev/null +++ b/concepts/pointers/about.md @@ -0,0 +1,136 @@ +# Introduction + +Like many other languages, C++ has _pointers_. +You already know _references_ and _pointers_ are similar, but think of them as a level closer to the inner workings of your computer. +_Pointers_ are variables that hold object addresses. +They are used to directly interact with objects, enabling dynamic memory allocation and efficient data manipulation in C++. + +If you're new to _pointers_, they can feel a little mysterious but once you get used to them, they're quite straight-forward. + +They're a crucial part of C++, so take some time to really understand them. +The bare-bone version in this concept is also called _dumb pointer_ or _raw pointer_. +With modern C++ there are also _smart pointers_, the basic type is not smart at all and you have to handle all the work manually. + +Before digging into the details, it's worth understanding the use of _pointers_. +_Pointers_ are a way to share an object's address with other parts of our program, which is useful for two major reasons: + +1. Like _references_, pointers avoid copies and help to reduce the resource-footprint of your program. +1. Unlike _references_, pointers can be reassigned to different objects. +1. Pointers can also point to a null value, to indicate, that they currently do not point to any object. + +## General Syntax + +A pointer declaration in C++ involves specifying the data type to which the the pointer is pointing, followed by an asterisk (`*`) and the pointer's name. +When pointers are declared, they are not automatically initialized. +Without explicit assignment, a pointer typically holds an indeterminate value, often referred to as a "garbage address." +While certain compilers might initialize pointers to `nullptr`, this behavior is not guaranteed across all compilers, so it's essential not to rely on it. +It's best practice to explicitly initialize raw pointers and verify their non-null status before utilization to avoid potential issues. + +```cpp +int* ptr{nullptr}; // Declares a pointer and makes sure it is not invalid +``` + +To assign the address of a variable to a pointer, you use the address-of operator (`&`). +Dereferencing a pointer is done using the _indirection operator_ (`*`) operator. + +```cpp +std::string opponent{"Solomon Lane"}; +// 'ethan' points to the address of the string opponent +std::string* ethan{&opponent}; +// Instead of ethan's, the opponent's name address is given to the passPort +std::string passportName{*ethan}; +``` + +Attention: dereferencing has to be done explicitly, while _references_ just worked like an alias. + +## Pointer Arithmetic + +_Pointer arithmetic_ allows you to perform arithmetic operations on pointers, which is particularly useful when working with arrays. +Adding an integer to a pointer makes it point to a different element. + +```cpp +// Stargate Coordinate Code +int gateCode[] = {462, 753, 218, 611, 977}; +// 'ptr' points to the first element of 'gateCode' +int* ptr{&gateCode[0]}; +// Accesses the third Stargate address through pointer arithmetic +int dialedAddress{*(ptr + 2)}; +// Chevron encoded! Dialing Stargate address: +openStarGate(dialedAddress); +``` + +~~~~exercism/caution +Pointer arithmetic in C++ can easily lead to __undefined behavior__ if not handled carefully. +Undefined behavior can manifest in unexpected program outcomes, crashes, or even security vulnerabilities. +One infamous example of the consequences of undefined behavior occurred in the [explosion of the Ariane 5 rocket][ariane-flight-v88] in 1996, where a software exception caused by the conversion of a 64-bit floating-point number to a 16-bit signed integer led to a catastrophic failure. + +[ariane-flight-v88]: https://en.wikipedia.org/wiki/Ariane_flight_V88 +~~~~ + +## Accessing member variables + +In C++, the `->` operator is used to access members of an object through a pointer to that object. +It is a shorthand which simplifies accessing members of objects pointed to by pointers. +For instance, if `ptr` is a pointer to an object with a member variable `x`, instead of using `(*ptr).x`, you can directly use `ptr->x`. +This operator enhances code readability and reduces verbosity when working with pointers to objects. + +Here's a brief example, with a _struct_ `Superhero` that has a member variable `superpower`. +The main function creates a pointer `dianaPrince` to a `Superhero` object (representing Wonder Woman). +The `->` operator is used to access the member variable `superpower`, showcasing Wonder Woman's iconic "Lasso of Truth." + +```cpp +struct Superhero { + std::string superpower; +}; + +Superhero wonder_woman{}; +Superhero* dianaPrince = &wonder_woman; +dianaPrince->superpower = "Lasso of Truth"; + +// Using the -> operator to access member variable superpower: +std::cout << "Wonder Woman, possesses the mighty " << dianaPrince->superpower; + +// Memory cleanup: +delete dianaPrince; +``` + +## Pointers vs. references + +Pointers and references both enable indirect access to objects, but they differ in their capabilities and safety considerations. +Pointers offer the flexibility of changing their target object and can be assigned null. +However, this flexibility introduces risks, such as dereferencing null pointers or creating dangling pointers. +References, on the other hand, cannot be null and are bound to valid objects upon creation, avoiding these risks. +Given their safer nature, references should be preferred over pointers unless the additional functionalities provided by pointers are necessary. + +~~~~exercism/advanced +## Dynamic Memory Allocation and Null Pointers + +In C++, `new` is used to dynamically allocate memory for objects on the heap during runtime. +It returns a pointer to the allocated memory address, allowing objects to have lifetimes not tied to a specific scope. +However, it's important to always pair `new` with `delete` to properly deallocate memory. +Dynamic memory allocation should be used cautiously to prevent common issues like memory leaks and accessing deallocated memory. + +Pointers can also be set to a special value called a _null pointer_, which indicates that they do not point to a valid address. +Null pointers are commonly used to initialize pointers before assigning them to valid values. + +```cpp +// There is a dark mark bearer, but who is it? +std::string* darkMarkBearer{nullptr}; +// It is Bellatrix! +darkMarkBearer = new std::string{"Bellatrix Lestrange"}; +// She has been defeated +delete darkMarkBearer; +// Reset pointer to null, symbolizing there is no more darkMarkBearer at the moment +darkMarkBearer = nullptr; +``` + +A pointer should either hold the address of a valid object, or be set to `nullptr`. +That way you only need to test pointers for null, and can assume any non-null pointer is valid. +When an object is destroyed, any pointers to the destroyed object will be left _dangling_ (they will not be automatically set to `nullptr`). +It is your responsibility to detect these cases and ensure those pointers are subsequently set to `nullptr`. + + +In older code, you might encounter two alternatives to `nullptr`. +Firstly, the literal `0` is specifically interpreted as a null value for pointers, though it's the only scenario where an integral literal can be assigned to a pointer. +Secondly, the `preprocessor macro` `NULL`, inherited from C and defined in the `` header, is another representation of a null pointer, though its usage is less common in modern C++ code. +~~~~ diff --git a/concepts/pointers/introduction.md b/concepts/pointers/introduction.md new file mode 100644 index 000000000..6db1296fc --- /dev/null +++ b/concepts/pointers/introduction.md @@ -0,0 +1,100 @@ +# Introduction + +Like many other languages, C++ has _pointers_. +You already know _references_ and _pointers_ are similar, but think of them as a level closer to the inner workings of your computer. +_Pointers_ are variables that hold object addresses. +They are used to directly interact with objects, enabling dynamic memory allocation and efficient data manipulation in C++. + +If you're new to _pointers_, they can feel a little mysterious but once you get used to them, they're quite straight-forward. + +They're a crucial part of C++, so take some time to really understand them. +The bare-bone version in this concept is also called _dumb pointer_ or _raw pointer_. +With modern C++ there are also _smart pointers_, the basic type is not smart at all and you have to handle all the work manually. + +Before digging into the details, it's worth understanding the use of _pointers_. +_Pointers_ are a way to share an object's address with other parts of our program, which is useful for two major reasons: + +1. Like _references_, pointers avoid copies and help to reduce the resource-footprint of your program. +1. Unlike _references_, pointers can be reassigned to different objects. +1. Pointers can also point to a null value, to indicate, that they currently do not point to any object. + +## General Syntax + +A pointer declaration in C++ involves specifying the data type to which the the pointer is pointing, followed by an asterisk (`*`) and the pointer's name. +When pointers are declared, they are not automatically initialized. +Without explicit assignment, a pointer typically holds an indeterminate value, often referred to as a "garbage address." +While certain compilers might initialize pointers to `nullptr`, this behavior is not guaranteed across all compilers, so it's essential not to rely on it. +It's best practice to explicitly initialize raw pointers and verify their non-null status before utilization to avoid potential issues. + +```cpp +int* ptr{nullptr}; // Declares a pointer and makes sure it is not invalid +``` + +To assign the address of a variable to a pointer, you use the address-of operator (`&`). +Dereferencing a pointer is done using the _indirection operator_ (`*`) operator. + +```cpp +std::string opponent{"Solomon Lane"}; +// 'ethan' points to the address of the string opponent +std::string* ethan{&opponent}; +// Instead of ethan's, the opponent's name address is given to the passPort +std::string passportName{*ethan}; +``` + +Attention: dereferencing has to be done explicitly, while _references_ just worked like an alias. + +## Pointer Arithmetic + +_Pointer arithmetic_ allows you to perform arithmetic operations on pointers, which is particularly useful when working with arrays. +Adding an integer to a pointer makes it point to a different element. + +```cpp +// Stargate Coordinate Code +int gateCode[] = {462, 753, 218, 611, 977}; +// 'ptr' points to the first element of 'gateCode' +int* ptr{&gateCode[0]}; +// Accesses the third Stargate address through pointer arithmetic +int dialedAddress{*(ptr + 2)}; +// Chevron encoded! Dialing Stargate address: +openStarGate(dialedAddress); +``` + +~~~~exercism/caution +Pointer arithmetic in C++ can easily lead to __undefined behavior__ if not handled carefully. +Undefined behavior can manifest in unexpected program outcomes, crashes, or even security vulnerabilities. +One infamous example of the consequences of undefined behavior occurred in the [explosion of the Ariane 5 rocket][ariane-flight-v88] in 1996, where a software exception caused by the conversion of a 64-bit floating-point number to a 16-bit signed integer led to a catastrophic failure. + +[ariane-flight-v88]: https://en.wikipedia.org/wiki/Ariane_flight_V88 +~~~~ + +## Accessing member variables + +In C++, the `->` operator is used to access members of an object through a pointer to that object. +It is a shorthand which simplifies accessing members of objects pointed to by pointers. +For instance, if `ptr` is a pointer to an object with a member variable `x`, instead of using `(*ptr).x`, you can directly use `ptr->x`. +This operator enhances code readability and reduces verbosity when working with pointers to objects. + +Here's a brief example, with a _struct_ `Superhero` that has a member variable `superpower`. +The main function creates a pointer `dianaPrince` to a `Superhero` object (representing Wonder Woman). +The `->` operator is used to access the member variable `superpower`, showcasing Wonder Woman's iconic "Lasso of Truth." + +```cpp +struct Superhero { + std::string superpower; +}; +Superhero wonder_woman{}; +Superhero* dianaPrince = &wonder_woman; +dianaPrince->superpower = "Lasso of Truth"; +// Using the -> operator to access member variable superpower: +std::cout << "Wonder Woman, possesses the mighty " << dianaPrince->superpower; +// Memory cleanup: +delete dianaPrince; +``` + +## Pointers vs. references + +Pointers and references both enable indirect access to objects, but they differ in their capabilities and safety considerations. +Pointers offer the flexibility of changing their target object and can be assigned null. +However, this flexibility introduces risks, such as dereferencing null pointers or creating dangling pointers. +References, on the other hand, cannot be null and are bound to valid objects upon creation, avoiding these risks. +Given their safer nature, references should be preferred over pointers unless the additional functionalities provided by pointers are necessary. diff --git a/concepts/pointers/links.json b/concepts/pointers/links.json new file mode 100644 index 000000000..b6c74d4b0 --- /dev/null +++ b/concepts/pointers/links.json @@ -0,0 +1,14 @@ +[ + { + "url": "https://en.cppreference.com/w/c/language/pointer", + "description": "C++ reference on pointers" + }, + { + "url": "https://en.cppreference.com/w/cpp/memory/new", + "description": "C++ reference on dynamic memory allocation with new" + }, + { + "url": "https://en.cppreference.com/w/cpp/language/delete", + "description": "C++ reference on dynamic memory deallocation with delete" + } +] diff --git a/concepts/references/about.md b/concepts/references/about.md index 969025e09..86bafd3d8 100644 --- a/concepts/references/about.md +++ b/concepts/references/about.md @@ -52,8 +52,8 @@ int& future_budget; ## `void` -With the power of `references` you might not need to return a value from a function at all. -`void` is used as a return type in this scenario. +With the power of `references` you might not need to return a value from a function at all. +`void` is used as a return type in this scenario. ```cpp void increase_power(int& level) { @@ -65,4 +65,4 @@ increase_power(goku); // It's over 9000! ``` -[Reseating]: https://stackoverflow.com/questions/728233/why-are-references-not-reseatable-in-c \ No newline at end of file +[Reseating]: https://stackoverflow.com/questions/728233/why-are-references-not-reseatable-in-c diff --git a/concepts/references/introduction.md b/concepts/references/introduction.md index 9ab3909a9..b769dc5f4 100644 --- a/concepts/references/introduction.md +++ b/concepts/references/introduction.md @@ -52,8 +52,8 @@ int& future_budget; ## `void` -With the power of `references` you might not need to return a value from a function at all. -`void` is used as a return type in this scenario. +With the power of `references` you might not need to return a value from a function at all. +`void` is used as a return type in this scenario. ```cpp void increase_power(int& level) { @@ -63,4 +63,4 @@ int goku{8700}; increase_power(goku); // goku's power level? // It's over 9000! -``` \ No newline at end of file +``` diff --git a/concepts/references/links.json b/concepts/references/links.json index b5eca2e1f..2d90ebcd3 100644 --- a/concepts/references/links.json +++ b/concepts/references/links.json @@ -3,4 +3,4 @@ "url": "https://en.cppreference.com/w/cpp/language/reference", "description": "C++ reference on references" } -] \ No newline at end of file +] diff --git a/concepts/smart-pointers/about.md b/concepts/smart-pointers/about.md index ad66e0a3b..c74c0538a 100644 --- a/concepts/smart-pointers/about.md +++ b/concepts/smart-pointers/about.md @@ -6,7 +6,7 @@ They act as wrappers around raw pointers, adding additional functionality such a ## General Syntax Smart pointers are typically implemented as class templates in the C++ standard library. -The two most commonly used smart pointers are `std::unique_ptr` and `std::shared_ptr`. +The two most commonly used smart pointers are `std::unique_ptr` and `std::shared_ptr`. ## Unique Pointers @@ -83,7 +83,7 @@ auto your_flatmates_boyfriends_account = your_flatmates_account; ## `std::weak_ptr` and Cyclic Ownership -`std::weak_ptr` was designed to address the issue of cyclic ownership, also known as circular references, that can occur when using `std::shared_ptr`. +`std::weak_ptr` was designed to address the issue of cyclic ownership, also known as circular references, that can occur when using `std::shared_ptr`. In a cyclic ownership scenario, two or more `std::shared_ptr` objects are referencing each other, creating a cycle where none of the objects can be deleted because they have strong references to each other, leading to memory leaks. diff --git a/concepts/smart-pointers/introduction.md b/concepts/smart-pointers/introduction.md index 61c60f694..dd84b7882 100644 --- a/concepts/smart-pointers/introduction.md +++ b/concepts/smart-pointers/introduction.md @@ -6,7 +6,7 @@ They act as wrappers around raw pointers, adding additional functionality such a ## General Syntax Smart pointers are typically implemented as class templates in the C++ standard library. -The two most commonly used smart pointers are `std::unique_ptr` and `std::shared_ptr`. +The two most commonly used smart pointers are `std::unique_ptr` and `std::shared_ptr`. ## Unique Pointers @@ -82,7 +82,7 @@ auto your_flatmates_boyfriends_account = your_flatmates_account; ``` Weak pointers are useful in scenarios where cyclic references need to be broken to prevent memory leaks. -`std::weak_ptr` was designed to address the issue of cyclic ownership, also known as circular references, that can occur when using `std::shared_ptr`. +`std::weak_ptr` was designed to address the issue of cyclic ownership, also known as circular references, that can occur when using `std::shared_ptr`. In a cyclic ownership scenario, two or more `std::shared_ptr` objects are referencing each other, creating a cycle where none of the objects can be deleted because they have strong references to each other, leading to memory leaks. `std::weak_ptr` provides a solution to this problem by allowing weak references to shared objects without contributing to their reference count. This means that it can observe and access the shared object but doesn't prevent it from being deleted. diff --git a/concepts/smart-pointers/links.json b/concepts/smart-pointers/links.json index ebcb824f9..da71e152a 100644 --- a/concepts/smart-pointers/links.json +++ b/concepts/smart-pointers/links.json @@ -11,4 +11,4 @@ "url": "https://en.cppreference.com/w/cpp/memory/weak_ptr", "description": "C++ reference on std::weak_ptr" } -] \ No newline at end of file +] diff --git a/concepts/strings/about.md b/concepts/strings/about.md index c0aabb04d..1d5d48422 100644 --- a/concepts/strings/about.md +++ b/concepts/strings/about.md @@ -1,6 +1,6 @@ # About -A `string` in C++ is a mutable object that represents text as a sequence of characters (letters, digits, punctuation, etc.). +A `string` in C++ is a mutable object that represents text as a sequence of characters (letters, digits, punctuation, etc.). Strings are manipulated by calling the string's methods. ## Strings Library @@ -32,7 +32,7 @@ Later in the syllabus, you will learn more about member functions and the connec ```cpp std::string qualification{"awesome"}; // 1st argument: from the index to the end of the string: -std::string who_is_awesome = qualification.substr(5); +std::string who_is_awesome = qualification.substr(5); // => "me" // 2nd optional argument for the length: diff --git a/concepts/strings/introduction.md b/concepts/strings/introduction.md index 8d4aa19ad..171e651a4 100644 --- a/concepts/strings/introduction.md +++ b/concepts/strings/introduction.md @@ -1,6 +1,6 @@ # Introduction -A `string` in C++ is a mutable object that represents text as a sequence of characters (letters, digits, punctuation, etc.). +A `string` in C++ is a mutable object that represents text as a sequence of characters (letters, digits, punctuation, etc.). Strings are manipulated by calling the string's methods. ## Strings Library @@ -33,7 +33,7 @@ Later in the syllabus, you will learn more about member functions and the connec ```cpp std::string qualification{"awesome"}; // 1st argument: from the index to the end of the string: -std::string who_is_awesome = qualification.substr(5); +std::string who_is_awesome = qualification.substr(5); // => "me" // 2nd optional argument for the length: diff --git a/concepts/strings/links.json b/concepts/strings/links.json index 4715085de..5ba25e76f 100644 --- a/concepts/strings/links.json +++ b/concepts/strings/links.json @@ -3,4 +3,4 @@ "url": "https://en.cppreference.com/w/cpp/string/basic_string", "description": "C++ reference on strings" } -] \ No newline at end of file +] diff --git a/concepts/switch/about.md b/concepts/switch/about.md index 3a955a5b0..500c10176 100644 --- a/concepts/switch/about.md +++ b/concepts/switch/about.md @@ -67,4 +67,4 @@ Many languages can do switches based on boolean expression or even regular expre You can think of the C++ version is an extended goto/switch construct. Only the switch statement can jump to a label. Afterwards all other labels are ignored and you have to use the `break` statement to break out of the code block. -~~~~ \ No newline at end of file +~~~~ diff --git a/concepts/switch/introduction.md b/concepts/switch/introduction.md index 8a306245d..2963c8313 100644 --- a/concepts/switch/introduction.md +++ b/concepts/switch/introduction.md @@ -58,5 +58,5 @@ case 3: default: book_house(group_size); } -// book_apartment happens wheng roup_size is 2 or 3 -``` \ No newline at end of file +// book_apartment happens when group_size is 2 or 3 +``` diff --git a/concepts/switch/links.json b/concepts/switch/links.json index d9d1a3335..477189236 100644 --- a/concepts/switch/links.json +++ b/concepts/switch/links.json @@ -2,9 +2,9 @@ { "url": "https://en.cppreference.com/w/cpp/language/switch", "description": "C++ reference on switch statements" - }, + }, { "url": "https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Res-break", "description": "CppCoreGuidelines' hints on switch statements" } -] \ No newline at end of file +] diff --git a/concepts/vector-arrays/about.md b/concepts/vector-arrays/about.md index 406ac5f73..09bab8b60 100644 --- a/concepts/vector-arrays/about.md +++ b/concepts/vector-arrays/about.md @@ -12,10 +12,10 @@ Arrays also need a size. Look at these examples to see the two container types' initializations: ```cpp -#include +#include #include -// std::array variable_name {list of elements} +// std::array variable_name {list of elements} std::array indie_rock {"yeah", "yeah", "yeah"}; // indie_rock contains the elements "yeah" three times ``` @@ -24,10 +24,10 @@ Vectors usually need more space, as they allocate memory for further growth. You do not need to specify a size: ```cpp -#include +#include -// std::vector variable_name {list of elements} -std::vector countdown {3, 2, 1}; +// std::vector variable_name {list of elements} +std::vector countdown {3, 2, 1}; // my_vector contains the elements 3, 2 and 1 ``` @@ -46,7 +46,7 @@ countdown.at(2); // => 1 countdown[1] = 4; // countdown now contains 3, 4 and 1 -indie_rock.back() = "yeahs"; +indie_rock.back() = "yeahs"; // indie_rock is now "yeah", "yeah", "yeahs" ``` @@ -55,12 +55,12 @@ indie_rock.back() = "yeahs"; ### Vector modifiers -As a `vector` is not fixed in size, it is possible to add or remove elements. +As a `vector` is not fixed in size, it is possible to add or remove elements. Two common functions for that purpose are `emplace_back` and `pop_back`. ```cpp std::vector witches {"Holly", "Alyssa", "Shannen"}; -witches.pop_back(); +witches.pop_back(); // Shannen is no longer with the witches witches.emplace_back("Rose"); // Rose has joined the team diff --git a/concepts/vector-arrays/introduction.md b/concepts/vector-arrays/introduction.md index ca28b607c..7e96cbb39 100644 --- a/concepts/vector-arrays/introduction.md +++ b/concepts/vector-arrays/introduction.md @@ -15,7 +15,7 @@ Look at these examples to see the two container types' initializations: #include #include -// std::array variable_name {list of elements} +// std::array variable_name {list of elements} std::array indie_rock {"yeah", "yeah", "yeah"}; // indie_rock contains the elements "yeah" three times ``` @@ -46,7 +46,7 @@ countdown.at(2); // => 1 countdown[1] = 4; // countdown now contains 3, 4 and 1 -indie_rock.back() = "yeahs"; +indie_rock.back() = "yeahs"; // indie_rock is now "yeah", "yeah", "yeahs" ``` @@ -55,12 +55,12 @@ indie_rock.back() = "yeahs"; ### Vector modifiers -As a `vector` is not fixed in size, it is possible to add or remove elements. +As a `vector` is not fixed in size, it is possible to add or remove elements. Two common functions for that purpose are `emplace_back` and `pop_back`. ```cpp std::vector witches {"Holly", "Alyssa", "Shannen"}; -witches.pop_back(); +witches.pop_back(); // Shannen is no longer with the witches witches.emplace_back("Rose"); // Rose has joined the team diff --git a/concepts/vector-arrays/links.json b/concepts/vector-arrays/links.json index 781f24945..2699bfe12 100644 --- a/concepts/vector-arrays/links.json +++ b/concepts/vector-arrays/links.json @@ -7,4 +7,4 @@ "url": "https://en.cppreference.com/w/cpp/container/vector", "description": "C++ reference on vectors" } -] \ No newline at end of file +] diff --git a/config.json b/config.json index 935751bff..5e5b97153 100644 --- a/config.json +++ b/config.json @@ -196,6 +196,30 @@ "references", "headers" ] + }, + { + "slug": "power-of-troy", + "name": "Power of Troy", + "uuid": "9f5e64e5-2838-4237-9cc6-fef500aacd7b", + "concepts": [ + "auto", + "smart-pointers" + ], + "prerequisites": [ + "pointers" + ] + }, + { + "slug": "speedywagon", + "name": "Speedywagon Foundation", + "uuid": "ed2148a5-674c-4660-a050-b11ab240b876", + "concepts": [ + "pointers" + ], + "prerequisites": [ + "classes", + "references" + ] } ], "practice": [ @@ -302,7 +326,7 @@ }, { "slug": "two-fer", - "name": "Two Fer", + "name": "Two-Fer", "uuid": "95a162a4-d825-4874-9e2f-014787cbdfb5", "practices": [], "prerequisites": [], @@ -997,7 +1021,7 @@ }, { "slug": "isbn-verifier", - "name": "Isbn Verifier", + "name": "ISBN Verifier", "uuid": "5fcc6fd8-1dc7-4493-970a-731c7602b229", "practices": [], "prerequisites": [], @@ -1010,7 +1034,7 @@ }, { "slug": "linked-list", - "name": "Linked List ", + "name": "Linked List", "uuid": "6f6c55dd-db6b-40ca-96f2-d9b7232dcbb0", "practices": [], "prerequisites": [], @@ -1024,7 +1048,7 @@ }, { "slug": "simple-linked-list", - "name": "Simple linked list", + "name": "Simple Linked List", "uuid": "ffccabe9-9779-4914-9cff-c6f5696c8afe", "practices": [ "pointers" @@ -1107,13 +1131,22 @@ "prerequisites": [], "difficulty": 3 }, + { + "slug": "flower-field", + "name": "Flower Field", + "uuid": "d17d040b-b214-4079-ad3e-b518f776aeeb", + "practices": [], + "prerequisites": [], + "difficulty": 5 + }, { "slug": "minesweeper", "name": "Minesweeper", "uuid": "3753a72a-78b7-429f-b79a-f68d55a00387", "practices": [], "prerequisites": [], - "difficulty": 5 + "difficulty": 5, + "status": "deprecated" }, { "slug": "sublist", @@ -1206,6 +1239,62 @@ "practices": [], "prerequisites": [], "difficulty": 4 + }, + { + "slug": "rail-fence-cipher", + "name": "Rail Fence Cipher", + "uuid": "8a7f6f8c-ff36-4afd-9ab3-6dbd355d0263", + "practices": [], + "prerequisites": [ + "basics", + "namespaces", + "loops", + "numbers", + "strings" + ], + "difficulty": 4 + }, + { + "slug": "affine-cipher", + "name": "Affine Cipher", + "uuid": "61374c16-0a99-4616-9244-a38919eafbe1", + "practices": [ + "math", + "exceptions" + ], + "prerequisites": [ + "functions", + "comparisons", + "loops", + "booleans" + ], + "difficulty": 6 + }, + { + "slug": "alphametics", + "name": "Alphametics", + "uuid": "0c69f8bd-c99a-4cb2-b113-82deaf0915ee", + "practices": [ + "auto", + "literals" + ], + "prerequisites": [ + "includes", + "namespaces", + "if-statements", + "booleans", + "headers", + "comparisons" + ], + "difficulty": 6 + }, + { + "slug": "twelve-days", + "name": "Twelve Days", + "uuid": "0daec3e8-a0d1-49e8-9de5-0ad73f9c3243", + "practices": [], + "prerequisites": [], + "difficulty": 3 } ], "foregone": [ @@ -1293,6 +1382,11 @@ "slug": "functions", "name": "Functions" }, + { + "uuid": "c071a5e8-796c-4538-945a-3bdd2006fc2b", + "slug": "pointers", + "name": "Pointers" + }, { "uuid": "0316eb64-d1e9-44cc-b7d4-ea4b88f85ac3", "slug": "smart-pointers", diff --git a/docs/INSTALLATION.md b/docs/INSTALLATION.md index 8d6331522..aea73633f 100644 --- a/docs/INSTALLATION.md +++ b/docs/INSTALLATION.md @@ -64,6 +64,20 @@ of the Microsoft Visual C++ compiler. You should be able to use other integrated IDE's such as JetBrains' CLion in a similar manner. +### Installing Boost on Windows + +The `meetup` and `gigasecond` exercises depend on the [Boost][boost-website] libraries. +The following steps describe how to set that up. + +1. Download the [prebuilt windows libraries][sourceforge-boost-binaries] for Boost. + - The exercises require a minimum Boost version of 1.58. + - You can find the version of MSVC by clicking "Modify" in the Visual Studio Installer. +1. Extract the libraries to a local folder. +1. Set the `BOOST_ROOT` environment variable to the folder where you installed the Boost libraries. +1. If you had Visual Studio open while doing this, close it to make sure the value of `BOOST_ROOT` gets picked up. +1. Start Visual Studio and open the folder containing the `gigasecond` or `meetup` exercise. +1. The "Startup Item" should be `gigasecond.exe` or `meetup.exe` and you should get build errors in either `gigasecond_test.cpp` or `meetup_test.cpp` telling you to implement missing items, similar to the other exercises. + ## Linux All recent Linux distribution releases have compatible C++14 compilers, you @@ -86,3 +100,7 @@ to figure out how to install the minimum compiler version. MacOS users can install GCC with [Homebrew](http://brew.sh/) via `brew install gcc`. + + +[boost-website]: https://www.boost.org/ +[sourceforge-boost-binaries]: https://sourceforge.net/projects/boost/files/boost-binaries/ diff --git a/docs/TESTS.md b/docs/TESTS.md index 3aebe9786..5b659c291 100644 --- a/docs/TESTS.md +++ b/docs/TESTS.md @@ -54,6 +54,7 @@ code using the appropriate command for your environment: * Linux with make: `make` * Windows with Visual Studio: Select Build / Build Solution from the menu. * MacOS with Xcode: Select Build from the toolbar +* MacOS with "Unix Makefile": `make` _If using the exercism CLI app_ Examples of running CMake for different environments are shown below. @@ -73,8 +74,8 @@ $ make This example shows creating empty files for the implementation before running CMake. -Simply type `make` in the build directory to compile the tests. This should -generate compile time errors. Once the errors are fixed, `make` will build and +Simply type `make` in the build directory to compile the tests. This should +generate compile time errors. Once the errors are fixed, `make` will build and run the tests. ### Windows with Visual Studio @@ -97,7 +98,7 @@ $ cmake -G Xcode .. ``` This example generates the XCode files so that you can open the project in XCode. -With the project opened in XCode you may need to add another target. +With the project opened in XCode you may need to add another target. For a new target go to File -> New -> Target from the menu, _OS X \ Application \ Command Line Tool_ -> Next _C++_ as the language and provide a target name. Run the code using the target. If your terminal throws an `Xcode x.x not supported` error, it is highly likely that Xcode is not installed on your machine or that your version is out of date. @@ -105,4 +106,24 @@ Please download and install Xcode via the App Store or via [this link][web-xcode Errors similar to `The CXX compiler identification is unknown` will likely be resolved by following the [instructions to install GCC][cpp-installation-instructions] or by adding another target in Xcode as per the above paragraph. [web-xcode-download]: https://apps.apple.com/us/app/xcode/id497799835?mt=12 -[cpp-installation-instructions]: https://exercism.org/docs/tracks/cpp/installation \ No newline at end of file +[cpp-installation-instructions]: https://exercism.org/docs/tracks/cpp/installation + +### MacOS with Make _when using the Exercism CLI_ +#### This example specifically assists those who want to use the Exercism CLI app for configuring, testing, and submitting their C++ exercises. + +The generator name for CMake is `Unix Makefiles`. +Assuming the current exercise is `bob` and we're in the exercise folder: + +```sh +$ touch bob.{h,cpp} +$ cmake -G "Unix Makefiles" . +$ exercism test +``` + +In this example, we do create empty files for the implementation before running CMake, but we do **not** create an empty build directory. +This is because the Exercism CLI uses the `.exercism/metadata.json` file in the root directory to parse the test cases. + +Simply type `exercism test` in the root directory to compile the tests. This should generate compile-time errors. +Once the errors are fixed, running `exercism test` again will build and execute the tests using the Exercism CLI. + +[cpp-installation-instructions]: https://exercism.org/docs/tracks/cpp/installation diff --git a/exercises/concept/doctor-data/.docs/instructions.md b/exercises/concept/doctor-data/.docs/instructions.md index 309546279..52ae5f14c 100644 --- a/exercises/concept/doctor-data/.docs/instructions.md +++ b/exercises/concept/doctor-data/.docs/instructions.md @@ -38,7 +38,7 @@ You even got one of the enumerations: `BetaHydri`. Prepare the source and header files with your discovered information. You need two namespaces: `heaven` and `star_map`. The `heaven` namespace has a class `Vessel`, which can be called with two or three arguments. -The `System` enum is to be placed in the `star_map` namespace and has an `EpsilonEridani` enumeration. +The `System` enum is to be placed in the `star_map` namespace and has an `BetaHydri` enumeration. Keep an eye out for other enumerations, so that you can constantly update the `System` enum. ## 2. Find more details @@ -105,4 +105,4 @@ You see two functions, that are not members of the `Vessel` class, as they are n Implement the last missing functions from the recovered lines above. -[van-neumann-probes]: https://en.wikipedia.org/wiki/Self-replicating_spacecraft \ No newline at end of file +[van-neumann-probes]: https://en.wikipedia.org/wiki/Self-replicating_spacecraft diff --git a/exercises/concept/doctor-data/.docs/introduction.md b/exercises/concept/doctor-data/.docs/introduction.md index c8d9c68ff..e7db48e12 100644 --- a/exercises/concept/doctor-data/.docs/introduction.md +++ b/exercises/concept/doctor-data/.docs/introduction.md @@ -10,7 +10,7 @@ The header file will tell you _what_ a codebase has to offer without going into The most common file extension for header files is `.h`. Some projects use `.hpp` or skip the extension completely. -The definitions are located in a separate `.cpp` file. +The definitions are located in a separate `.cpp` file. To reunite the parts, the source file starts by _including_ the respective header file. If you want to write a library called "quick_math" that offers a function "super_root" that you want to use often, the files would look like this: @@ -81,7 +81,7 @@ int robots::Flower::get_size() {return size;} When the header is used as an API overview, that is where a person would look for information like default values. The `size` parameter's default of the constructor is therefore handled in the header and not in the implementation. The definitions in the source file are prefixed with the namespace `robots` and the class type `Flower`. - + Another layout option is a _header only_ library, that does not have a `.cpp` file at all: ```cpp diff --git a/exercises/concept/doctor-data/.docs/introduction.md.tpl b/exercises/concept/doctor-data/.docs/introduction.md.tpl index 70899ec3d..4bc156890 100644 --- a/exercises/concept/doctor-data/.docs/introduction.md.tpl +++ b/exercises/concept/doctor-data/.docs/introduction.md.tpl @@ -1,3 +1,3 @@ # Introduction -%{concept:headers} \ No newline at end of file +%{concept:headers} diff --git a/exercises/concept/doctor-data/CMakeLists.txt b/exercises/concept/doctor-data/CMakeLists.txt index 3b0589fd0..dba98a931 100644 --- a/exercises/concept/doctor-data/CMakeLists.txt +++ b/exercises/concept/doctor-data/CMakeLists.txt @@ -55,9 +55,12 @@ if(${EXERCISM_RUN_ALL_TESTS}) endif() # Tell MSVC not to warn us about unchecked iterators in debug builds +# Treat warnings as errors +# Treat type conversion warnings C4244 and C4267 as level 4 warnings, i.e. ignore them in level 3 if(${MSVC}) set_target_properties(${exercise} PROPERTIES - COMPILE_DEFINITIONS_DEBUG _SCL_SECURE_NO_WARNINGS) + COMPILE_DEFINITIONS_DEBUG _SCL_SECURE_NO_WARNINGS + COMPILE_FLAGS "/WX /w44244 /w44267") endif() # Run the tests on every build diff --git a/exercises/concept/doctor-data/doctor_data.cpp b/exercises/concept/doctor-data/doctor_data.cpp index 0771dfcfe..7e069e14c 100644 --- a/exercises/concept/doctor-data/doctor_data.cpp +++ b/exercises/concept/doctor-data/doctor_data.cpp @@ -1,4 +1,4 @@ // ERROR: FILE CORRUPTED. Please supply valid C++ Code. hp4,ölacöiömthö%Äsmaö%Äsubö(311040ö%Äspaö%Äaddö(311040ö%Ädacöiömthö%Äcountö.hpt,hp4ö%Äxctöhd2ö%Ädacöiöma1 -hp2,öjmpö. \ No newline at end of file +hp2,öjmpö. diff --git a/exercises/concept/doctor-data/doctor_data.h b/exercises/concept/doctor-data/doctor_data.h index d4ea27b06..54aa69087 100644 --- a/exercises/concept/doctor-data/doctor_data.h +++ b/exercises/concept/doctor-data/doctor_data.h @@ -1,3 +1,8 @@ // ERROR: FILE CORRUPTED. Please supply valid C++ Code. -hp1,üapöhp2ö%Äcountöiöma1,öhp2ö%Älawöhp3öö/önextöstepö%Ädacöiöml1ö%Älawö7ö%Ädacöiömb1ö%Ärandomöö%Äscrö9sö%Äsirö9sö%Äxctöhr1ö%Äaddöiömx1ö%Ädacöiömx1ö%Äswapö%Äaddöiömy1ö%Ädacöiömy1ö%Ärandomö%Äscrö9sö%Äsirö9sö%Äxctöhr2ö%Ädacöiömdyö%Ädioöiömdxö%Äsetupö.hpt,3ö%Älacöranö%Ädacöiömth +hp1, üapöhp2ö % Äcountöiöma1, + öhp2ö % Älawöhp3öö / önextöstepö % Ädacöiöml1ö % Älawö7ö % Ädacöiömb1ö % + Ärandomöö % Äscrö9sö % Äsirö9sö % Äxctöhr1ö % Äaddöiömx1ö % + Ädacöiömx1ö % Äswapö % Äaddöiömy1ö % Ädacöiömy1ö % Ärandomö % Äscrö9sö % + Äsirö9sö % Äxctöhr2ö % Ädacöiömdyö % Ädioöiömdxö % Äsetupö.hpt, + 3ö % Älacöranö % Ädacöiömth diff --git a/exercises/concept/doctor-data/test/catch.hpp b/exercises/concept/doctor-data/test/catch.hpp index 36eaeb27f..ff40b4fd6 100644 --- a/exercises/concept/doctor-data/test/catch.hpp +++ b/exercises/concept/doctor-data/test/catch.hpp @@ -3175,8 +3175,8 @@ namespace Detail { } // end namespace Detail namespace literals { - Detail::Approx operator "" _a(long double val); - Detail::Approx operator "" _a(unsigned long long val); + Detail::Approx operator ""_a(long double val); + Detail::Approx operator ""_a(unsigned long long val); } // end namespace literals template<> @@ -7911,10 +7911,10 @@ namespace Detail { } // end namespace Detail namespace literals { - Detail::Approx operator "" _a(long double val) { + Detail::Approx operator ""_a(long double val) { return Detail::Approx(val); } - Detail::Approx operator "" _a(unsigned long long val) { + Detail::Approx operator ""_a(unsigned long long val) { return Detail::Approx(val); } } // end namespace literals diff --git a/exercises/concept/election-day/.docs/hints.md b/exercises/concept/election-day/.docs/hints.md index 62dc5315e..b21eed65f 100644 --- a/exercises/concept/election-day/.docs/hints.md +++ b/exercises/concept/election-day/.docs/hints.md @@ -16,10 +16,10 @@ - You need to create a function with a `reference` to an `ElectionResult`, in other words, a `ElectionResult&`. - - Although you are receiving a `reference` to an `ElectionResult`, you can change its member variables with the dot `.` notation, as if it wasn't a `reference`! -## 3. Vote counting and Presidency +## 3. Vote counting and Presidency - You can iterate a reference to a `vector` like a normal vector with a loop. - You can get the size of a vector with `myvector.size()`. -[learncpp-references]: https://www.learncpp.com/cpp-tutorial/lvalue-references/ \ No newline at end of file +[learncpp-references]: https://www.learncpp.com/cpp-tutorial/lvalue-references/ diff --git a/exercises/concept/election-day/.docs/instructions.md b/exercises/concept/election-day/.docs/instructions.md index 14a71a670..9a4a29946 100644 --- a/exercises/concept/election-day/.docs/instructions.md +++ b/exercises/concept/election-day/.docs/instructions.md @@ -22,7 +22,7 @@ struct ElectionResult { }; ``` -As all members in the `struct` are public, you don't need to write a `constructor` to initialize an `ElectionResult` object. +As all members in the `struct` are public, you don't need to write a `constructor` to initialize an `ElectionResult` object. You can use an `initializer list` instead: ```cpp @@ -53,12 +53,12 @@ vote_count(burr); // => 1804 ``` -## 3. Vote counting and Presidency +## 3. Vote counting and Presidency The school handed in their votes and it is now time to check the results for the winner. Create a function `determine_result` that receives a reference to a final count and returns a reference to the `ElectionResult` of the new president. -It should also change the name of the winner by prefixing it with "President". +It should also change the name of the winner by prefixing it with "President". The final count is given in the form of a `reference` to `std::vector`, a vector with `ElectionResults` of all the participating candidates. ```cpp @@ -74,4 +74,4 @@ winner.name; To keep things simple, you can assume the following: - The `vector` has at least one element. -- There will be no ties for first place. \ No newline at end of file +- There will be no ties for first place. diff --git a/exercises/concept/election-day/.docs/introduction.md b/exercises/concept/election-day/.docs/introduction.md index 2bf28e118..c0c5d2e69 100644 --- a/exercises/concept/election-day/.docs/introduction.md +++ b/exercises/concept/election-day/.docs/introduction.md @@ -54,8 +54,8 @@ int& future_budget; ### `void` -With the power of `references` you might not need to return a value from a function at all. -`void` is used as a return type in this scenario. +With the power of `references` you might not need to return a value from a function at all. +`void` is used as a return type in this scenario. ```cpp void increase_power(int& level) { diff --git a/exercises/concept/election-day/.docs/introduction.md.tpl b/exercises/concept/election-day/.docs/introduction.md.tpl index ee0e6b3df..d67949a9d 100644 --- a/exercises/concept/election-day/.docs/introduction.md.tpl +++ b/exercises/concept/election-day/.docs/introduction.md.tpl @@ -1,3 +1,3 @@ # Introduction -%{concept:references} \ No newline at end of file +%{concept:references} diff --git a/exercises/concept/election-day/.meta/design.md b/exercises/concept/election-day/.meta/design.md index 15393c32f..a7cc939ba 100644 --- a/exercises/concept/election-day/.meta/design.md +++ b/exercises/concept/election-day/.meta/design.md @@ -24,4 +24,4 @@ The Concepts this exercise unlocks are: ## Prerequisites - `classes` -- `strings` \ No newline at end of file +- `strings` diff --git a/exercises/concept/election-day/.meta/exemplar.cpp b/exercises/concept/election-day/.meta/exemplar.cpp index e1202866b..a630b57c2 100644 --- a/exercises/concept/election-day/.meta/exemplar.cpp +++ b/exercises/concept/election-day/.meta/exemplar.cpp @@ -31,7 +31,7 @@ void increment_vote_count(ElectionResult& result, int votes) { ElectionResult& determine_result(std::vector& count) { int winner_idx = 0; for (int i{}; i < count.size(); ++i) { - if(count.at(i).votes > count.at(winner_idx).votes) { + if (count.at(i).votes > count.at(winner_idx).votes) { winner_idx = i; } } diff --git a/exercises/concept/election-day/CMakeLists.txt b/exercises/concept/election-day/CMakeLists.txt index e46606bd5..ba6b66368 100644 --- a/exercises/concept/election-day/CMakeLists.txt +++ b/exercises/concept/election-day/CMakeLists.txt @@ -58,9 +58,12 @@ if(${EXERCISM_RUN_ALL_TESTS}) endif() # Tell MSVC not to warn us about unchecked iterators in debug builds +# Treat warnings as errors +# Treat type conversion warnings C4244 and C4267 as level 4 warnings, i.e. ignore them in level 3 if(${MSVC}) set_target_properties(${exercise} PROPERTIES - COMPILE_DEFINITIONS_DEBUG _SCL_SECURE_NO_WARNINGS) + COMPILE_DEFINITIONS_DEBUG _SCL_SECURE_NO_WARNINGS + COMPILE_FLAGS "/WX /w44244 /w44267") endif() # Run the tests on every build diff --git a/exercises/concept/election-day/election_day.cpp b/exercises/concept/election-day/election_day.cpp index 67ab88890..f568210bf 100644 --- a/exercises/concept/election-day/election_day.cpp +++ b/exercises/concept/election-day/election_day.cpp @@ -16,13 +16,11 @@ struct ElectionResult { // vote_count takes a reference to an `ElectionResult` as an argument and will // return the number of votes in the `ElectionResult. - // TODO: Task 2 // increment_vote_count takes a reference to an `ElectionResult` as an argument // and a number of votes (int), and will increment the `ElectionResult` by that // number of votes. - // TODO: Task 3 // determine_result receives the reference to a final_count and returns a // reference to the `ElectionResult` of the new president. It also changes the @@ -30,5 +28,4 @@ struct ElectionResult { // in the form of a `reference` to `std::vector`, a vector with // `ElectionResults` of all the participating candidates. - -} // namespace election \ No newline at end of file +} // namespace election diff --git a/exercises/concept/election-day/election_day_test.cpp b/exercises/concept/election-day/election_day_test.cpp index ce22962d4..b6b060498 100644 --- a/exercises/concept/election-day/election_day_test.cpp +++ b/exercises/concept/election-day/election_day_test.cpp @@ -63,7 +63,6 @@ TEST_CASE("Presidency, two candidates", "[task_3]") { REQUIRE(result.name == expected); } - TEST_CASE("Presidency, several candidates", "[task_3]") { ElectionResult option1{"David", 11}; ElectionResult option2{"Shaw", 12}; diff --git a/exercises/concept/election-day/test/catch.hpp b/exercises/concept/election-day/test/catch.hpp index 36eaeb27f..ff40b4fd6 100644 --- a/exercises/concept/election-day/test/catch.hpp +++ b/exercises/concept/election-day/test/catch.hpp @@ -3175,8 +3175,8 @@ namespace Detail { } // end namespace Detail namespace literals { - Detail::Approx operator "" _a(long double val); - Detail::Approx operator "" _a(unsigned long long val); + Detail::Approx operator ""_a(long double val); + Detail::Approx operator ""_a(unsigned long long val); } // end namespace literals template<> @@ -7911,10 +7911,10 @@ namespace Detail { } // end namespace Detail namespace literals { - Detail::Approx operator "" _a(long double val) { + Detail::Approx operator ""_a(long double val) { return Detail::Approx(val); } - Detail::Approx operator "" _a(unsigned long long val) { + Detail::Approx operator ""_a(unsigned long long val) { return Detail::Approx(val); } } // end namespace literals diff --git a/exercises/concept/ellens-alien-game/.docs/hints.md b/exercises/concept/ellens-alien-game/.docs/hints.md index 279798ef6..0551e83f1 100644 --- a/exercises/concept/ellens-alien-game/.docs/hints.md +++ b/exercises/concept/ellens-alien-game/.docs/hints.md @@ -19,4 +19,4 @@ ## 5. The `collision_detection` Function -- All `public` member variables can be accessed from outside the class. \ No newline at end of file +- All `public` member variables can be accessed from outside the class. diff --git a/exercises/concept/ellens-alien-game/.docs/instructions.md b/exercises/concept/ellens-alien-game/.docs/instructions.md index 17184177f..0382739ab 100644 --- a/exercises/concept/ellens-alien-game/.docs/instructions.md +++ b/exercises/concept/ellens-alien-game/.docs/instructions.md @@ -36,7 +36,7 @@ Ellen wants to introduce shields at a later point, which would then report `fals ```cpp Alien alien {0, 0}; -alien.get_health(); +alien.get_health(); // => 3 (Initial health value) alien.hit(); // Decrements health by 1 point. @@ -80,7 +80,7 @@ alien.y_coordinate; ## 5. The `collision_detection` Function If the aliens can be hit by something, then they need to be able to detect when such a collision might occur. -Ellen needs to know if two aliens occupy the same coordinates. +Ellen needs to know if two aliens occupy the same coordinates. The `collision_detection()` function takes another alien object as an argument and returns a `bool`. ```cpp @@ -91,4 +91,4 @@ lrrr.collision_detection(ndnd); ndnd.teleport(3, 6); ndnd.collision_detection(lrrr); // => true -``` \ No newline at end of file +``` diff --git a/exercises/concept/ellens-alien-game/.docs/introduction.md b/exercises/concept/ellens-alien-game/.docs/introduction.md index f640213ad..75c25927d 100644 --- a/exercises/concept/ellens-alien-game/.docs/introduction.md +++ b/exercises/concept/ellens-alien-game/.docs/introduction.md @@ -54,7 +54,7 @@ silverhand.cast_spell(); silverhand.name = "Laeral"; // damage is private: -silverhand.damage = 500; +silverhand.damage = 500; // => Compilation error ``` diff --git a/exercises/concept/ellens-alien-game/.docs/introduction.md.tpl b/exercises/concept/ellens-alien-game/.docs/introduction.md.tpl index ccc7c42df..5fd766bb8 100644 --- a/exercises/concept/ellens-alien-game/.docs/introduction.md.tpl +++ b/exercises/concept/ellens-alien-game/.docs/introduction.md.tpl @@ -1,3 +1,3 @@ # Introduction -%{concept:classes} \ No newline at end of file +%{concept:classes} diff --git a/exercises/concept/ellens-alien-game/.meta/design.md b/exercises/concept/ellens-alien-game/.meta/design.md index b6c340710..ea87e7cea 100644 --- a/exercises/concept/ellens-alien-game/.meta/design.md +++ b/exercises/concept/ellens-alien-game/.meta/design.md @@ -41,4 +41,4 @@ These are the concepts/concept exercises the student needs to complete/understan ## Resources -- [Class (and struct) tutorial)](https://www.learncpp.com/cpp-tutorial/classes-and-class-members/) \ No newline at end of file +- [Class (and struct) tutorial)](https://www.learncpp.com/cpp-tutorial/classes-and-class-members/) diff --git a/exercises/concept/ellens-alien-game/.meta/exemplar.cpp b/exercises/concept/ellens-alien-game/.meta/exemplar.cpp index e670bc74a..85331a31c 100644 --- a/exercises/concept/ellens-alien-game/.meta/exemplar.cpp +++ b/exercises/concept/ellens-alien-game/.meta/exemplar.cpp @@ -28,4 +28,4 @@ class Alien { private: int health{3}; }; -} // namespace targets \ No newline at end of file +} // namespace targets diff --git a/exercises/concept/ellens-alien-game/CMakeLists.txt b/exercises/concept/ellens-alien-game/CMakeLists.txt index b79c51e67..8e21222a2 100644 --- a/exercises/concept/ellens-alien-game/CMakeLists.txt +++ b/exercises/concept/ellens-alien-game/CMakeLists.txt @@ -57,9 +57,12 @@ if(${EXERCISM_RUN_ALL_TESTS}) endif() # Tell MSVC not to warn us about unchecked iterators in debug builds +# Treat warnings as errors +# Treat type conversion warnings C4244 and C4267 as level 4 warnings, i.e. ignore them in level 3 if(${MSVC}) set_target_properties(${exercise} PROPERTIES - COMPILE_DEFINITIONS_DEBUG _SCL_SECURE_NO_WARNINGS) + COMPILE_DEFINITIONS_DEBUG _SCL_SECURE_NO_WARNINGS + COMPILE_FLAGS "/WX /w44244 /w44267") endif() # Run the tests on every build diff --git a/exercises/concept/ellens-alien-game/ellens_alien_game.cpp b/exercises/concept/ellens-alien-game/ellens_alien_game.cpp index 98820f043..ccffc7258 100644 --- a/exercises/concept/ellens-alien-game/ellens_alien_game.cpp +++ b/exercises/concept/ellens-alien-game/ellens_alien_game.cpp @@ -1,4 +1,4 @@ namespace targets { // TODO: Insert the code for the alien class here -} // namespace targets \ No newline at end of file +} // namespace targets diff --git a/exercises/concept/ellens-alien-game/ellens_alien_game_test.cpp b/exercises/concept/ellens-alien-game/ellens_alien_game_test.cpp index e1b719074..cbd5e6a4f 100644 --- a/exercises/concept/ellens-alien-game/ellens_alien_game_test.cpp +++ b/exercises/concept/ellens-alien-game/ellens_alien_game_test.cpp @@ -32,7 +32,9 @@ TEST_CASE("Alien is always hit", "[task_2]") { REQUIRE(alien.hit()); } -TEST_CASE("Alien is alive while health is greater than 0 and stays dead afterwards", "[task_3]") { +TEST_CASE( + "Alien is alive while health is greater than 0 and stays dead afterwards", + "[task_3]") { Alien alien{2, 54}; REQUIRE(alien.is_alive()); alien.hit(); @@ -43,6 +45,7 @@ TEST_CASE("Alien is alive while health is greater than 0 and stays dead afterwar REQUIRE(!alien.is_alive()); alien.hit(); REQUIRE(!alien.is_alive()); + REQUIRE(alien.get_health() == 0); } TEST_CASE("Alien Teleports reports succesful", "[task_4]") { diff --git a/exercises/concept/ellens-alien-game/test/catch.hpp b/exercises/concept/ellens-alien-game/test/catch.hpp index 36eaeb27f..ff40b4fd6 100644 --- a/exercises/concept/ellens-alien-game/test/catch.hpp +++ b/exercises/concept/ellens-alien-game/test/catch.hpp @@ -3175,8 +3175,8 @@ namespace Detail { } // end namespace Detail namespace literals { - Detail::Approx operator "" _a(long double val); - Detail::Approx operator "" _a(unsigned long long val); + Detail::Approx operator ""_a(long double val); + Detail::Approx operator ""_a(unsigned long long val); } // end namespace literals template<> @@ -7911,10 +7911,10 @@ namespace Detail { } // end namespace Detail namespace literals { - Detail::Approx operator "" _a(long double val) { + Detail::Approx operator ""_a(long double val) { return Detail::Approx(val); } - Detail::Approx operator "" _a(unsigned long long val) { + Detail::Approx operator ""_a(unsigned long long val) { return Detail::Approx(val); } } // end namespace literals diff --git a/exercises/concept/freelancer-rates/.docs/instructions.md b/exercises/concept/freelancer-rates/.docs/instructions.md index e7ae74588..d6b95b3ca 100644 --- a/exercises/concept/freelancer-rates/.docs/instructions.md +++ b/exercises/concept/freelancer-rates/.docs/instructions.md @@ -26,7 +26,7 @@ The returned daily rate should be of type `double`. ## 2. Calculate a discounted price -Implement a function `apply_discount` to calculates the price after a discount. +Implement a function `apply_discount` to calculate the price after a discount. It should accept two parameters: the original price and the discount rate in percent. ```cpp diff --git a/exercises/concept/freelancer-rates/.docs/introduction.md b/exercises/concept/freelancer-rates/.docs/introduction.md index a97f047d8..83c6c1419 100644 --- a/exercises/concept/freelancer-rates/.docs/introduction.md +++ b/exercises/concept/freelancer-rates/.docs/introduction.md @@ -4,7 +4,7 @@ Integers are whole numbers like `0`, `691`, or `-2`. Floating point numbers are numbers with a decimal point like `6.02214076`, `0.1`, or `-1.616`. ## Integers -The following example shows the declaration and initialization of four different variables +The following example shows the declaration and initialization of four different variables ```cpp int m_morales{9241}; // base 10: 0-9 @@ -19,7 +19,7 @@ A literal is a hard-coded number like `9241`. There are different integer literals for several bases of the representation. Decimal integer literals are the most common and use the digits `0` to `9`. By adding a special prefix, like `0x`, it is possible to use other bases. -The example above shows the number `9421` in its four representations and prefixes. +The example above shows the number `9241` in its four representations and prefixes. All variables are initialized to the same value. For more details on the different representation systems, take a look at [a small tutorial][cpp_numerical_bases]. @@ -29,7 +29,7 @@ You can use an apostrophe to separate digits for easier readability. ## Floating-Point Numbers -The floating-point literals come in two flavors. +The floating-point literals come in two flavors. In addition to the intuitive `0.0024` it is possible to use its scientific notation `2.4e-3`. The most common floating-point type is `double`. @@ -60,15 +60,15 @@ Consider also that we are only assigning the value of `width` to `length` at the Therefore, if the value of `width` changes at a later moment, it will not affect the value taken by `length`. Assignment operator can be combined with the other operators(arithmetic & bitwise) known as `compound assignment` operators `+=`, `-=`, `*=`, `/=`, `%=`. -These operators modifies the current value of a variable by performing an operation on it. +These operators modify the current value of a variable by performing an operation on it. ```cpp // we start with 0 people int people{}; // we need 0 eggs -int eggs{}; +int eggs{}; // two people joined: -people += 2; +people += 2; // people is now 2 // let's add 3 eggs per person eggs += 3 * people; diff --git a/exercises/concept/freelancer-rates/.docs/introduction.md.tpl b/exercises/concept/freelancer-rates/.docs/introduction.md.tpl index 376f97b27..ce74d2829 100644 --- a/exercises/concept/freelancer-rates/.docs/introduction.md.tpl +++ b/exercises/concept/freelancer-rates/.docs/introduction.md.tpl @@ -1,3 +1,3 @@ # Introduction -%{concept:numbers} \ No newline at end of file +%{concept:numbers} diff --git a/exercises/concept/freelancer-rates/.meta/exemplar.cpp b/exercises/concept/freelancer-rates/.meta/exemplar.cpp index 89d8bc823..82035a4be 100644 --- a/exercises/concept/freelancer-rates/.meta/exemplar.cpp +++ b/exercises/concept/freelancer-rates/.meta/exemplar.cpp @@ -19,9 +19,8 @@ int monthly_rate(double hourly_rate, double discount) { int workdays_per_month{22}; double per_month{per_day * workdays_per_month}; double after_discount{apply_discount(per_month, discount)}; - int rounded_up{std::ceil(after_discount)}; - return rounded_up; + return std::ceil(after_discount); } // days_in_budget calculates the number of workdays given a budget, hourly rate, @@ -32,4 +31,4 @@ int days_in_budget(int budget, double hourly_rate, double discount) { double discounted_daily{daily_rate(discounted_per_hour)}; return static_cast(budget / discounted_daily); -} \ No newline at end of file +} diff --git a/exercises/concept/freelancer-rates/CMakeLists.txt b/exercises/concept/freelancer-rates/CMakeLists.txt index b79c51e67..8e21222a2 100644 --- a/exercises/concept/freelancer-rates/CMakeLists.txt +++ b/exercises/concept/freelancer-rates/CMakeLists.txt @@ -57,9 +57,12 @@ if(${EXERCISM_RUN_ALL_TESTS}) endif() # Tell MSVC not to warn us about unchecked iterators in debug builds +# Treat warnings as errors +# Treat type conversion warnings C4244 and C4267 as level 4 warnings, i.e. ignore them in level 3 if(${MSVC}) set_target_properties(${exercise} PROPERTIES - COMPILE_DEFINITIONS_DEBUG _SCL_SECURE_NO_WARNINGS) + COMPILE_DEFINITIONS_DEBUG _SCL_SECURE_NO_WARNINGS + COMPILE_FLAGS "/WX /w44244 /w44267") endif() # Run the tests on every build diff --git a/exercises/concept/freelancer-rates/freelancer_rates.cpp b/exercises/concept/freelancer-rates/freelancer_rates.cpp index cdf8897b5..3f57eb000 100644 --- a/exercises/concept/freelancer-rates/freelancer_rates.cpp +++ b/exercises/concept/freelancer-rates/freelancer_rates.cpp @@ -29,4 +29,4 @@ int days_in_budget(int budget, double hourly_rate, double discount) { // TODO: Implement a function that takes a budget, an hourly rate, and a // discount, and calculates how many complete days of work that covers. return 0; -} \ No newline at end of file +} diff --git a/exercises/concept/freelancer-rates/freelancer_rates_test.cpp b/exercises/concept/freelancer-rates/freelancer_rates_test.cpp index 857af4e83..91e03a031 100644 --- a/exercises/concept/freelancer-rates/freelancer_rates_test.cpp +++ b/exercises/concept/freelancer-rates/freelancer_rates_test.cpp @@ -5,23 +5,33 @@ #include "test/catch.hpp" #endif +// About the REQUIRE_THAT macro: +// If unsure about the syntax of this test see: +// https://github.com/catchorg/Catch2/blob/devel/docs/comparing-floating-point-numbers.md#withinrel + using namespace std; -TEST_CASE("it's the hourly_rate times 8", "[task_1]") { REQUIRE(daily_rate(50) == 400.0); } +TEST_CASE("it's the hourly_rate times 8", "[task_1]") { + REQUIRE_THAT(daily_rate(50), Catch::Matchers::WithinRel(400.0, 0.000001)); +} #if defined(EXERCISM_RUN_ALL_TESTS) -TEST_CASE("it always returns a float", "[task_1]") { REQUIRE(daily_rate(60) == 480.0); } +TEST_CASE("it always returns a float", "[task_1]") { + REQUIRE_THAT(daily_rate(60), Catch::Matchers::WithinRel(480.0, 0.000001)); +} -TEST_CASE("it does not round", "[task_1]") { REQUIRE(daily_rate(55.1) == 440.8); } +TEST_CASE("it does not round", "[task_1]") { + REQUIRE_THAT(daily_rate(55.1), Catch::Matchers::WithinRel(440.8, 0.000001)); +} -TEST_CASE("a discount of 10 percent leaves 90 percent of the original price", "[task_2]") { - REQUIRE(apply_discount(140.0, 10) == 126.0); +TEST_CASE("a discount of 10 percent leaves 90 percent of the original price", + "[task_2]") { + REQUIRE_THAT(apply_discount(140.0, 10), + Catch::Matchers::WithinRel(126.0, 0.000001)); } TEST_CASE("it doesn't round", "[task_2]") { - // If unsure about the syntax of this test see: - // https://github.com/catchorg/Catch2/blob/devel/docs/comparing-floating-point-numbers.md#withinrel REQUIRE_THAT(apply_discount(111.11, 13.5), Catch::Matchers::WithinRel(96.11015, 0.000001)); } diff --git a/exercises/concept/freelancer-rates/test/catch.hpp b/exercises/concept/freelancer-rates/test/catch.hpp index 36eaeb27f..ff40b4fd6 100644 --- a/exercises/concept/freelancer-rates/test/catch.hpp +++ b/exercises/concept/freelancer-rates/test/catch.hpp @@ -3175,8 +3175,8 @@ namespace Detail { } // end namespace Detail namespace literals { - Detail::Approx operator "" _a(long double val); - Detail::Approx operator "" _a(unsigned long long val); + Detail::Approx operator ""_a(long double val); + Detail::Approx operator ""_a(unsigned long long val); } // end namespace literals template<> @@ -7911,10 +7911,10 @@ namespace Detail { } // end namespace Detail namespace literals { - Detail::Approx operator "" _a(long double val) { + Detail::Approx operator ""_a(long double val) { return Detail::Approx(val); } - Detail::Approx operator "" _a(unsigned long long val) { + Detail::Approx operator ""_a(unsigned long long val) { return Detail::Approx(val); } } // end namespace literals diff --git a/exercises/concept/interest-is-interesting/.docs/introduction.md b/exercises/concept/interest-is-interesting/.docs/introduction.md index 05d1f14be..52cd111e5 100644 --- a/exercises/concept/interest-is-interesting/.docs/introduction.md +++ b/exercises/concept/interest-is-interesting/.docs/introduction.md @@ -84,7 +84,7 @@ In contrast, the keyword `continue` only stops the execution of the current iter ```cpp int equal_sum{0}; for (int i{1}; i < 7; ++i) { - if (n%2 == 1) { + if (i%2 == 1) { continue; } equal_sum += i; diff --git a/exercises/concept/interest-is-interesting/.meta/exemplar.cpp b/exercises/concept/interest-is-interesting/.meta/exemplar.cpp index 00b3e15e6..024d00274 100644 --- a/exercises/concept/interest-is-interesting/.meta/exemplar.cpp +++ b/exercises/concept/interest-is-interesting/.meta/exemplar.cpp @@ -31,4 +31,4 @@ int years_until_desired_balance(double balance, double target_balance) { balance = annual_balance_update(balance); } return years; -} \ No newline at end of file +} diff --git a/exercises/concept/interest-is-interesting/CMakeLists.txt b/exercises/concept/interest-is-interesting/CMakeLists.txt index b79c51e67..8e21222a2 100644 --- a/exercises/concept/interest-is-interesting/CMakeLists.txt +++ b/exercises/concept/interest-is-interesting/CMakeLists.txt @@ -57,9 +57,12 @@ if(${EXERCISM_RUN_ALL_TESTS}) endif() # Tell MSVC not to warn us about unchecked iterators in debug builds +# Treat warnings as errors +# Treat type conversion warnings C4244 and C4267 as level 4 warnings, i.e. ignore them in level 3 if(${MSVC}) set_target_properties(${exercise} PROPERTIES - COMPILE_DEFINITIONS_DEBUG _SCL_SECURE_NO_WARNINGS) + COMPILE_DEFINITIONS_DEBUG _SCL_SECURE_NO_WARNINGS + COMPILE_FLAGS "/WX /w44244 /w44267") endif() # Run the tests on every build diff --git a/exercises/concept/interest-is-interesting/interest_is_interesting.cpp b/exercises/concept/interest-is-interesting/interest_is_interesting.cpp index 7fb33b4c7..a84f04f0d 100644 --- a/exercises/concept/interest-is-interesting/interest_is_interesting.cpp +++ b/exercises/concept/interest-is-interesting/interest_is_interesting.cpp @@ -22,4 +22,4 @@ double annual_balance_update(double balance) { int years_until_desired_balance(double balance, double target_balance) { // TODO: Implement the years_until_desired_balance function return 0; -} \ No newline at end of file +} diff --git a/exercises/concept/interest-is-interesting/interest_is_interesting_test.cpp b/exercises/concept/interest-is-interesting/interest_is_interesting_test.cpp index 55f289b93..646c875ae 100644 --- a/exercises/concept/interest-is-interesting/interest_is_interesting_test.cpp +++ b/exercises/concept/interest-is-interesting/interest_is_interesting_test.cpp @@ -8,7 +8,8 @@ TEST_CASE("Minimal first interest rate", "[task_1]") { double balance{0}; double want{0.5}; - REQUIRE_THAT(interest_rate(balance), Catch::Matchers::WithinRel(want, 0.000001)); + REQUIRE_THAT(interest_rate(balance), + Catch::Matchers::WithinRel(want, 0.000001)); } #if defined(EXERCISM_RUN_ALL_TESTS) @@ -16,136 +17,164 @@ TEST_CASE("Minimal first interest rate", "[task_1]") { TEST_CASE("Tiny first interest rate", "[task_1]") { double balance{0.000001}; double want{0.5}; - REQUIRE_THAT(interest_rate(balance), Catch::Matchers::WithinRel(want, 0.000001)); + REQUIRE_THAT(interest_rate(balance), + Catch::Matchers::WithinRel(want, 0.000001)); } TEST_CASE("Maximum first interest rate", "[task_1]") { double balance{999.9999}; double want{0.5}; - REQUIRE_THAT(interest_rate(balance), Catch::Matchers::WithinRel(want, 0.000001)); + REQUIRE_THAT(interest_rate(balance), + Catch::Matchers::WithinRel(want, 0.000001)); } TEST_CASE("Minimal second interest rate", "[task_1]") { double balance{1000.0}; double want{1.621}; - REQUIRE_THAT(interest_rate(balance), Catch::Matchers::WithinRel(want, 0.000001)); + REQUIRE_THAT(interest_rate(balance), + Catch::Matchers::WithinRel(want, 0.000001)); } TEST_CASE("Tiny second interest rate", "[task_1]") { double balance{1000.0001}; double want{1.621}; - REQUIRE_THAT(interest_rate(balance), Catch::Matchers::WithinRel(want, 0.000001)); + REQUIRE_THAT(interest_rate(balance), + Catch::Matchers::WithinRel(want, 0.000001)); } TEST_CASE("Maximum second interest rate", "[task_1]") { double balance{4999.9990}; double want{1.621}; - REQUIRE_THAT(interest_rate(balance), Catch::Matchers::WithinRel(want, 0.000001)); + REQUIRE_THAT(interest_rate(balance), + Catch::Matchers::WithinRel(want, 0.000001)); } TEST_CASE("Minimal third interest rate", "[task_1]") { double balance{5000.0000}; double want{2.475}; - REQUIRE_THAT(interest_rate(balance), Catch::Matchers::WithinRel(want, 0.000001)); + REQUIRE_THAT(interest_rate(balance), + Catch::Matchers::WithinRel(want, 0.000001)); } TEST_CASE("Tiny third interest rate", "[task_1]") { double balance{5000.0001}; double want{2.475}; - REQUIRE_THAT(interest_rate(balance), Catch::Matchers::WithinRel(want, 0.000001)); + REQUIRE_THAT(interest_rate(balance), + Catch::Matchers::WithinRel(want, 0.000001)); } TEST_CASE("Large third interest rate", "[task_1]") { double balance{5639998.742909}; double want{2.475}; - REQUIRE_THAT(interest_rate(balance), Catch::Matchers::WithinRel(want, 0.000001)); + REQUIRE_THAT(interest_rate(balance), + Catch::Matchers::WithinRel(want, 0.000001)); } TEST_CASE("Rate on minimal negative balance", "[task_1]") { double balance{-0.000001}; double want{3.213}; - REQUIRE_THAT(interest_rate(balance), Catch::Matchers::WithinRel(want, 0.000001)); + REQUIRE_THAT(interest_rate(balance), + Catch::Matchers::WithinRel(want, 0.000001)); } TEST_CASE("Rate on small negative balance", "[task_1]") { double balance{-0.123}; double want{3.213}; - REQUIRE_THAT(interest_rate(balance), Catch::Matchers::WithinRel(want, 0.000001)); + REQUIRE_THAT(interest_rate(balance), + Catch::Matchers::WithinRel(want, 0.000001)); } TEST_CASE("Rate on regular negative balance", "[task_1]") { double balance{-300.0}; double want{3.213}; - REQUIRE_THAT(interest_rate(balance), Catch::Matchers::WithinRel(want, 0.000001)); + REQUIRE_THAT(interest_rate(balance), + Catch::Matchers::WithinRel(want, 0.000001)); } TEST_CASE("Rate on large negative balance", "[task_1]") { double balance{-152964.231}; double want{3.213}; - REQUIRE_THAT(interest_rate(balance), Catch::Matchers::WithinRel(want, 0.000001)); + REQUIRE_THAT(interest_rate(balance), + Catch::Matchers::WithinRel(want, 0.000001)); } TEST_CASE("Interest on negative balance", "[task_2]") { double balance{-10000.0}; double want{-321.3}; - REQUIRE_THAT(yearly_interest(balance), Catch::Matchers::WithinRel(want, 0.000001)); + REQUIRE_THAT(yearly_interest(balance), + Catch::Matchers::WithinRel(want, 0.000001)); } TEST_CASE("Interest on small balance", "[task_2]") { double balance{555.43}; double want{2.77715}; - REQUIRE_THAT(yearly_interest(balance), Catch::Matchers::WithinRel(want, 0.000001)); + REQUIRE_THAT(yearly_interest(balance), + Catch::Matchers::WithinRel(want, 0.000001)); } TEST_CASE("Interest on medium balance", "[task_2]") { double balance{4999.99}; double want{81.0498379}; - REQUIRE_THAT(yearly_interest(balance), Catch::Matchers::WithinRel(want, 0.000001)); + REQUIRE_THAT(yearly_interest(balance), + Catch::Matchers::WithinRel(want, 0.000001)); } TEST_CASE("Interest on large balance", "[task_2]") { double balance{34600.80}; double want{856.3698}; - REQUIRE_THAT(yearly_interest(balance), Catch::Matchers::WithinRel(want, 0.000001)); + REQUIRE_THAT(yearly_interest(balance), + Catch::Matchers::WithinRel(want, 0.000001)); } TEST_CASE("Annual balance update for empty start balance", "[task_3]") { double balance{0.0}; double want{0.0000}; - REQUIRE_THAT(annual_balance_update(balance), Catch::Matchers::WithinRel(want, 0.000001)); + REQUIRE_THAT(annual_balance_update(balance), + Catch::Matchers::WithinRel(want, 0.000001)); } -TEST_CASE("Annual balance update for small positive start balance", "[task_3]") { +TEST_CASE("Annual balance update for small positive start balance", + "[task_3]") { double balance{0.000001}; double want{0.000001005}; - REQUIRE_THAT(annual_balance_update(balance), Catch::Matchers::WithinRel(want, 0.000001)); + REQUIRE_THAT(annual_balance_update(balance), + Catch::Matchers::WithinRel(want, 0.000001)); } -TEST_CASE("Annual balance update for average positive start balance", "[task_3]") { +TEST_CASE("Annual balance update for average positive start balance", + "[task_3]") { double balance{1000.0}; double want{1016.210000}; - REQUIRE_THAT(annual_balance_update(balance), Catch::Matchers::WithinRel(want, 0.000001)); + REQUIRE_THAT(annual_balance_update(balance), + Catch::Matchers::WithinRel(want, 0.000001)); } -TEST_CASE("Annual balance update for large positive start balance", "[task_3]") { +TEST_CASE("Annual balance update for large positive start balance", + "[task_3]") { double balance{1000.2001}; double want{1016.413343621}; - REQUIRE_THAT(annual_balance_update(balance), Catch::Matchers::WithinRel(want, 0.000001)); + REQUIRE_THAT(annual_balance_update(balance), + Catch::Matchers::WithinRel(want, 0.000001)); } TEST_CASE("Annual balance update for huge positive start balance", "[task_3]") { double balance{898124017.826243404425}; double want{920352587.2674429417}; - REQUIRE_THAT(annual_balance_update(balance), Catch::Matchers::WithinRel(want, 0.000001)); + REQUIRE_THAT(annual_balance_update(balance), + Catch::Matchers::WithinRel(want, 0.000001)); } -TEST_CASE("Annual balance update for small negative start balance", "[task_3]") { +TEST_CASE("Annual balance update for small negative start balance", + "[task_3]") { double balance{-0.123}; double want{-0.12695199}; - REQUIRE_THAT(annual_balance_update(balance), Catch::Matchers::WithinRel(want, 0.000001)); + REQUIRE_THAT(annual_balance_update(balance), + Catch::Matchers::WithinRel(want, 0.000001)); } -TEST_CASE("Annual balance update for large negative start balance", "[task_3]") { +TEST_CASE("Annual balance update for large negative start balance", + "[task_3]") { double balance{-152964.231}; double want{-157878.97174203}; - REQUIRE_THAT(annual_balance_update(balance), Catch::Matchers::WithinRel(want, 0.000001)); + REQUIRE_THAT(annual_balance_update(balance), + Catch::Matchers::WithinRel(want, 0.000001)); } TEST_CASE("Years before desired balance for small start balance", "[task_4]") { @@ -154,7 +183,8 @@ TEST_CASE("Years before desired balance for small start balance", "[task_4]") { int want{47}; REQUIRE(years_until_desired_balance(balance, target_balance) == want); } -TEST_CASE("Years before desired balance for average start balance", "[task_4]") { +TEST_CASE("Years before desired balance for average start balance", + "[task_4]") { double balance{1000.0}; double target_balance{1100.0}; int want{6}; @@ -166,7 +196,8 @@ TEST_CASE("Years before desired balance for large start balance", "[task_4]") { int want{5}; REQUIRE(years_until_desired_balance(balance, target_balance) == want); } -TEST_CASE("Years before large difference between start and target balance", "[task_4]") { +TEST_CASE("Years before large difference between start and target balance", + "[task_4]") { double balance{2345.67}; double target_balance{12345.6789}; int want{85}; diff --git a/exercises/concept/interest-is-interesting/test/catch.hpp b/exercises/concept/interest-is-interesting/test/catch.hpp index 36eaeb27f..ff40b4fd6 100644 --- a/exercises/concept/interest-is-interesting/test/catch.hpp +++ b/exercises/concept/interest-is-interesting/test/catch.hpp @@ -3175,8 +3175,8 @@ namespace Detail { } // end namespace Detail namespace literals { - Detail::Approx operator "" _a(long double val); - Detail::Approx operator "" _a(unsigned long long val); + Detail::Approx operator ""_a(long double val); + Detail::Approx operator ""_a(unsigned long long val); } // end namespace literals template<> @@ -7911,10 +7911,10 @@ namespace Detail { } // end namespace Detail namespace literals { - Detail::Approx operator "" _a(long double val) { + Detail::Approx operator ""_a(long double val) { return Detail::Approx(val); } - Detail::Approx operator "" _a(unsigned long long val) { + Detail::Approx operator ""_a(unsigned long long val) { return Detail::Approx(val); } } // end namespace literals diff --git a/exercises/concept/lasagna-master/.docs/instructions.md b/exercises/concept/lasagna-master/.docs/instructions.md index 0d13bd227..9d2e08a22 100644 --- a/exercises/concept/lasagna-master/.docs/instructions.md +++ b/exercises/concept/lasagna-master/.docs/instructions.md @@ -49,12 +49,12 @@ It was amazing and had something special to it. The friend sent you the list of ingredients and told you the last item on the list is the "secret ingredient" that made the meal so special. Now you want to add that secret ingredient to your recipe as well. -Write a function `addSecretIngredient` that accepts two `string` vectors of ingredients as parameters. -The first parameter is the list your friend sent you, the second is the ingredient list of your own recipe. +Write a function `addSecretIngredient` that accepts two `vector of strings` as parameters. +The first parameter is a _reference_ to the ingredients of your own recipe, and the second _vector_ of strings has the ingredients your friend sent you. The last element in your ingredient list is always `"?"`. The function should replace it with the last item from your friends list. **Note:** `addSecretIngredient` does not return anything - you should modify the list of your ingredients directly. -The list with your friend's ingredients should **not** be modified. +The list with your friend's ingredients can also be a reference (for improving the performance), but it should **not** be modified. Make sure the list will not be modified with a `const` reference. ```cpp diff --git a/exercises/concept/lasagna-master/.docs/introduction.md b/exercises/concept/lasagna-master/.docs/introduction.md index b832a0a5a..76d7b3175 100644 --- a/exercises/concept/lasagna-master/.docs/introduction.md +++ b/exercises/concept/lasagna-master/.docs/introduction.md @@ -22,7 +22,7 @@ admin_detected // Function name ~~~~exercism/advanced The declaration works like a note to the compiler, that there is a function of that name, return type and parameter list. The code will not work, if the definition is missing. -Declarations are optional, they are needed if you use the function before its definiton. +Declarations are optional, they are needed if you use the function before its definition. Declarations can solve problems like cyclic references and they can be used to separate the interface from the implementation. ~~~~ @@ -38,7 +38,7 @@ number_of_dragon_balls--; // compilation error ~~~~exercism/note You will often see constants written in _UPPER_SNAKE_CASE_. -It is recommened to reserve this casing for macros, if there is no other convention. +It is recommended to reserve this casing for macros, if there is no other convention. ~~~~ If you try to change a constant variable after it has been set, your code will not compile. @@ -66,7 +66,7 @@ class Stubborn { response = reply; } string answer(const string& question) const { - if (question.lenghth() == 0) { return "";} + if (question.length() == 0) { return ""; } return response; } private: diff --git a/exercises/concept/lasagna-master/.docs/introduction.md.tpl b/exercises/concept/lasagna-master/.docs/introduction.md.tpl index 5c58bbfd4..81f4307de 100644 --- a/exercises/concept/lasagna-master/.docs/introduction.md.tpl +++ b/exercises/concept/lasagna-master/.docs/introduction.md.tpl @@ -1,3 +1,3 @@ # Introduction -%{concept:functions} \ No newline at end of file +%{concept:functions} diff --git a/exercises/concept/lasagna-master/.meta/design.md b/exercises/concept/lasagna-master/.meta/design.md index 5d9fbcb72..8368b8459 100644 --- a/exercises/concept/lasagna-master/.meta/design.md +++ b/exercises/concept/lasagna-master/.meta/design.md @@ -41,4 +41,4 @@ The following concepts are needed to solve the exercise: The story was inspired by the [Lasagna Master Exercise in the Javascipt track][javascript-lasagna-master]. Some tasks needed to be changed though to achieve an exercise that fits the C++ learning objectives. -[javascript-lasagna-master]: https://github.com/exercism/javascript/blob/main/exercises/concept/lasagna-master/.docs/instructions.md \ No newline at end of file +[javascript-lasagna-master]: https://github.com/exercism/javascript/blob/main/exercises/concept/lasagna-master/.docs/instructions.md diff --git a/exercises/concept/lasagna-master/.meta/exemplar.cpp b/exercises/concept/lasagna-master/.meta/exemplar.cpp index 00e8e954b..f293dbca2 100644 --- a/exercises/concept/lasagna-master/.meta/exemplar.cpp +++ b/exercises/concept/lasagna-master/.meta/exemplar.cpp @@ -29,7 +29,7 @@ void addSecretIngredient(std::vector& myList, } std::vector scaleRecipe(const std::vector& quantities, - int portions) { + int portions) { std::vector result(quantities); for (auto& quantity : result) { quantity *= portions / 2.0; diff --git a/exercises/concept/lasagna-master/.meta/exemplar.h b/exercises/concept/lasagna-master/.meta/exemplar.h index 9bc99488c..95c2d3651 100644 --- a/exercises/concept/lasagna-master/.meta/exemplar.h +++ b/exercises/concept/lasagna-master/.meta/exemplar.h @@ -1,16 +1,22 @@ #pragma once -#include #include +#include namespace lasagna_master { -struct amount { int noodles; double sauce; }; +struct amount { + int noodles; + double sauce; +}; int preparationTime(const std::vector& layers, int prepTime = 2); amount quantities(const std::vector& layers); -void addSecretIngredient(std::vector& myList, const std::vector& friendsList); -void addSecretIngredient(std::vector& myList, const std::string& secretIngredient); -std::vector scaleRecipe(const std::vector& quantities, int portions); +void addSecretIngredient(std::vector& myList, + const std::vector& friendsList); +void addSecretIngredient(std::vector& myList, + const std::string& secretIngredient); +std::vector scaleRecipe(const std::vector& quantities, + int portions); } // namespace lasagna_master diff --git a/exercises/concept/lasagna-master/CMakeLists.txt b/exercises/concept/lasagna-master/CMakeLists.txt index 3b0589fd0..dba98a931 100644 --- a/exercises/concept/lasagna-master/CMakeLists.txt +++ b/exercises/concept/lasagna-master/CMakeLists.txt @@ -55,9 +55,12 @@ if(${EXERCISM_RUN_ALL_TESTS}) endif() # Tell MSVC not to warn us about unchecked iterators in debug builds +# Treat warnings as errors +# Treat type conversion warnings C4244 and C4267 as level 4 warnings, i.e. ignore them in level 3 if(${MSVC}) set_target_properties(${exercise} PROPERTIES - COMPILE_DEFINITIONS_DEBUG _SCL_SECURE_NO_WARNINGS) + COMPILE_DEFINITIONS_DEBUG _SCL_SECURE_NO_WARNINGS + COMPILE_FLAGS "/WX /w44244 /w44267") endif() # Run the tests on every build diff --git a/exercises/concept/lasagna-master/lasagna_master.cpp b/exercises/concept/lasagna-master/lasagna_master.cpp index f855bfbb3..2639fc4d8 100644 --- a/exercises/concept/lasagna-master/lasagna_master.cpp +++ b/exercises/concept/lasagna-master/lasagna_master.cpp @@ -2,5 +2,6 @@ namespace lasagna_master { +// TODO: add your solution here } // namespace lasagna_master diff --git a/exercises/concept/lasagna-master/lasagna_master_test.cpp b/exercises/concept/lasagna-master/lasagna_master_test.cpp index 66ae15fe6..466b6229b 100644 --- a/exercises/concept/lasagna-master/lasagna_master_test.cpp +++ b/exercises/concept/lasagna-master/lasagna_master_test.cpp @@ -11,26 +11,21 @@ using namespace lasagna_master; // As long as we have catch2 v2 and v3 in parallel, we can't use either // of their comparison marcors for floating point comparisons. -#define REQUIRE_VECTOR_APROX_EQUAL(vec1, vec2, margin) \ - REQUIRE(vec1.size() == vec2.size()); \ - for (size_t i = 0; i < vec1.size(); i++) { \ - REQUIRE( std::abs(vec1.at(i) - vec2.at(i)) < margin); \ - } - -TEST_CASE("preparationTime: Preparation time for many layers with custom average time", "[task_1]") { +#define REQUIRE_VECTOR_APROX_EQUAL(vec1, vec2, margin) \ + REQUIRE(vec1.size() == vec2.size()); \ + for (size_t i = 0; i < vec1.size(); i++) { \ + REQUIRE(std::abs(vec1.at(i) - vec2.at(i)) < margin); \ + } + +TEST_CASE( + // clang-format off + "preparationTime: Preparation time for many layers with custom average time", + // clang-format on + "[task_1]") { std::vector layers{ - "sauce", - "noodles", - "béchamel", - "meat", - "mozzarella", - "noodles", - "ricotta", - "eggplant", - "béchamel", - "noodles", - "sauce", - "mozzarella", + "sauce", "noodles", "béchamel", "meat", + "mozzarella", "noodles", "ricotta", "eggplant", + "béchamel", "noodles", "sauce", "mozzarella", }; int time{1}; int expected{12}; @@ -59,7 +54,7 @@ TEST_CASE("preparationTime: Preparation time for default case", "[task_1]") { } TEST_CASE("quantities: few layers", "[task_2]") { - std::vector layers {"noodles", "sauce", "noodles"}; + std::vector layers{"noodles", "sauce", "noodles"}; int expNoodles{100}; double expSauce{0.2}; amount amount = quantities(layers); @@ -68,19 +63,10 @@ TEST_CASE("quantities: few layers", "[task_2]") { } TEST_CASE("quantities: many layers", "[task_2]") { - std::vector layers{ - "sauce", - "noodles", - "béchamel", - "meat", - "mozzarella", - "noodles", - "ricotta", - "eggplant", - "béchamel", - "noodles", - "sauce", - "mozzarella"}; + std::vector layers{"sauce", "noodles", "béchamel", + "meat", "mozzarella", "noodles", + "ricotta", "eggplant", "béchamel", + "noodles", "sauce", "mozzarella"}; int expNoodles{150}; double expSauce{0.4}; amount amount = quantities(layers); @@ -89,12 +75,8 @@ TEST_CASE("quantities: many layers", "[task_2]") { } TEST_CASE("quantities: no noodles", "[task_2]") { - std::vector layers{ - "sauce", - "meat", - "mozzarella", - "sauce", - "mozzarella"}; + std::vector layers{"sauce", "meat", "mozzarella", "sauce", + "mozzarella"}; int expNoodles{0}; double expSauce{0.4}; amount amount = quantities(layers); @@ -103,12 +85,8 @@ TEST_CASE("quantities: no noodles", "[task_2]") { } TEST_CASE("quantities: no sauce", "[task_2]") { - std::vector layers{ - "noodles", - "meat", - "mozzarella", - "noodles", - "mozzarella"}; + std::vector layers{"noodles", "meat", "mozzarella", "noodles", + "mozzarella"}; int expNoodles{100}; double expSauce{0.0}; amount amount = quantities(layers); @@ -117,9 +95,12 @@ TEST_CASE("quantities: no sauce", "[task_2]") { } TEST_CASE("Adds secret vector ingredient", "[task_3]") { - const std::vector friendsList{"sauce", "noodles", "béchamel", "marjoram"}; - std::vector myList{"sauce", "noodles", "meat", "tomatoes", "?"}; - std::vector expected{"sauce", "noodles", "meat", "tomatoes", "marjoram"}; + const std::vector friendsList{"sauce", "noodles", "béchamel", + "marjoram"}; + std::vector myList{"sauce", "noodles", "meat", "tomatoes", + "?"}; + std::vector expected{"sauce", "noodles", "meat", "tomatoes", + "marjoram"}; addSecretIngredient(myList, friendsList); REQUIRE(myList == expected); } @@ -149,7 +130,7 @@ TEST_CASE("scaleRecipe: scales down correctly", "[task_4]") { } TEST_CASE("scaleRecipe: empty recipe", "[task_4]") { - const std::vector input{}; + const std::vector input{}; int portions{100}; std::vector expected{}; std::vector scaled{scaleRecipe(input, portions)}; @@ -158,8 +139,10 @@ TEST_CASE("scaleRecipe: empty recipe", "[task_4]") { TEST_CASE("Adds secret string ingredient", "[task_5]") { const std::string auntiesSecret{"mirkwood mushrooms"}; - std::vector myList{"sauce", "noodles", "meat", "tomatoes", "?"}; - std::vector expected{"sauce", "noodles", "meat", "tomatoes", "mirkwood mushrooms"}; + std::vector myList{"sauce", "noodles", "meat", "tomatoes", + "?"}; + std::vector expected{"sauce", "noodles", "meat", "tomatoes", + "mirkwood mushrooms"}; addSecretIngredient(myList, auntiesSecret); REQUIRE(myList == expected); } diff --git a/exercises/concept/lasagna-master/test/catch.hpp b/exercises/concept/lasagna-master/test/catch.hpp index 36eaeb27f..ff40b4fd6 100644 --- a/exercises/concept/lasagna-master/test/catch.hpp +++ b/exercises/concept/lasagna-master/test/catch.hpp @@ -3175,8 +3175,8 @@ namespace Detail { } // end namespace Detail namespace literals { - Detail::Approx operator "" _a(long double val); - Detail::Approx operator "" _a(unsigned long long val); + Detail::Approx operator ""_a(long double val); + Detail::Approx operator ""_a(unsigned long long val); } // end namespace literals template<> @@ -7911,10 +7911,10 @@ namespace Detail { } // end namespace Detail namespace literals { - Detail::Approx operator "" _a(long double val) { + Detail::Approx operator ""_a(long double val) { return Detail::Approx(val); } - Detail::Approx operator "" _a(unsigned long long val) { + Detail::Approx operator ""_a(unsigned long long val) { return Detail::Approx(val); } } // end namespace literals diff --git a/exercises/concept/lasagna/.docs/introduction.md.tpl b/exercises/concept/lasagna/.docs/introduction.md.tpl index 5f0e01404..cd2cef4ed 100644 --- a/exercises/concept/lasagna/.docs/introduction.md.tpl +++ b/exercises/concept/lasagna/.docs/introduction.md.tpl @@ -1,3 +1,3 @@ # Introduction -%{concept:basics} \ No newline at end of file +%{concept:basics} diff --git a/exercises/concept/lasagna/.meta/exemplar.cpp b/exercises/concept/lasagna/.meta/exemplar.cpp index 54e612475..ffbfc6635 100644 --- a/exercises/concept/lasagna/.meta/exemplar.cpp +++ b/exercises/concept/lasagna/.meta/exemplar.cpp @@ -21,4 +21,4 @@ int preparationTime(int numberOfLayers) { // far. int elapsedTime(int numberOfLayers, int actualMinutesInOven) { return preparationTime(numberOfLayers) + actualMinutesInOven; -} \ No newline at end of file +} diff --git a/exercises/concept/lasagna/CMakeLists.txt b/exercises/concept/lasagna/CMakeLists.txt index b79c51e67..8e21222a2 100644 --- a/exercises/concept/lasagna/CMakeLists.txt +++ b/exercises/concept/lasagna/CMakeLists.txt @@ -57,9 +57,12 @@ if(${EXERCISM_RUN_ALL_TESTS}) endif() # Tell MSVC not to warn us about unchecked iterators in debug builds +# Treat warnings as errors +# Treat type conversion warnings C4244 and C4267 as level 4 warnings, i.e. ignore them in level 3 if(${MSVC}) set_target_properties(${exercise} PROPERTIES - COMPILE_DEFINITIONS_DEBUG _SCL_SECURE_NO_WARNINGS) + COMPILE_DEFINITIONS_DEBUG _SCL_SECURE_NO_WARNINGS + COMPILE_FLAGS "/WX /w44244 /w44267") endif() # Run the tests on every build diff --git a/exercises/concept/lasagna/test/catch.hpp b/exercises/concept/lasagna/test/catch.hpp index 36eaeb27f..ff40b4fd6 100644 --- a/exercises/concept/lasagna/test/catch.hpp +++ b/exercises/concept/lasagna/test/catch.hpp @@ -3175,8 +3175,8 @@ namespace Detail { } // end namespace Detail namespace literals { - Detail::Approx operator "" _a(long double val); - Detail::Approx operator "" _a(unsigned long long val); + Detail::Approx operator ""_a(long double val); + Detail::Approx operator ""_a(unsigned long long val); } // end namespace literals template<> @@ -7911,10 +7911,10 @@ namespace Detail { } // end namespace Detail namespace literals { - Detail::Approx operator "" _a(long double val) { + Detail::Approx operator ""_a(long double val) { return Detail::Approx(val); } - Detail::Approx operator "" _a(unsigned long long val) { + Detail::Approx operator ""_a(unsigned long long val) { return Detail::Approx(val); } } // end namespace literals diff --git a/exercises/concept/last-will/.docs/introduction.md b/exercises/concept/last-will/.docs/introduction.md index cb69db98d..69218dcfb 100644 --- a/exercises/concept/last-will/.docs/introduction.md +++ b/exercises/concept/last-will/.docs/introduction.md @@ -2,7 +2,7 @@ ## Namespaces -An important method for code organization are namespaces. +An important method for code organization is the use of namespaces. Two functions might have a naming collision, which can be resolved by putting them in different namespaces. Namespaces can be nested, which might help to structure big code bases. Access to the namespaces is done via the scope-resolution operator `::`. diff --git a/exercises/concept/last-will/.docs/introduction.md.tpl b/exercises/concept/last-will/.docs/introduction.md.tpl index 10f577e26..58e43378d 100644 --- a/exercises/concept/last-will/.docs/introduction.md.tpl +++ b/exercises/concept/last-will/.docs/introduction.md.tpl @@ -1,3 +1,3 @@ # Introduction -%{concept:namespaces} \ No newline at end of file +%{concept:namespaces} diff --git a/exercises/concept/last-will/.meta/exemplar.cpp b/exercises/concept/last-will/.meta/exemplar.cpp index 44abf98e4..ef8f15ae5 100644 --- a/exercises/concept/last-will/.meta/exemplar.cpp +++ b/exercises/concept/last-will/.meta/exemplar.cpp @@ -2,54 +2,59 @@ // Secret knowledge of the Zhang family: namespace zhang { - int bank_number_part(int secret_modifier) { - int zhang_part{8'541}; - return (zhang_part*secret_modifier) % 10000; - } - namespace red { - int code_fragment() {return 512;} - } - namespace blue { - int code_fragment() {return 677;} - } +int bank_number_part(int secret_modifier) { + int zhang_part{8'541}; + return (zhang_part * secret_modifier) % 10000; } +namespace red { +int code_fragment() { return 512; } +} // namespace red +namespace blue { +int code_fragment() { return 677; } +} // namespace blue +} // namespace zhang // Secret knowledge of the Khan family: namespace khan { - int bank_number_part(int secret_modifier) { - int khan_part{4'142}; - return (khan_part*secret_modifier) % 10000; - } - namespace red { - int code_fragment() {return 148;} - } - namespace blue { - int code_fragment() {return 875;} - } +int bank_number_part(int secret_modifier) { + int khan_part{4'142}; + return (khan_part * secret_modifier) % 10000; } +namespace red { +int code_fragment() { return 148; } +} // namespace red +namespace blue { +int code_fragment() { return 875; } +} // namespace blue +} // namespace khan // Secret knowledge of the Garcia family: namespace garcia { - int bank_number_part(int secret_modifier) { - int garcia_part{4'023}; - return (garcia_part*secret_modifier) % 10000; - } - namespace red { - int code_fragment() {return 118;} - } - namespace blue { - int code_fragment() {return 923;} - } +int bank_number_part(int secret_modifier) { + int garcia_part{4'023}; + return (garcia_part * secret_modifier) % 10000; } +namespace red { +int code_fragment() { return 118; } +} // namespace red +namespace blue { +int code_fragment() { return 923; } +} // namespace blue +} // namespace garcia // Enter your code below namespace estate_executor { - int assemble_account_number(int secret_modifier) { - return zhang::bank_number_part(secret_modifier) + khan::bank_number_part(secret_modifier) + garcia::bank_number_part(secret_modifier); - } +int assemble_account_number(int secret_modifier) { + return zhang::bank_number_part(secret_modifier) + + khan::bank_number_part(secret_modifier) + + garcia::bank_number_part(secret_modifier); +} - int assemble_code() { - return ( zhang::red::code_fragment() + garcia::red::code_fragment() + khan::red::code_fragment() ) * ( zhang::blue::code_fragment() + garcia::blue::code_fragment() + khan::blue::code_fragment() ); - } -} \ No newline at end of file +int assemble_code() { + return (zhang::red::code_fragment() + garcia::red::code_fragment() + + khan::red::code_fragment()) * + (zhang::blue::code_fragment() + garcia::blue::code_fragment() + + khan::blue::code_fragment()); +} +} // namespace estate_executor diff --git a/exercises/concept/last-will/CMakeLists.txt b/exercises/concept/last-will/CMakeLists.txt index b79c51e67..8e21222a2 100644 --- a/exercises/concept/last-will/CMakeLists.txt +++ b/exercises/concept/last-will/CMakeLists.txt @@ -57,9 +57,12 @@ if(${EXERCISM_RUN_ALL_TESTS}) endif() # Tell MSVC not to warn us about unchecked iterators in debug builds +# Treat warnings as errors +# Treat type conversion warnings C4244 and C4267 as level 4 warnings, i.e. ignore them in level 3 if(${MSVC}) set_target_properties(${exercise} PROPERTIES - COMPILE_DEFINITIONS_DEBUG _SCL_SECURE_NO_WARNINGS) + COMPILE_DEFINITIONS_DEBUG _SCL_SECURE_NO_WARNINGS + COMPILE_FLAGS "/WX /w44244 /w44267") endif() # Run the tests on every build diff --git a/exercises/concept/last-will/last_will.cpp b/exercises/concept/last-will/last_will.cpp index ad52cda48..3cb9fff85 100644 --- a/exercises/concept/last-will/last_will.cpp +++ b/exercises/concept/last-will/last_will.cpp @@ -2,44 +2,44 @@ // Secret knowledge of the Zhang family: namespace zhang { - int bank_number_part(int secret_modifier) { - int zhang_part{8'541}; - return (zhang_part*secret_modifier) % 10000; - } - namespace red { - int code_fragment() {return 512;} - } - namespace blue { - int code_fragment() {return 677;} - } +int bank_number_part(int secret_modifier) { + int zhang_part{8'541}; + return (zhang_part * secret_modifier) % 10000; } +namespace red { +int code_fragment() { return 512; } +} // namespace red +namespace blue { +int code_fragment() { return 677; } +} // namespace blue +} // namespace zhang // Secret knowledge of the Khan family: namespace khan { - int bank_number_part(int secret_modifier) { - int khan_part{4'142}; - return (khan_part*secret_modifier) % 10000; - } - namespace red { - int code_fragment() {return 148;} - } - namespace blue { - int code_fragment() {return 875;} - } +int bank_number_part(int secret_modifier) { + int khan_part{4'142}; + return (khan_part * secret_modifier) % 10000; } +namespace red { +int code_fragment() { return 148; } +} // namespace red +namespace blue { +int code_fragment() { return 875; } +} // namespace blue +} // namespace khan // Secret knowledge of the Garcia family: namespace garcia { - int bank_number_part(int secret_modifier) { - int garcia_part{4'023}; - return (garcia_part*secret_modifier) % 10000; - } - namespace red { - int code_fragment() {return 118;} - } - namespace blue { - int code_fragment() {return 923;} - } +int bank_number_part(int secret_modifier) { + int garcia_part{4'023}; + return (garcia_part * secret_modifier) % 10000; } +namespace red { +int code_fragment() { return 118; } +} // namespace red +namespace blue { +int code_fragment() { return 923; } +} // namespace blue +} // namespace garcia -// Enter your code below \ No newline at end of file +// Enter your code below diff --git a/exercises/concept/last-will/last_will_test.cpp b/exercises/concept/last-will/last_will_test.cpp index bd69bbc39..66fd16bf4 100644 --- a/exercises/concept/last-will/last_will_test.cpp +++ b/exercises/concept/last-will/last_will_test.cpp @@ -1,9 +1,3 @@ -// Trick to let the code compile, even if the function has not been implemented: -namespace estate_executor { - int assemble_account_number(int) __attribute__((weak)); - int assemble_code() __attribute__((weak)); -} - #include "last_will.cpp" #ifdef EXERCISM_TEST_SUITE #include @@ -14,9 +8,9 @@ namespace estate_executor { using namespace std; TEST_CASE("Family secrets have not been altered", "[task_1]") { - // We cannot test the existence of a namespace in the compiled + // We cannot test the existence of a namespace in the compiled // Code. - // This test merely checks if the numbers in the file have + // This test merely checks if the numbers in the file have // been changed. They have to be correct for the test to work. REQUIRE(zhang::bank_number_part(1) == 8541); @@ -35,7 +29,8 @@ TEST_CASE("Family secrets have not been altered", "[task_1]") { REQUIRE(garcia::blue::code_fragment() == 923); } -TEST_CASE("Account number assembly function exists in correct namespace", "[task_2]") { +TEST_CASE("Account number assembly function exists in correct namespace", + "[task_2]") { REQUIRE_NOTHROW(estate_executor::assemble_account_number(0)); } @@ -45,11 +40,14 @@ TEST_CASE("Account number assembly works correctly", "[task_2]") { int account_with_secret_1{16706}; int account_with_secret_23{14238}; - REQUIRE(estate_executor::assemble_account_number(1) == account_with_secret_1); - REQUIRE(estate_executor::assemble_account_number(23) == account_with_secret_23); + REQUIRE(estate_executor::assemble_account_number(1) == + account_with_secret_1); + REQUIRE(estate_executor::assemble_account_number(23) == + account_with_secret_23); } -TEST_CASE("Code fragment number assembly function exists in correct namespace", "[task_3]") { +TEST_CASE("Code fragment number assembly function exists in correct namespace", + "[task_3]") { REQUIRE_NOTHROW(estate_executor::assemble_code()); } diff --git a/exercises/concept/last-will/test/catch.hpp b/exercises/concept/last-will/test/catch.hpp index 36eaeb27f..ff40b4fd6 100644 --- a/exercises/concept/last-will/test/catch.hpp +++ b/exercises/concept/last-will/test/catch.hpp @@ -3175,8 +3175,8 @@ namespace Detail { } // end namespace Detail namespace literals { - Detail::Approx operator "" _a(long double val); - Detail::Approx operator "" _a(unsigned long long val); + Detail::Approx operator ""_a(long double val); + Detail::Approx operator ""_a(unsigned long long val); } // end namespace literals template<> @@ -7911,10 +7911,10 @@ namespace Detail { } // end namespace Detail namespace literals { - Detail::Approx operator "" _a(long double val) { + Detail::Approx operator ""_a(long double val) { return Detail::Approx(val); } - Detail::Approx operator "" _a(unsigned long long val) { + Detail::Approx operator ""_a(unsigned long long val) { return Detail::Approx(val); } } // end namespace literals diff --git a/exercises/concept/log-levels/.docs/introduction.md.tpl b/exercises/concept/log-levels/.docs/introduction.md.tpl index bd4f8dd2b..a0da96918 100644 --- a/exercises/concept/log-levels/.docs/introduction.md.tpl +++ b/exercises/concept/log-levels/.docs/introduction.md.tpl @@ -2,4 +2,4 @@ %{concept:includes} -%{concept:strings} \ No newline at end of file +%{concept:strings} diff --git a/exercises/concept/log-levels/.meta/exemplar.cpp b/exercises/concept/log-levels/.meta/exemplar.cpp index 6210b49a2..073cd4161 100644 --- a/exercises/concept/log-levels/.meta/exemplar.cpp +++ b/exercises/concept/log-levels/.meta/exemplar.cpp @@ -1,15 +1,15 @@ #include namespace log_line { - std::string message(const std::string& line) { - return line.substr(line.find(':') + 2); - } +std::string message(const std::string& line) { + return line.substr(line.find(':') + 2); +} - std::string log_level(const std::string& line) { - return line.substr(1, line.find(']') - 1); - } +std::string log_level(const std::string& line) { + return line.substr(1, line.find(']') - 1); +} - std::string reformat(const std::string& line) { - return message(line) + " (" + log_level(line) + ')'; - } -} // namespace log_line +std::string reformat(const std::string& line) { + return message(line) + " (" + log_level(line) + ')'; +} +} // namespace log_line diff --git a/exercises/concept/log-levels/CMakeLists.txt b/exercises/concept/log-levels/CMakeLists.txt index 621e22b9e..44ef334b3 100644 --- a/exercises/concept/log-levels/CMakeLists.txt +++ b/exercises/concept/log-levels/CMakeLists.txt @@ -57,9 +57,12 @@ if(${EXERCISM_RUN_ALL_TESTS}) endif() # Tell MSVC not to warn us about unchecked iterators in debug builds +# Treat warnings as errors +# Treat type conversion warnings C4244 and C4267 as level 4 warnings, i.e. ignore them in level 3 if(${MSVC}) set_target_properties(${exercise} PROPERTIES - COMPILE_DEFINITIONS_DEBUG _SCL_SECURE_NO_WARNINGS) + COMPILE_DEFINITIONS_DEBUG _SCL_SECURE_NO_WARNINGS + COMPILE_FLAGS "/WX /w44244 /w44267") endif() # Run the tests on every build diff --git a/exercises/concept/log-levels/log_levels.cpp b/exercises/concept/log-levels/log_levels.cpp index 92d9531b4..44b8502c7 100644 --- a/exercises/concept/log-levels/log_levels.cpp +++ b/exercises/concept/log-levels/log_levels.cpp @@ -1,15 +1,15 @@ #include namespace log_line { - std::string message(std::string line) { - // return the message - } +std::string message(std::string line) { + // return the message +} - std::string log_level(std::string line) { - // return the log level - } +std::string log_level(std::string line) { + // return the log level +} - std::string reformat(std::string line) { - // return the reformatted message - } +std::string reformat(std::string line) { + // return the reformatted message } +} // namespace log_line diff --git a/exercises/concept/log-levels/log_levels_test.cpp b/exercises/concept/log-levels/log_levels_test.cpp index 24e06907c..4f39bc676 100644 --- a/exercises/concept/log-levels/log_levels_test.cpp +++ b/exercises/concept/log-levels/log_levels_test.cpp @@ -7,8 +7,7 @@ using namespace std; -TEST_CASE("Error message", "[task_1]") -{ +TEST_CASE("Error message", "[task_1]") { const string actual = log_line::message("[ERROR]: Stack overflow"); const string expected{"Stack overflow"}; @@ -17,8 +16,7 @@ TEST_CASE("Error message", "[task_1]") } #if defined(EXERCISM_RUN_ALL_TESTS) -TEST_CASE("Warning message", "[task_1]") -{ +TEST_CASE("Warning message", "[task_1]") { const string actual = log_line::message("[WARNING]: Disk almost full"); const string expected{"Disk almost full"}; @@ -26,8 +24,7 @@ TEST_CASE("Warning message", "[task_1]") REQUIRE(actual == expected); } -TEST_CASE("Info message", "[task_1]") -{ +TEST_CASE("Info message", "[task_1]") { const string actual = log_line::message("[INFO]: File moved"); const string expected{"File moved"}; @@ -35,8 +32,7 @@ TEST_CASE("Info message", "[task_1]") REQUIRE(actual == expected); } -TEST_CASE("Error log level", "[task_2]") -{ +TEST_CASE("Error log level", "[task_2]") { const string actual = log_line::log_level("[ERROR]: Disk full"); const string expected{"ERROR"}; @@ -44,8 +40,7 @@ TEST_CASE("Error log level", "[task_2]") REQUIRE(actual == expected); } -TEST_CASE("Warning log level", "[task_2]") -{ +TEST_CASE("Warning log level", "[task_2]") { const string actual = log_line::log_level("[WARNING]: Unsafe password"); const string expected{"WARNING"}; @@ -53,8 +48,7 @@ TEST_CASE("Warning log level", "[task_2]") REQUIRE(actual == expected); } -TEST_CASE("Info log level", "[task_2]") -{ +TEST_CASE("Info log level", "[task_2]") { const string actual = log_line::log_level("[INFO]: Timezone changed"); const string expected{"INFO"}; @@ -62,8 +56,7 @@ TEST_CASE("Info log level", "[task_2]") REQUIRE(actual == expected); } -TEST_CASE("Error reformat", "[task_3]") -{ +TEST_CASE("Error reformat", "[task_3]") { const string actual = log_line::reformat("[ERROR]: Segmentation fault"); const string expected{"Segmentation fault (ERROR)"}; @@ -71,17 +64,16 @@ TEST_CASE("Error reformat", "[task_3]") REQUIRE(actual == expected); } -TEST_CASE("Warning reformat", "[task_3]") -{ - const string actual = log_line::reformat("[WARNING]: Decreased performance"); +TEST_CASE("Warning reformat", "[task_3]") { + const string actual = + log_line::reformat("[WARNING]: Decreased performance"); const string expected{"Decreased performance (WARNING)"}; REQUIRE(actual == expected); } -TEST_CASE("Info reformat", "[task_3]") -{ +TEST_CASE("Info reformat", "[task_3]") { const string actual = log_line::reformat("[INFO]: Disk defragmented"); const string expected{"Disk defragmented (INFO)"}; diff --git a/exercises/concept/log-levels/test/catch.hpp b/exercises/concept/log-levels/test/catch.hpp index 36eaeb27f..ff40b4fd6 100644 --- a/exercises/concept/log-levels/test/catch.hpp +++ b/exercises/concept/log-levels/test/catch.hpp @@ -3175,8 +3175,8 @@ namespace Detail { } // end namespace Detail namespace literals { - Detail::Approx operator "" _a(long double val); - Detail::Approx operator "" _a(unsigned long long val); + Detail::Approx operator ""_a(long double val); + Detail::Approx operator ""_a(unsigned long long val); } // end namespace literals template<> @@ -7911,10 +7911,10 @@ namespace Detail { } // end namespace Detail namespace literals { - Detail::Approx operator "" _a(long double val) { + Detail::Approx operator ""_a(long double val) { return Detail::Approx(val); } - Detail::Approx operator "" _a(unsigned long long val) { + Detail::Approx operator ""_a(unsigned long long val) { return Detail::Approx(val); } } // end namespace literals diff --git a/exercises/concept/making-the-grade/.docs/hints.md b/exercises/concept/making-the-grade/.docs/hints.md index f47b1ce15..08ccbebe9 100644 --- a/exercises/concept/making-the-grade/.docs/hints.md +++ b/exercises/concept/making-the-grade/.docs/hints.md @@ -22,24 +22,22 @@ Also being familiar with the following can help with completing the tasks: - A results counter does need to be set up and _incremented_ -- you'll want to `return` the count of non-passing students when the loop terminates. -## 3. The "Best" +## 3. Calculating Letter Grades -- - Having an empty `vector` to add the "best" marks to is helpful here. -- `.emplace_back()` can help add things to the results `vector`. - -## 4. Calculating Letter Grades - -- These are _lower thresholds_. The _lower threshold_ for a "D" is a score of **41**, since an "F" is **<= 40**. +- The score needed to avoid failing is always 41, since an "F" is **<= 40**. The remaining score range, from 41 to the highest score, should be divided into four equal intervals, one for each letter grade. +- Subtract 40 from the highest score to get the total range of scores that qualify for letter grades (A to D). +- Divide this total range by 4 to get the size of each grade interval. +- Add this interval size to 40 repeatedly to calculate the lower bounds for each letter grade. - `static_cast` without parameters should round off increments nicely. - You are expected to return an array, not a vector. -## 5. Matching Names to Scores +## 4. Matching Names to Scores - If both containers are the same length and sorted the same way, could you use the `index` from one to retrieve a `value` from the other? - `std::to_string(int)` can be used to convert a number to string. - Don't forget the follow the format of the example's output. -## 6. A "Perfect" Score +## 5. A "Perfect" Score - There may be or may not be a student with a score of 100, and you can't return an empty string without checking **all** scores. - The `control flow` statements `continue` and `break` may be useful here to move past unwanted values. diff --git a/exercises/concept/making-the-grade/.docs/instructions.md b/exercises/concept/making-the-grade/.docs/instructions.md index ca51ef684..058689ac9 100644 --- a/exercises/concept/making-the-grade/.docs/instructions.md +++ b/exercises/concept/making-the-grade/.docs/instructions.md @@ -21,6 +21,13 @@ round_down_scores(student_scores) // => {90, 40, 55, 70, 30, 25, 80, 95, 38, 40} ``` +There are other methods which achieve the same result, but a _cast_ is a common sight. + +```cpp +int new_PI{static_cast(3.14) + static_cast(0.001592653589)}; +// new_PI is 3. +``` + ## 2. Non-Passing Students As you were grading the exam, you noticed some students weren't performing as well as you'd hoped. @@ -35,20 +42,7 @@ count_failed_students({90,40,55,70,30,25,80,95,38,40}); // => 5 ``` -## 3. The "Best" - -The teacher you're assisting wants to find the group of students who've performed "the best" on this exam. -What qualifies as "the best" fluctuates, so you need to find the student scores that are **greater than or equal to** the current threshold. - -Create the function `above_threshold()` taking `student_scores` (a `vector` of grades), and `threshold` (an `int`, the "top score" threshold) as parameters. -This function should return a `vector` of all scores that are `>=` to `threshold`. - -```cpp -above_threshold({90,40,55,70,30,68,70,75,83,96}, 75); -// => {90,75,83,96} -``` - -## 4. Calculating Letter Grades +## 3. Calculating Letter Grades The teacher you're assisting likes to assign letter grades as well as numeric scores. Since students rarely score 100 on an exam, the "letter grade" lower thresholds are calculated based on the highest score achieved, and increment evenly between the high score and the failing threshold of **<= 40**. @@ -80,7 +74,7 @@ letter_grades(88); // => {41, 53, 65, 77} ``` -## 5. Matching Names to Scores +## 4. Matching Names to Scores You have exam scores in descending order, and the respective student names (sorted in the order of their exam scores). You would like to match each student's name with their exam score and print out an overall class ranking. @@ -98,7 +92,7 @@ student_ranking(student_scores, student_names) // {"1. Joci: 100", "2. Sara: 99", "3. Kora: 90", "4. Jan: 84", "5. Indra: 66", "6. Bern: 53", "7. Fred: 47"} ``` -## 6. A "Perfect" Score +## 5. A "Perfect" Score Although a "perfect" score of 100 is rare on an exam, it is interesting to know if at least one student has achieved it. diff --git a/exercises/concept/making-the-grade/.meta/exemplar.cpp b/exercises/concept/making-the-grade/.meta/exemplar.cpp index 2d06eda4c..7c5cefee0 100644 --- a/exercises/concept/making-the-grade/.meta/exemplar.cpp +++ b/exercises/concept/making-the-grade/.meta/exemplar.cpp @@ -5,60 +5,51 @@ // Round down all provided student scores. std::vector round_down_scores(std::vector student_scores) { std::vector rounded{}; - for(int i{}; i < student_scores.size(); ++i) + for (int i{}; i < student_scores.size(); ++i) rounded.emplace_back(student_scores.at(i)); return rounded; } - // Count the number of failing students out of the group provided. int count_failed_students(std::vector student_scores) { int counter{}; - for(int i{}; i < student_scores.size(); ++i) { - if (student_scores.at(i) < 41) - ++counter; + for (int i{}; i < student_scores.size(); ++i) { + if (student_scores.at(i) < 41) ++counter; } return counter; } -// Determine how many of the provided student scores were 'the best' based on the provided threshold. -std::vector above_threshold(std::vector student_scores, int threshold) { - std::vector above{}; - for(int i{}; i < student_scores.size(); ++i) { - if (student_scores.at(i) >= threshold) - above.emplace_back(student_scores.at(i)); - } - - return above; -} - // Create a list of grade thresholds based on the provided highest grade. std::array letter_grades(int highest_score) { std::array grades{}; - for(int i{}, lower_threshold{41}, step_size{(highest_score - 40) / 4}; - i < 4; ++i) { + for (int i{}, lower_threshold{41}, step_size{(highest_score - 40) / 4}; + i < 4; ++i) { grades.at(i) = lower_threshold + step_size * i; } return grades; } // Organize the student's rank, name, and grade information in ascending order. -std::vector student_ranking(std::vector student_scores, std::vector student_names) { +std::vector student_ranking( + std::vector student_scores, std::vector student_names) { std::vector ranking{}; - for(int i{}; i < student_scores.size(); ++i) { - ranking.emplace_back(std::to_string(i + 1) + ". " + student_names.at(i) + ": " + std::to_string(student_scores.at(i))); - } - + for (int i{}; i < student_scores.size(); ++i) { + ranking.emplace_back(std::to_string(i + 1) + ". " + + student_names.at(i) + ": " + + std::to_string(student_scores.at(i))); + } + return ranking; } -// Create a string that contains the name of the first student to make a perfect score on the exam. -std::string perfect_score(std::vector student_scores, std::vector student_names) { +// Create a string that contains the name of the first student to make a perfect +// score on the exam. +std::string perfect_score(std::vector student_scores, + std::vector student_names) { std::vector ranking{}; - for(int i{}; i < student_scores.size(); ++i) { - if (student_scores.at(i) == 100) - return student_names.at(i); - } - + for (int i{}; i < student_scores.size(); ++i) { + if (student_scores.at(i) == 100) return student_names.at(i); + } + return ""; -} \ No newline at end of file +} diff --git a/exercises/concept/making-the-grade/CMakeLists.txt b/exercises/concept/making-the-grade/CMakeLists.txt index e46606bd5..ba6b66368 100644 --- a/exercises/concept/making-the-grade/CMakeLists.txt +++ b/exercises/concept/making-the-grade/CMakeLists.txt @@ -58,9 +58,12 @@ if(${EXERCISM_RUN_ALL_TESTS}) endif() # Tell MSVC not to warn us about unchecked iterators in debug builds +# Treat warnings as errors +# Treat type conversion warnings C4244 and C4267 as level 4 warnings, i.e. ignore them in level 3 if(${MSVC}) set_target_properties(${exercise} PROPERTIES - COMPILE_DEFINITIONS_DEBUG _SCL_SECURE_NO_WARNINGS) + COMPILE_DEFINITIONS_DEBUG _SCL_SECURE_NO_WARNINGS + COMPILE_FLAGS "/WX /w44244 /w44267") endif() # Run the tests on every build diff --git a/exercises/concept/making-the-grade/making_the_grade.cpp b/exercises/concept/making-the-grade/making_the_grade.cpp index 6684d59bb..3ef90da9d 100644 --- a/exercises/concept/making-the-grade/making_the_grade.cpp +++ b/exercises/concept/making-the-grade/making_the_grade.cpp @@ -8,19 +8,12 @@ std::vector round_down_scores(std::vector student_scores) { return {}; } - // Count the number of failing students out of the group provided. int count_failed_students(std::vector student_scores) { // TODO: Implement count_failed_students return 0; } -// Determine how many of the provided student scores were 'the best' based on the provided threshold. -std::vector above_threshold(std::vector student_scores, int threshold) { - // TODO: Implement above_threshold - return {}; -} - // Create a list of grade thresholds based on the provided highest grade. std::array letter_grades(int highest_score) { // TODO: Implement letter_grades @@ -28,13 +21,16 @@ std::array letter_grades(int highest_score) { } // Organize the student's rank, name, and grade information in ascending order. -std::vector student_ranking(std::vector student_scores, std::vector student_names) { +std::vector student_ranking( + std::vector student_scores, std::vector student_names) { // TODO: Implement student_ranking return {}; } -// Create a string that contains the name of the first student to make a perfect score on the exam. -std::string perfect_score(std::vector student_scores, std::vector student_names) { +// Create a string that contains the name of the first student to make a perfect +// score on the exam. +std::string perfect_score(std::vector student_scores, + std::vector student_names) { // TODO: Implement perfect_score return ""; } diff --git a/exercises/concept/making-the-grade/making_the_grade_test.cpp b/exercises/concept/making-the-grade/making_the_grade_test.cpp index a045855e8..e66b7a58d 100644 --- a/exercises/concept/making-the-grade/making_the_grade_test.cpp +++ b/exercises/concept/making-the-grade/making_the_grade_test.cpp @@ -49,57 +49,21 @@ TEST_CASE("Count failed students (some failed)", "[task_2]") { REQUIRE(expected == actual); } -TEST_CASE("Test threshold (empty)", "[task_3]") { - vector input{}; - int threshold{98}; - vector expected{}; - vector actual = above_threshold(input, threshold); - - REQUIRE(expected == actual); -} - -TEST_CASE("Test threshold (some above threshold)", "[task_3]") { - vector input{88, 29, 91, 64, 78, 43, 41, 77, 36, 50}; - int threshold{80}; - vector expected{88, 91}; - vector actual = above_threshold(input, threshold); - - REQUIRE(expected == actual); -} - -TEST_CASE("Test threshold (none above threshold)", "[task_3]") { - vector input{88, 29, 91, 64, 78, 43, 41, 77, 36, 50}; - int threshold{99}; - vector expected{}; - vector actual = above_threshold(input, threshold); - - REQUIRE(expected == actual); -} - -TEST_CASE("Test threshold (some on threshold)", "[task_3]") { - vector input{88, 29, 91, 64, 78, 43, 41, 77, 80, 80}; - int threshold{80}; - vector expected{88, 91, 80, 80}; - vector actual = above_threshold(input, threshold); - - REQUIRE(expected == actual); -} - -TEST_CASE("Test letter grades: 100", "[task_4]") { +TEST_CASE("Test letter grades: 100", "[task_3]") { int input{100}; array expected{41, 56, 71, 86}; array actual = letter_grades(input); REQUIRE(expected == actual); } -TEST_CASE("Test letter grades: 97", "[task_4]") { +TEST_CASE("Test letter grades: 97", "[task_3]") { int input{97}; array expected{41, 55, 69, 83}; array actual = letter_grades(input); REQUIRE(expected == actual); } -TEST_CASE("Test letter grades: 81", "[task_4]") { +TEST_CASE("Test letter grades: 81", "[task_3]") { int input{81}; array expected{41, 51, 61, 71}; array actual = letter_grades(input); @@ -107,7 +71,7 @@ TEST_CASE("Test letter grades: 81", "[task_4]") { REQUIRE(expected == actual); } -TEST_CASE("Rank one student", "[task_5]") { +TEST_CASE("Rank one student", "[task_4]") { vector grades{82}; vector names{"Betty"}; vector expected{"1. Betty: 82"}; @@ -116,37 +80,42 @@ TEST_CASE("Rank one student", "[task_5]") { REQUIRE(expected == actual); } -TEST_CASE("Rank several student", "[task_5]") { +TEST_CASE("Rank several student", "[task_4]") { vector grades{100, 98, 92, 86, 70, 68, 67, 60}; - vector names{"Rui", "Betty", "Joci", "Yoshi", "Kora", "Bern", "Jan", "Rose"}; - vector expected{"1. Rui: 100", "2. Betty: 98", "3. Joci: 92", "4. Yoshi: 86", - "5. Kora: 70", "6. Bern: 68", "7. Jan: 67", "8. Rose: 60"}; + vector names{"Rui", "Betty", "Joci", "Yoshi", + "Kora", "Bern", "Jan", "Rose"}; + vector expected{"1. Rui: 100", "2. Betty: 98", "3. Joci: 92", + "4. Yoshi: 86", "5. Kora: 70", "6. Bern: 68", + "7. Jan: 67", "8. Rose: 60"}; vector actual = student_ranking(grades, names); REQUIRE(expected == actual); } -TEST_CASE("No perfect score", "[task_6]") { +TEST_CASE("No perfect score", "[task_5]") { vector grades{11, 34, 92, 23, 70, 76, 67, 60}; - vector names{"Rui", "Betty", "Joci", "Yoshi", "Kora", "Bern", "Jan", "Rose"}; + vector names{"Rui", "Betty", "Joci", "Yoshi", + "Kora", "Bern", "Jan", "Rose"}; string expected{""}; string actual = perfect_score(grades, names); REQUIRE(expected == actual); } -TEST_CASE("One perfect score", "[task_6]") { +TEST_CASE("One perfect score", "[task_5]") { vector grades{11, 34, 92, 23, 70, 76, 67, 100}; - vector names{"Rui", "Betty", "Joci", "Yoshi", "Kora", "Bern", "Jan", "Rose"}; + vector names{"Rui", "Betty", "Joci", "Yoshi", + "Kora", "Bern", "Jan", "Rose"}; string expected{"Rose"}; string actual = perfect_score(grades, names); REQUIRE(expected == actual); } -TEST_CASE("Several perfect scores", "[task_6]") { +TEST_CASE("Several perfect scores", "[task_5]") { vector grades{11, 100, 92, 23, 70, 100, 67, 100}; - vector names{"Rui", "Betty", "Joci", "Yoshi", "Kora", "Bern", "Jan", "Rose"}; + vector names{"Rui", "Betty", "Joci", "Yoshi", + "Kora", "Bern", "Jan", "Rose"}; string expected{"Betty"}; string actual = perfect_score(grades, names); diff --git a/exercises/concept/making-the-grade/test/catch.hpp b/exercises/concept/making-the-grade/test/catch.hpp index 36eaeb27f..ff40b4fd6 100644 --- a/exercises/concept/making-the-grade/test/catch.hpp +++ b/exercises/concept/making-the-grade/test/catch.hpp @@ -3175,8 +3175,8 @@ namespace Detail { } // end namespace Detail namespace literals { - Detail::Approx operator "" _a(long double val); - Detail::Approx operator "" _a(unsigned long long val); + Detail::Approx operator ""_a(long double val); + Detail::Approx operator ""_a(unsigned long long val); } // end namespace literals template<> @@ -7911,10 +7911,10 @@ namespace Detail { } // end namespace Detail namespace literals { - Detail::Approx operator "" _a(long double val) { + Detail::Approx operator ""_a(long double val) { return Detail::Approx(val); } - Detail::Approx operator "" _a(unsigned long long val) { + Detail::Approx operator ""_a(unsigned long long val) { return Detail::Approx(val); } } // end namespace literals diff --git a/exercises/concept/pacman-rules/.meta/exemplar.cpp b/exercises/concept/pacman-rules/.meta/exemplar.cpp index 734f47afb..0ca1c6da2 100644 --- a/exercises/concept/pacman-rules/.meta/exemplar.cpp +++ b/exercises/concept/pacman-rules/.meta/exemplar.cpp @@ -25,4 +25,4 @@ bool lost(bool power_pellet_active, bool touching_ghost) { bool won(bool has_eaten_all_dots, bool power_pellet_active, bool touching_ghost) { return has_eaten_all_dots && !lost(power_pellet_active, touching_ghost); -} \ No newline at end of file +} diff --git a/exercises/concept/pacman-rules/CMakeLists.txt b/exercises/concept/pacman-rules/CMakeLists.txt index b79c51e67..8e21222a2 100644 --- a/exercises/concept/pacman-rules/CMakeLists.txt +++ b/exercises/concept/pacman-rules/CMakeLists.txt @@ -57,9 +57,12 @@ if(${EXERCISM_RUN_ALL_TESTS}) endif() # Tell MSVC not to warn us about unchecked iterators in debug builds +# Treat warnings as errors +# Treat type conversion warnings C4244 and C4267 as level 4 warnings, i.e. ignore them in level 3 if(${MSVC}) set_target_properties(${exercise} PROPERTIES - COMPILE_DEFINITIONS_DEBUG _SCL_SECURE_NO_WARNINGS) + COMPILE_DEFINITIONS_DEBUG _SCL_SECURE_NO_WARNINGS + COMPILE_FLAGS "/WX /w44244 /w44267") endif() # Run the tests on every build diff --git a/exercises/concept/pacman-rules/pacman_rules.cpp b/exercises/concept/pacman-rules/pacman_rules.cpp index 8160dc752..8625a2596 100644 --- a/exercises/concept/pacman-rules/pacman_rules.cpp +++ b/exercises/concept/pacman-rules/pacman_rules.cpp @@ -29,4 +29,4 @@ bool won(bool has_eaten_all_dots, bool power_pellet_active, bool touching_ghost) { // TODO: Please implement the won function return false; -} \ No newline at end of file +} diff --git a/exercises/concept/pacman-rules/pacman_rules_test.cpp b/exercises/concept/pacman-rules/pacman_rules_test.cpp index 549dc5cd7..70314a9cd 100644 --- a/exercises/concept/pacman-rules/pacman_rules_test.cpp +++ b/exercises/concept/pacman-rules/pacman_rules_test.cpp @@ -5,59 +5,65 @@ #include "test/catch.hpp" #endif - -TEST_CASE( "ghost gets eaten", "[task_1]") { - REQUIRE( can_eat_ghost(true, true)); +TEST_CASE("ghost gets eaten", "[task_1]") { + REQUIRE(can_eat_ghost(true, true)); } #if defined(EXERCISM_RUN_ALL_TESTS) -TEST_CASE( "ghost does not get eaten because no power pellet active", "[task_1]") { - REQUIRE_FALSE( can_eat_ghost(false, true)); +TEST_CASE("ghost does not get eaten because no power pellet active", + "[task_1]") { + REQUIRE_FALSE(can_eat_ghost(false, true)); } -TEST_CASE( "ghost does not get eaten because not touching ghost", "[task_1]") { - REQUIRE_FALSE( can_eat_ghost(true, false)); +TEST_CASE("ghost does not get eaten because not touching ghost", "[task_1]") { + REQUIRE_FALSE(can_eat_ghost(true, false)); } -TEST_CASE( "ghost does not get eaten because no power pellet is active, even if not touching ghost", "[task_1]") { - REQUIRE_FALSE( can_eat_ghost(false, false)); -} - -TEST_CASE("score when eating dot", "[task_2]") { - REQUIRE( scored(false, true)); +TEST_CASE( + // clang-format off + "ghost does not get eaten because no power pellet is active, even if not touching ghost", + // clang-format on + "[task_1]") { + REQUIRE_FALSE(can_eat_ghost(false, false)); } +TEST_CASE("score when eating dot", "[task_2]") { REQUIRE(scored(false, true)); } + TEST_CASE("score when eating power pellet", "[task_2]") { - REQUIRE( scored(true, false)); + REQUIRE(scored(true, false)); } TEST_CASE("no score when nothing eaten", "[task_2]") { - REQUIRE_FALSE( scored(false, false)); + REQUIRE_FALSE(scored(false, false)); } - -TEST_CASE("lose if touching a ghost without a power pellet active", "[task_3]") { - REQUIRE( lost(false, true)); + +TEST_CASE("lose if touching a ghost without a power pellet active", + "[task_3]") { + REQUIRE(lost(false, true)); } -TEST_CASE("don't lose if touching a ghost with a power pellet active", "[task_3]") { - REQUIRE_FALSE( lost(true, true)); +TEST_CASE("don't lose if touching a ghost with a power pellet active", + "[task_3]") { + REQUIRE_FALSE(lost(true, true)); } TEST_CASE("don't lose if not touching a ghost", "[task_3]") { - REQUIRE_FALSE( lost(true, false)); + REQUIRE_FALSE(lost(true, false)); } -TEST_CASE( "win if all dots eaten", "[task_4]") { - REQUIRE( won(true, false, false)); +TEST_CASE("win if all dots eaten", "[task_4]") { + REQUIRE(won(true, false, false)); } -TEST_CASE( "don't win if all dots eaten, but touching a ghost", "[task_4]") { - REQUIRE_FALSE( won(true, false, true)); +TEST_CASE("don't win if all dots eaten, but touching a ghost", "[task_4]") { + REQUIRE_FALSE(won(true, false, true)); } -TEST_CASE( "win if all dots eaten and touching a ghost with a power pellet active", "[task_4]") { - REQUIRE( won(true, true, true)); +TEST_CASE( + "win if all dots eaten and touching a ghost with a power pellet active", + "[task_4]") { + REQUIRE(won(true, true, true)); } #endif diff --git a/exercises/concept/pacman-rules/test/catch.hpp b/exercises/concept/pacman-rules/test/catch.hpp index 36eaeb27f..ff40b4fd6 100644 --- a/exercises/concept/pacman-rules/test/catch.hpp +++ b/exercises/concept/pacman-rules/test/catch.hpp @@ -3175,8 +3175,8 @@ namespace Detail { } // end namespace Detail namespace literals { - Detail::Approx operator "" _a(long double val); - Detail::Approx operator "" _a(unsigned long long val); + Detail::Approx operator ""_a(long double val); + Detail::Approx operator ""_a(unsigned long long val); } // end namespace literals template<> @@ -7911,10 +7911,10 @@ namespace Detail { } // end namespace Detail namespace literals { - Detail::Approx operator "" _a(long double val) { + Detail::Approx operator ""_a(long double val) { return Detail::Approx(val); } - Detail::Approx operator "" _a(unsigned long long val) { + Detail::Approx operator ""_a(unsigned long long val) { return Detail::Approx(val); } } // end namespace literals diff --git a/exercises/concept/power-of-troy/.docs/after.md b/exercises/concept/power-of-troy/.docs/after.md new file mode 100644 index 000000000..df322194f --- /dev/null +++ b/exercises/concept/power-of-troy/.docs/after.md @@ -0,0 +1,97 @@ +# After + +Smart pointers are a modern C++ feature designed to provide automatic memory management, helping to prevent memory leaks and dangling pointers commonly associated with raw pointers. +They act as wrappers around raw pointers, adding additional functionality such as automatic memory deallocation when the pointer is no longer needed. + +## General Syntax + +Smart pointers are typically implemented as class templates in the C++ standard library. +The two most commonly used smart pointers are `std::unique_ptr` and `std::shared_ptr`. + +## Unique Pointers + +`std::unique_ptr` is a smart pointer that owns the object exclusively. +It ensures that at any given time, only one `std::unique_ptr` object owns the resource. +When the owning `std::unique_ptr` is destroyed or reset, it automatically destructs the objects and releases its memory. + +```cpp +#include +// Declaring and defining a unique pointer +auto rightful_king_of_england = std::make_unique("Excalibur"); + +// Unique pointers cannot be copied or assigned +auto mordred = rightful_king_of_england; // Error: Cannot copy a unique_ptr +``` + +## Advantages of `std::make_unique()` + +When creating a `std::unique_ptr`, it's preferable to use `std::make_unique()` instead of directly using `new` to allocate memory. +`std::make_unique()` provides several advantages: + +1. **Exception Safety**: `std::make_unique()` guarantees exception safety. + If an exception is thrown during the construction of the object, memory will be automatically deallocated, preventing memory leaks. +2. **Clarity**: Using `std::make_unique()` makes code clearer and more concise. + It eliminates the need to explicitly specify the type being allocated, as the template arguments are deduced automatically. +3. **Optimization Opportunities**: Compilers have the opportunity to optimize `std::make_unique()` more effectively than manually allocating memory with `new`, potentially resulting in improved performance. +4. **Avoiding Misuse**: Deleting the underlying resource is possible, when the `std::unique_ptr` is constructed manually. + That would lead to undefined behavior, when the `std::unique_ptr` tries to delete it at its end of scope. + +## Shared Pointers + +`std::shared_ptr` is a smart pointer that allows multiple `std::shared_ptr` objects to share ownership of the same resource. +It keeps track of how many shared pointers are referencing the resource, and deallocates the memory only when the last shared pointer owning the resource goes out of scope or is reset. + +```cpp +// Declaring and defining a shared pointer to a dynamically allocated string +auto martian_congressional_republic = std::make_shared("protomolecule"); + +// Creating more shared pointer that shares ownership +auto outer_planets_alliance = martian_congressional_republic; +auto united_nations = martian_congressional_republic; +``` + +~~~~exercism/caution +In C++17 and below, using `std::shared_ptr` with arrays via `std::make_shared` is not directly supported. +While it's possible to allocate arrays with `std::make_shared`, creating shared pointers directly from them may lead to undefined behavior due to differences in memory management between single objects and arrays. +Instead, consider using `std::vector` or custom deletion functions to manage arrays with shared pointers effectively. +Always ensure compatibility with your compiler and standard library implementation when dealing with array allocations and shared pointers in C++17. +~~~~ + +## Advantages of `std::make_shared()` + +Similar to `std::make_unique()`, `std::make_shared()` offers benefits such as improved memory efficiency, exception safety, and readability. +It combines memory allocation for the control block and the managed object into a single operation, enhancing efficiency and reducing the risk of memory leaks. +Additionally, automatic deduction of template arguments simplifies code and enhances readability. +Using `std::make_shared()` promotes cleaner, safer, and more efficient code when working with `std::shared_ptr` objects in C++. + +~~~~exercism/advanced +## Weak Pointers + +`std::weak_ptr` is a companion class to `std::shared_ptr` that provides a non-owning "weak" reference to an object managed by a shared pointer. + +```cpp +// Creating a shared pointer +auto your_account = std::make_shared("secret_subscription_password"); +// Creating a shared pointer that shares ownership +auto your_flatmates_account = your_account; + +// Creating a weak pointer from the shared pointer +auto your_flatmates_boyfriends_account = your_flatmates_account; +// if your_account and your_flatmates_account are deleted, there is no more reference to the shared pointer. +// your_flatmates_boyfriends_account will be a null pointer and cannot use the associated object any longer. +``` + +Weak pointers are useful in scenarios where cyclic references need to be broken to prevent memory leaks. +`std::weak_ptr` was designed to address the issue of cyclic ownership, also known as circular references, that can occur when using `std::shared_ptr`. +In a cyclic ownership scenario, two or more `std::shared_ptr` objects are referencing each other, creating a cycle where none of the objects can be deleted because they have strong references to each other, leading to memory leaks. +`std::weak_ptr` provides a solution to this problem by allowing weak references to shared objects without contributing to their reference count. +This means that it can observe and access the shared object but doesn't prevent it from being deleted. +~~~~ + +## Usage advice + +Use smart pointers by default: `std::unique_ptr` for exclusive ownership and `std::shared_ptr` for shared ownership. +Reserve raw pointers for non-owning references or when interfacing with legacy code. +In most cases, `std::unique_ptr` is sufficient for exclusive ownership, as it offers lightweight memory management without the overhead of reference counting. +`std::shared_ptr` should be used sparingly, as it introduces overhead and complexity unless true shared ownership is needed. +`std::weak_ptr` is specialized for breaking cyclic dependencies or observing shared objects, but it's not commonly used. diff --git a/exercises/concept/power-of-troy/.docs/hints.md b/exercises/concept/power-of-troy/.docs/hints.md new file mode 100644 index 000000000..90876e410 --- /dev/null +++ b/exercises/concept/power-of-troy/.docs/hints.md @@ -0,0 +1,43 @@ +# Hints + +## 1. Bring humans to the world of Troy + +- The core of this exercise is the usage of `unique_ptr` and `shared_ptr`. + Which kind of smart pointer should be used for each of the `human` variables? +- `artifacts` are not shared, but `powers` are needed to track influenced people. +- the `possession` pointer should be unique, the power pointers should be shared. + +## 2. Bring Artifacts into Troy + +- You need to create a smart pointer and assign it to the `possession` variable +- Use _references_ to change the object outside of the function. +- Look up [`std::make_unique`][make_unique] for some hints. +- The type of the pointer's target object has to be put in the angled brackets and again inside the parens to define the object. +- Here is a full example: `variable = std::make_unique(int{23});` + +## 3. Make items tradeable + +- You can look through the [unique_ptr reference][unique_ptr] to find a fitting function. +- Do you think `std::swap` can help you? + +## 4. Give Power to the People + +- You need to create a smart pointer and assign it to the `own_power` variable +- Use _references_ to change the object outside of the function. +- Look up [`std::make_shared`][make_shared] for some hints. +- The type of the pointer's target object has to be put in the angled brackets and again inside the parens to define the object. +- Here is a full example: `variable = std::make_shared(int{23});` + +## 5. Use the Power + +- Use _references_ to change the object outside of the function. + +## 6. Keep watch on the power's intensity + +- You can look through the [shared_ptr reference][shared_ptr] to find a fitting function. +- Do you think `use_count` can help you? + +[unique_ptr]: https://en.cppreference.com/w/cpp/memory/unique_ptr +[make_unique]: https://en.cppreference.com/w/cpp/memory/unique_ptr/make_unique +[shared_ptr]: https://en.cppreference.com/w/cpp/memory/shared_ptr +[make_shared]: https://en.cppreference.com/w/cpp/memory/shared_ptr/make_shared diff --git a/exercises/concept/power-of-troy/.docs/instructions.md b/exercises/concept/power-of-troy/.docs/instructions.md new file mode 100644 index 000000000..b4eb37608 --- /dev/null +++ b/exercises/concept/power-of-troy/.docs/instructions.md @@ -0,0 +1,145 @@ +# Instructions + +This exercise takes you to the world of Troy. +The lives of its people are full of wonder and magic. +Many humans in Troy possess _powers_, that are used frequently in their daily lives. +Powers are used to re-shape the world or influence Troy's fauna and other people. +Magic also manifests in _unique artifacts_, that are highly sought after by adventurers, artisans and sages. + +In this exercise you are going to write code to model the humans of Troy, their possessed artifacts and power interactions. + +You have six tasks. +The first one is related to creating a human, the other five are about handling powers and artifacts. + +## 1. Bring humans to the world of Troy + +For your model of Troy, humans are the most important feature. +Your model human should be able to possess a _unique artifact_. +They should also have the ability to manifest a _power_. +These powers might affect other humans, so you also want to model if a human is influenced by some other power. + +You are provided with basic implementations of `artifact` and `power` structs. +Implement a `human` struct (or class) that has a _smart-pointer_ to an `artifact` member variable named `possession`. +Each artifact can only be possessed by a single human at any given time. + +A `human` must have two additional member variables. +One holds their `own_power` and the other is a power they are `influenced_by`. +Both `own_power` and `influenced_by` are _smart-pointers_ to `powers`. +Each `power` might be owned by a single human, but also influence other humans at the same time. + +By default, humans are born without any artifact and neither own any powers nor are they influenced by them. + +```cpp +human mindy_mccready{}; +mindy_mccready.possession; +// => nullptr +mindy_mccready.own_power; +// => nullptr +mindy_mccready.influenced_by; +// => nullptr +``` + +## 2. Bring Artifacts into Troy + +Your model is boring without the interaction of its parts. +You want to create unique artifacts and give them to certain humans. + +Define the function `give_new_artifact` which returns nothing but takes a reference to a `human` and a `string`. +With the `string` it should define a new `artifact` object and set the `possession` pointer of the `human` accordingly. +The function should not return anything. + +```cpp +human erik_magnus_lehnsherr{}; +give_new_artifact(erik_magnus_lehnsherr, "Mind shielding helmet"); + +erik_magnus_lehnsherr.possession->name; +// "Mind shielding helmet" +``` + +## 3. Make items tradeable + +The world of Troy is all about interaction. +You want people to make trades by exchanging their possessions. + +Write a function `exchange_artifacts` that returns nothing but takes two artifact smart-pointers to exchange the items. +Remember, that you cannot copy a `unique_ptr`. +This includes the usage in function parameters. +Use a reference to the `unique_ptr` instead. + +```cpp +human uchiha{}; +give_new_artifact(uchiha, "konoha headband"); +human uzumaki{}; +give_new_artifact(uzumaki, "forehead protector"); + +exchange_artifacts(uchiha.possession, uzumaki.possession); + +uchiha.possession->name; +// "forehead protector" +uzumaki.possession->name; +// "konoha headband" +``` + +## 4. Give Power to the People + +The most exciting feature of Troy are the special powers that people might wield. +Some can smelt iron with their thoughts, while others can heal every wound instantly at nighttime. + +Define the function `manifest_power` which returns nothing but takes a reference to a `human` and a `string`. +With the `string` it should define a new `power` object and set the `own_power` pointer of the `human` accordingly. +The function should not return anything. + +```cpp +human eleven {}; +manifest_power(eleven, "psychokinesis"); + +eleven.own_power->effect; +// "psychokinesis" +``` + +## 5. Use the Power + +What use are the greatest powers, if you cannot use them. +Your model concentrates on humans, so you want to track the influence of powers. + +Write a _void_ function `use_power` that takes two references to humans. +The first human is the caster and the second represents the target. +The target's `influenced_by` pointer should be pointed to the power of the caster. + +For simplicity, humans can only be influenced by a single power. +This power stays in place even if the caster does not exist any longer. + +```cpp +human pamela_isley{}; +manifest_power(pamela_isley, "control pheromones"); + +human count_vertigo{}; +use_power(pamela_isley, count_vertigo); +count_vertigo.influenced_by->effect; +// "control pheromones" +``` + +## 6. Keep watch on the power's intensity + +Certain powers lose their potency or trigger certain effects in your simulation when they are applied to several humans. +You want to track the number of people who are connected to each power. + +Define the function `power_intensity`, that takes a human and returns the intensity of their power as an _int_. +If the person has no power, the return value should be `0`. +Otherwise the intensity should reflect the caster and all currently influenced people. + +```cpp +human jean_grey{}; +manifest_power(jean_grey, "uplifting personality"); + +human scott{}; +human logan{}; +human ororo{}; + +use_power(jean_grey, ororo); +use_power(jean_grey, logan); +use_power(jean_grey, scott); + +power_intensity(jean_grey); +// 4 +``` diff --git a/exercises/concept/power-of-troy/.docs/introduction.md b/exercises/concept/power-of-troy/.docs/introduction.md new file mode 100644 index 000000000..329968d5f --- /dev/null +++ b/exercises/concept/power-of-troy/.docs/introduction.md @@ -0,0 +1,114 @@ +# Introduction + +## The `auto` Keyword in C++ + +In C++, the `auto` keyword is a powerful feature introduced in C++11, used to declare variables with an inferred data type. +The compiler deduces the type of the variable based on its initializer, which can make code more readable and easier to maintain. + +## Example Usage + +Consider the following example where `auto` is used to declare variables: + +```cpp +auto dragon_population{3}; // dragon_population is deduced as an integer +auto westeros{7.7777}; // westeros is deduced as a double +auto wedding_location{"The Twins"}; // wedding_location is deduced as a const char*, not std::string +``` + +In each case, the type of the variable is inferred from the value it is initialized with. + +## Type Inference + +The `auto` keyword helps by writing more concise and readable code by reducing the verbosity of explicit types. + +```cpp +const std::vector pigeon_pie{"flour", "butter", "pigeon", "salt"}; +auto purple_wedding_pie{pigeon_pie}; +purple_wedding_pie.emplace_back("the strangler"); +``` + +In this loop, `auto` deduces the type of `purple_wedding_pie` as `std::vector`, avoiding the need to explicitly specify the type again. + +## Compatibility + +The `auto` keyword is compatible with various C++ constructs making it a versatile tool in modern C++ programming. + +```cpp +auto& element{array[0]}; // reference to an element +const auto object{otherObject}; // const type version of otherObject's type +auto* ptr{&x}; // pointer to x with the same type as x, but as a pointer. +``` + +In later concept we will often see the `auto` keyword with lambda expressions, range-based for-loops, and iterators. + +## Smart Pointers + +Smart pointers are a modern C++ feature designed to provide automatic memory management, helping to prevent memory leaks and dangling pointers commonly associated with raw pointers. +They act as wrappers around raw pointers, adding additional functionality such as automatic memory deallocation when the pointer is no longer needed. + +## General Syntax + +Smart pointers are typically implemented as class templates in the C++ standard library. +The two most commonly used smart pointers are `std::unique_ptr` and `std::shared_ptr`. + +## Unique Pointers + +`std::unique_ptr` is a smart pointer that owns the object exclusively. +It ensures that at any given time, only one `std::unique_ptr` object owns the resource. +When the owning `std::unique_ptr` is destroyed or reset, it automatically destructs the objects and releases its memory. + +```cpp +#include +// Declaring and defining a unique pointer +auto rightful_king_of_england = std::make_unique("Excalibur"); + +// Unique pointers cannot be copied or assigned +auto mordred = rightful_king_of_england; // Error: Cannot copy a unique_ptr +``` + +## Advantages of `std::make_unique()` + +When creating a `std::unique_ptr`, it's preferable to use `std::make_unique()` instead of directly using `new` to allocate memory. +`std::make_unique()` provides several advantages: +1. **Exception Safety**: `std::make_unique()` guarantees exception safety. + If an exception is thrown during the construction of the object, memory will be automatically deallocated, preventing memory leaks. +2. **Clarity**: Using `std::make_unique()` makes code clearer and more concise. + It eliminates the need to explicitly specify the type being allocated, as the template arguments are deduced automatically. +3. **Optimization Opportunities**: Compilers have the opportunity to optimize `std::make_unique()` more effectively than manually allocating memory with `new`, potentially resulting in improved performance. +4. **Avoiding Misuse**: Deleting the underlying resource is possible, when the `std::unique_ptr` is constructed manually. + That would lead to undefined behavior, when the `std::unique_ptr` tries to delete it at its end of scope. + +## Shared Pointers + +`std::shared_ptr` is a smart pointer that allows multiple `std::shared_ptr` objects to share ownership of the same resource. +It keeps track of how many shared pointers are referencing the resource, and deallocates the memory only when the last shared pointer owning the resource goes out of scope or is reset. + +```cpp +// Declaring and defining a shared pointer to a dynamically allocated string +auto martian_congressional_republic = std::make_shared("protomolecule"); + +// Creating more shared pointer that shares ownership +auto outer_planets_alliance = martian_congressional_republic; +auto united_nations = martian_congressional_republic; +``` + +~~~~exercism/caution +In C++17 and below, using `std::shared_ptr` with arrays via `std::make_shared` is not directly supported. +While it's possible to allocate arrays with `std::make_shared`, creating shared pointers directly from them may lead to undefined behavior due to differences in memory management between single objects and arrays. +Instead, consider using `std::vector` or custom deletion functions to manage arrays with shared pointers effectively. +Always ensure compatibility with your compiler and standard library implementation when dealing with array allocations and shared pointers in C++17. +~~~~ + +## Advantages of `std::make_shared()` + +Similar to `std::make_unique()`, `std::make_shared()` offers benefits such as improved memory efficiency, exception safety, and readability. +It combines memory allocation for the control block and the managed object into a single operation, enhancing efficiency and reducing the risk of memory leaks. +Additionally, automatic deduction of template arguments simplifies code and enhances readability. +Using `std::make_shared()` promotes cleaner, safer, and more efficient code when working with `std::shared_ptr` objects in C++. + +## Usage advice + +Use smart pointers by default: `std::unique_ptr` for exclusive ownership and `std::shared_ptr` for shared ownership. +Reserve raw pointers for non-owning references or when interfacing with legacy code. +In most cases, `std::unique_ptr` is sufficient for exclusive ownership, as it offers lightweight memory management without the overhead of reference counting. +`std::shared_ptr` should be used sparingly, as it introduces overhead and complexity unless true shared ownership is needed. diff --git a/exercises/concept/power-of-troy/.meta/config.json b/exercises/concept/power-of-troy/.meta/config.json new file mode 100644 index 000000000..754c49e90 --- /dev/null +++ b/exercises/concept/power-of-troy/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "vaeng" + ], + "files": { + "solution": [ + "power_of_troy.cpp", + "power_of_troy.h" + ], + "test": [ + "power_of_troy_test.cpp" + ], + "exemplar": [ + ".meta/exemplar.cpp", + ".meta/exemplar.h" + ] + }, + "blurb": "Learn about smart pointers by using magic and artifacts in the world of Troy." +} diff --git a/exercises/concept/power-of-troy/.meta/design.md b/exercises/concept/power-of-troy/.meta/design.md new file mode 100644 index 000000000..da599fc0c --- /dev/null +++ b/exercises/concept/power-of-troy/.meta/design.md @@ -0,0 +1,22 @@ +# Design + +## Learning objectives + +- Know what a unique_ptr is +- Know what a shared_ptr is + +## Out of scope + +- weak_ptr + +## Concepts + +- `smart-pointers` + +## Prerequisites + +- `pointers` + +## Analyzer + +- - diff --git a/exercises/concept/power-of-troy/.meta/exemplar.cpp b/exercises/concept/power-of-troy/.meta/exemplar.cpp new file mode 100644 index 000000000..1c2ff464d --- /dev/null +++ b/exercises/concept/power-of-troy/.meta/exemplar.cpp @@ -0,0 +1,27 @@ +#include "power_of_troy.h" + +namespace troy { + +void give_new_artifact(human& receiver, std::string item_name) { + receiver.possession = + std::make_unique(artifact{item_name}); // Include hint! +} + +void exchange_artifacts(std::unique_ptr& item_a, + std::unique_ptr& item_b) { + std::swap(item_a, item_b); +} + +void manifest_power(human& receiver, std::string power_effect) { + receiver.own_power = std::make_shared(power{power_effect}); +} + +void use_power(const human& caster, human& receiver) { + receiver.influenced_by = caster.own_power; +} + +int power_intensity(const human& caster) { + return caster.own_power.use_count(); +} + +} // namespace troy diff --git a/exercises/concept/power-of-troy/.meta/exemplar.h b/exercises/concept/power-of-troy/.meta/exemplar.h new file mode 100644 index 000000000..b74daa515 --- /dev/null +++ b/exercises/concept/power-of-troy/.meta/exemplar.h @@ -0,0 +1,33 @@ +#pragma once + +#include +#include + +namespace troy { + +struct artifact { + // constructors needed (until C++20) + artifact(std::string name) : name(name) {} + std::string name; +}; + +struct power { + // constructors needed (until C++20) + power(std::string effect) : effect(effect) {} + std::string effect; +}; + +struct human { + std::unique_ptr possession; + std::shared_ptr own_power; + std::shared_ptr influenced_by; +}; + +void give_new_artifact(human& receiver, std::string item_name); +void exchange_artifacts(std::unique_ptr& item_a, + std::unique_ptr& item_b); +void manifest_power(human& receiver, std::string power_effect); +void use_power(const human& caster, human& receiver); +int power_intensity(const human& caster); + +} // namespace troy diff --git a/exercises/concept/power-of-troy/CMakeLists.txt b/exercises/concept/power-of-troy/CMakeLists.txt new file mode 100644 index 000000000..3b0589fd0 --- /dev/null +++ b/exercises/concept/power-of-troy/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/concept/power-of-troy/power_of_troy.cpp b/exercises/concept/power-of-troy/power_of_troy.cpp new file mode 100644 index 000000000..21221f7e3 --- /dev/null +++ b/exercises/concept/power-of-troy/power_of_troy.cpp @@ -0,0 +1,3 @@ +#include "power_of_troy.h" + +namespace troy {} // namespace troy diff --git a/exercises/concept/power-of-troy/power_of_troy.h b/exercises/concept/power-of-troy/power_of_troy.h new file mode 100644 index 000000000..8c09eb49e --- /dev/null +++ b/exercises/concept/power-of-troy/power_of_troy.h @@ -0,0 +1,19 @@ +#pragma once + +#include + +namespace troy { + +struct artifact { + // constructors needed (until C++20) + artifact(std::string name) : name(name) {} + std::string name; +}; + +struct power { + // constructors needed (until C++20) + power(std::string effect) : effect(effect) {} + std::string effect; +}; + +} // namespace troy diff --git a/exercises/concept/power-of-troy/power_of_troy_test.cpp b/exercises/concept/power-of-troy/power_of_troy_test.cpp new file mode 100644 index 000000000..ae95965a8 --- /dev/null +++ b/exercises/concept/power-of-troy/power_of_troy_test.cpp @@ -0,0 +1,118 @@ +#include "power_of_troy.h" +#ifdef EXERCISM_TEST_SUITE +#include +#else +#include "test/catch.hpp" +#endif + +using namespace troy; + +TEST_CASE("Create a human", "[task_1]") { + human lanfeust{}; + + REQUIRE(lanfeust.possession == nullptr); + REQUIRE(lanfeust.own_power == nullptr); + REQUIRE(lanfeust.influenced_by == nullptr); +} + +#if defined(EXERCISM_RUN_ALL_TESTS) + +TEST_CASE("Give a new artifact to a human", "[task_2]") { + human lanfeust{}; + std::string pommel{"Magohamoth Ivory Sword Pommel"}; + + give_new_artifact(lanfeust, pommel); + + REQUIRE(lanfeust.possession != nullptr); + REQUIRE(lanfeust.possession->name == pommel); +} + +TEST_CASE("Exchange artifact with another human", "[task_3]") { + human zoltan{}; + std::string worldstone_shard{"Soulstone"}; + give_new_artifact(zoltan, worldstone_shard); + human tal_rasha{}; + + exchange_artifacts(zoltan.possession, tal_rasha.possession); + + REQUIRE(zoltan.possession == nullptr); + REQUIRE(tal_rasha.possession->name == worldstone_shard); +} + +TEST_CASE("Manifest power in a human", "[task_4]") { + human cian{}; + std::string gift_of_night{"heal"}; + + manifest_power(cian, gift_of_night); + + REQUIRE(cian.own_power != nullptr); + REQUIRE(cian.own_power->effect == gift_of_night); +} + +TEST_CASE("Use power on another human", "[task_5]") { + human cian{}; + manifest_power(cian, "heal"); + human lanfeust{}; + + use_power(cian, lanfeust); + + REQUIRE(cian.influenced_by == nullptr); + REQUIRE(lanfeust.influenced_by == cian.own_power); +} + +TEST_CASE("Check power intensity of person without power", "[task_6]") { + human cixi{}; + + REQUIRE(power_intensity(cixi) == 0); +} + +TEST_CASE("Check power intensity when not in use", "[task_6]") { + human nicolede{}; + manifest_power(nicolede, "enchantment"); + + REQUIRE(power_intensity(nicolede) == 1); +} + +TEST_CASE("Check power intensity when used on just one person", "[task_6]") { + human nicolede{}; + manifest_power(nicolede, "enchantment"); + human hebus{}; + + use_power(nicolede, hebus); + + REQUIRE(power_intensity(nicolede) == 2); +} + +TEST_CASE("Check power intensity when used on group of four", "[task_6]") { + human sue{}; + human reed{}; + human johnny{}; + human ben{}; + + human victor{}; + manifest_power(victor, "technopathic super-genius"); + + use_power(victor, reed); + use_power(victor, johnny); + use_power(victor, ben); + use_power(victor, sue); + + REQUIRE(power_intensity(victor) == 5); +} + +TEST_CASE("Check power intensity drop after usage", "[task_6]") { + human palpatine{}; + manifest_power(palpatine, "force torrent"); + + // let's start a non-canon duel: + // (Everything in the scope of the brackets is deleted after the brackets + // close) + { + human grievous{}; + use_power(palpatine, grievous); + REQUIRE(power_intensity(palpatine) == 2); + } + REQUIRE(power_intensity(palpatine) == 1); +} + +#endif diff --git a/exercises/practice/complex-numbers/test/catch.hpp b/exercises/concept/power-of-troy/test/catch.hpp similarity index 99% rename from exercises/practice/complex-numbers/test/catch.hpp rename to exercises/concept/power-of-troy/test/catch.hpp index 36eaeb27f..ff40b4fd6 100644 --- a/exercises/practice/complex-numbers/test/catch.hpp +++ b/exercises/concept/power-of-troy/test/catch.hpp @@ -3175,8 +3175,8 @@ namespace Detail { } // end namespace Detail namespace literals { - Detail::Approx operator "" _a(long double val); - Detail::Approx operator "" _a(unsigned long long val); + Detail::Approx operator ""_a(long double val); + Detail::Approx operator ""_a(unsigned long long val); } // end namespace literals template<> @@ -7911,10 +7911,10 @@ namespace Detail { } // end namespace Detail namespace literals { - Detail::Approx operator "" _a(long double val) { + Detail::Approx operator ""_a(long double val) { return Detail::Approx(val); } - Detail::Approx operator "" _a(unsigned long long val) { + Detail::Approx operator ""_a(unsigned long long val) { return Detail::Approx(val); } } // end namespace literals diff --git a/exercises/concept/power-of-troy/test/tests-main.cpp b/exercises/concept/power-of-troy/test/tests-main.cpp new file mode 100644 index 000000000..0c7c351f4 --- /dev/null +++ b/exercises/concept/power-of-troy/test/tests-main.cpp @@ -0,0 +1,2 @@ +#define CATCH_CONFIG_MAIN +#include "catch.hpp" diff --git a/exercises/concept/speedywagon/.docs/hints.md b/exercises/concept/speedywagon/.docs/hints.md new file mode 100644 index 000000000..cdb3033c2 --- /dev/null +++ b/exercises/concept/speedywagon/.docs/hints.md @@ -0,0 +1,46 @@ +# Hints + +## General + +- Pay close attention to pointer syntax. + You will be using `*` (dereference operator) and `->` (member access through pointer). +- Make sure to check for null pointers (`nullptr`) where necessary to avoid accessing invalid memory. +- You can run the tests even if your code isn't complete; a rough structure is enough to see test results. +- All functions used by the tests must be declared in the header file. +- If your program crashes or behaves unexpectedly, it's often due to null pointer dereferencing. + Double-check that you handle `nullptr` properly. +- When using pointer arithmetic, ensure that you stay within the bounds of the sensor array. + Going beyond the array's capacity can lead to memory issues. + +## 1. Check Sensor Connection (`connection_check`) + +- The task is mainly about verifying whether a pointer is null or not. +- Use the comparison operator `!=` to check if a pointer is valid. +- If you're unsure whether you're checking the pointer correctly, think about what `nullptr` represents (the absence of a valid memory address). + + +## 2. Count Activity of Sensors (`activity_counter`) + +- You need to iterate over the array of sensors. + An array in C++ can be treated as a pointer to its first element. +- Use pointer arithmetic (`sensor_array + i`) to access the sensor at index `i`. +- The `->` operator is used to access a member of the struct through a pointer. + +### Example + +```cpp +int sum = (sensor_array + i)->activity; // Access activity using pointer arithmetic +``` + +## 3. Alarm Control (`alarm_control`) + +- First, check if the pointer is null before accessing the sensor. +- Use the `->` operator to access the `activity` member of the `pillar_men_sensor` struct. +- Think carefully about what should happen if the sensor's activity level is `0`. + Should the alarm trigger? + +## 4. Checking the data for anomalies with the `uv_alarm` function + +- Use the `&` operator to pass a pointer to the sensor's data array into the `uv_light_heuristic` function. +- Ensure you correctly check for a null pointer before accessing the sensor's data. +- Compare the result of `uv_light_heuristic` with the sensor's `activity` value to determine if the alarm should trigger. diff --git a/exercises/concept/speedywagon/.docs/instructions.md b/exercises/concept/speedywagon/.docs/instructions.md new file mode 100644 index 000000000..98c4e9793 --- /dev/null +++ b/exercises/concept/speedywagon/.docs/instructions.md @@ -0,0 +1,84 @@ +# Instructions + +Welcome, Engineer! +You are one of the last veterans of the Speedywagon Foundation, a secret organization that, for decades, has been battling ancient threats like the Pillar Men. +In the course of this effort, you've spent years maintaining the Foundation's technological systems, built using a mix of cutting-edge tech and aging libraries. + +However, in recent times, the sensors that track Pillar Men activities are malfunctioning. +The Foundation's systems are old, and the code interacts with a legacy C++ library that cannot be updated. +Your task is to implement four core functions that monitor Pillar Men sensor activity using an old-fashioned pointer-based library. + +As a modern C++ engineer, you’d prefer using smart pointers, but alas, legacy code demands respect for the old ways. +The fate of humanity may rest on these pointers, so proceed carefully, and may the Hamon energy guide you. + +~~~~exercism/note +As sensor readings can be huge, we supply a mockup _struct_ that is used in the actual library. +The code has already been implemented in the header file for you. + +```cpp +struct pillar_men_sensor { + int activity{}; + std::string location{}; + std::vector data{}; +}; +``` +~~~~ + +## 1. Check Sensor Connection (`connection_check`) + +Your first task is to ensure that the Pillar Men sensor is connected properly. +We can't have false alarms triggered by disconnected sensors. +You will write a function `connection_check`, which tests if the sensor's pointer is valid by checking for `nullptr`. + +- Define a function that accepts a pointer to a `pillar_men_sensor` _struct_. +- The function should return `true` if the sensor pointer is not null, and `false` otherwise. + +```cpp +pillar_men_sensor* sensor{nullptr}; +bool isConnected = connection_check(sensor); +// isConnected => false +``` + +## 2. Count Activity of Sensors (`activity_counter`) + +Pillar Men are lurking in the shadows, and we need to know if sensors have detected any activity. +You will write the `activity_counter` function, which takes in an array of sensors and a capacity indicating the number of sensors in the array. + +- Define a function that accepts a pointer to the first element of an array and the arrays capacity. +- Use pointer arithmetic to loop through the sensor array and accumulate the activity readings. +- Return the accumulated activity. + +```cpp +pillar_men_sensor sensor_array[3] = {{0}, {101}, {22}}; +int totalActivity = activity_counter(sensor_array, 3); +// totalActivity => 123 +``` + +## 3. Alarm Control (`alarm_control`) + +Not every sensor should trigger an alarm unless there’s real danger. +The `alarm_control` function ensures that a sensor only triggers an alarm if its activity level is greater than 0. +This function should also check for null sensors to prevent system crashes. + +- Define a function that accepts the pointer to a `pillar_men_sensor`. +- The function should first check for a `nullptr` sensor. If the sensor is `nullptr`, return `false`. +- If the sensor is valid and its activity is greater than 0, return `true`; otherwise, return `false`. + +```cpp +pillar_men_sensor db{9008, "songokunoie", {7, 7, 7}}; +bool alarm = alarm_control(&db); +// alarm => true +``` + +## 4. Checking the data for anomalies with the `uv_alarm` function + +In this task, you will implement the `uv_alarm` function to determine whether an alarm should be triggered based on UV light exposure levels and sensor activity. +The `uv_alarm` function should use the provided `uv_light_heuristic` function, which operates on a vector of data and returns a value based on certain thresholds. +This is a mockup version of the complex code that will run during production, please don't change the interface. + +Define the `uv_alarm` function in the `speedywagon` namespace. It should: + +- Take a pointer to a `pillar_men_sensor` _struct_ as its parameter. +- Return `false` if the sensor pointer is null. +- Call the `uv_light_heuristic` function, passing the address of the sensor's `data` array. +- Return `true` if the value returned by `uv_light_heuristic` is greater than the `sensor->activity` level, otherwise return `false`. diff --git a/exercises/concept/speedywagon/.docs/introduction.md b/exercises/concept/speedywagon/.docs/introduction.md new file mode 100644 index 000000000..94297f94f --- /dev/null +++ b/exercises/concept/speedywagon/.docs/introduction.md @@ -0,0 +1,98 @@ +# Introduction + +Like many other languages, C++ has _pointers_. +You already know _references_ and _pointers_ are similar, but think of them as a level closer to the inner workings of your computer. +_Pointers_ are variables that hold object addresses. +They are used to directly interact with objects, enabling dynamic memory allocation and efficient data manipulation in C++. + +If you're new to _pointers_, they can feel a little mysterious but once you get used to them, they're quite straight-forward. + +They're a crucial part of C++, so take some time to really understand them. +The bare-bone version in this concept is also called _dumb pointer_ or _raw pointer_. +With modern C++ there are also _smart pointers_, the basic type is not smart at all and you have to handle all the work manually. + +Before digging into the details, it's worth understanding the use of _pointers_. +_Pointers_ are a way to share an object's address with other parts of our program, which is useful for two major reasons: + +1. Like _references_, pointers avoid copies and help to reduce the resource-footprint of your program. +1. Unlike _references_, pointers can be reassigned to different objects. +1. Pointers can also point to a null value, to indicate, that they currently do not point to any object. + +## General Syntax + +A pointer declaration in C++ involves specifying the data type to which the the pointer is pointing, followed by an asterisk (`*`) and the pointer's name. +When pointers are declared, they are not automatically initialized. +Without explicit assignment, a pointer typically holds an indeterminate value, often referred to as a "garbage address." +While certain compilers might initialize pointers to `nullptr`, this behavior is not guaranteed across all compilers, so it's essential not to rely on it. +It's best practice to explicitly initialize raw pointers and verify their non-null status before utilization to avoid potential issues. + +```cpp +int* ptr{nullptr}; // Declares a pointer and makes sure it is not invalid +``` + +To assign the address of a variable to a pointer, you use the address-of operator (`&`). +Dereferencing a pointer is done using the _indirection operator_ (`*`) operator. + +```cpp +std::string opponent{"Solomon Lane"}; +// 'ethan' points to the address of the string opponent +std::string* ethan{&opponent}; +// Instead of ethan's, the opponent's name address is given to the passPort +std::string passportName{*ethan}; +``` + +Attention: dereferencing has to be done explicitly, while _references_ just worked like an alias. + +## Pointer Arithmetic + +_Pointer arithmetic_ allows you to perform arithmetic operations on pointers, which is particularly useful when working with arrays. +Adding an integer to a pointer makes it point to a different element. + +```cpp +// Stargate Coordinate Code +int gateCode[] = {462, 753, 218, 611, 977}; +// 'ptr' points to the first element of 'gateCode' +int* ptr{&gateCode[0]}; +// Accesses the third Stargate address through pointer arithmetic +int dialedAddress{*(ptr + 2)}; +// Chevron encoded! Dialing Stargate address: +openStarGate(dialedAddress); +``` + +~~~~exercism/caution +Pointer arithmetic in C++ can easily lead to __undefined behavior__ if not handled carefully. +Undefined behavior can manifest in unexpected program outcomes, crashes, or even security vulnerabilities. +One infamous example of the consequences of undefined behavior occurred in the [explosion of the Ariane 5 rocket][ariane-flight-v88] in 1996, where a software exception caused by the conversion of a 64-bit floating-point number to a 16-bit signed integer led to a catastrophic failure. + +[ariane-flight-v88]: https://en.wikipedia.org/wiki/Ariane_flight_V88 +~~~~ + +## Accessing member variables + +In C++, the `->` operator is used to access members of an object through a pointer to that object. +It is a shorthand which simplifies accessing members of objects pointed to by pointers. +For instance, if `ptr` is a pointer to an object with a member variable `x`, instead of using `(*ptr).x`, you can directly use `ptr->x`. +This operator enhances code readability and reduces verbosity when working with pointers to objects. + +Here's a brief example, with a _struct_ `Superhero` that has a member variable `superpower`. +The main function creates a pointer `dianaPrince` to a `Superhero` object (representing Wonder Woman). +The `->` operator is used to access the member variable `superpower`, showcasing Wonder Woman's iconic "Lasso of Truth." + +```cpp +struct Superhero { + std::string superpower; +}; +Superhero wonder_woman{}; +Superhero* dianaPrince = &wonder_woman; +dianaPrince->superpower = "Lasso of Truth"; +// Using the -> operator to access member variable superpower: +std::cout << "Wonder Woman, possesses the mighty " << dianaPrince->superpower; +``` + +## Pointers vs. references + +Pointers and references both enable indirect access to objects, but they differ in their capabilities and safety considerations. +Pointers offer the flexibility of changing their target object and can be assigned null. +However, this flexibility introduces risks, such as dereferencing null pointers or creating dangling pointers. +References, on the other hand, cannot be null and are bound to valid objects upon creation, avoiding these risks. +Given their safer nature, references should be preferred over pointers unless the additional functionalities provided by pointers are necessary. diff --git a/exercises/concept/speedywagon/.docs/introduction.md.tpl b/exercises/concept/speedywagon/.docs/introduction.md.tpl new file mode 100644 index 000000000..8ea648717 --- /dev/null +++ b/exercises/concept/speedywagon/.docs/introduction.md.tpl @@ -0,0 +1,3 @@ +# Introduction + +%{concept:pointers} diff --git a/exercises/concept/speedywagon/.meta/config.json b/exercises/concept/speedywagon/.meta/config.json new file mode 100644 index 000000000..1e5531301 --- /dev/null +++ b/exercises/concept/speedywagon/.meta/config.json @@ -0,0 +1,20 @@ +{ + "authors": [ + "vaeng" + ], + "files": { + "solution": [ + "speedywagon.cpp", + "speedywagon.h" + ], + "test": [ + "speedywagon_test.cpp" + ], + "exemplar": [ + ".meta/exemplar.cpp", + ".meta/exemplar.h" + ] + }, + "forked_from": [], + "blurb": "Learn about pointers by writing wrappers for an old library." +} diff --git a/exercises/concept/speedywagon/.meta/design.md b/exercises/concept/speedywagon/.meta/design.md new file mode 100644 index 000000000..bfdc962ed --- /dev/null +++ b/exercises/concept/speedywagon/.meta/design.md @@ -0,0 +1,25 @@ +# Design + +## Goal + +The goal of this exercise is to teach the basics of pointers and how they work in C++. + +## Learning objectives + +- Know how to create a pointer from a variable +- Know how to work with pointers to structs +- Know how to work with array pointers + +## Out of scope + +- Smart pointers + +## Concepts + +The Concepts this exercise unlocks are: + +- `pointers`: how to work with pointers; + +## Prerequisites + +- `classes` diff --git a/exercises/concept/speedywagon/.meta/exemplar.cpp b/exercises/concept/speedywagon/.meta/exemplar.cpp new file mode 100644 index 000000000..214f39ee8 --- /dev/null +++ b/exercises/concept/speedywagon/.meta/exemplar.cpp @@ -0,0 +1,38 @@ +#include "speedywagon.h" + +namespace speedywagon { + +int uv_light_heuristic(std::vector* data_array) { + double avg{}; + for (auto element : *data_array) { + avg += element; + } + avg /= data_array->size(); + int uv_index{}; + for (auto element : *data_array) { + if (element > avg) ++uv_index; + } + return uv_index; +} + +bool connection_check(pillar_men_sensor* sensor) { return sensor != nullptr; } + +int activity_counter(pillar_men_sensor* sensor_array, int capacity) { + int sum{}; + for (int i{}; i < capacity; ++i) { + sum += (sensor_array + i)->activity; + } + return sum; +} + +bool alarm_control(pillar_men_sensor* sensor) { + if (sensor == nullptr) return false; + return sensor->activity > 0; +} + +bool uv_alarm(pillar_men_sensor* sensor) { + if (sensor == nullptr) return false; + return uv_light_heuristic(&(sensor->data)) > sensor->activity; +} + +} // namespace speedywagon diff --git a/exercises/concept/speedywagon/.meta/exemplar.h b/exercises/concept/speedywagon/.meta/exemplar.h new file mode 100644 index 000000000..8dec041fe --- /dev/null +++ b/exercises/concept/speedywagon/.meta/exemplar.h @@ -0,0 +1,24 @@ +#pragma once + +#include +#include + +namespace speedywagon { + +struct pillar_men_sensor { + int activity{}; + std::string location{}; + std::vector data{}; +}; + +int uv_light_heuristic(std::vector* data_array); + +bool connection_check(pillar_men_sensor* sensor); + +int activity_counter(pillar_men_sensor* sensor_array, int capacity); + +bool alarm_control(pillar_men_sensor* sensor); + +bool uv_alarm(pillar_men_sensor* sensor); + +} // namespace speedywagon diff --git a/exercises/concept/speedywagon/CMakeLists.txt b/exercises/concept/speedywagon/CMakeLists.txt new file mode 100644 index 000000000..3b0589fd0 --- /dev/null +++ b/exercises/concept/speedywagon/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/concept/speedywagon/speedywagon.cpp b/exercises/concept/speedywagon/speedywagon.cpp new file mode 100644 index 000000000..a1cc1f2c4 --- /dev/null +++ b/exercises/concept/speedywagon/speedywagon.cpp @@ -0,0 +1,21 @@ +#include "speedywagon.h" + +namespace speedywagon { + +// Enter your code below: + +// Please don't change the interface of the uv_light_heuristic function +int uv_light_heuristic(std::vector* data_array) { + double avg{}; + for (auto element : *data_array) { + avg += element; + } + avg /= data_array->size(); + int uv_index{}; + for (auto element : *data_array) { + if (element > avg) ++uv_index; + } + return uv_index; +} + +} // namespace speedywagon diff --git a/exercises/concept/speedywagon/speedywagon.h b/exercises/concept/speedywagon/speedywagon.h new file mode 100644 index 000000000..b6909b44d --- /dev/null +++ b/exercises/concept/speedywagon/speedywagon.h @@ -0,0 +1,16 @@ +#pragma once + +#include +#include + +namespace speedywagon { + +struct pillar_men_sensor { + int activity{}; + std::string location{}; + std::vector data{}; +}; + +int uv_light_heuristic(std::vector* data_array); + +} // namespace speedywagon diff --git a/exercises/concept/speedywagon/speedywagon_test.cpp b/exercises/concept/speedywagon/speedywagon_test.cpp new file mode 100644 index 000000000..32c91f0b3 --- /dev/null +++ b/exercises/concept/speedywagon/speedywagon_test.cpp @@ -0,0 +1,61 @@ +#include "speedywagon.h" +#ifdef EXERCISM_TEST_SUITE +#include +#else +#include "test/catch.hpp" +#endif + +TEST_CASE("connection_check: test for nullptr", "[task_1]") { + speedywagon::pillar_men_sensor* nothing_connected{nullptr}; + REQUIRE_FALSE(speedywagon::connection_check(nothing_connected)); +} + +#if defined(EXERCISM_RUN_ALL_TESTS) + +TEST_CASE("connection_check: test for connected sensor", "[task_1]") { + speedywagon::pillar_men_sensor active_sensor{42, "colloseum", {}}; + REQUIRE(speedywagon::connection_check(&active_sensor)); +} + +TEST_CASE("activity_counter: sum for three nullptr", "[task_2]") { + speedywagon::pillar_men_sensor rome[3]{}; + REQUIRE(speedywagon::activity_counter(&rome[0], 3) == 0); +} + +TEST_CASE("activity_counter: sum for two with real data", "[task_2]") { + speedywagon::pillar_men_sensor rome[2]{{4900, "kars", {}}, + {4102, "wham", {}}}; + REQUIRE(speedywagon::activity_counter(&rome[0], 2) == 9002); +} + +TEST_CASE("activity_counter: sum for a nullptr", "[task_2]") { + speedywagon::pillar_men_sensor rome[2]{{4900, "kars", {}}, + {4102, "wham", {}}}; + REQUIRE(speedywagon::activity_counter(nullptr, 0) == 0); +} + +TEST_CASE("alarm_control: works correctly for pointer", "[task_3]") { + speedywagon::pillar_men_sensor* kars_in_space{nullptr}; + REQUIRE_FALSE(speedywagon::alarm_control(kars_in_space)); +} + +TEST_CASE("alarm_control: works correctly for nullptr", "[task_3]") { + speedywagon::pillar_men_sensor santana{0, "Mexico", {1981, 1987}}; + REQUIRE_FALSE(speedywagon::alarm_control(&santana)); + santana.activity = 9002; + REQUIRE(speedywagon::alarm_control(&santana)); +} + +TEST_CASE("uv_alarm: works correctly for nullptr", "[task_4]") { + speedywagon::pillar_men_sensor* wham{nullptr}; + REQUIRE_FALSE(speedywagon::uv_alarm(wham)); +} + +TEST_CASE("uv_alarm: works correctly with mock data", "[task_4]") { + speedywagon::pillar_men_sensor wham{0, "Rome", {1, 605, 313, 4000}}; + REQUIRE(speedywagon::uv_alarm(&wham)); + wham.activity = 9001; + REQUIRE_FALSE(speedywagon::uv_alarm(&wham)); +} + +#endif diff --git a/exercises/concept/speedywagon/test/catch.hpp b/exercises/concept/speedywagon/test/catch.hpp new file mode 100644 index 000000000..ff40b4fd6 --- /dev/null +++ b/exercises/concept/speedywagon/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