72 Commits
Author SHA1 Message Date
studiosi 1dcb4c85c5 Solved: 53 - Pipeline Ranges 2026-08-24 19:50:20 +03:00
studiosi 64b29cfebe Solved: 52 - Monadic Expected 2026-08-24 19:43:33 +03:00
studiosi 45bcd09bc1 Solved: 51 - Custom Formatter 2026-08-24 19:33:30 +03:00
studiosi 986be65d61 Solved: 50 - Constexpr Frontier 2026-08-24 19:27:20 +03:00
studiosi e907849c57 Solved: 49 - Ranges Zip 2026-08-24 19:20:50 +03:00
studiosi dea138ca04 Solved: 48 - Print and Format 2026-08-24 18:36:49 +03:00
studiosi 1e538bdd4b Solved: 47 - MDSpan 2026-08-24 18:10:37 +03:00
studiosi 602e5d757b Solved: 46 - Expected 2026-08-23 21:12:02 +03:00
studiosi 519e90e66f Solved: 45 - Span 2026-08-22 11:55:54 +03:00
studiosi 758b9fdaa8 Solved: 44 - Spaceship Operator 2026-08-22 11:45:03 +03:00
studiosi e25e965489 Solved: 44 - Ranges 2026-08-22 11:36:10 +03:00
studiosi 57693c5de2 Solved: 43 - Concepts 2026-08-22 11:33:04 +03:00
studiosi 8fa5630858 Solved: 42 - Variant 2026-08-22 10:24:26 +03:00
studiosi 29df33a4e9 Solved: 41 - Structured Bindings 2026-08-22 10:16:53 +03:00
studiosi b4a46bece7 Solved: 40 - Optional 2026-08-22 09:54:50 +03:00
studiosi 75221d0124 Solved: 39 - If Constexpr 2026-08-22 09:37:46 +03:00
studiosi 9d2ba83869 Solved: 38 - Make Unique 2026-08-22 09:22:32 +03:00
studiosi 40387c9218 Solved: 37 - Generic Lambdas 2026-08-22 09:09:20 +03:00
David Gil de Gómez Pérez 9928855c1e Merge remote-tracking branch 'origin/main'
# Conflicts:
#	modules/10_cpp14/src/digit_separators.cpp
2026-08-18 10:07:58 +03:00
David Gil de Gómez Pérez 68fc104f31 Solved: 36 - Digit Separators 2026-08-18 10:07:41 +03:00
David Gil de Gómez Pérez d05a9f44fa Solved: 36 - Digit Separators 2026-08-18 10:07:24 +03:00
David Gil de Gómez Pérez a72d03277e Solved: 35 - Auto Return 2026-08-18 09:59:56 +03:00
studiosi 0a0c430ebe Solved: 34 - Smart Pointers 2026-08-18 07:03:07 +03:00
studiosi d26d32a245 Solved: 33 - Move Semantics 2026-08-18 06:58:05 +03:00
studiosi 2ec26ecd04 Solved: 32 - Constexpr and Nullptr 2026-08-17 21:38:41 +03:00
studiosi 8807a9228c Solved: 32 - Constexpr and Nullptr 2026-08-17 21:35:13 +03:00
studiosi 3131313253 Solved: 32 - Auto and Range For 2026-08-17 21:30:16 +03:00
studiosi 8319d391be Solved: 31 - Transform and Reduce 2026-08-17 21:14:50 +03:00
studiosi 5867900588 Solved: 30 - Sort and Find 2026-08-17 20:59:45 +03:00
David Gil de Gómez Pérez 5fa04b30c7 Solved: 29 - Iterators 2026-08-17 13:42:40 +03:00
studiosi 7a8e430982 Solved: 28 - Algorithm Lambdas 2026-08-16 12:15:10 +03:00
studiosi 5f4bbc0918 Solved: 27 - Unordered Containers 2026-08-16 10:57:20 +03:00
studiosi 4314f9126a Fixed: 26 - Sequential Containers 2026-08-16 10:10:37 +03:00
studiosi 00a5178b01 Updated: 25 - Container Adapters 2026-08-16 09:41:15 +03:00
studiosi 362ef757b3 Solved: 25 - Container Adapters 2026-08-16 09:02:44 +03:00
studiosi dd981b5968 Solved: 23 - Associative Containers 2026-08-15 21:04:29 +03:00
studiosi 7a44e8fbc2 Solved: 22 - Polymorphism 2026-08-15 21:00:19 +03:00
studiosi a33ef36d8e Solved: 21 - Inheritance 2026-08-15 20:58:48 +03:00
studiosi 61d91878b9 Solved: 20 - Constructors 2026-08-15 20:56:31 +03:00
studiosi 564cc1b765 Solved: 20 - Classes and Objects 2026-08-15 17:43:30 +03:00
studiosi 8b82257ed6 Solved: 19 - References 2026-08-15 17:24:26 +03:00
studiosi 9676acc893 Solved: 18 - Pointer Basics 2026-08-15 17:20:47 +03:00
studiosi d9e08afbcb Solved: 17 - Pointer Arithmetic 2026-08-15 17:12:19 +03:00
studiosi 7ddd9f1bc3 Solved: 16 - Dynamic Memory 2026-08-15 17:04:40 +03:00
studiosi ec1c1f1ce7 Merge remote-tracking branch 'origin/main' 2026-08-15 16:56:00 +03:00
studiosi 8688803952 Solved: 15 - STD String 2026-08-15 16:55:46 +03:00
David Gil de Gómez Pérez f2495e1fb5 Updated: 13 - C Arrays
Using Compiler Explorer, increased the efficiency of reverse_array by removing the lambda.
2026-08-13 12:55:38 +03:00
studiosi 1aacfbbd1a Solved: 14 - Multidimensional 2026-08-12 21:55:27 +03:00
studiosi 925d766bcf Solved: 13 - C Arrays 2026-08-12 21:27:42 +03:00
David Gil de Gómez Pérez 97e72b545f Update: 12 - Recursion 2026-08-12 17:40:20 +03:00
David Gil de Gómez Pérez e6bdb3bdd8 Solved: 12 - Recursion 2026-08-12 17:30:55 +03:00
David Gil de Gómez Pérez 11af4914ad Solved: 11 - Overloading 2026-08-12 17:09:48 +03:00
David Gil de Gómez Pérez bee8344fdf Solved: 10 - Function Basics 2026-08-12 17:04:54 +03:00
David Gil de Gómez Pérez 3c4777e840 Solved: 09 - Default Parameters 2026-08-12 17:02:13 +03:00
David Gil de Gómez Pérez d1fbb1edbd Fix: Brought back suppressions.txt 2026-08-12 15:01:25 +03:00
David Gil de Gómez Pérez 626b01cf8a Solved: 08 - Switch Statements
Added a contract precondition to apply_operation
2026-08-12 14:58:20 +03:00
David Gil de Gómez Pérez 88cc7728a6 Solved: 07 - Loops
Added a contract precondition to factorial
2026-08-12 14:47:10 +03:00
David Gil de Gómez Pérez ba6d3ea5d4 Update: Changed contract violation handler to be able to test contract violations with Google Test 2026-08-12 14:07:12 +03:00
David Gil de Gómez Pérez ca42c2c9d4 Update: Using C++26 with contracts enabled 2026-08-12 13:54:19 +03:00
David Gil de Gómez Pérez 5c28159a9f Fix: 06 - Conditionals
Simplified max_of_three.
2026-08-12 13:49:55 +03:00
David Gil de Gómez Pérez 28a315195e Update: Using C++26 with contracts enabled 2026-08-12 13:49:04 +03:00
David Gil de Gómez Pérez 41111dba30 Update: Using C++26 with contracts enabled 2026-08-12 13:47:50 +03:00
David Gil de Gómez Pérez 206742e9b3 Update: Using C++26 with contracts enabled 2026-08-12 13:28:20 +03:00
David Gil de Gómez Pérez 583f8d73db Update: Using C++26 with contracts enabled 2026-08-12 13:19:12 +03:00
David Gil de Gómez Pérez ea0e601850 Update: Using C++26 with contracts enabled 2026-08-12 13:18:20 +03:00
studiosi 3cce26e72d Solved: 06 - Conditionals 2026-08-12 09:09:41 +03:00
studiosi bd85800a30 Solved: 05 - Break/Continue 2026-08-12 09:01:20 +03:00
studiosi d9c7987269 Solved: 04 - Variables and Types 2026-08-12 08:56:24 +03:00
David Gil de Gómez Pérez 2d25dd503a Solved: 03 - Operators 2026-08-11 18:41:26 +03:00
David Gil de Gómez Pérez 35afea97c0 Solved: 03 - Operators 2026-08-11 18:35:45 +03:00
David Gil de Gómez Pérez 6af86468d0 Solved: 02 - Hello World! 2026-08-11 18:23:17 +03:00
David Gil de Gómez Pérez 8de2e83c0b Solved: 01 - Basic IO 2026-08-11 17:56:35 +03:00
101 changed files with 1293 additions and 489 deletions
+1
View File
@@ -1,5 +1,6 @@
# Build directories
build/
build-gcc26/
cmake-build-*/
out/
+22
View File
@@ -12,14 +12,33 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 16)
message(
FATAL_ERROR
"GCC 16+ is required (found ${CMAKE_CXX_COMPILER_VERSION}). "
"Use the 'default' CMake preset or cmake/toolchains/gcc-16.cmake."
)
endif()
else()
message(
FATAL_ERROR
"This project requires GCC 16+. Found compiler: ${CMAKE_CXX_COMPILER_ID}. "
"Select the GCC 16 toolchain / default CMake preset in CLion."
)
endif()
option(COURSE_BUILD_TESTS "Build Google Test exercise targets" ON)
option(COURSE_WARNINGS_AS_ERRORS "Treat compiler warnings as errors" OFF)
option(COURSE_ENABLE_CONTRACTS "Enable C++26 contracts on GCC 16+" ON)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
include(CourseOptions)
include(CourseExercise)
add_subdirectory(support)
if(COURSE_BUILD_TESTS)
include(FetchContent)
FetchContent_Declare(
@@ -34,3 +53,6 @@ if(COURSE_BUILD_TESTS)
endif()
add_subdirectory(modules)
include(Cppcheck)
course_add_cppcheck_targets()
+51
View File
@@ -0,0 +1,51 @@
{
"version": 6,
"cmakeMinimumRequired": {
"major": 3,
"minor": 20,
"patch": 0
},
"configurePresets": [
{
"name": "default",
"displayName": "GCC 16 + C++26",
"generator": "Unix Makefiles",
"binaryDir": "${sourceDir}/cmake-build-debug-gcc-16-cpp26",
"toolchainFile": "${sourceDir}/cmake/toolchains/gcc-16.cmake",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"COURSE_ENABLE_CONTRACTS": "ON"
}
},
{
"name": "release",
"displayName": "GCC 16 + C++26 (Release)",
"generator": "Unix Makefiles",
"binaryDir": "${sourceDir}/cmake-build-release-gcc-16-cpp26",
"toolchainFile": "${sourceDir}/cmake/toolchains/gcc-16.cmake",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release",
"COURSE_ENABLE_CONTRACTS": "ON"
}
}
],
"buildPresets": [
{
"name": "default",
"configurePreset": "default"
},
{
"name": "release",
"configurePreset": "release"
}
],
"testPresets": [
{
"name": "default",
"configurePreset": "default",
"output": {
"outputOnFailure": true
}
}
]
}
+121 -50
View File
@@ -5,32 +5,52 @@ A hands-on C++ course with **56 Google Test exercises** organized into **14 modu
## Requirements
- **CMake** 3.20+
- **C++ compiler** with C++23 support for later modules
- Apple Clang 15+, GCC 13+, or MSVC 19.34+ recommended
- **GCC 16+** with C++26 and contracts support
- **CLion** (recommended) or any CMake-aware IDE
- Internet access on first configure (Google Test is fetched automatically)
Install GCC 16 on macOS (Homebrew):
```bash
brew install gcc@16
```
## Quick Start (CLion)
1. Open this folder in CLion (`File → Open…`).
2. CLion detects `CMakeLists.txt` and configures automatically.
3. Pick an exercise target (e.g. `01_fundamentals_hello_world`) in the run configuration dropdown.
4. Implement the TODOs in the matching `src/*.cpp` file.
5. Run the test target until all assertions pass.
1. Open this folder in CLion.
2. **Settings → Build, Execution, Deployment → CMake**
3. Enable profile **`default`** (display name **GCC 16 + C++26** from `CMakePresets.json`).
4. Disable old profiles that use Apple Clang (e.g. custom profiles without the preset toolchain).
5. Click **Reload CMake Project**.
If configure fails with *"This project requires GCC 16+"*, CLion is still using Apple Clang. Enable the **`default`** preset or set the toolchain C++ compiler to `g++-16`.
If configure fails with *"generator does not match"*, delete the build folder (`cmake-build-debug-gcc-16-cpp26`) and reload CMake.
6. Pick an exercise target (e.g. `02_control_flow_loops`) and run tests.
## Quick Start (Terminal)
```bash
cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug
cmake --build build
ctest --test-dir build --output-on-failure
cmake --preset default
cmake --build cmake-build-debug-gcc-16-cpp26
ctest --test-dir cmake-build-debug-gcc-16-cpp26 --output-on-failure
```
Run a single exercise:
```bash
cmake --build build --target 01_fundamentals_hello_world
./build/modules/01_fundamentals/01_fundamentals_hello_world
cmake --build cmake-build-debug-gcc-16-cpp26 --target 02_control_flow_loops
./cmake-build-debug-gcc-16-cpp26/modules/02_control_flow/02_control_flow_loops
```
Manual configure (without presets):
```bash
cmake -S . -B cmake-build-debug-gcc-16-cpp26 \
-DCMAKE_TOOLCHAIN_FILE=cmake/toolchains/gcc-16.cmake \
-DCOURSE_ENABLE_CONTRACTS=ON
cmake --build cmake-build-debug-gcc-16-cpp26
```
## Project Structure
@@ -38,30 +58,22 @@ cmake --build build --target 01_fundamentals_hello_world
```
cppc/
├── CMakeLists.txt # Root project + Google Test
├── CMakePresets.json # GCC 16 + C++26 preset
├── cmake/
│ ├── CourseExercise.cmake # add_course_exercise() helper
── CourseOptions.cmake # Warnings and standards
── CourseOptions.cmake # Warnings, standards, contracts
│ └── toolchains/gcc-16.cmake # GCC 16 toolchain file
├── support/ # Contract violation handler
└── modules/
├── 01_fundamentals/ # Types, operators, I/O
├── 02_control_flow/ # if, switch, loops
── 03_functions/ # Functions and recursion
├── 04_arrays_and_strings/ # Arrays, string, vector
├── 05_pointers_and_references/
├── 06_oop_basics/ # Classes, inheritance
├── 07_stl_containers/
├── 08_stl_algorithms/
├── 09_cpp11/ # C++11 features
├── 10_cpp14/
├── 11_cpp17/
├── 12_cpp20/ # Concepts, ranges, <=>
├── 13_cpp23/ # expected, mdspan, format
└── 14_cpp26/ # Frontier / C++26 direction
├── 01_fundamentals/
├── 02_control_flow/
── ... # 14 modules total
```
Each module contains:
- `README.md` — learning goals and exercise list
- `include/` — function and class declarations (your contract)
- `include/` — function and class declarations
- `src/`**your implementation** (start here)
- `test/` — Google Test files (do not edit unless extending)
@@ -75,22 +87,22 @@ Each module contains:
## Course Map
| Module | Topic | Exercises | C++ Standard |
|--------|-------|-----------|--------------|
| 01 | Fundamentals | 4 | C++17 |
| 02 | Control flow | 4 | C++17 |
| 03 | Functions | 4 | C++17 |
| 04 | Arrays & strings | 4 | C++17 |
| 05 | Pointers & references | 4 | C++17 |
| 06 | OOP basics | 4 | C++17 |
| 07 | STL containers | 4 | C++17 |
| 08 | STL algorithms | 4 | C++17 |
| 09 | C++11 | 4 | C++11 |
| 10 | C++14 | 4 | C++14 |
| 11 | C++17 | 4 | C++17 |
| 12 | C++20 | 4 | C++20 |
| 13 | C++23 | 4 | C++23 |
| 14 | C++26 frontier | 4 | C++23+ |
| Module | Topic | Exercises | Build standard |
|--------|-------|-----------|----------------|
| 01 | Fundamentals | 4 | C++26 |
| 02 | Control flow | 4 | C++26 |
| 03 | Functions | 4 | C++26 |
| 04 | Arrays & strings | 4 | C++26 |
| 05 | Pointers & references | 4 | C++26 |
| 06 | OOP basics | 4 | C++26 |
| 07 | STL containers | 4 | C++26 |
| 08 | STL algorithms | 4 | C++26 |
| 09 | C++11 features | 4 | C++26 |
| 10 | C++14 features | 4 | C++26 |
| 11 | C++17 features | 4 | C++26 |
| 12 | C++20 features | 4 | C++26 |
| 13 | C++23 features | 4 | C++26 |
| 14 | C++26 frontier | 4 | C++26 |
## CMake Options
@@ -98,22 +110,81 @@ Each module contains:
|--------|---------|-------------|
| `COURSE_BUILD_TESTS` | ON | Build Google Test exercise targets |
| `COURSE_WARNINGS_AS_ERRORS` | OFF | Treat warnings as errors |
| `COURSE_ENABLE_CONTRACTS` | ON | Enable `-fcontracts` on GCC 16+ |
Example:
```bash
cmake -S . -B build -DCOURSE_WARNINGS_AS_ERRORS=ON
cmake --preset default -DCOURSE_WARNINGS_AS_ERRORS=ON
```
## C++26 Contracts
On GCC 16+, the build enables:
- `-fcontracts`
- `-fcontract-evaluation-semantic=enforce`
- A shared `handle_contract_violation` handler in `support/contract_handler.cpp`
Example:
```cpp
#include <contracts>
[[nodiscard]] auto factorial(const int n) -> long long pre(n >= 0);
```
```cpp
auto factorial(const int n) -> long long
pre(n >= 0)
{
// ...
}
```
## CLion Tips
- Use **Run | Run…** and filter by module prefix (e.g. `12_cpp20`).
- Enable **Google Test** integration in CLion to see individual tests in the tree view.
- Set breakpoints in your `src/` implementation while debugging failing tests.
- `compile_commands.json` is exported for clangd/clang-tidy if you use external tools.
- Use the **GCC 16** toolchain, not Apple Clang.
- Disable **Clangd** and **Clang-Tidy** inspections — they use the Clang frontend and do not support GCC C++26 contracts.
- **Cppcheck plugin:** disable inline analysis for this project (see [Cppcheck](#cppcheck) below).
- Use **Run | Run…** and filter by module prefix (e.g. `02_control_flow`).
- Enable **Google Test** integration to see individual tests in the tree view.
## Cppcheck
Cppcheck **does not understand GCC C++26 contracts** (`pre(...)`) or GCC 16 libstdc++ when the CLion plugin analyzes headers in isolation. That produces false IDE errors such as:
- `Include file: <contracts> not found`
- `failed to evaluate #elif condition` in libstdc++ headers
- parse errors on `pre(...)`
### Recommended: disable the plugin, use the CMake target
1. **Settings → Editor → Inspections → C/C++ → Cppcheck****disable**
2. Configure and build once:
```bash
cmake --preset default
cmake --build build
```
3. Run Cppcheck from CLion or terminal:
```bash
cmake --build build --target cppcheck_modules
```
This uses `compile_commands.json` from your **GCC 16** build and suppresses known false positives (`cppcheck/suppressions.txt`).
### If you keep the plugin anyway
**Settings → Cppcheck configuration → Options:**
```
--language=c++ --std=c++26 --max-configs=1 --suppress=missingIncludeSystem --suppress=syntaxError
```
Expect remaining false positives on contract syntax. The plugin is not a good fit for this codebase.
## Notes on C++26
C++26 is still in active standardization. Module 14 focuses on techniques and library directions that remain relevant—deep `constexpr`, monadic `expected`, ranges pipelines, and `std::formatter`—using C++23 as the practical baseline.
All exercises build with **C++26**. Module READMEs describe the language feature each exercise teaches (C++11, C++17, etc.), but the toolchain baseline is C++26 throughout.
Happy learning!
+6 -1
View File
@@ -21,7 +21,7 @@ function(add_course_exercise)
endif()
if(NOT EXERCISE_STANDARD)
set(EXERCISE_STANDARD 23)
set(EXERCISE_STANDARD 26)
endif()
set(target_name "${EXERCISE_MODULE}_${EXERCISE_NAME}")
@@ -33,6 +33,11 @@ function(add_course_exercise)
"${CMAKE_CURRENT_SOURCE_DIR}/include"
)
course_set_cxx_standard(${target_name} ${EXERCISE_STANDARD})
if(EXERCISE_STANDARD GREATER_EQUAL 26)
course_enable_contracts(${target_name})
endif()
course_apply_warnings(${target_name})
if(COURSE_BUILD_TESTS)
+33 -1
View File
@@ -21,5 +21,37 @@ function(course_apply_warnings target_name)
endfunction()
function(course_set_cxx_standard target_name standard)
target_compile_features(${target_name} PRIVATE cxx_std_${standard})
# Use explicit -std flags so older CLion/CMake builds still get C++26.
if(standard GREATER_EQUAL 26)
target_compile_options(${target_name} PRIVATE -std=c++26)
elseif(standard GREATER_EQUAL 23)
target_compile_options(${target_name} PRIVATE -std=c++23)
elseif(standard GREATER_EQUAL 20)
target_compile_options(${target_name} PRIVATE -std=c++20)
elseif(standard GREATER_EQUAL 17)
target_compile_options(${target_name} PRIVATE -std=c++17)
elseif(standard GREATER_EQUAL 14)
target_compile_options(${target_name} PRIVATE -std=c++14)
else()
target_compile_options(${target_name} PRIVATE -std=c++11)
endif()
endfunction()
function(course_enable_contracts target_name)
if(NOT COURSE_ENABLE_CONTRACTS)
return()
endif()
if(NOT (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 16))
return()
endif()
target_compile_options(
${target_name}
PRIVATE
-fcontracts
-fcontract-evaluation-semantic=enforce
)
target_link_options(${target_name} PRIVATE -fcontracts)
target_link_libraries(${target_name} PRIVATE course_contract_support)
endfunction()
+42
View File
@@ -0,0 +1,42 @@
function(course_add_cppcheck_targets)
find_program(CPPCHECK_EXECUTABLE cppcheck)
if(NOT CPPCHECK_EXECUTABLE)
message(STATUS "cppcheck not found; cppcheck targets will not be available")
return()
endif()
set(_compile_commands "${CMAKE_BINARY_DIR}/compile_commands.json")
set(_suppressions "${CMAKE_SOURCE_DIR}/cppcheck/suppressions.txt")
add_custom_target(
cppcheck_modules
COMMAND
"${CPPCHECK_EXECUTABLE}"
--project=${_compile_commands}
--enable=warning,style,performance
--std=c++26
--inline-suppr
--suppressions-list=${_suppressions}
-i${CMAKE_SOURCE_DIR}/support
-i${CMAKE_BINARY_DIR}/_deps
--quiet
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}"
COMMENT "Running cppcheck on course modules (build once before running this target)"
VERBATIM
)
add_custom_target(
cppcheck_project
COMMAND
"${CPPCHECK_EXECUTABLE}"
--project=${_compile_commands}
--enable=warning,style,performance
--std=c++26
--inline-suppr
--suppressions-list=${_suppressions}
--quiet
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}"
COMMENT "Running cppcheck on entire project (build once before running this target)"
VERBATIM
)
endfunction()
+22
View File
@@ -0,0 +1,22 @@
# GCC 16 toolchain for C++26 and contracts.
find_program(
COURSE_GCC16_C
NAMES gcc-16
HINTS /opt/homebrew/bin /usr/local/bin /opt/local/bin
)
find_program(
COURSE_GCC16_CXX
NAMES g++-16
HINTS /opt/homebrew/bin /usr/local/bin /opt/local/bin
)
if(NOT COURSE_GCC16_CXX)
message(
FATAL_ERROR
"g++-16 not found. Install GCC 16, e.g. 'brew install gcc@16', "
"then ensure g++-16 is on your PATH."
)
endif()
set(CMAKE_C_COMPILER "${COURSE_GCC16_C}" CACHE FILEPATH "C compiler" FORCE)
set(CMAKE_CXX_COMPILER "${COURSE_GCC16_CXX}" CACHE FILEPATH "C++ compiler" FORCE)
+19
View File
@@ -0,0 +1,19 @@
# Suppress Cppcheck noise for this GCC 16 / C++26 course project.
#
# Prefer: cmake --build cmake-build-debug-gcc-16-cpp26 --target cppcheck_modules
# Disable the CLion Cppcheck plugin — it analyzes headers in isolation.
# GCC / libstdc++ / contracts false positives (especially in CLion plugin mode)
missingIncludeSystem
syntaxError
# Third-party (Google Test / Google Mock) — analyzed by cppcheck_project
*:_deps/*
# Course exercise stubs — intentional teaching patterns (TODO implementations)
passedByValue:*modules/*
useStlAlgorithm:*modules/*
functionStatic:*modules/*
uninitMemberVarNoCtor:*modules/*
constVariable:*modules/*
bitwiseOnBoolean:*modules/*
+4 -4
View File
@@ -1,7 +1,7 @@
add_course_exercise(
NAME hello_world
MODULE 01_fundamentals
STANDARD 17
STANDARD 26
SOURCES
src/hello_world.cpp
test/hello_world_test.cpp
@@ -10,7 +10,7 @@ add_course_exercise(
add_course_exercise(
NAME variables_and_types
MODULE 01_fundamentals
STANDARD 17
STANDARD 26
SOURCES
src/variables_and_types.cpp
test/variables_and_types_test.cpp
@@ -19,7 +19,7 @@ add_course_exercise(
add_course_exercise(
NAME operators
MODULE 01_fundamentals
STANDARD 17
STANDARD 26
SOURCES
src/operators.cpp
test/operators_test.cpp
@@ -28,7 +28,7 @@ add_course_exercise(
add_course_exercise(
NAME basic_io
MODULE 01_fundamentals
STANDARD 17
STANDARD 26
SOURCES
src/basic_io.cpp
test/basic_io_test.cpp
+25 -13
View File
@@ -5,24 +5,36 @@
namespace fundamentals {
auto join_words(const std::vector<std::string>& words, char separator) -> std::string {
// TODO: Join words with separator, no trailing separator.
(void)words;
(void)separator;
return {};
auto join_words(const std::vector<std::string>& words, const char separator) -> std::string {
std::ostringstream oss;
size_t i = 0;
for (const auto& word : words) {
i++;
oss << word;
if (i < words.size()) {
oss << separator;
}
}
return oss.str();
}
auto parse_integers(const std::string& csv) -> std::vector<int> {
// TODO: Parse comma-separated integers (e.g. "1,2,3").
(void)csv;
return {};
std::vector<int> numbers;
std::istringstream iss(csv);
int n;
char c;
do {
iss >> n;
numbers.push_back(n);
iss >> c;
} while (!iss.eof());
return numbers;
}
auto format_score(const std::string& player, int score) -> std::string {
// TODO: Return "<player> scored <score> points".
(void)player;
(void)score;
return {};
auto format_score(const std::string& player, const int score) -> std::string {
std::ostringstream oss;
oss << player << " scored " << score << " points";
return oss.str();
}
} // namespace fundamentals
+13 -3
View File
@@ -1,11 +1,21 @@
#include "hello_world.hpp"
#include <cstring>
#include <string>
namespace fundamentals {
auto greet(const char* name) -> const char* {
// TODO: Return a static string in the format "Hello, <name>!"
(void)name;
return "Hello, World!";
const auto n = std::string(name);
const auto c = "Hello, " + n + "!";
// LESSON: Never return pointers to local objects -> dangling -> undefined behavior
// NO! --> return c.c_str();
// The destructor will be called when c goes out of scope, destroying the object and freeing its memory
// This is shit C++ and should use std::string instead as a return value
const auto p = new char[c.length() + 1]; // Give space for the null terminated pointer
strcpy(p, c.c_str());
return p;
// TL;DR -> Never use C-style strings if possible
}
} // namespace fundamentals
+17 -25
View File
@@ -2,39 +2,31 @@
namespace fundamentals {
auto absolute_difference(int lhs, int rhs) -> int {
// TODO: Return |lhs - rhs| without using std::abs.
(void)lhs;
(void)rhs;
return 0;
auto absolute_difference(const int lhs, const int rhs) -> int {
// NOTE: std::abs not allowed
return lhs < rhs ? rhs - lhs : lhs - rhs;
}
auto is_in_range(int value, int min, int max) -> bool {
// TODO: Return true when min <= value <= max (inclusive).
(void)value;
(void)min;
(void)max;
return false;
auto is_in_range(const int value, const int min, const int max) -> bool {
return value >= min && value <= max;
}
auto count_set_bits(std::uint8_t value) -> int {
// TODO: Count how many bits are set to 1.
(void)value;
return 0;
auto count_set_bits(const std::uint8_t value) -> int {
auto count = 0;
for (int i = 0; i < 8; i++) {
if (((value >> i) & 1) == 1) count++;
}
return count;
}
auto logical_and(bool lhs, bool rhs) -> bool {
// TODO: Implement logical AND without using &&.
(void)lhs;
(void)rhs;
return false;
auto logical_and(const bool lhs, const bool rhs) -> bool {
// NOTE: && can't be used
return (lhs & rhs) == 1;
}
auto logical_or(bool lhs, bool rhs) -> bool {
// TODO: Implement logical OR without using ||.
(void)lhs;
(void)rhs;
return false;
auto logical_or(const bool lhs, const bool rhs) -> bool {
// NOTE: || can't be used
return (lhs | rhs) == 1;
}
} // namespace fundamentals
@@ -1,43 +1,38 @@
#include "variables_and_types.hpp"
#include <sstream>
namespace fundamentals {
auto add_integers(int lhs, int rhs) -> int {
// TODO: Return the sum.
(void)lhs;
(void)rhs;
return 0;
auto add_integers(const int lhs, const int rhs) -> int {
return lhs + rhs;
}
auto multiply_doubles(double lhs, double rhs) -> double {
// TODO: Return the product.
(void)lhs;
(void)rhs;
return 0.0;
auto multiply_doubles(const double lhs, const double rhs) -> double {
return lhs * rhs;
}
auto is_even(std::int64_t value) -> bool {
// TODO: Return true when value is divisible by 2.
(void)value;
return false;
auto is_even(const std::int64_t value) -> bool {
return value % 2 == 0;
}
auto describe_type(int value) -> std::string {
// TODO: Return "int:" followed by the decimal representation.
(void)value;
return "int:0";
auto describe_type(const int value) -> std::string {
auto oss = std::ostringstream{};
oss << "int:" << value;
return oss.str();
}
auto describe_type(double value) -> std::string {
// TODO: Return "double:" followed by the value with one decimal place.
(void)value;
return "double:0.0";
auto describe_type(const double value) -> std::string {
auto oss = std::ostringstream{};
oss << "double:" << value;
return oss.str();
}
auto describe_type(bool value) -> std::string {
// TODO: Return "bool:true" or "bool:false".
(void)value;
return "bool:false";
auto describe_type(const bool value) -> std::string {
auto oss = std::ostringstream{};
const std::string representation = value ? "true" : "false";
oss << "bool:" << representation;
return oss.str();
}
} // namespace fundamentals
+4 -4
View File
@@ -1,8 +1,8 @@
add_course_exercise(NAME conditionals MODULE 02_control_flow STANDARD 17
add_course_exercise(NAME conditionals MODULE 02_control_flow STANDARD 26
SOURCES src/conditionals.cpp test/conditionals_test.cpp)
add_course_exercise(NAME switch_statements MODULE 02_control_flow STANDARD 17
add_course_exercise(NAME switch_statements MODULE 02_control_flow STANDARD 26
SOURCES src/switch_statements.cpp test/switch_statements_test.cpp)
add_course_exercise(NAME loops MODULE 02_control_flow STANDARD 17
add_course_exercise(NAME loops MODULE 02_control_flow STANDARD 26
SOURCES src/loops.cpp test/loops_test.cpp)
add_course_exercise(NAME break_continue MODULE 02_control_flow STANDARD 17
add_course_exercise(NAME break_continue MODULE 02_control_flow STANDARD 26
SOURCES src/break_continue.cpp test/break_continue_test.cpp)
+2 -1
View File
@@ -5,7 +5,8 @@
namespace control_flow {
[[nodiscard]] auto sum_range(int from, int to) -> int;
[[nodiscard]] auto factorial(int n) -> long long;
// ReSharper disable once CppConstParameterInDeclaration
[[nodiscard]] auto factorial(const int n) -> long long pre(n >= 0);
[[nodiscard]] auto count_occurrences(const std::vector<int>& data, int target) -> int;
[[nodiscard]] auto first_index_of(const std::vector<int>& data, int target) -> int;
@@ -7,7 +7,9 @@ namespace control_flow {
enum class Operation { Add, Subtract, Multiply, Divide, Unknown };
[[nodiscard]] auto parse_operation(char op) -> Operation;
[[nodiscard]] auto apply_operation(Operation op, int lhs, int rhs) -> int;
// ReSharper disable once CppConstParameterInDeclaration
[[nodiscard]] auto apply_operation(const Operation op, const int lhs, const int rhs) -> int
pre(op != Operation::Unknown);
[[nodiscard]] auto day_name(int day) -> std::string;
} // namespace control_flow
+15 -6
View File
@@ -3,18 +3,27 @@
namespace control_flow {
auto sum_positive(const std::vector<int>& data) -> int {
(void)data;
return 0;
auto sum = 0;
for (const auto i : data) {
if (i > 0) sum += i;
}
return sum;
}
auto first_multiple_of(const std::vector<int>& data, int divisor) -> int {
(void)data; (void)divisor;
auto first_multiple_of(const std::vector<int>& data, const int divisor) -> int {
for (const auto i : data) {
if (i > divisor && i % divisor == 0) return i;
}
return -1;
}
auto collect_until_negative(const std::vector<int>& data) -> std::vector<int> {
(void)data;
return {};
std::vector<int> result;
for (const auto i : data) {
if (i < 0) break;
result.push_back(i);
}
return result;
}
} // namespace control_flow
+14 -10
View File
@@ -2,21 +2,25 @@
namespace control_flow {
auto classify_score(int score) -> Grade {
// TODO: A>=90, B>=80, C>=70, D>=60, else F
(void)score;
auto classify_score(const int score) -> Grade {
if (score >= 90) return Grade::A;
if (score >= 80) return Grade::B;
if (score >= 70) return Grade::C;
if (score >= 60) return Grade::D;
return Grade::F;
}
auto max_of_three(int a, int b, int c) -> int {
(void)a; (void)b; (void)c;
return 0;
auto max_of_three(const int a, const int b, const int c) -> int {
if (a >= b) {
if (a >= c) return a;
return c;
}
if (b >= c) return b;
return c;
}
auto sign_of(int value) -> int {
// TODO: Return -1, 0, or 1
(void)value;
return 0;
auto sign_of(const int value) -> int {
return value == 0 ? 0 : value > 0 ? 1 : -1;
}
} // namespace control_flow
+28 -13
View File
@@ -1,26 +1,41 @@
#include "loops.hpp"
#include <algorithm>
#include <ranges>
namespace control_flow {
auto sum_range(int from, int to) -> int {
(void)from; (void)to;
return 0;
auto sum_range(const int from, const int to) -> int {
return std::ranges::fold_left(
std::views::iota(from, to + 1), // End-exclusive
0,
[](const int acc, const int x) { return acc + x; }
);
}
auto factorial(int n) -> long long {
(void)n;
return 1;
auto factorial(const int n) -> long long
pre(n >= 0)
{
if (n == 0 || n == 1) return 1;
return std::ranges::fold_left(
std::views::iota(2, n + 1), // End-exclusive
1LL,
[](const long long acc, const int x) { return acc * x; }
);
}
auto count_occurrences(const std::vector<int>& data, int target) -> int {
(void)data; (void)target;
return 0;
auto count_occurrences(const std::vector<int>& data, const int target) -> int {
int count = 0;
std::ranges::for_each(data, [target, &count](const int x) {
if (x == target) ++count;
});
return count;
}
auto first_index_of(const std::vector<int>& data, int target) -> int {
// TODO: Return index or -1 if not found
(void)data; (void)target;
return -1;
auto first_index_of(const std::vector<int>& data, const int target) -> int {
const auto it = std::ranges::find(data, target);
if (it == data.end()) return -1;
return static_cast<int>(std::distance(data.begin(), it));
}
} // namespace control_flow
@@ -2,20 +2,40 @@
namespace control_flow {
auto parse_operation(char op) -> Operation {
(void)op;
return Operation::Unknown;
// enum class Operation { Add, Subtract, Multiply, Divide, Unknown };
auto parse_operation(const char op) -> Operation {
switch (op) {
case '+': return Operation::Add;
case '-': return Operation::Subtract;
case '*': return Operation::Multiply;
case '/': return Operation::Divide;
default: return Operation::Unknown;
}
}
auto apply_operation(Operation op, int lhs, int rhs) -> int {
(void)op; (void)lhs; (void)rhs;
return 0;
auto apply_operation(const Operation op, const int lhs, const int rhs) -> int
pre(op != Operation::Unknown)
{
switch (op) {
case Operation::Add: return lhs + rhs;
case Operation::Subtract: return lhs - rhs;
case Operation::Multiply: return lhs * rhs;
case Operation::Divide: return lhs / rhs;
default: return -1; // Unreachable due to contract
}
}
auto day_name(int day) -> std::string {
// TODO: 1=Monday ... 7=Sunday, else "Invalid"
(void)day;
return "Invalid";
auto day_name(const int day) -> std::string {
switch (day) {
case 1: return "Monday";
case 2: return "Tuesday";
case 3: return "Wednesday";
case 4: return "Thursday";
case 5: return "Friday";
case 6: return "Saturday";
case 7: return "Sunday";
default: return "Invalid";
}
}
} // namespace control_flow
@@ -9,6 +9,12 @@ TEST(Loops, SumRange) {
TEST(Loops, Factorial) {
EXPECT_EQ(control_flow::factorial(0), 1);
EXPECT_EQ(control_flow::factorial(5), 120);
// Breach of contract
EXPECT_DEATH(
{
(void)control_flow::factorial(-1);
},
"contract violation");
}
TEST(Loops, CountOccurrences) {
@@ -9,6 +9,12 @@ TEST(SwitchStatements, ParseOperation) {
TEST(SwitchStatements, ApplyOperation) {
EXPECT_EQ(control_flow::apply_operation(control_flow::Operation::Add, 2, 3), 5);
EXPECT_EQ(control_flow::apply_operation(control_flow::Operation::Multiply, 4, 5), 20);
// Breach of contract
EXPECT_DEATH(
{
(void)control_flow::apply_operation(control_flow::Operation::Unknown, 2, 3);
},
"contract violation");
}
TEST(SwitchStatements, DayName) {
+4 -4
View File
@@ -1,8 +1,8 @@
add_course_exercise(NAME function_basics MODULE 03_functions STANDARD 17
add_course_exercise(NAME function_basics MODULE 03_functions STANDARD 26
SOURCES src/function_basics.cpp test/function_basics_test.cpp)
add_course_exercise(NAME overloading MODULE 03_functions STANDARD 17
add_course_exercise(NAME overloading MODULE 03_functions STANDARD 26
SOURCES src/overloading.cpp test/overloading_test.cpp)
add_course_exercise(NAME default_parameters MODULE 03_functions STANDARD 17
add_course_exercise(NAME default_parameters MODULE 03_functions STANDARD 26
SOURCES src/default_parameters.cpp test/default_parameters_test.cpp)
add_course_exercise(NAME recursion MODULE 03_functions STANDARD 17
add_course_exercise(NAME recursion MODULE 03_functions STANDARD 26
SOURCES src/recursion.cpp test/recursion_test.cpp)
@@ -1,9 +1,26 @@
#include "default_parameters.hpp"
#include <cmath>
#include <sstream>
namespace functions {
auto repeat(char ch, int count) -> std::string { (void)ch; (void)count; return {}; }
auto power(int base, int exponent) -> long long { (void)base; (void)exponent; return 0; }
auto clamp(int value, int min, int max) -> int { (void)value; (void)min; (void)max; return 0; }
auto repeat(const char ch, const int count) -> std::string {
std::ostringstream oss;
for (int i = 0; i < count; i++) {
oss << ch;
}
return oss.str();
}
auto power(const int base, const int exponent) -> long long {
return std::pow(base, exponent);
}
auto clamp(const int value, const int min, const int max) -> int {
if (value < min) return min;
if (value > max) return max;
return value;
}
} // namespace functions
+20 -4
View File
@@ -1,10 +1,26 @@
#include "function_basics.hpp"
#include <ranges>
namespace functions {
auto square(int value) -> int { (void)value; return 0; }
void swap_integers(int& lhs, int& rhs) { (void)lhs; (void)rhs; }
auto concatenate(const std::vector<std::string>& parts) -> std::string { (void)parts; return {}; }
void append_suffix(std::string& text, const std::string& suffix) { (void)text; (void)suffix; }
auto square(const int value) -> int {
return value * value;
}
void swap_integers(int& lhs, int& rhs) {
const int tmp = lhs;
lhs = rhs;
rhs = tmp;
}
auto concatenate(const std::vector<std::string>& parts) -> std::string {
return std::ranges::to<std::string>(std::views::join(parts));
}
void append_suffix(std::string& text, const std::string& suffix) {
// The string is passed by reference, so it can have text appended
text += suffix;
}
} // namespace functions
+10 -5
View File
@@ -2,10 +2,15 @@
namespace functions {
auto max_value(int a, int b) -> int { (void)a; (void)b; return 0; }
auto max_value(double a, double b) -> double { (void)a; (void)b; return 0.0; }
auto max_value(const std::string& a, const std::string& b) -> std::string { (void)a; (void)b; return {}; }
auto area(int side) -> int { (void)side; return 0; }
auto area(int width, int height) -> int { (void)width; (void)height; return 0; }
// Overloading based in parameter type
auto max_value(const int a, const int b) -> int { return a > b ? a : b; }
auto max_value(const double a, const double b) -> double { return a > b ? a : b; }
auto max_value(const std::string& a, const std::string& b) -> std::string { return a > b ? a : b; }
// Overloading based in parameter count
auto area(const int side) -> int { return side * side; }
auto area(const int width, const int height) -> int { return width * height; }
} // namespace functions
+29 -3
View File
@@ -2,8 +2,34 @@
namespace functions {
auto fibonacci(int n) -> long long { (void)n; return 0; }
auto sum_digits(int n) -> int { (void)n; return 0; }
auto is_palindrome(int n) -> bool { (void)n; return false; }
auto fibonacci(const int n) -> long long {
if (n == 0) return 0;
if (n == 1) return 1;
return fibonacci(n - 1) + fibonacci(n - 2);
}
auto sum_digits(const int n) -> int {
if (n < 10) return n;
return n % 10 + sum_digits(n / 10);
}
// Advanced recursion with recursive lambda helper
auto is_palindrome(const int n) -> bool {
auto f = [](const auto& self, const int x, const int d) -> bool {
if (x < 0) return false;
if (x < 10) return true;
if (x / d != x % 10) return false;
if (d < 10) return true;
const int m = (x / d) / 10;
return self(self, m, d / 100);
};
if (n < 0) return false;
if (n < 10) return true;
int d = 1;
while (n / d >= 10) {
d *= 10;
}
return f(f, n, d);
}
} // namespace functions
+4 -4
View File
@@ -1,8 +1,8 @@
add_course_exercise(NAME c_arrays MODULE 04_arrays_and_strings STANDARD 17
add_course_exercise(NAME c_arrays MODULE 04_arrays_and_strings STANDARD 26
SOURCES src/c_arrays.cpp test/c_arrays_test.cpp)
add_course_exercise(NAME std_string MODULE 04_arrays_and_strings STANDARD 17
add_course_exercise(NAME std_string MODULE 04_arrays_and_strings STANDARD 26
SOURCES src/std_string.cpp test/std_string_test.cpp)
add_course_exercise(NAME std_vector MODULE 04_arrays_and_strings STANDARD 17
add_course_exercise(NAME std_vector MODULE 04_arrays_and_strings STANDARD 26
SOURCES src/std_vector.cpp test/std_vector_test.cpp)
add_course_exercise(NAME multidimensional MODULE 04_arrays_and_strings STANDARD 17
add_course_exercise(NAME multidimensional MODULE 04_arrays_and_strings STANDARD 26
SOURCES src/multidimensional.cpp test/multidimensional_test.cpp)
@@ -4,9 +4,9 @@
namespace arrays {
[[nodiscard]] auto to_uppercase(std::string text) -> std::string;
[[nodiscard]] auto to_uppercase(const std::string &text) -> std::string;
[[nodiscard]] auto trim(const std::string& text) -> std::string;
[[nodiscard]] auto replace_all(std::string text, char from, char to) -> std::string;
[[nodiscard]] auto replace_all(const std::string &text, char from, char to) -> std::string;
[[nodiscard]] auto starts_with(const std::string& text, const std::string& prefix) -> bool;
} // namespace arrays
+28 -3
View File
@@ -1,9 +1,34 @@
#include "c_arrays.hpp"
#include <climits>
namespace arrays {
auto array_sum(const int* data, std::size_t size) -> int { (void)data; (void)size; return 0; }
auto array_max(const int* data, std::size_t size) -> int { (void)data; (void)size; return 0; }
void reverse_array(int* data, std::size_t size) { (void)data; (void)size; }
auto array_sum(const int* data, const std::size_t size) -> int {
auto sum = 0;
for (std::size_t i = 0; i < size; ++i) {
sum += data[i];
}
return sum;
}
auto array_max(const int* data, const std::size_t size) -> int {
auto max = INT_MIN;
for (std::size_t i = 0; i < size; ++i) {
if (data[i] > max) {
max = data[i];
}
}
return max;
}
void reverse_array(int* data, const std::size_t size) {
for (std::size_t i = 0; i < size / 2; ++i) {
const auto temp = data[i];
data[i] = data[size - i - 1];
data[size - i - 1] = temp;
}
}
} // namespace arrays
@@ -1,9 +1,32 @@
#include "multidimensional.hpp"
#include <algorithm>
#include <numeric>
namespace arrays {
auto create_matrix(int rows, int cols, int fill) -> Matrix { (void)rows; (void)cols; (void)fill; return {}; }
auto transpose(const Matrix& matrix) -> Matrix { (void)matrix; return {}; }
auto row_sums(const Matrix& matrix) -> std::vector<int> { (void)matrix; return {}; }
auto create_matrix(const int rows, const int cols, const int fill) -> Matrix {
return Matrix(rows, std::vector(cols, fill));
}
auto transpose(const Matrix& matrix) -> Matrix {
auto new_mat = Matrix(matrix[0].size(), std::vector(matrix.size(), 0));
for (size_t row = 0; row < matrix.size(); ++row) {
for (size_t col = 0; col < matrix[row].size(); ++col) {
new_mat[col][row] = matrix[row][col];
}
}
return new_mat;
}
auto row_sums(const Matrix& matrix) -> std::vector<int> {
auto sums = std::vector(matrix.size(), 0);
auto idx = 0;
for (auto row: matrix) {
sums[idx] = std::ranges::fold_left(row, 0, std::plus{});
idx++;
}
return sums;
}
} // namespace arrays
@@ -1,10 +1,46 @@
#include "std_string.hpp"
#include <algorithm>
#include <locale>
#include <ranges>
#include <sstream>
namespace arrays {
auto to_uppercase(std::string text) -> std::string { (void)text; return {}; }
auto trim(const std::string& text) -> std::string { (void)text; return {}; }
auto replace_all(std::string text, char from, char to) -> std::string { (void)text; (void)from; (void)to; return {}; }
auto starts_with(const std::string& text, const std::string& prefix) -> bool { (void)text; (void)prefix; return false; }
auto to_uppercase(const std::string &text) -> std::string {
// Returns copy of the string without mutating the original string
auto s = std::string{text};
auto c_to_upper = [](const unsigned char c) { return std::toupper(c); };
std::ranges::transform(s, s.begin(), c_to_upper);
return s;
}
auto trim(const std::string& text) -> std::string {
// Returns a trimmed copy of the string
auto s = std::string{text};
auto is_not_space = [](const unsigned char c) { return !std::isspace(c); };
const auto first = std::ranges::find_if(s, is_not_space);
const auto last = std::ranges::find_if(s.rbegin(), s.rend(), is_not_space).base();
s.erase(last, s.end());
s.erase(s.begin(), first);
return s;
}
auto replace_all(const std::string &text, const char from, const char to) -> std::string {
// This one also copies the string
auto s = std::string{text};
std::ranges::replace(s, from, to);
return s;
}
auto starts_with(const std::string& text, const std::string& prefix) -> bool {
// Since C++20 you can use std::string::starts_with, but anyways.
if (text.size() < prefix.size()) return false;
// uz -> unsigned size_t
for (auto idx = 0uz; idx < prefix.size(); ++idx) {
if (text[idx] != prefix[idx]) return false;
}
return true;
}
} // namespace arrays
@@ -7,6 +7,7 @@ TEST(StdString, ToUppercase) {
TEST(StdString, Trim) {
EXPECT_EQ(arrays::trim(" hi "), "hi");
EXPECT_EQ(arrays::trim(" a b c "), "a b c");
}
TEST(StdString, ReplaceAll) {
@@ -1,8 +1,8 @@
add_course_exercise(NAME pointer_basics MODULE 05_pointers_and_references STANDARD 17
add_course_exercise(NAME pointer_basics MODULE 05_pointers_and_references STANDARD 26
SOURCES src/pointer_basics.cpp test/pointer_basics_test.cpp)
add_course_exercise(NAME references MODULE 05_pointers_and_references STANDARD 17
add_course_exercise(NAME references MODULE 05_pointers_and_references STANDARD 26
SOURCES src/references.cpp test/references_test.cpp)
add_course_exercise(NAME pointer_arithmetic MODULE 05_pointers_and_references STANDARD 17
add_course_exercise(NAME pointer_arithmetic MODULE 05_pointers_and_references STANDARD 26
SOURCES src/pointer_arithmetic.cpp test/pointer_arithmetic_test.cpp)
add_course_exercise(NAME dynamic_memory MODULE 05_pointers_and_references STANDARD 17
add_course_exercise(NAME dynamic_memory MODULE 05_pointers_and_references STANDARD 26
SOURCES src/dynamic_memory.cpp test/dynamic_memory_test.cpp)
@@ -5,7 +5,7 @@
namespace pointers {
[[nodiscard]] auto allocate_and_fill(std::size_t count, int value) -> int*;
void deallocate(int* ptr);
void deallocate(const int* ptr);
[[nodiscard]] auto clone_array(const int* source, std::size_t count) -> int*;
} // namespace pointers
@@ -2,7 +2,7 @@
namespace pointers {
[[nodiscard]] auto get_value(int* ptr) -> int;
[[nodiscard]] auto get_value(const int* ptr) -> int;
void set_value(int* ptr, int value);
[[nodiscard]] auto is_null(const int* ptr) -> bool;
void swap_via_pointers(int* a, int* b);
@@ -1,9 +1,23 @@
#include "dynamic_memory.hpp"
#include <algorithm>
namespace pointers {
auto allocate_and_fill(std::size_t count, int value) -> int* { (void)count; (void)value; return nullptr; }
void deallocate(int* ptr) { delete[] ptr; }
auto clone_array(const int* source, std::size_t count) -> int* { (void)source; (void)count; return nullptr; }
auto allocate_and_fill(const std::size_t count, const int value) -> int* {
const auto na = new int[count];
std::fill_n(na, count, value);
return na;
}
void deallocate(const int* ptr) {
delete[] ptr;
}
auto clone_array(const int* source, const std::size_t count) -> int* {
const auto na = new int[count];
std::copy_n(source, count, na);
return na;
}
} // namespace pointers
@@ -2,8 +2,24 @@
namespace pointers {
auto pointer_distance(const int* begin, const int* end) -> std::size_t { (void)begin; (void)end; return 0; }
auto find_pointer(const int* begin, const int* end, int target) -> const int* { (void)begin; (void)end; (void)target; return end; }
void reverse_in_place(int* begin, int* end) { (void)begin; (void)end; }
auto pointer_distance(const int* begin, const int* end) -> std::size_t {
return end - begin;
}
auto find_pointer(const int* begin, const int* end, int target) -> const int* {
while (*begin != target && ++begin != end) {
if (*begin == target) return begin;
begin++;
}
return begin;
}
void reverse_in_place(int* begin, int* end) {
while (begin != end && begin != --end) {
const auto aux = *begin;
*begin++ = *end;
*end = aux;
}
}
} // namespace pointers
@@ -2,9 +2,22 @@
namespace pointers {
auto get_value(int* ptr) -> int { (void)ptr; return 0; }
void set_value(int* ptr, int value) { (void)ptr; (void)value; }
auto is_null(const int* ptr) -> bool { (void)ptr; return true; }
void swap_via_pointers(int* a, int* b) { (void)a; (void)b; }
auto get_value(const int* ptr) -> int {
return *ptr;
}
void set_value(int* ptr, int value) {
*ptr = value;
}
auto is_null(const int* ptr) -> bool {
return ptr == nullptr;
}
void swap_via_pointers(int* a, int* b) {
const auto aux = *a;
*a = *b;
*b = aux;
}
} // namespace pointers
@@ -2,9 +2,19 @@
namespace pointers {
auto double_value(const int& value) -> int { (void)value; return 0; }
void increment(int& value) { (void)value; }
auto max_ref(const int& a, const int& b) -> const int& { (void)a; (void)b; return a; }
auto sum_three(const int& a, const int& b, const int& c) -> int { (void)a; (void)b; (void)c; return 0; }
auto double_value(const int& value) -> int {
return value * 2;
}
void increment(int& value) {
value++;
}
auto max_ref(const int& a, const int& b) -> const int& {
return a > b ? a : b;
}
auto sum_three(const int& a, const int& b, const int& c) -> int {
return a + b + c;
}
} // namespace pointers
+4 -4
View File
@@ -1,8 +1,8 @@
add_course_exercise(NAME classes_and_objects MODULE 06_oop_basics STANDARD 17
add_course_exercise(NAME classes_and_objects MODULE 06_oop_basics STANDARD 26
SOURCES src/classes_and_objects.cpp test/classes_and_objects_test.cpp)
add_course_exercise(NAME constructors MODULE 06_oop_basics STANDARD 17
add_course_exercise(NAME constructors MODULE 06_oop_basics STANDARD 26
SOURCES src/constructors.cpp test/constructors_test.cpp)
add_course_exercise(NAME inheritance MODULE 06_oop_basics STANDARD 17
add_course_exercise(NAME inheritance MODULE 06_oop_basics STANDARD 26
SOURCES src/inheritance.cpp test/inheritance_test.cpp)
add_course_exercise(NAME polymorphism MODULE 06_oop_basics STANDARD 17
add_course_exercise(NAME polymorphism MODULE 06_oop_basics STANDARD 26
SOURCES src/polymorphism.cpp src/inheritance.cpp test/polymorphism_test.cpp)
@@ -11,8 +11,8 @@ public:
[[nodiscard]] auto owner() const -> const std::string&;
[[nodiscard]] auto balance() const -> double;
void deposit(double amount);
auto withdraw(double amount) -> bool;
void deposit(double amount) pre(amount > 0);
auto withdraw(double amount) -> bool pre(amount > 0);
private:
std::string owner_;
@@ -8,7 +8,7 @@ namespace oop {
class StringBuilder {
public:
StringBuilder() = default;
explicit StringBuilder(std::string initial);
explicit StringBuilder(const std::string &initial);
StringBuilder(const StringBuilder& other);
auto operator=(const StringBuilder& other) -> StringBuilder&;
~StringBuilder() = default;
@@ -2,20 +2,23 @@
namespace oop {
BankAccount::BankAccount(std::string owner, double balance)
BankAccount::BankAccount(std::string owner, const double balance)
: owner_(std::move(owner)), balance_(balance) {}
auto BankAccount::owner() const -> const std::string& { return owner_; }
auto BankAccount::balance() const -> double { return balance_; }
void BankAccount::deposit(double amount) {
// TODO: Add amount when positive
(void)amount;
void BankAccount::deposit(const double amount)
{
this->balance_ += amount;
}
auto BankAccount::withdraw(double amount) -> bool {
// TODO: Return false if insufficient funds, else subtract and return true
(void)amount;
auto BankAccount::withdraw(const double amount) -> bool
{
if (this->balance_ >= amount) {
this->balance_ -= amount;
return true;
}
return false;
}
+6 -7
View File
@@ -2,12 +2,12 @@
namespace oop {
StringBuilder::StringBuilder(std::string initial) {
// TODO: Initialize buffer_ from initial
(void)initial;
}
StringBuilder::StringBuilder(const StringBuilder& other) : buffer_(other.buffer_) {}
StringBuilder::StringBuilder(const std::string &initial)
: buffer_(initial.begin(), initial.end()) {}
StringBuilder::StringBuilder(const StringBuilder& other)
: buffer_(other.buffer_) {}
auto StringBuilder::operator=(const StringBuilder& other) -> StringBuilder& {
if (this != &other) {
@@ -17,8 +17,7 @@ auto StringBuilder::operator=(const StringBuilder& other) -> StringBuilder& {
}
void StringBuilder::append(const std::string& text) {
// TODO: Append all characters from text
(void)text;
std::ranges::copy(text, std::back_inserter(this->buffer_));
}
auto StringBuilder::str() const -> std::string {
+3 -2
View File
@@ -2,11 +2,12 @@
namespace oop {
Circle::Circle(double radius) : radius_(radius) {}
Circle::Circle(const double radius) : radius_(radius) {}
auto Circle::name() const -> std::string { return "Circle"; }
auto Circle::area() const -> double { return 3.141592653589793 * radius_ * radius_; }
Rectangle::Rectangle(double width, double height) : width_(width), height_(height) {}
Rectangle::Rectangle(const double width, const double height) : width_(width), height_(height) {}
auto Rectangle::name() const -> std::string { return "Rectangle"; }
auto Rectangle::area() const -> double { return width_ * height_; }
+2 -4
View File
@@ -5,8 +5,7 @@ namespace oop {
auto total_area(const std::vector<std::unique_ptr<Shape>>& shapes) -> double {
double total = 0.0;
for (const auto& shape : shapes) {
// TODO: Add each shape's area using polymorphism
(void)shape;
total += shape->area();
}
return total;
}
@@ -15,8 +14,7 @@ auto shape_names(const std::vector<std::unique_ptr<Shape>>& shapes)
-> std::vector<std::string> {
std::vector<std::string> names;
for (const auto& shape : shapes) {
// TODO: Collect shape->name()
(void)shape;
names.push_back(shape->name());
}
return names;
}
@@ -8,6 +8,8 @@ TEST(ClassesAndObjects, DepositAndWithdraw) {
EXPECT_TRUE(account.withdraw(30.0));
EXPECT_DOUBLE_EQ(account.balance(), 120.0);
EXPECT_FALSE(account.withdraw(1000.0));
EXPECT_DEATH(account.withdraw(-10.0), "amount > 0");
EXPECT_DEATH(account.deposit(-10.0), "amount > 0");
}
TEST(ClassesAndObjects, OwnerName) {
@@ -8,7 +8,7 @@ TEST(Constructors, InitialAndAppend) {
}
TEST(Constructors, CopySemantics) {
oop::StringBuilder original("C++");
const oop::StringBuilder original("C++");
oop::StringBuilder copy = original;
copy.append("11");
EXPECT_EQ(original.str(), "C++");
+4 -4
View File
@@ -1,8 +1,8 @@
add_course_exercise(NAME sequential_containers MODULE 07_stl_containers STANDARD 17
add_course_exercise(NAME sequential_containers MODULE 07_stl_containers STANDARD 26
SOURCES src/sequential_containers.cpp test/sequential_containers_test.cpp)
add_course_exercise(NAME associative_containers MODULE 07_stl_containers STANDARD 17
add_course_exercise(NAME associative_containers MODULE 07_stl_containers STANDARD 26
SOURCES src/associative_containers.cpp test/associative_containers_test.cpp)
add_course_exercise(NAME unordered_containers MODULE 07_stl_containers STANDARD 17
add_course_exercise(NAME unordered_containers MODULE 07_stl_containers STANDARD 26
SOURCES src/unordered_containers.cpp test/unordered_containers_test.cpp)
add_course_exercise(NAME container_adapters MODULE 07_stl_containers STANDARD 17
add_course_exercise(NAME container_adapters MODULE 07_stl_containers STANDARD 26
SOURCES src/container_adapters.cpp test/container_adapters_test.cpp)
@@ -9,6 +9,6 @@ namespace stl_containers {
[[nodiscard]] auto merge_sorted_vectors(const std::vector<int>& a, const std::vector<int>& b)
-> std::vector<int>;
[[nodiscard]] auto list_to_vector(const std::list<int>& data) -> std::vector<int>;
[[nodiscard]] auto rotate_deque(std::deque<int> data, int steps) -> std::deque<int>;
[[nodiscard]] auto rotate_deque(const std::deque<int> &data, int steps) -> std::deque<int>;
} // namespace stl_containers
@@ -4,18 +4,25 @@ namespace stl_containers {
auto word_frequencies(const std::vector<std::string>& words)
-> std::map<std::string, int> {
(void)words;
return {};
auto m = std::map<std::string, int>();
for (const auto& word : words) {
++m[word];
}
return m;
}
auto unique_sorted(const std::vector<int>& data) -> std::set<int> {
(void)data;
return {};
auto s = std::set<int>();
for (const auto& value : data) {
s.insert(value);
}
return s;
}
auto invert_map(const std::map<int, std::string>& input) -> std::map<std::string, int> {
(void)input;
return {};
auto m = std::map<std::string, int>();
for (const auto&[k, v] : input) m[v] = k;
return m;
}
} // namespace stl_containers
@@ -1,20 +1,52 @@
#include "container_adapters.hpp"
#include <algorithm>
#include <set>
namespace stl_containers {
auto is_balanced_parentheses(const std::string& text) -> bool {
(void)text;
std::stack<char> s;
for (const auto c: text) {
switch (c) {
case '(':
s.push(')');
break;
case '[':
s.push(']');
break;
case '{':
s.push('}');
break;
case ')':
case ']':
case '}': {
if (const auto n = s.top(); c != n) return false;
s.pop();
break;
}
default:
return false;
}
}
if (s.empty()) return true;
return false;
}
auto simulate_queue(const std::vector<int>& arrivals) -> std::vector<int> {
(void)arrivals;
return {};
auto v = std::vector<int>{};
const auto push = [&v](const int val){v.push_back(val);};
std::ranges::for_each(arrivals, push);
return v;
}
auto top_k_largest(const std::vector<int>& data, int k) -> std::vector<int> {
(void)data; (void)k;
return {};
auto top_k_largest(const std::vector<int>& data, const int k) -> std::vector<int> {;
// Remove duplicates
std::set<int> s{data.begin(), data.end()};
auto v = std::vector<int>{s.begin(), s.end()};
std::ranges::sort(v, std::ranges::greater{});
v.resize(k);
return v;
}
} // namespace stl_containers
@@ -4,18 +4,38 @@ namespace stl_containers {
auto merge_sorted_vectors(const std::vector<int>& a, const std::vector<int>& b)
-> std::vector<int> {
(void)a; (void)b;
return {};
std::vector<int> v;
auto aIt = a.begin();
auto bIt = b.begin();
while (aIt != a.end() && bIt != b.end()) {
if (*aIt >= *bIt) {
v.push_back(*bIt++);
} else {
v.push_back(*aIt++);
}
}
while (aIt != a.end()) {
v.push_back(*aIt++);
}
while (bIt != b.end()) {
v.push_back(*bIt++);
}
return v;
}
auto list_to_vector(const std::list<int>& data) -> std::vector<int> {
(void)data;
return {};
return std::vector(data.begin(), data.end());
}
auto rotate_deque(std::deque<int> data, int steps) -> std::deque<int> {
(void)data; (void)steps;
return {};
auto rotate_deque(const std::deque<int> &data, const int steps) -> std::deque<int> {
auto result = std::deque{data};
for (auto i = 0; i < steps; ++i) {
// Take from the front, add to the end
auto aux = result.front();
result.push_back(aux);
result.pop_front();
}
return result;
}
} // namespace stl_containers
@@ -1,21 +1,37 @@
#include "unordered_containers.hpp"
#include <algorithm>
#include <set>
namespace stl_containers {
auto first_unique(const std::vector<std::string>& words) -> std::string {
(void)words;
return {};
auto s = std::set<std::string>();
for (const auto& word : words) {
if (!s.contains(word)) {
s.insert(word);
} else {
s.erase(word);
}
}
return s.empty() ? "" : *s.begin();
}
auto group_anagrams(const std::vector<std::string>& words)
-> std::unordered_map<std::string, std::vector<std::string>> {
(void)words;
return {};
auto groups = std::unordered_map<std::string, std::vector<std::string>>();
for (const auto& word : words) {
auto key = word;
std::ranges::sort(key);
groups[key].push_back(word);
}
return groups;
}
auto has_duplicate(const std::vector<int>& data) -> bool {
(void)data;
return false;
auto s = std::set<int>{};
for (auto i : data) s.insert(i);
return s.size() != data.size();
}
} // namespace stl_containers
@@ -12,4 +12,5 @@ TEST(ContainerAdapters, SimulateQueue) {
TEST(ContainerAdapters, TopKLargest) {
EXPECT_EQ(stl_containers::top_k_largest({3, 1, 4, 1, 5}, 3), (std::vector<int>{5, 4, 3}));
EXPECT_EQ(stl_containers::top_k_largest({3, 1, 4, 1, 5, 5, 5}, 3), (std::vector<int>{5, 4, 3}));
}
@@ -12,4 +12,5 @@ TEST(SequentialContainers, ListToVector) {
TEST(SequentialContainers, RotateDeque) {
EXPECT_EQ(stl_containers::rotate_deque({1, 2, 3, 4}, 1), (std::deque<int>{2, 3, 4, 1}));
EXPECT_EQ(stl_containers::rotate_deque({1, 2, 3, 4}, 2), (std::deque<int>{3, 4, 1, 2}));
}
@@ -1,4 +1,7 @@
#include "unordered_containers.hpp"
#include <algorithm>
#include <ranges>
#include <gtest/gtest.h>
TEST(UnorderedContainers, FirstUnique) {
@@ -9,3 +12,42 @@ TEST(UnorderedContainers, HasDuplicate) {
EXPECT_TRUE(stl_containers::has_duplicate({1, 2, 2}));
EXPECT_FALSE(stl_containers::has_duplicate({1, 2, 3}));
}
TEST(UnorderedContainers, GroupAnagramsBasic) {
auto result = stl_containers::group_anagrams({"eat", "tea", "tan", "ate", "nat", "bat"});
// Sort each group for deterministic comparison
for (auto &group: result | std::views::values) {
std::ranges::sort(group);
}
ASSERT_EQ(result.size(), 3);
EXPECT_EQ(result["aet"], (std::vector<std::string>{"ate", "eat", "tea"}));
EXPECT_EQ(result["ant"], (std::vector<std::string>{"nat", "tan"}));
EXPECT_EQ(result["abt"], (std::vector<std::string>{"bat"}));
}
TEST(UnorderedContainers, GroupAnagramsEmpty) {
auto result = stl_containers::group_anagrams({});
EXPECT_TRUE(result.empty());
}
TEST(UnorderedContainers, GroupAnagramsSingleWord) {
auto result = stl_containers::group_anagrams({"hello"});
ASSERT_EQ(result.size(), 1);
EXPECT_EQ(result["ehllo"], (std::vector<std::string>{"hello"}));
}
TEST(UnorderedContainers, GroupAnagramsNoAnagrams) {
auto result = stl_containers::group_anagrams({"abc", "def", "ghi"});
ASSERT_EQ(result.size(), 3);
EXPECT_EQ(result["abc"].size(), 1);
EXPECT_EQ(result["def"].size(), 1);
EXPECT_EQ(result["ghi"].size(), 1);
}
TEST(UnorderedContainers, GroupAnagramsAllSame) {
auto result = stl_containers::group_anagrams({"abc", "bca", "cab"});
ASSERT_EQ(result.size(), 1);
auto& group = result["abc"];
std::ranges::sort(group);
EXPECT_EQ(group, (std::vector<std::string>{"abc", "bca", "cab"}));
}
+4 -4
View File
@@ -1,8 +1,8 @@
add_course_exercise(NAME sort_and_find MODULE 08_stl_algorithms STANDARD 17
add_course_exercise(NAME sort_and_find MODULE 08_stl_algorithms STANDARD 26
SOURCES src/sort_and_find.cpp test/sort_and_find_test.cpp)
add_course_exercise(NAME transform_reduce MODULE 08_stl_algorithms STANDARD 17
add_course_exercise(NAME transform_reduce MODULE 08_stl_algorithms STANDARD 26
SOURCES src/transform_reduce.cpp test/transform_reduce_test.cpp)
add_course_exercise(NAME iterators MODULE 08_stl_algorithms STANDARD 17
add_course_exercise(NAME iterators MODULE 08_stl_algorithms STANDARD 26
SOURCES src/iterators.cpp test/iterators_test.cpp)
add_course_exercise(NAME algorithm_lambdas MODULE 08_stl_algorithms STANDARD 17
add_course_exercise(NAME algorithm_lambdas MODULE 08_stl_algorithms STANDARD 26
SOURCES src/algorithm_lambdas.cpp test/algorithm_lambdas_test.cpp)
@@ -1,20 +1,29 @@
#include "algorithm_lambdas.hpp"
#include <algorithm>
namespace stl_algorithms {
auto filter_length(const std::vector<std::string>& words, std::size_t min_len)
-> std::vector<std::string> {
(void)words; (void)min_len;
return {};
const auto is_valid = [min_len](const auto& word) { return word.size() >= min_len; };
auto r = std::vector<std::string>();
std::ranges::copy_if(words,std::back_inserter(r), is_valid);
return r;
}
auto map_to_lengths(const std::vector<std::string>& words) -> std::vector<int> {
(void)words;
return {};
auto r = std::vector<int>();
for (const auto& word : words) {
r.push_back(static_cast<int>(word.size()));
}
return r;
}
auto first_match(const std::vector<int>& data, int threshold) -> int {
(void)data; (void)threshold;
auto first_match(const std::vector<int>& data, const int threshold) -> int {
for (const auto& value : data) {
if (value >= threshold) return value;
}
return -1;
}
+22 -3
View File
@@ -1,9 +1,28 @@
#include "iterators.hpp"
#include <algorithm>
#include <ranges>
namespace stl_algorithms {
auto reverse_copy(const std::vector<int>& data) -> std::vector<int> { (void)data; return {}; }
auto countGreaterThan(const std::vector<int>& data, int threshold) -> int { (void)data; (void)threshold; return 0; }
auto everyEven(const std::vector<int>& data) -> bool { (void)data; return false; }
auto reverse_copy(const std::vector<int>& data) -> std::vector<int> {
std::vector<int> result;
for (const auto& element : data | std::views::reverse) {
result.push_back(element);
}
return result;
}
auto countGreaterThan(const std::vector<int>& data, const int threshold) -> int {
auto count = 0;
for (const auto& element : data) {
if (element > threshold) count++;
}
return count;
}
auto everyEven(const std::vector<int>& data) -> bool {
return std::ranges::all_of(data, [](const int x) { return x % 2 == 0; });
}
} // namespace stl_algorithms
@@ -1,9 +1,19 @@
#include "sort_and_find.hpp"
#include <algorithm>
namespace stl_algorithms {
auto sorted_copy(std::vector<int> data) -> std::vector<int> { (void)data; return {}; }
auto contains(const std::vector<int>& data, int value) -> bool { (void)data; (void)value; return false; }
auto lower_bound_index(const std::vector<int>& sorted, int value) -> int { (void)sorted; (void)value; return -1; }
auto sorted_copy(std::vector<int> data) -> std::vector<int> {
std::ranges::sort(data);
return data;
}
auto contains(const std::vector<int>& data, const int value) -> bool {
return std::ranges::find(data, value) != data.end();
}
auto lower_bound_index(const std::vector<int>& sorted, const int value) -> int {
return static_cast<int>(std::ranges::lower_bound(sorted, value) - sorted.begin());
}
} // namespace stl_algorithms
@@ -1,9 +1,20 @@
#include "transform_reduce.hpp"
#include <algorithm>
namespace stl_algorithms {
auto square_all(const std::vector<int>& data) -> std::vector<int> { (void)data; return {}; }
auto sum_all(const std::vector<int>& data) -> int { (void)data; return 0; }
auto product_positive(const std::vector<int>& data) -> long long { (void)data; return 0; }
auto square_all(const std::vector<int>& data) -> std::vector<int> {
auto result = std::vector<int>{};
result.reserve(data.size());
std::ranges::transform(data, std::back_inserter(result), [](const int value) { return value * value; });
return result;
}
auto sum_all(const std::vector<int>& data) -> int {
return std::ranges::fold_left(data, 0, std::plus<int>{});
}
auto product_positive(const std::vector<int>& data) -> long long {
return std::ranges::fold_left(data, 1, [](const int accumulator, const int value) { return value > 0 ? value * accumulator : accumulator; });
}
} // namespace stl_algorithms
+4 -4
View File
@@ -1,8 +1,8 @@
add_course_exercise(NAME auto_and_range_for MODULE 09_cpp11 STANDARD 11
add_course_exercise(NAME auto_and_range_for MODULE 09_cpp11 STANDARD 26
SOURCES src/auto_and_range_for.cpp test/auto_and_range_for_test.cpp)
add_course_exercise(NAME smart_pointers MODULE 09_cpp11 STANDARD 11
add_course_exercise(NAME smart_pointers MODULE 09_cpp11 STANDARD 26
SOURCES src/smart_pointers.cpp test/smart_pointers_test.cpp)
add_course_exercise(NAME move_semantics MODULE 09_cpp11 STANDARD 11
add_course_exercise(NAME move_semantics MODULE 09_cpp11 STANDARD 26
SOURCES src/move_semantics.cpp test/move_semantics_test.cpp)
add_course_exercise(NAME constexpr_nullptr MODULE 09_cpp11 STANDARD 11
add_course_exercise(NAME constexpr_nullptr MODULE 09_cpp11 STANDARD 26
SOURCES src/constexpr_nullptr.cpp test/constexpr_nullptr_test.cpp)
@@ -7,7 +7,7 @@ namespace cpp11 {
enum class Color { Red, Green, Blue };
[[nodiscard]] auto to_index(Color color) -> int;
[[nodiscard]] auto square(int value) -> int;
[[nodiscard]] constexpr auto square(const int value) -> int { return value * value; }
[[nodiscard]] auto find_null(int* ptr) -> int*;
} // namespace cpp11
+12 -6
View File
@@ -1,20 +1,26 @@
#include "auto_and_range_for.hpp"
#include <algorithm>
namespace cpp11 {
auto double_values(const std::vector<int>& input) -> std::vector<int> {
(void)input;
return {};
auto result = std::vector<int>{};
result.reserve(input.size());
std::ranges::for_each(input, [&result](const int value) { result.push_back(value * 2); });
return result;
}
auto join_with_auto(const std::vector<std::string>& parts) -> std::string {
(void)parts;
return {};
auto result = std::string{};
std::ranges::for_each(parts, [&result](const std::string& part) { result += part; });
return result;
}
auto count_if_positive(const std::vector<int>& input) -> int {
(void)input;
return 0;
auto count = 0;
std::ranges::for_each(input, [&count](const int value) { if (value > 0) ++count; });
return count;
}
} // namespace cpp11
+2 -8
View File
@@ -2,7 +2,7 @@
namespace cpp11 {
auto to_index(Color color) -> int {
auto to_index(const Color color) -> int {
switch (color) {
case Color::Red: return 0;
case Color::Green: return 1;
@@ -11,14 +11,8 @@ auto to_index(Color color) -> int {
return -1;
}
auto square(int value) -> int {
(void)value;
return 0;
}
auto find_null(int* ptr) -> int* {
(void)ptr;
return nullptr;
return ptr;
}
} // namespace cpp11
+1 -2
View File
@@ -17,8 +17,7 @@ auto MovableBuffer::size() const -> std::size_t { return data_.size(); }
auto MovableBuffer::data() const -> const std::vector<int>& { return data_; }
auto consume(MovableBuffer buffer) -> std::size_t {
(void)buffer;
return 0;
return buffer.size();
}
} // namespace cpp11
+7 -6
View File
@@ -3,18 +3,19 @@
namespace cpp11 {
auto make_counter(int start) -> std::unique_ptr<int> {
(void)start;
return nullptr;
return std::make_unique<int>(start);
}
auto shared_total(const std::vector<std::shared_ptr<int>>& values) -> int {
(void)values;
return 0;
int total = 0;
for (const auto& value : values) {
total += *value;
}
return total;
}
auto clone_unique(const std::unique_ptr<int>& value) -> std::unique_ptr<int> {
(void)value;
return nullptr;
return std::make_unique<int>(*value);
}
} // namespace cpp11
+4 -4
View File
@@ -1,8 +1,8 @@
add_course_exercise(NAME generic_lambdas MODULE 10_cpp14 STANDARD 14
add_course_exercise(NAME generic_lambdas MODULE 10_cpp14 STANDARD 26
SOURCES src/generic_lambdas.cpp test/generic_lambdas_test.cpp)
add_course_exercise(NAME auto_return MODULE 10_cpp14 STANDARD 14
add_course_exercise(NAME auto_return MODULE 10_cpp14 STANDARD 26
SOURCES src/auto_return.cpp test/auto_return_test.cpp)
add_course_exercise(NAME make_unique MODULE 10_cpp14 STANDARD 14
add_course_exercise(NAME make_unique MODULE 10_cpp14 STANDARD 26
SOURCES src/make_unique.cpp test/make_unique_test.cpp)
add_course_exercise(NAME digit_separators MODULE 10_cpp14 STANDARD 14
add_course_exercise(NAME digit_separators MODULE 10_cpp14 STANDARD 26
SOURCES src/digit_separators.cpp test/digit_separators_test.cpp)
+1 -3
View File
@@ -6,9 +6,7 @@
namespace cpp14 {
[[nodiscard]] inline auto copy_or_reference(const std::vector<int>& input) -> decltype(auto) {
(void)input;
static std::vector<int> empty;
return empty;
return input;
}
[[nodiscard]] inline auto identity(int value) -> decltype(auto) { return value; }
+8 -6
View File
@@ -3,18 +3,20 @@
namespace cpp14 {
auto million() -> int {
// TODO: Return 1'000'000 using digit separators
return 0;
return 1'000'000;
}
auto mask() -> std::uint32_t {
// TODO: Return 0xFF00'00FF
return 0;
return 0xFF00'00FF;
}
auto bits_set() -> int {
// TODO: Return population count of mask()
return 0;
const auto m = mask();
auto count = 0;
for (auto i = 0; i < 32; i++) {
if (m & (1 << i)) ++count;
}
return count;
}
} // namespace cpp14
+9 -4
View File
@@ -1,16 +1,21 @@
#include "generic_lambdas.hpp"
#include <algorithm>
namespace cpp14 {
auto apply_twice(const std::vector<int>& values) -> std::vector<int> {
(void)values;
return {};
auto r = std::vector<int>(values.size());
std::ranges::transform(values, r.begin(), [](auto x) { return x * 2; });
return r;
}
auto concat_any(const std::vector<std::string>& a, const std::vector<std::string>& b)
-> std::vector<std::string> {
(void)a; (void)b;
return {};
auto r = std::vector<std::string>(a.size() + b.size());
std::ranges::transform(a, r.begin(), [](auto x) { return x; });
std::ranges::transform(b, r.begin() + a.size(), [](auto x) { return x; });
return r;
}
} // namespace cpp14
+5 -6
View File
@@ -1,20 +1,19 @@
#include "make_unique.hpp"
#include <algorithm>
namespace cpp14 {
auto make_task(std::string name, int priority) -> std::unique_ptr<Task> {
(void)name; (void)priority;
return nullptr;
return std::make_unique<Task>(name, priority);
}
auto clone_task(const Task& task) -> std::unique_ptr<Task> {
(void)task;
return nullptr;
return std::make_unique<Task>(task);
}
auto total_priority(const std::vector<std::unique_ptr<Task>>& tasks) -> int {
(void)tasks;
return 0;
return std::ranges::fold_left(tasks, 0, [](int acc, const auto& x) { return acc + x->priority; });
}
} // namespace cpp14
+4 -4
View File
@@ -1,8 +1,8 @@
add_course_exercise(NAME structured_bindings MODULE 11_cpp17 STANDARD 17
add_course_exercise(NAME structured_bindings MODULE 11_cpp17 STANDARD 26
SOURCES src/structured_bindings.cpp test/structured_bindings_test.cpp)
add_course_exercise(NAME optional MODULE 11_cpp17 STANDARD 17
add_course_exercise(NAME optional MODULE 11_cpp17 STANDARD 26
SOURCES src/optional.cpp test/optional_test.cpp)
add_course_exercise(NAME variant MODULE 11_cpp17 STANDARD 17
add_course_exercise(NAME variant MODULE 11_cpp17 STANDARD 26
SOURCES src/variant.cpp test/variant_test.cpp)
add_course_exercise(NAME if_constexpr MODULE 11_cpp17 STANDARD 17
add_course_exercise(NAME if_constexpr MODULE 11_cpp17 STANDARD 26
SOURCES src/if_constexpr.cpp test/if_constexpr_test.cpp)
+6 -2
View File
@@ -5,8 +5,12 @@
namespace cpp17 {
auto stringify_ints(const std::vector<int>& data) -> std::string {
(void)data;
return {};
auto oss = std::stringstream();
for (auto i = 0uz; i < data.size(); ++i) {
if (i > 0) oss << ",";
oss << data[i];
}
return oss.str();
}
} // namespace cpp17
+13 -4
View File
@@ -2,19 +2,28 @@
namespace cpp17 {
auto safe_divide(int lhs, int rhs) -> std::optional<double> {
(void)lhs; (void)rhs;
auto safe_divide(const int lhs, const int rhs) -> std::optional<double> {
if (rhs == 0) {
return std::nullopt;
}
return std::optional(lhs / static_cast<double>(rhs));
}
auto find_user(const std::vector<std::string>& users, const std::string& name)
-> std::optional<std::size_t> {
(void)users; (void)name;
const auto idx = std::ranges::find(users, name);
if (idx == users.end()) {
return std::nullopt;
}
return std::optional<std::size_t>(std::distance(users.begin(), idx));
}
auto first_positive(const std::vector<int>& data) -> std::optional<int> {
(void)data;
for (const auto& elem : data) {
if (elem > 0) {
return std::optional(elem);
}
}
return std::nullopt;
}
+18 -6
View File
@@ -1,20 +1,32 @@
#include "structured_bindings.hpp"
#include <ranges>
namespace cpp17 {
auto minmax_pair(const std::vector<int>& data) -> std::pair<int, int> {
(void)data;
return {0, 0};
auto min = std::numeric_limits<int>::max();
auto max = std::numeric_limits<int>::min();
for (const auto i : data) {
if (i < min) min = i;
if (i > max) max = i;
}
return {min, max};
}
auto split_key_value(const std::string& text) -> std::pair<std::string, std::string> {
(void)text;
return {"", ""};
auto r = std::views::split(text, '=');
auto it = r.begin();
auto key = *it | std::ranges::to<std::string>();
++it;
auto value = *it | std::ranges::to<std::string>();
return {key, value};
}
auto first_pair(const std::map<std::string, int>& scores) -> std::tuple<std::string, int, bool> {
(void)scores;
return {"", 0, false};
if (scores.empty()) return {"", 0, false};
const auto& [name, score] = *scores.begin();
return {name, score, true};
}
} // namespace cpp17
+19 -5
View File
@@ -3,18 +3,32 @@
namespace cpp17 {
auto variant_to_string(const Value& value) -> std::string {
(void)value;
if (std::holds_alternative<int>(value)) {
return "int:" + std::to_string(std::get<int>(value));
}
if (std::holds_alternative<double>(value)) {
return "double:" + std::to_string(std::get<double>(value));
}
if (std::holds_alternative<std::string>(value)) {
return "string:" +std::get<std::string>(value);
}
return {};
}
auto sum_numeric_variants(const std::vector<Value>& values) -> double {
(void)values;
return 0.0;
auto sum = 0.0;
for (const auto& value : values) {
if (std::holds_alternative<int>(value)) {
sum += static_cast<double>(std::get<int>(value));
} else if (std::holds_alternative<double>(value)) {
sum += std::get<double>(value);
}
}
return sum;
}
auto is_string(const Value& value) -> bool {
(void)value;
return false;
return std::holds_alternative<std::string>(value);
}
} // namespace cpp17
+4 -4
View File
@@ -1,8 +1,8 @@
add_course_exercise(NAME concepts MODULE 12_cpp20 STANDARD 20
add_course_exercise(NAME concepts MODULE 12_cpp20 STANDARD 26
SOURCES src/concepts.cpp test/concepts_test.cpp)
add_course_exercise(NAME ranges MODULE 12_cpp20 STANDARD 20
add_course_exercise(NAME ranges MODULE 12_cpp20 STANDARD 26
SOURCES src/ranges.cpp test/ranges_test.cpp)
add_course_exercise(NAME spaceship_operator MODULE 12_cpp20 STANDARD 20
add_course_exercise(NAME spaceship_operator MODULE 12_cpp20 STANDARD 26
SOURCES src/spaceship_operator.cpp test/spaceship_operator_test.cpp)
add_course_exercise(NAME span MODULE 12_cpp20 STANDARD 20
add_course_exercise(NAME span MODULE 12_cpp20 STANDARD 26
SOURCES src/span.cpp test/span_test.cpp)
+14 -7
View File
@@ -3,6 +3,7 @@
#include <algorithm>
#include <cctype>
#include <concepts>
#include <sstream>
#include <string>
#include <vector>
@@ -10,14 +11,13 @@ namespace cpp20 {
template <std::integral T>
[[nodiscard]] auto double_value(T value) -> T {
(void)value;
return T{};
return value * 2;
}
template <std::floating_point T>
[[nodiscard]] auto clamp01(T value) -> T {
(void)value;
return T{};
// Converts the 0 and 1 to the right type, which fulfills the std::floating_point concept
return std::clamp(value, T{0}, T{1});
}
template <typename T>
@@ -28,10 +28,17 @@ concept StringLike = requires(T value) {
template <StringLike T>
[[nodiscard]] auto uppercase_copy(const T& text) -> std::string {
(void)text;
return {};
auto oss = std::ostringstream{};
for (auto idx = 0uz; idx < text.size(); idx++) {
oss << static_cast<char>(std::toupper(text.data()[idx]));
}
return oss.str();
}
[[nodiscard]] auto sum_integral(const std::vector<int>& data) -> int;
template<typename T>
requires std::integral<T>
[[nodiscard]] auto sum_integral(const std::vector<T>& data) -> T {
return std::ranges::fold_left(data, T{0}, std::plus{});
}
} // namespace cpp20
-4
View File
@@ -2,9 +2,5 @@
namespace cpp20 {
auto sum_integral(const std::vector<int>& data) -> int {
(void)data;
return 0;
}
} // namespace cpp20
+6 -6
View File
@@ -3,18 +3,18 @@
namespace cpp20 {
auto even_numbers(const std::vector<int>& input) -> std::vector<int> {
(void)input;
return {};
return std::ranges::filter_view(input, [](auto x) { return x % 2 == 0; })
| std::ranges::to<std::vector<int>>();
}
auto take_first_three(const std::vector<int>& input) -> std::vector<int> {
(void)input;
return {};
return std::ranges::take_view(input, 3)
| std::ranges::to<std::vector<int>>();
}
auto join_strings(const std::vector<std::string>& parts) -> std::string {
(void)parts;
return {};
return std::ranges::join_view(parts)
| std::ranges::to<std::string>();
}
} // namespace cpp20
+6 -4
View File
@@ -1,15 +1,17 @@
#include "spaceship_operator.hpp"
#include <algorithm>
#include <ranges>
namespace cpp20 {
auto sort_versions(std::vector<Version> versions) -> std::vector<Version> {
(void)versions;
return {};
std::ranges::sort(versions);
return versions;
}
auto is_sorted_versions(const std::vector<Version>& versions) -> bool {
(void)versions;
return false;
return std::ranges::is_sorted(versions);
}
} // namespace cpp20
+9 -7
View File
@@ -1,21 +1,23 @@
#include "span.hpp"
#include <algorithm>
#include <ranges>
namespace cpp20 {
auto span_sum(std::span<const int> data) -> int {
(void)data;
return 0;
return std::ranges::fold_left(data, 0, std::plus<>{});
}
auto first_and_last(std::span<const int> data) -> std::pair<int, int> {
(void)data;
return {0, 0};
return {*data.begin(), *(--data.end())};
}
auto make_subspan(std::span<const int> data, std::size_t offset, std::size_t count)
auto make_subspan(std::span<const int> data, const std::size_t offset, std::size_t count)
-> std::vector<int> {
(void)data; (void)offset; (void)count;
return {};
return std::views::drop(data, offset)
| std::views::take(count)
| std::ranges::to<std::vector<int>>();
}
} // namespace cpp20
+1 -1
View File
@@ -15,5 +15,5 @@ TEST(Concepts, UppercaseCopy) {
}
TEST(Concepts, SumIntegral) {
EXPECT_EQ(cpp20::sum_integral({1, 2, 3}), 6);
EXPECT_EQ(cpp20::sum_integral<int>({1, 2, 3}), 6);
}
+4 -4
View File
@@ -1,8 +1,8 @@
add_course_exercise(NAME expected MODULE 13_cpp23 STANDARD 23
add_course_exercise(NAME expected MODULE 13_cpp23 STANDARD 26
SOURCES src/expected.cpp test/expected_test.cpp)
add_course_exercise(NAME print_and_format MODULE 13_cpp23 STANDARD 23
add_course_exercise(NAME print_and_format MODULE 13_cpp23 STANDARD 26
SOURCES src/print_and_format.cpp test/print_and_format_test.cpp)
add_course_exercise(NAME mdspan MODULE 13_cpp23 STANDARD 23
add_course_exercise(NAME mdspan MODULE 13_cpp23 STANDARD 26
SOURCES src/mdspan.cpp test/mdspan_test.cpp)
add_course_exercise(NAME ranges_zip MODULE 13_cpp23 STANDARD 23
add_course_exercise(NAME ranges_zip MODULE 13_cpp23 STANDARD 26
SOURCES src/ranges_zip.cpp test/ranges_zip_test.cpp)
@@ -1,5 +1,6 @@
#pragma once
#include <cstdint>
#include <string>
#include <vector>
+19 -5
View File
@@ -1,20 +1,34 @@
#include "expected.hpp"
#include <cmath>
namespace cpp23 {
auto parse_int(const std::string& text) -> std::expected<int, ParseError> {
(void)text;
if (text.empty()) {
return std::unexpected(ParseError::EmptyInput);
}
try {
const auto i = std::stoi(text);
return i;
}
catch (const std::invalid_argument&) {
return std::unexpected(ParseError::InvalidNumber);
}
catch (const std::out_of_range&) {
return std::unexpected(ParseError::InvalidNumber);
}
}
auto safe_sqrt(int value) -> std::expected<double, std::string> {
(void)value;
auto safe_sqrt(const int value) -> std::expected<double, std::string> {
if (value < 0) {
return std::unexpected(std::string{"negative"});
}
return std::sqrt(value);
}
auto chain_parse_and_double(const std::string& text) -> std::expected<int, ParseError> {
(void)text;
return std::unexpected(ParseError::InvalidNumber);
return parse_int(text).transform([](const auto i) { return i * 2; });
}
} // namespace cpp23
+12 -13
View File
@@ -2,23 +2,22 @@
namespace cpp23 {
auto make_row_major_matrix(int rows, int cols, int fill) -> std::vector<int> {
(void)rows; (void)cols; (void)fill;
return {};
auto make_row_major_matrix(const int rows, const int cols, const int fill) -> std::vector<int> {
return std::vector(static_cast<size_t>(rows * cols), fill);
}
auto matrix_element(
std::mdspan<const int, std::extents<int, std::dynamic_extent, std::dynamic_extent>> matrix,
int row, int col) -> int {
(void)matrix; (void)row; (void)col;
return 0;
auto matrix_element(const std::mdspan<const int, std::extents<int, std::dynamic_extent, std::dynamic_extent>> matrix, const int row, const int col) -> int {
return matrix[row, col];
}
auto row_sums(
std::mdspan<const int, std::extents<int, std::dynamic_extent, std::dynamic_extent>> matrix)
-> std::vector<int> {
(void)matrix;
return {};
auto row_sums(const std::mdspan<const int, std::extents<int, std::dynamic_extent, std::dynamic_extent>> matrix) -> std::vector<int> {
auto sums = std::vector<int>(matrix.extent(0));
for (auto i = 0; i < matrix.extent(0); ++i) {
for (auto j = 0; j < matrix.extent(1); ++j) {
sums[i] += matrix[i, j];
}
}
return sums;
}
} // namespace cpp23
+12 -8
View File
@@ -1,20 +1,24 @@
#include "print_and_format.hpp"
#include <ranges>
#include <sstream>
namespace cpp23 {
auto format_greeting(const std::string& name, int score) -> std::string {
(void)name; (void)score;
return {};
auto format_greeting(const std::string& name, const int score) -> std::string {
return std::format("{} scored {} points", name, score)
| std::ranges::to<std::string>();
}
auto format_table_row(const std::vector<std::string>& columns) -> std::string {
(void)columns;
return {};
return columns
| std::views::join_with(std::string_view{" | "})
| std::ranges::to<std::string>();
}
auto format_hex(std::uint32_t value) -> std::string {
(void)value;
return {};
auto format_hex(const std::uint32_t value) -> std::string {
return std::format("0x{:X}", value)
| std::ranges::to<std::string>();
}
} // namespace cpp23
+12 -8
View File
@@ -3,19 +3,23 @@
namespace cpp23 {
auto zip_sum(const std::vector<int>& a, const std::vector<int>& b) -> std::vector<int> {
(void)a; (void)b;
return {};
return std::views::zip_transform(std::plus{}, a, b)
| std::ranges::to<std::vector>();
}
auto chunk_strings(const std::vector<std::string>& words, std::size_t chunk_size)
-> std::vector<std::vector<std::string>> {
(void)words; (void)chunk_size;
return {};
auto chunk_strings(const std::vector<std::string>& words, const std::size_t chunk_size) -> std::vector<std::vector<std::string>> {
return words
| std::views::chunk(chunk_size)
| std::views::transform([](const auto& chunk) {
return chunk | std::ranges::to<std::vector<std::string>>();
})
| std::ranges::to<std::vector<std::vector<std::string>>>();
}
auto adjacent_differences(const std::vector<int>& data) -> std::vector<int> {
(void)data;
return {};
return data
| std::views::adjacent_transform<2>([](const int x, const int y) { return y - x; })
| std::ranges::to<std::vector<int>>();
}
} // namespace cpp23
+4 -4
View File
@@ -1,8 +1,8 @@
add_course_exercise(NAME constexpr_frontier MODULE 14_cpp26 STANDARD 23
add_course_exercise(NAME constexpr_frontier MODULE 14_cpp26 STANDARD 26
SOURCES src/constexpr_frontier.cpp test/constexpr_frontier_test.cpp)
add_course_exercise(NAME monadic_expected MODULE 14_cpp26 STANDARD 23
add_course_exercise(NAME monadic_expected MODULE 14_cpp26 STANDARD 26
SOURCES src/monadic_expected.cpp test/monadic_expected_test.cpp)
add_course_exercise(NAME pipeline_ranges MODULE 14_cpp26 STANDARD 23
add_course_exercise(NAME pipeline_ranges MODULE 14_cpp26 STANDARD 26
SOURCES src/pipeline_ranges.cpp test/pipeline_ranges_test.cpp)
add_course_exercise(NAME custom_formatter MODULE 14_cpp26 STANDARD 23
add_course_exercise(NAME custom_formatter MODULE 14_cpp26 STANDARD 26
SOURCES src/custom_formatter.cpp test/custom_formatter_test.cpp)
@@ -1,12 +1,23 @@
#pragma once
#include <algorithm>
#include <array>
#include <cstddef>
namespace cpp26 {
[[nodiscard]] auto compile_time_factorial(int n) -> long long;
[[nodiscard]] auto compile_time_sum(std::array<int, 5> values) -> int;
[[nodiscard]] auto is_sorted(std::array<int, 5> values) -> bool;
[[nodiscard]] constexpr auto compile_time_factorial(int n) -> long long {
auto result = 1LL;
for (auto i = 2; i <= n; ++i) {
result *= i;
}
return result;
}
[[nodiscard]] constexpr auto compile_time_sum(std::array<int, 5> values) -> int {
return std::ranges::fold_left(values, 0, std::plus{});
}
[[nodiscard]] constexpr auto is_sorted(const std::array<int, 5> &values) -> bool {
return std::ranges::is_sorted(values); // also a constexpr function
}
} // namespace cpp26
+1 -15
View File
@@ -1,20 +1,6 @@
#include "constexpr_frontier.hpp"
namespace cpp26 {
auto compile_time_factorial(int n) -> long long {
(void)n;
return 1;
}
auto compile_time_sum(std::array<int, 5> values) -> int {
(void)values;
return 0;
}
auto is_sorted(std::array<int, 5> values) -> bool {
(void)values;
return false;
}
// constexpr functions should be defined in the header file
} // namespace cpp26
+2 -4
View File
@@ -3,13 +3,11 @@
namespace cpp26 {
auto format_point(const Point& point) -> std::string {
(void)point;
return {};
return std::format("{}", point);
}
auto format_points(const Point& a, const Point& b) -> std::string {
(void)a; (void)b;
return {};
return std::format("{} -> {}", a, b);
}
} // namespace cpp26
+10 -5
View File
@@ -3,18 +3,23 @@
namespace cpp26 {
auto parse_id(const std::string& text) -> std::expected<int, ErrorCode> {
(void)text;
int id = 0;
if (auto [ptr, ec] = std::from_chars(text.data(), text.data() + text.size(), id);
ec != std::errc{} || ptr != text.data() + text.size()) {
return std::unexpected(ErrorCode::Invalid);
}
return id;
}
auto load_user(int id) -> std::expected<std::string, ErrorCode> {
(void)id;
auto load_user(const int id) -> std::expected<std::string, ErrorCode> {
if (id == 999) {
return std::unexpected(ErrorCode::NotFound);
}
return "User-" + std::to_string(id);
}
auto load_user_name(const std::string& text) -> std::expected<std::string, ErrorCode> {
(void)text;
return std::unexpected(ErrorCode::Invalid);
return parse_id(text).and_then(load_user);
}
} // namespace cpp26
+14 -8
View File
@@ -1,17 +1,23 @@
#include "pipeline_ranges.hpp"
#include <map>
#include <ranges>
namespace cpp26 {
auto top_values_by_category(const std::vector<Record>& records, int min_value)
-> std::vector<Record> {
(void)records; (void)min_value;
return {};
auto top_values_by_category(const std::vector<Record>& records, const int min_value) -> std::vector<Record> {
return records
| std::views::filter([min_value](const auto& record) { return record.value > min_value; })
| std::ranges::to<std::vector<Record>>();
}
auto total_by_category(const std::vector<Record>& records)
-> std::vector<std::pair<std::string, int>> {
(void)records;
return {};
auto total_by_category(const std::vector<Record>& records) -> std::vector<std::pair<std::string, int>> {
std::map<std::string, int> grouped;
for (const auto&[category, value] : records) {
grouped[category] += value;
}
return grouped
| std::ranges::to<std::vector<std::pair<std::string, int>>>();
}
} // namespace cpp26
+8
View File
@@ -0,0 +1,8 @@
add_library(course_contract_support STATIC contract_handler.cpp)
target_compile_options(course_contract_support PUBLIC -std=c++26)
set_target_properties(course_contract_support PROPERTIES POSITION_INDEPENDENT_CODE ON)
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND COURSE_ENABLE_CONTRACTS)
target_compile_options(course_contract_support PRIVATE -fcontracts)
target_link_options(course_contract_support PRIVATE -fcontracts)
endif()

Some files were not shown because too many files have changed in this diff Show More