diff --git a/.clang-format b/.clang-format index 84d194c..53b3163 100644 --- a/.clang-format +++ b/.clang-format @@ -1,4 +1,7 @@ BasedOnStyle: Google IndentWidth: 2 -TabWidth: 3 +TabWidth: 2 ColumnLimit: 100 +RequiresClausePosition: OwnLine +RequiresExpressionIndentation: OuterScope +SpacesInContainerLiterals: true diff --git a/.clang-tidy b/.clang-tidy index eb2b980..eea9376 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -1,19 +1,45 @@ Checks: > -*, bugprone-*, - modernize-*, - readability-*, - cppcoreguidelines-*, - performance-*, clang-analyzer-*, - cert-*, misc-*, - google-*, - llvm-*, - hicpp-* + modernize-*, + performance-*, + readability-const-return-type, + readability-container-size-empty, + readability-make-member-function-const, + readability-redundant-member-init, + readability-redundant-smartptr-get, + readability-redundant-string-cstr, + readability-simplify-boolean-expr, + readability-static-accessed-through-instance, + readability-string-compare, + cppcoreguidelines-init-variables, + cppcoreguidelines-prefer-member-initializer, + cppcoreguidelines-slicing, + -bugprone-easily-swappable-parameters, + -misc-const-correctness, + -misc-include-cleaner, + -misc-no-recursion, + -misc-non-private-member-variables-in-classes, + -misc-unused-parameters, + -misc-use-anonymous-namespace, + -misc-definitions-in-headers, + -misc-use-internal-linkage, + -modernize-use-trailing-return-type + +WarningsAsErrors: > + bugprone-use-after-move, + bugprone-dangling-handle + +HeaderFilterRegex: 'src/.*\.(hpp|h)$' + +FormatStyle: file CheckOptions: - key: modernize-use-nullptr.NullMacros - value: 'Google' - - key: modernize-use-override.IgnoreDestructors - value: true \ No newline at end of file + value: 'NULL' + - key: performance-move-const-arg.CheckTriviallyCopyableMove + value: 'false' + - key: misc-non-private-member-variables-in-classes.IgnoreClassesWithAllMemberVariablesBeingPublic + value: 'true' diff --git a/.github/workflows/cpp-ci.yml b/.github/workflows/cpp-ci.yml index 8898a34..4b80fa5 100644 --- a/.github/workflows/cpp-ci.yml +++ b/.github/workflows/cpp-ci.yml @@ -2,21 +2,47 @@ name: C++ CI on: push: - branches: [ "main" ] + branches: ["main"] pull_request: - branches: [ "main" ] + branches: ["main"] jobs: - build_and_test: - runs-on: ubuntu-latest + format-check: + name: Format Check + runs-on: ubuntu-24.04 steps: - name: Check out repository - uses: actions/checkout@v4 - - name: Install Dependencies + uses: actions/checkout@v6 + + - name: Check format + run: | + clang-format --version + find src tests \( -name "*.hpp" -o -name "*.cpp" -o -name "*.h" \) | \ + xargs clang-format --dry-run --Werror + + build-and-test: + name: Build and Test + runs-on: ubuntu-24.04 + needs: format-check + steps: + - name: Check out repository + uses: actions/checkout@v6 + + - name: Install dependencies run: | sudo apt-get update - sudo apt-get install -y cmake build-essential libgtest-dev - - name: Build and run tests + sudo apt-get install -y libgtest-dev + + - name: Show tool versions run: | - chmod +x ./scripts/run_tests.sh - ./scripts/run_tests.sh + cmake --version + g++ --version + + - name: Configure + run: cmake --preset ci + + - name: Build + run: cmake --build --preset ci + + - name: Test + run: ctest --preset ci diff --git a/.vscode/settings.json b/.vscode/settings.json index c29377f..dd75e23 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -4,5 +4,9 @@ "C_Cpp.default.includePath": [ "${workspaceFolder}/src" ], - "C_Cpp.default.intelliSenseMode": "clang-x64" + "C_Cpp.default.intelliSenseMode": "clang-x64", + "files.associations": { + ".clang-tidy": "yaml", + ".clang-format": "yaml" + } } diff --git a/CMakeLists.txt b/CMakeLists.txt index d9e45b5..d26b8eb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,20 +1,15 @@ -cmake_minimum_required(VERSION 3.10) +cmake_minimum_required(VERSION 3.25) project(CLAVIS LANGUAGES CXX) -set(CMAKE_CXX_STANDARD 20) -set(CMAKE_CXX_STANDARD_REQUIRED True) # Set build type (default is Debug) if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE Debug) endif() -# Basic compiler flags -if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra") -endif() - -# Collect source files +# NOTE: file(GLOB) is not recommended by CMake official docs. +# Consider listing source files explicitly for reliable rebuilds. +# See: https://cmake.org/cmake/help/latest/command/file.html#glob file(GLOB CORE_SOURCES src/*.cpp src/graph/*.hpp @@ -38,6 +33,14 @@ set(SOURCES ${CORE_SOURCES}) # Create library add_library(clavis_algorithm ${SOURCES}) +# Set C++ standard (modern target-based approach) +target_compile_features(clavis_algorithm PUBLIC cxx_std_20) + +# Set compiler warnings (target-based, not global CMAKE_CXX_FLAGS) +target_compile_options(clavis_algorithm PRIVATE + $<$:-Wall -Wextra> +) + # Set include directories target_include_directories(clavis_algorithm PUBLIC ${CMAKE_SOURCE_DIR}/src @@ -57,14 +60,20 @@ target_include_directories(clavis_algorithm_test PRIVATE target_link_libraries(clavis_algorithm_test clavis_algorithm GTest::GTest GTest::Main) -# Register test -add_test(NAME AlgorithmTest COMMAND clavis_algorithm_test) +# Set compiler warnings for tests +target_compile_options(clavis_algorithm_test PRIVATE + $<$:-Wall -Wextra> +) + +# Discover and register tests +include(GoogleTest) +gtest_discover_tests(clavis_algorithm_test) # ============================================================================= # Code Quality Tools # ============================================================================= -# Collect all C++ files for formatting/linting +# Collect all C++ files for formatting file(GLOB_RECURSE ALL_CXX_FILES ${CMAKE_SOURCE_DIR}/src/*.hpp ${CMAKE_SOURCE_DIR}/src/*.cpp @@ -72,11 +81,20 @@ file(GLOB_RECURSE ALL_CXX_FILES ${CMAKE_SOURCE_DIR}/tests/*.cpp ) +# Collect source files only for linting (exclude tests) +file(GLOB_RECURSE SRC_CXX_FILES + ${CMAKE_SOURCE_DIR}/src/*.hpp + ${CMAKE_SOURCE_DIR}/src/*.cpp + ${CMAKE_SOURCE_DIR}/src/*.h +) + # clang-format targets find_program(CLANG_FORMAT clang-format HINTS + $ENV{LLVM_DIR}/bin /opt/homebrew/opt/llvm/bin /usr/local/opt/llvm/bin + /usr/bin ) if(CLANG_FORMAT) add_custom_target(format @@ -97,13 +115,22 @@ endif() # clang-tidy target find_program(CLANG_TIDY clang-tidy HINTS + $ENV{LLVM_DIR}/bin /opt/homebrew/opt/llvm/bin /usr/local/opt/llvm/bin + /usr/bin ) if(CLANG_TIDY) add_custom_target(lint - COMMAND ${CLANG_TIDY} -p ${CMAKE_BINARY_DIR} ${ALL_CXX_FILES} - COMMENT "Running clang-tidy" + COMMAND ${CLANG_TIDY} + -p ${CMAKE_BINARY_DIR} + -header-filter=${CMAKE_SOURCE_DIR}/src/.* + ${SRC_CXX_FILES} + -- + -x c++ + -std=c++20 + -I${CMAKE_SOURCE_DIR}/src + COMMENT "Running clang-tidy on source files" VERBATIM ) else() diff --git a/CMakePresets.json b/CMakePresets.json new file mode 100644 index 0000000..3c60293 --- /dev/null +++ b/CMakePresets.json @@ -0,0 +1,107 @@ +{ + "$schema": "https://cmake.org/cmake/help/latest/_downloads/3e2d73bff478d88a7de0de736ba5e361/schema.json", + "version": 8, + "cmakeMinimumRequired": { + "major": 3, + "minor": 25, + "patch": 0 + }, + "configurePresets": [ + { + "name": "base", + "hidden": true, + "generator": "Ninja", + "binaryDir": "${sourceDir}/build/${presetName}", + "cacheVariables": { + "CMAKE_CXX_STANDARD": "20", + "CMAKE_CXX_STANDARD_REQUIRED": "ON", + "CMAKE_EXPORT_COMPILE_COMMANDS": "ON" + } + }, + { + "name": "debug", + "displayName": "Debug", + "inherits": "base", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug" + } + }, + { + "name": "release", + "displayName": "Release", + "inherits": "base", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Release" + } + }, + { + "name": "ci", + "displayName": "CI", + "inherits": "base", + "generator": "Unix Makefiles", + "binaryDir": "${sourceDir}/build", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug" + } + } + ], + "buildPresets": [ + { + "name": "debug", + "configurePreset": "debug" + }, + { + "name": "release", + "configurePreset": "release" + }, + { + "name": "ci", + "configurePreset": "ci", + "jobs": 4 + } + ], + "testPresets": [ + { + "name": "base", + "hidden": true, + "output": { + "outputOnFailure": true, + "verbosity": "default" + }, + "execution": { + "noTestsAction": "error", + "stopOnFailure": false + } + }, + { + "name": "debug", + "configurePreset": "debug", + "inherits": "base" + }, + { + "name": "release", + "configurePreset": "release", + "inherits": "base" + }, + { + "name": "ci", + "configurePreset": "ci", + "inherits": "base", + "output": { + "outputOnFailure": true, + "verbosity": "verbose" + } + } + ], + "workflowPresets": [ + { + "name": "ci", + "displayName": "CI Workflow", + "steps": [ + { "type": "configure", "name": "ci" }, + { "type": "build", "name": "ci" }, + { "type": "test", "name": "ci" } + ] + } + ] +} diff --git a/README.md b/README.md index e5c78b4..0d273d7 100644 --- a/README.md +++ b/README.md @@ -3,3 +3,53 @@ ## A Treasury of Algorithms That Make Even Computers Laugh Welcome to Clavis! Here, efficient algorithms and unnecessarily complex C++ code form an unstable relationship. If you find a bug, please call it a "feature." Big O notation is our only lover, computational complexity our best friend. + +## Requirements + +| Tool | Version | Install (macOS) | +|------|---------|-----------------| +| CMake | 3.25+ | `brew install cmake` | +| Ninja | any | `brew install ninja` | +| GTest | any | `brew install googletest` | +| LLVM | any | `brew install llvm` | + +### Quick Setup (macOS) + +```bash +brew install cmake ninja googletest llvm +``` + +## Build & Test + +```bash +# Build +cmake --preset debug +cmake --build --preset debug + +# Test +ctest --preset debug + +# Test (verbose) +ctest --preset debug --verbose +``` + +### Available Presets + +| Preset | Generator | Use Case | +|--------|-----------|----------| +| `debug` | Ninja | Local development | +| `release` | Ninja | Production build | +| `ci` | Unix Makefiles | GitHub Actions | + +## Code Quality + +```bash +# Format +cmake --build build/debug -t format + +# Format check +cmake --build build/debug -t format-check + +# Lint +cmake --build build/debug -t lint +``` diff --git a/scripts/run_tests.sh b/scripts/run_tests.sh deleted file mode 100755 index c32d088..0000000 --- a/scripts/run_tests.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/bash -set -e # Exit immediately if a command exits with a non-zero status - -# Create build directory (if it doesn't exist) -if [ ! -d "build" ]; then - mkdir build -fi - -cd build - -# CMake configuration -cmake -DCMAKE_BUILD_TYPE=Debug \ - -DCMAKE_CXX_STANDARD=20 \ - -DCMAKE_CXX_STANDARD_REQUIRED=ON \ - .. - -# Build (using parallel build) -JOBS=$(nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || echo 2) -cmake --build . -- -j"$JOBS" - -# Run tests -GTEST_COLOR=1 ctest --verbose --output-on-failure diff --git a/src/data_structure/fenwick_tree.hpp b/src/data_structure/fenwick_tree.hpp index d98922f..4129d57 100644 --- a/src/data_structure/fenwick_tree.hpp +++ b/src/data_structure/fenwick_tree.hpp @@ -26,7 +26,7 @@ class FenwickTree { // Returns the sum of elements in [0..idx] // If idx < 0, returns 0 - int query(std::size_t idx) const { + [[nodiscard]] int query(std::size_t idx) const { if (idx >= size_) { throw std::out_of_range("Index out of range in FenwickTree::query"); } @@ -41,7 +41,7 @@ class FenwickTree { // Returns the sum of elements in [left..right] // If left > right, returns 0 - int rangeQuery(std::size_t left, std::size_t right) const { + [[nodiscard]] int rangeQuery(std::size_t left, std::size_t right) const { if (left > right) { return 0; } diff --git a/src/data_structure/max_heap.hpp b/src/data_structure/max_heap.hpp index 67f6205..2d51eba 100644 --- a/src/data_structure/max_heap.hpp +++ b/src/data_structure/max_heap.hpp @@ -44,10 +44,10 @@ class MaxHeap { } // Returns true if the heap has no elements - bool empty() const { return data_.empty(); } + [[nodiscard]] bool empty() const { return data_.empty(); } // Returns the number of elements in the heap - std::size_t size() const { return data_.size(); } + [[nodiscard]] std::size_t size() const { return data_.size(); } private: std::vector data_; diff --git a/src/data_structure/segment_tree.hpp b/src/data_structure/segment_tree.hpp index 15bf0f9..c4fd8e8 100644 --- a/src/data_structure/segment_tree.hpp +++ b/src/data_structure/segment_tree.hpp @@ -13,7 +13,7 @@ template class SegmentTree { private: - int n; // Number of leaves + int n = 1; // Number of leaves std::vector tree; // Container to store the segment tree std::function op; // Binary operation to merge intervals T identity; // Identity element for the operation @@ -46,7 +46,6 @@ class SegmentTree { : op(op), identity(identity) { // Expand n to the next power of two int size = (int)data.size(); - n = 1; while (n < size) n <<= 1; tree.assign(2 * n, identity); diff --git a/src/data_structure/union_find.hpp b/src/data_structure/union_find.hpp index 64f627d..4a7120d 100644 --- a/src/data_structure/union_find.hpp +++ b/src/data_structure/union_find.hpp @@ -49,7 +49,7 @@ class UnionFind { if (rx == ry) return; std::cout << "Uniting groups: " << rx << " and " << ry << " (ranks: " << rank[rx] << ", " - << rank[ry] << ")" << std::endl; + << rank[ry] << ")\n"; if (rank[rx] < rank[ry]) { parent[rx] = ry; diff --git a/src/graph/bfs.hpp b/src/graph/bfs.hpp index 54b32ff..a000652 100644 --- a/src/graph/bfs.hpp +++ b/src/graph/bfs.hpp @@ -12,10 +12,12 @@ template concept GraphNode = std::equality_comparable && std::copy_constructible; +// clang-format off template concept HashableNode = GraphNode && requires(T x) { { std::hash{}(x) } -> std::convertible_to; }; +// clang-format on template class BFS { diff --git a/src/graph/dfs.hpp b/src/graph/dfs.hpp index d6104df..ad061fd 100644 --- a/src/graph/dfs.hpp +++ b/src/graph/dfs.hpp @@ -12,10 +12,12 @@ template concept GraphNode = std::equality_comparable && std::copy_constructible; +// clang-format off template concept HashableNode = GraphNode && requires(T x) { { std::hash{}(x) } -> std::convertible_to; }; +// clang-format on template class DFS { @@ -187,7 +189,7 @@ class DFS { // Topological sort (only works for DAGs) [[nodiscard]] std::vector topologicalSort() const { if (hasCycle()) { - std::cout << "Graph has a cycle, topological sort not possible" << std::endl; + std::cout << "Graph has a cycle, topological sort not possible\n"; return {}; } diff --git a/src/graph/dijkstra.hpp b/src/graph/dijkstra.hpp index d4c0c44..22dc5f7 100644 --- a/src/graph/dijkstra.hpp +++ b/src/graph/dijkstra.hpp @@ -29,8 +29,8 @@ std::vector dijkstra(const std::vector>& graph, int // Priority queue that always returns the pair with the smallest distance using Pi = std::pair; // (distance, node) - std::priority_queue, std::greater> pq; - pq.push({0, start}); + std::priority_queue, std::greater<>> pq; + pq.emplace(0, start); while (!pq.empty()) { auto [curDist, u] = pq.top(); @@ -44,7 +44,7 @@ std::vector dijkstra(const std::vector>& graph, int long long nd = curDist + e.cost; if (dist[e.to] > nd) { dist[e.to] = nd; - pq.push({nd, e.to}); + pq.emplace(nd, e.to); } } } diff --git a/src/graph/kruskal.hpp b/src/graph/kruskal.hpp index 494cc72..ff12d4c 100644 --- a/src/graph/kruskal.hpp +++ b/src/graph/kruskal.hpp @@ -85,8 +85,8 @@ class DisjointSet { * @return Vector of edges that form the MST and the total weight of the MST */ std::pair, long long> kruskal(int n, std::vector& edges) { - // Sort edges by weight - std::sort(edges.begin(), edges.end()); + // Sort edges by weight (NOLINT: ranges::sort incompatible with member operator<) + std::sort(edges.begin(), edges.end()); // NOLINT(modernize-use-ranges) DisjointSet dsu(n); std::vector mst; diff --git a/src/math/extended_gcd.hpp b/src/math/extended_gcd.hpp index 6cfc887..3e4c3e4 100644 --- a/src/math/extended_gcd.hpp +++ b/src/math/extended_gcd.hpp @@ -32,14 +32,14 @@ struct ExtGcdResult { */ ExtGcdResult extended_gcd(int64_t a, int64_t b) { if (b == 0) { - return {a, 1, 0}; + return {.gcd = a, .x = 1, .y = 0}; } auto [g, x1, y1] = extended_gcd(b, a % b); int64_t x = y1; int64_t y = x1 - (a / b) * y1; - return {g, x, y}; + return {.gcd = g, .x = x, .y = y}; } /** @@ -71,7 +71,7 @@ ExtGcdResult extended_gcd_iterative(int64_t a, int64_t b) { y0 = temp; } - return {a, x0, y0}; + return {.gcd = a, .x = x0, .y = y0}; } /** diff --git a/src/math/fast_exp.hpp b/src/math/fast_exp.hpp index 56dd272..5615b95 100644 --- a/src/math/fast_exp.hpp +++ b/src/math/fast_exp.hpp @@ -7,11 +7,13 @@ /** * @brief Concept for types that support modular exponentiation */ +// clang-format off template concept ModularArithmetic = std::integral || requires(T a, T b) { { a * b } -> std::convertible_to; { a % b } -> std::convertible_to; }; +// clang-format on /** * @brief Fast Exponentiation (Binary Exponentiation) with modulo @@ -36,11 +38,11 @@ int64_t mod_pow(int64_t base, int64_t exp, int64_t mod) { while (exp > 0) { // If exp is odd, multiply base with result if (exp & 1) { - result = (__int128_t)result * base % mod; + result = static_cast((__int128_t)result * base % mod); } // exp must be even now exp >>= 1; - base = (__int128_t)base * base % mod; + base = static_cast((__int128_t)base * base % mod); } return result; diff --git a/src/math/sieve.hpp b/src/math/sieve.hpp index acc5320..859e227 100644 --- a/src/math/sieve.hpp +++ b/src/math/sieve.hpp @@ -2,6 +2,7 @@ #define SIEVE_HPP #include +#include #include /** @@ -51,7 +52,7 @@ std::vector sieve_of_eratosthenes(int64_t n) { * @return true if n is prime, false otherwise */ bool is_prime_with_sieve(int64_t n, const std::vector& sieve_result) { - if (n < 0 || n >= static_cast(sieve_result.size())) { + if (n < 0 || std::cmp_greater_equal(n, sieve_result.size())) { return false; } return sieve_result[n]; diff --git a/src/search/binary_search.hpp b/src/search/binary_search.hpp index 7cca283..8b89498 100644 --- a/src/search/binary_search.hpp +++ b/src/search/binary_search.hpp @@ -5,8 +5,7 @@ #include #include -namespace clavis { -namespace search { +namespace clavis::search { /** * @brief Binary search algorithm for finding an element in a sorted array @@ -118,7 +117,6 @@ T binary_search_predicate(T left, T right, const std::function& predica return left; // Returns right if no element satisfies the predicate } -} // namespace search -} // namespace clavis +} // namespace clavis::search #endif // BINARY_SEARCH_HPP diff --git a/src/sorting/heap_sort.hpp b/src/sorting/heap_sort.hpp index 942390f..74a9e76 100644 --- a/src/sorting/heap_sort.hpp +++ b/src/sorting/heap_sort.hpp @@ -10,7 +10,7 @@ template void heapify(std::vector& arr, size_t n, size_t i) { - std::cout << "Heapify at index " << i << " with size " << n << std::endl; + std::cout << "Heapify at index " << i << " with size " << n << '\n'; size_t largest = i; size_t left = 2 * i + 1; size_t right = 2 * i + 2; @@ -22,7 +22,7 @@ void heapify(std::vector& arr, size_t n, size_t i) { largest = right; } if (largest != i) { - std::cout << "Swapping elements at " << i << " and " << largest << std::endl; + std::cout << "Swapping elements at " << i << " and " << largest << '\n'; std::swap(arr[i], arr[largest]); heapify(arr, n, largest); } @@ -30,7 +30,7 @@ void heapify(std::vector& arr, size_t n, size_t i) { template void heapSort(std::vector& arr) { - std::cout << "Starting heapSort with array size: " << arr.size() << std::endl; + std::cout << "Starting heapSort with array size: " << arr.size() << '\n'; for (int i = arr.size() / 2 - 1; i >= 0; --i) { heapify(arr, arr.size(), i); } diff --git a/src/sorting/merge_sort.hpp b/src/sorting/merge_sort.hpp index 66f82d5..2c05dd4 100644 --- a/src/sorting/merge_sort.hpp +++ b/src/sorting/merge_sort.hpp @@ -12,7 +12,7 @@ template void merge(std::span arr, size_t left, size_t mid, size_t right) { - std::cout << "Merging: left=" << left << " mid=" << mid << " right=" << right << std::endl; + std::cout << "Merging: left=" << left << " mid=" << mid << " right=" << right << '\n'; std::vector temp(right - left + 1); size_t i = left, j = mid + 1, k = 0; @@ -39,7 +39,7 @@ void mergeSortImpl(std::span arr, size_t left, size_t right) { if (left >= arr.size() || right >= arr.size() || left >= right) { return; } - std::cout << "MergeSort: left=" << left << " right=" << right << std::endl; + std::cout << "MergeSort: left=" << left << " right=" << right << '\n'; size_t mid = left + (right - left) / 2; mergeSortImpl(arr, left, mid); mergeSortImpl(arr, mid + 1, right); @@ -48,7 +48,7 @@ void mergeSortImpl(std::span arr, size_t left, size_t right) { template void mergeSort(std::vector& arr) { - std::cout << "Starting mergeSort with array size: " << arr.size() << std::endl; + std::cout << "Starting mergeSort with array size: " << arr.size() << '\n'; std::span s{arr}; mergeSortImpl(s, 0, arr.size() - 1); } diff --git a/src/sorting/quick_sort.hpp b/src/sorting/quick_sort.hpp index 6e1d821..2f943ae 100644 --- a/src/sorting/quick_sort.hpp +++ b/src/sorting/quick_sort.hpp @@ -25,7 +25,7 @@ size_t partition(std::vector& arr, size_t low, size_t high) { template void quickSortImpl(std::vector& arr, size_t low, size_t high) { - std::cout << "QuickSort: low=" << low << " high=" << high << std::endl; + std::cout << "QuickSort: low=" << low << " high=" << high << '\n'; if (low < high) { size_t pi = partition(arr, low, high); if (pi > 0) quickSortImpl(arr, low, pi - 1); @@ -35,7 +35,7 @@ void quickSortImpl(std::vector& arr, size_t low, size_t high) { template void quickSort(std::vector& arr) { - std::cout << "Starting quickSort with array size: " << arr.size() << std::endl; + std::cout << "Starting quickSort with array size: " << arr.size() << '\n'; if (arr.size() > 1) { quickSortImpl(arr, 0, arr.size() - 1); } diff --git a/src/sorting/radix_sort.hpp b/src/sorting/radix_sort.hpp index 5168491..edc3151 100644 --- a/src/sorting/radix_sort.hpp +++ b/src/sorting/radix_sort.hpp @@ -9,7 +9,7 @@ template void radixSort(std::vector& arr) { - std::cout << "Starting radixSort with array size: " << arr.size() << std::endl; + std::cout << "Starting radixSort with array size: " << arr.size() << '\n'; if (arr.empty()) { return; }; @@ -21,7 +21,7 @@ void radixSort(std::vector& arr) { std::span s{arr}; for (T exp = 1; max / exp > 0; exp *= 10) { - std::cout << "Processing digit position: " << exp << std::endl; + std::cout << "Processing digit position: " << exp << '\n'; std::vector output(s.size()); std::array count{}; @@ -41,7 +41,7 @@ void radixSort(std::vector& arr) { ** std::ranges::move(output, arr.begin()); */ std::move(output.begin(), output.end(), arr.begin()); - std::cout << "Radix sort complete" << std::endl; + std::cout << "Radix sort complete" << '\n'; } } diff --git a/src/sorting/shell_sort.hpp b/src/sorting/shell_sort.hpp index 8896479..d50f69c 100644 --- a/src/sorting/shell_sort.hpp +++ b/src/sorting/shell_sort.hpp @@ -11,23 +11,23 @@ template void shellSort(std::vector& arr) { - std::cout << "Starting shellSort with array size: " << arr.size() << std::endl; + std::cout << "Starting shellSort with array size: " << arr.size() << '\n'; std::span s{arr}; size_t n = s.size(); for (size_t gap = n / 2; gap > 0; gap /= 2) { - std::cout << "Current gap size: " << gap << std::endl; + std::cout << "Current gap size: " << gap << '\n'; for (size_t i = gap; i < n; i++) { T temp = std::move(s[i]); - size_t j; - for (j = i; j >= gap && s[j - gap] > temp; j -= gap) { - std::cout << "Moving element from " << j - gap << " to " << j << std::endl; + size_t j = i; + for (; j >= gap && s[j - gap] > temp; j -= gap) { + std::cout << "Moving element from " << j - gap << " to " << j << '\n'; s[j] = std::move(s[j - gap]); } s[j] = std::move(temp); } } - std::cout << "Shell sort complete" << std::endl; + std::cout << "Shell sort complete" << '\n'; } #endif // SHELL_SORT_HPP \ No newline at end of file diff --git a/src/sorting/sorting.cpp b/src/sorting/sorting.cpp index 23a6a04..5bbb3c2 100644 --- a/src/sorting/sorting.cpp +++ b/src/sorting/sorting.cpp @@ -18,39 +18,44 @@ void printArray(const std::vector& arr, const std::string& label) { } int main() { - std::vector arr = {64, 34, 25, 12, 22, 11, 90}; - std::vector original = arr; - - printArray(arr, "Original array"); - - std::cout << "\nBubble Sort:\n"; - bubbleSort(arr); - printArray(arr, "After sorting"); - - arr = original; - std::cout << "\nQuick Sort:\n"; - quickSort(arr); - printArray(arr, "After sorting"); - - arr = original; - std::cout << "\nMerge Sort:\n"; - mergeSort(arr); - printArray(arr, "After sorting"); - - arr = original; - std::cout << "\nHeap Sort:\n"; - heapSort(arr); - printArray(arr, "After sorting"); - - arr = original; - std::cout << "\nRadix Sort:\n"; - radixSort(arr); - printArray(arr, "After sorting"); - - arr = original; - std::cout << "\nShell Sort:\n"; - shellSort(arr); - printArray(arr, "After sorting"); - - return 0; + try { + std::vector arr = {64, 34, 25, 12, 22, 11, 90}; + std::vector original = arr; + + printArray(arr, "Original array"); + + std::cout << "\nBubble Sort:\n"; + bubbleSort(arr); + printArray(arr, "After sorting"); + + arr = original; + std::cout << "\nQuick Sort:\n"; + quickSort(arr); + printArray(arr, "After sorting"); + + arr = original; + std::cout << "\nMerge Sort:\n"; + mergeSort(arr); + printArray(arr, "After sorting"); + + arr = original; + std::cout << "\nHeap Sort:\n"; + heapSort(arr); + printArray(arr, "After sorting"); + + arr = original; + std::cout << "\nRadix Sort:\n"; + radixSort(arr); + printArray(arr, "After sorting"); + + arr = original; + std::cout << "\nShell Sort:\n"; + shellSort(arr); + printArray(arr, "After sorting"); + + return 0; + } catch (const std::exception& e) { + std::cerr << "Error: " << e.what() << '\n'; + return 1; + } } \ No newline at end of file diff --git a/src/sorting/sorting_concepts.hpp b/src/sorting/sorting_concepts.hpp index b68fe2b..8b0e9e4 100644 --- a/src/sorting/sorting_concepts.hpp +++ b/src/sorting/sorting_concepts.hpp @@ -3,10 +3,12 @@ #include +// clang-format off template concept Sortable = requires(T a, T b) { { a < b } -> std::convertible_to; }; +// clang-format on template concept Pivotable = Sortable && std::movable;