diff --git a/.clang-format b/.clang-format
new file mode 100644
index 0000000..a061362
--- /dev/null
+++ b/.clang-format
@@ -0,0 +1,16 @@
+BasedOnStyle: LLVM
+IndentWidth: 4
+
+IncludeBlocks: Regroup
+IncludeCategories:
+ - Regex: '^".*'
+ Priority: 1
+ - Regex: '^<(safe)/.*'
+ Priority: 2
+ - Regex: '^<(boost|catch2|fmt|gmock|gtest|rapidcheck)/.*'
+ Priority: 3
+ - Regex: '<.*'
+ Priority: 4
+
+QualifierAlignment: Custom
+QualifierOrder: ['constexpr', 'static', 'inline', 'type', 'const', 'volatile']
diff --git a/.clang-tidy b/.clang-tidy
new file mode 100644
index 0000000..7a4adf6
--- /dev/null
+++ b/.clang-tidy
@@ -0,0 +1,39 @@
+---
+Checks: >
+ boost-use-to-string,
+ bugprone-*,
+ -bugprone-easily-swappable-parameters,
+ clang-diagnostic-*,
+ clang-analyzer-*,
+ cppcoreguidelines-*,
+ -cppcoreguidelines-avoid-magic-numbers,
+ -cppcoreguidelines-avoid-non-const-global-variables,
+ -cppcoreguidelines-macro-usage,
+ -cppcoreguidelines-pro-bounds-pointer-arithmetic,
+ google-build-explicit-make-pair,
+ google-default-arguments,
+ google-explicit-constructor,
+ google-readability-casting,
+ google-runtime-int,
+ hicpp-signed-bitwise,
+ misc-misplaced-const,
+ misc-non-copyable-objects,
+ misc-redundant-expression,
+ misc-static-assert,
+ misc-throw-by-value-catch-by-reference,
+ misc-uniqueptr-reset-release,
+ modernize-*,
+ performance-*,
+ portability-*,
+ readability-*,
+ -readability-identifier-length,
+ -readability-identifier-naming,
+ -readability-magic-numbers,
+ -readability-named-parameter,
+ -readability-qualified-auto,
+ -readability-uppercase-literal-suffix
+WarningsAsErrors: '*'
+HeaderFilterRegex: ''
+AnalyzeTemporaryDtors: false
+FormatStyle: file
+...
diff --git a/.cmake-format.yaml b/.cmake-format.yaml
new file mode 100644
index 0000000..4f94929
--- /dev/null
+++ b/.cmake-format.yaml
@@ -0,0 +1,3 @@
+format:
+ tab_size: 4
+ line_width: 80
diff --git a/.github/workflows/unit_tests.yml b/.github/workflows/unit_tests.yml
index c88e548..c4eaa03 100644
--- a/.github/workflows/unit_tests.yml
+++ b/.github/workflows/unit_tests.yml
@@ -1,13 +1,20 @@
name: Unit Tests
on:
+ workflow_dispatch:
+ merge_group:
push:
branches: [ main ]
pull_request:
branches: [ main ]
env:
- BUILD_TYPE: Debug
+ DEBIAN_FRONTEND: noninteractive
+ CMAKE_GENERATOR: Ninja
+
+concurrency:
+ group: ${{ github.head_ref || github.run_id }}
+ cancel-in-progress: true
jobs:
build_and_test:
@@ -15,69 +22,193 @@ jobs:
strategy:
fail-fast: false
matrix:
- compiler:
- - name: clang-16
+ compiler: [clang, gcc]
+ version: [12, 13, 14, 15, 16]
+ cxx_standard: [20]
+ stdlib: [libstdc++, libc++]
+ build_type: [Debug]
+ include:
+ - compiler: clang
+ cc: "clang"
+ cxx: "clang++"
+ - version: 16
+ compiler: clang
install: wget https://apt.llvm.org/llvm.sh && chmod +x llvm.sh && sudo ./llvm.sh 16
- cc: " /usr/lib/llvm-16/bin/clang"
- cxx: "/usr/lib/llvm-16/bin/clang++"
- - name: clang-15
- install: wget https://apt.llvm.org/llvm.sh && chmod +x llvm.sh && sudo ./llvm.sh 15
- cc: " /usr/lib/llvm-15/bin/clang"
- cxx: "/usr/lib/llvm-15/bin/clang++"
- - name: clang-14
- install: wget https://apt.llvm.org/llvm.sh && chmod +x llvm.sh && sudo ./llvm.sh 14
- cc: " /usr/lib/llvm-14/bin/clang"
- cxx: "/usr/lib/llvm-14/bin/clang++"
- - name: clang-13
- install: wget https://apt.llvm.org/llvm.sh && chmod +x llvm.sh && sudo ./llvm.sh 13
- cc: " /usr/lib/llvm-13/bin/clang"
- cxx: "/usr/lib/llvm-13/bin/clang++"
- - name: clang-12
- install: sudo apt update && sudo apt-get install -y clang-12
- cc: " /usr/lib/llvm-12/bin/clang"
- cxx: "/usr/lib/llvm-12/bin/clang++"
- - name: gcc-13
+ toolchain_root: "/usr/lib/llvm-16"
+ - version: 16
+ compiler: clang
+ stdlib: libc++
+ install: wget https://apt.llvm.org/llvm.sh && chmod +x llvm.sh && sudo ./llvm.sh 16 && sudo apt install -y libc++-16-dev libc++abi-16-dev
+ - version: 15
+ compiler: clang
+ install: sudo apt update && sudo apt install -y clang-15
+ toolchain_root: "/usr/lib/llvm-15"
+ - version: 15
+ compiler: clang
+ stdlib: libc++
+ install: sudo apt update && sudo apt install -y clang-15 libc++-15-dev libc++abi-15-dev
+ - version: 14
+ compiler: clang
+ install: sudo apt update && sudo apt install -y clang-14
+ toolchain_root: "/usr/lib/llvm-14"
+ - version: 14
+ compiler: clang
+ stdlib: libc++
+ install: sudo apt update && sudo apt install -y clang-14 libc++-14-dev libc++abi-14-dev
+ - version: 13
+ compiler: gcc
install: sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test && sudo apt update && sudo apt-get install -y gcc-13 g++-13
- cc: "/usr/bin/gcc-13"
- cxx: "/usr/bin/g++-13"
- - name: gcc-12
- install: sudo apt update && sudo apt-get install -y gcc-12 g++-12
- cc: "/usr/bin/gcc-12"
- cxx: "/usr/bin/g++-12"
- - name: gcc-11
- install: sudo apt update && sudo apt-get install -y gcc-11 g++-11
- cc: "/usr/bin/gcc-11"
- cxx: "/usr/bin/g++-11"
- - name: gcc-10
- install: sudo apt update && sudo apt-get install -y gcc-10 g++-10
- cc: "/usr/bin/gcc-10"
- cxx: "/usr/bin/g++-10"
-
-
+ toolchain_root: "/usr"
+ cc: "gcc-13"
+ cxx: "g++-13"
+ - version: 12
+ compiler: gcc
+ install: sudo apt update && sudo apt install -y gcc-12
+ toolchain_root: "/usr"
+ cc: "gcc-12"
+ cxx: "g++-12"
+ exclude:
+ - compiler: gcc
+ version: 16
+ - compiler: gcc
+ version: 15
+ - compiler: gcc
+ version: 14
+ - compiler: clang
+ version: 13
+ - compiler: clang
+ version: 12
+ - compiler: gcc
+ stdlib: libc++
+
steps:
- - name: install support tools
- run: sudo apt update && DEBIAN_FRONTEND=noninteractive TZ=America/Los_Angeles sudo apt-get install -y git wget software-properties-common gnupg cmake lsb-release libstdc++-10-dev ninja-build
+ - uses: actions/checkout@v3
+
+ - name: Install build tools
+ run: |
+ ${{ matrix.install }}
+ sudo apt install -y ninja-build
+
+ - name: Configure CMake
+ env:
+ CC: ${{matrix.toolchain_root}}/bin/${{matrix.cc}}
+ CXX: ${{matrix.toolchain_root}}/bin/${{matrix.cxx}}
+ CXX_STANDARD: ${{matrix.cxx_standard}}
+ CXX_STDLIB: ${{matrix.stdlib}}
+ run: cmake -B ${{github.workspace}}/build -DCMAKE_TOOLCHAIN_FILE=${{github.workspace}}/toolchains/${{matrix.compiler}}.cmake -DCMAKE_BUILD_TYPE=${{matrix.build_type}}
+
+ - name: Build Unit Tests
+ run: cmake --build ${{github.workspace}}/build --config ${{matrix.build_type}} -v -t build_unit_tests
- - name: install compiler
- run: ${{ matrix.compiler.install }}
+ - name: Test
+ working-directory: ${{github.workspace}}/build
+ run: ctest -j $(nproc) -C ${{matrix.build_type}}
+ quality_checks_pass:
+ runs-on: ubuntu-22.04
+ steps:
- uses: actions/checkout@v3
+ - name: Install build tools
+ run: |
+ wget https://apt.llvm.org/llvm.sh && chmod +x llvm.sh && sudo ./llvm.sh 16
+ sudo apt install -y ninja-build clang-tidy-16 clang-format-16
+
+ - name: Install cmake-format
+ run: |
+ pip3 install --upgrade pip
+ pip3 install pyyaml cmake-format
+
- name: Configure CMake
env:
- CC: ${{ matrix.compiler.cc }}
- CXX: ${{ matrix.compiler.cxx }}
- CXX_STANDARD: ${{ matrix.compiler.cxx_standard }}
- run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}}
+ CC: "/usr/lib/llvm-16/bin/clang"
+ CXX: "/usr/lib/llvm-16/bin/clang++"
+ CXX_STANDARD: 20
+ run: cmake -B ${{github.workspace}}/build
- - name: Build and Run Unit Tests
- run: cmake --build ${{github.workspace}}/build --target unit_tests
+ - name: Run quality checks
+ run: cmake --build ${{github.workspace}}/build -t quality
+ sanitize:
+ runs-on: ubuntu-22.04
+ strategy:
+ fail-fast: false
+ matrix:
+ sanitizer: [undefined, address, thread]
+ steps:
+ - uses: actions/checkout@v3
- quality_checks_pass:
- runs-on: ubuntu-20.04
- needs: build_and_test
+ - name: Install build tools
+ run: |
+ wget https://apt.llvm.org/llvm.sh && chmod +x llvm.sh && sudo ./llvm.sh 16
+ sudo apt install -y ninja-build
+
+ - name: Configure CMake
+ env:
+ CC: "/usr/lib/llvm-16/bin/clang"
+ CXX: "/usr/lib/llvm-16/bin/clang++"
+ CXX_STANDARD: 20
+ SANITIZERS: ${{matrix.sanitizer}}
+ run: cmake -B ${{github.workspace}}/build
+
+ - name: Build Unit Tests
+ run: cmake --build ${{github.workspace}}/build -t unit_tests
+
+ valgrind:
+ runs-on: ubuntu-22.04
+ steps:
+ - uses: actions/checkout@v3
+
+ - name: Install build tools
+ run: sudo apt update && sudo apt install -y gcc-12 ninja-build valgrind
+
+ - name: Configure CMake
+ env:
+ CC: "/usr/bin/gcc-12"
+ CXX: "/usr/bin/g++-12"
+ CXX_STANDARD: 20
+ run: cmake -B ${{github.workspace}}/build
+
+ - name: Build Unit Tests
+ run: cmake --build ${{github.workspace}}/build -t build_unit_tests
+
+ - name: Test
+ working-directory: ${{github.workspace}}/build
+ run: |
+ ctest -j $(nproc) -E EXPECT_FAIL -T memcheck
+
+ LOGFILE=$(ls ./Testing/Temporary/LastDynamicAnalysis_*.log)
+ FAILSIZE=$(du -c ./Testing/Temporary/MemoryChecker.* | tail -1 | cut -f1)
+ echo "" >> $GITHUB_STEP_SUMMARY
+
+ echo "" >> $GITHUB_STEP_SUMMARY
+ if [ $FAILSIZE != "0" ]; then
+ echo "Failing tests:" | tee -a $GITHUB_STEP_SUMMARY
+ else
+ echo "No failing tests" >> $GITHUB_STEP_SUMMARY
+ fi
+ echo "
" >> $GITHUB_STEP_SUMMARY
+
+ for f in ./Testing/Temporary/MemoryChecker.*
+ do
+ if [ -s $f ]; then
+ FILENAME=$(cd $(dirname $f) && pwd)/$(basename $f)
+ TEST_COMMAND=$(grep $FILENAME $LOGFILE)
+ echo "" | tee -a $GITHUB_STEP_SUMMARY
+ echo "========================================"
+ echo $TEST_COMMAND | tee -a $GITHUB_STEP_SUMMARY
+ echo "--------------------"
+ cat $f
+ fi
+ done
+
+ echo " " >> $GITHUB_STEP_SUMMARY
+ test $FAILSIZE = "0"
+
+ merge_ok:
+ runs-on: ubuntu-22.04
+ needs: [build_and_test, quality_checks_pass, sanitize, valgrind]
steps:
- - name: Say Hello
- run: echo "Hello!"
+ - name: Enable merge
+ run: echo "OK to merge!"
diff --git a/.gitignore b/.gitignore
index 962178d..c4902c9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,3 +6,4 @@
/cmake-build-*
.idea
.vscode
+.cache
diff --git a/.gitmodules b/.gitmodules
deleted file mode 100644
index e69de29..0000000
diff --git a/CMakeLists.txt b/CMakeLists.txt
index c7b08f9..a275d33 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,20 +1,27 @@
-cmake_minimum_required(VERSION 3.16)
-project(safe_arithmetic LANGUAGES CXX)
+cmake_minimum_required(VERSION 3.25)
-set(CMAKE_CXX_STANDARD 20)
+project(safe_arithmetic LANGUAGES CXX)
-include(cmake/CPM.cmake)
+if(PROJECT_SOURCE_DIR STREQUAL PROJECT_BINARY_DIR)
+ message(
+ FATAL_ERROR
+ "In-source builds are a bad idea. Please make a build directory instead."
+ )
+endif()
-include(cmake/libraries.cmake)
include(cmake/dependencies.cmake)
-include(cmake/test.cmake)
-include(cmake/sanitizers.cmake)
-include(CTest)
-enable_testing()
-
-add_versioned_package("gh:boostorg/mp11#boost-1.80.0")
+include(cmake/libraries.cmake)
+include(cmake/quality.cmake)
-add_subdirectory(include)
-add_subdirectory(test)
+add_versioned_package("gh:boostorg/mp11#boost-1.83.0")
+add_library(safe_arithmetic INTERFACE)
+target_compile_features(safe_arithmetic INTERFACE cxx_std_20)
+target_include_directories(safe_arithmetic INTERFACE include)
+target_link_libraries(safe_arithmetic INTERFACE boost_mp11)
+if(PROJECT_IS_TOP_LEVEL)
+ set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
+ # clang_tidy_interface(safe_arithmetic)
+ add_subdirectory(test)
+endif()
diff --git a/CMakePresets.json b/CMakePresets.json
new file mode 100644
index 0000000..b892fc2
--- /dev/null
+++ b/CMakePresets.json
@@ -0,0 +1,44 @@
+{
+ "version": 3,
+ "cmakeMinimumRequired": {
+ "major": 3,
+ "minor": 21,
+ "patch": 0
+ },
+ "configurePresets": [
+ {
+ "name": "base",
+ "hidden": true,
+ "generator": "Ninja",
+ "binaryDir": "${sourceDir}/build"
+ },
+ {
+ "name": "default",
+ "inherits": "base",
+ "description": "Build using Clang with libstdc++",
+ "toolchainFile": "${sourceDir}/toolchains/clang.cmake"
+ },
+ {
+ "name": "clang",
+ "inherits": "default"
+ },
+ {
+ "name": "clang-libstdc++",
+ "inherits": "default"
+ },
+ {
+ "name": "clang-libc++",
+ "inherits": "default",
+ "description": "Build using Clang with libc++",
+ "environment": {
+ "CXX_STDLIB": "libc++"
+ }
+ },
+ {
+ "name": "gcc",
+ "inherits": "base",
+ "description": "Build using GCC",
+ "toolchainFile": "${sourceDir}/toolchains/gcc.cmake"
+ }
+ ]
+}
diff --git a/cmake/quality.cmake b/cmake/quality.cmake
index edada42..13b005d 100644
--- a/cmake/quality.cmake
+++ b/cmake/quality.cmake
@@ -10,8 +10,10 @@ function(clang_tidy_interface TARGET)
endfunction()
if(PROJECT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
- if(DEFINED ENV{CLANG_TOOLS_PATH})
- list(APPEND CMAKE_PROGRAM_PATH $ENV{CLANG_TOOLS_PATH})
+ get_filename_component(CT_ROOT ${CMAKE_CXX_COMPILER} DIRECTORY)
+ find_program(CLANG_FORMAT_PROGRAM "clang-format" HINTS ${CT_ROOT})
+ if(CLANG_FORMAT_PROGRAM)
+ message(STATUS "clang-format found: ${CLANG_FORMAT_PROGRAM}")
endif()
include(${CMAKE_CURRENT_LIST_DIR}/sanitizers.cmake)
@@ -32,8 +34,9 @@ if(PROJECT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
add_dependencies(quality check-clang-format check-cmake-format)
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
- find_program(CLANG_TIDY_PROGRAM "clang-tidy")
+ find_program(CLANG_TIDY_PROGRAM "clang-tidy" HINTS ${CT_ROOT})
if(CLANG_TIDY_PROGRAM)
+ message(STATUS "clang-tidy found: ${CLANG_TIDY_PROGRAM}")
add_custom_target(clang-tidy)
include(${CMAKE_CURRENT_LIST_DIR}/clang-tidy.cmake)
else()
diff --git a/cmake/test.cmake b/cmake/test.cmake
index fb23170..bf6fa8d 100644
--- a/cmake/test.cmake
+++ b/cmake/test.cmake
@@ -13,28 +13,30 @@ set(MEMORYCHECK_SUPPRESSIONS_FILE
configure_file(${CMAKE_ROOT}/Modules/DartConfiguration.tcl.in
${PROJECT_BINARY_DIR}/DartConfiguration.tcl)
-add_versioned_package("gh:emil-e/rapidcheck#a5724ea")
+if(DEFINED ENV{CXX_STANDARD})
+ set(CMAKE_CXX_STANDARD $ENV{CXX_STANDARD})
+else()
+ set(CMAKE_CXX_STANDARD 17)
+endif()
macro(get_catch2)
- if(NOT DEFINED CPM_GOT_CATCH)
- add_versioned_package("gh:catchorg/Catch2@3.3.2")
+ if(NOT TARGET Catch2::Catch2WithMain)
+ add_versioned_package("gh:catchorg/Catch2@3.4.0")
list(APPEND CMAKE_MODULE_PATH ${Catch2_SOURCE_DIR}/extras)
include(Catch)
- set(CPM_GOT_CATCH 1)
endif()
endmacro()
macro(get_gtest)
- if(NOT DEFINED CPM_GOT_GTEST)
- add_versioned_package("gh:google/googletest@1.13.0")
+ if(NOT TARGET gtest)
+ add_versioned_package("gh:google/googletest@1.14.0")
include(GoogleTest)
- set(CPM_GOT_GTEST 1)
endif()
endmacro()
macro(get_gunit)
get_gtest()
- if(NOT DEFINED CPM_GOT_GUNIT)
+ if(NOT DEFINED gunit_SOURCE_DIR)
add_versioned_package(
NAME
gunit
@@ -44,27 +46,40 @@ macro(get_gunit)
cpp-testing/GUnit
DOWNLOAD_ONLY
YES)
- set(CPM_GOT_GUNIT 1)
endif()
endmacro()
macro(add_boost_di)
- if(NOT DEFINED CPM_GOT_BOOST_DI)
+ if(NOT TARGET Boost.DI)
add_versioned_package("gh:boost-ext/di#9866a4a")
- set(CPM_GOT_BOOST_DI 1)
endif()
endmacro()
macro(add_gherkin)
- if(NOT DEFINED CPM_GOT_GHERKIN)
+ if(NOT TARGET gherkin-cpp)
add_subdirectory(
${gunit_SOURCE_DIR}/libs/gherkin-cpp
${gunit_BINARY_DIR}/libs/gherkin-cpp EXCLUDE_FROM_ALL SYSTEM)
- set(CPM_GOT_GHERKIN 1)
endif()
endmacro()
-function(add_unit_test name)
+macro(add_rapidcheck)
+ if(NOT TARGET rapidcheck)
+ add_versioned_package(NAME rapidcheck GIT_TAG a5724ea GITHUB_REPOSITORY
+ emil-e/rapidcheck)
+ add_subdirectory(
+ ${rapidcheck_SOURCE_DIR}/extras/catch
+ ${rapidcheck_BINARY_DIR}/extras/catch EXCLUDE_FROM_ALL SYSTEM)
+ add_subdirectory(
+ ${rapidcheck_SOURCE_DIR}/extras/gtest
+ ${rapidcheck_BINARY_DIR}/extras/gtest EXCLUDE_FROM_ALL SYSTEM)
+ add_subdirectory(
+ ${rapidcheck_SOURCE_DIR}/extras/gmock
+ ${rapidcheck_BINARY_DIR}/extras/gmock EXCLUDE_FROM_ALL SYSTEM)
+ endif()
+endmacro()
+
+function(add_unit_test_target name)
set(options CATCH2 GTEST GUNIT)
set(multiValueArgs FILES INCLUDE_DIRECTORIES LIBRARIES SYSTEM_LIBRARIES)
cmake_parse_arguments(UNIT "${options}" "" "${multiValueArgs}" ${ARGN})
@@ -77,27 +92,38 @@ function(add_unit_test name)
add_dependencies(build_unit_tests ${name})
if(UNIT_CATCH2)
- get_catch2()
catch_discover_tests(${name})
- target_link_libraries_system(${name} PRIVATE Catch2::Catch2WithMain)
+ target_link_libraries_system(${name} PRIVATE Catch2::Catch2WithMain
+ rapidcheck rapidcheck_catch)
set(target_test_command $ "--order" "rand")
elseif(UNIT_GTEST)
- get_gtest()
gtest_discover_tests(${name})
- target_link_libraries_system(${name} PRIVATE gmock gtest gmock_main rapidcheck)
+ target_link_libraries_system(
+ ${name}
+ PRIVATE
+ gmock
+ gtest
+ gmock_main
+ rapidcheck
+ rapidcheck_gtest
+ rapidcheck_gmock)
set(target_test_command $ "--gtest_shuffle")
- target_include_directories(${name} SYSTEM PRIVATE ${rapidcheck_SOURCE_DIR}/extras/gtest/include)
elseif(UNIT_GUNIT)
- get_gunit()
- add_boost_di()
- gtest_discover_tests(${name})
target_include_directories(
${name} SYSTEM
PRIVATE ${gunit_SOURCE_DIR}/include
${gunit_SOURCE_DIR}/libs/json/single_include/nlohmann)
- target_link_libraries_system(${name} PRIVATE gtest_main gmock_main
- Boost.DI)
+ target_link_libraries_system(
+ ${name}
+ PRIVATE
+ gtest_main
+ gmock_main
+ Boost.DI
+ rapidcheck
+ rapidcheck_gtest
+ rapidcheck_gmock)
set(target_test_command $ "--gtest_shuffle")
+ add_test(NAME ${name} COMMAND ${target_test_command})
else()
set(target_test_command $)
add_test(NAME ${name} COMMAND ${target_test_command})
@@ -114,7 +140,38 @@ function(add_unit_test name)
add_dependencies(unit_tests "run_${name}")
endfunction()
-function(add_feature_test name)
+function(detect_test_framework)
+ set(options CATCH2 GTEST GUNIT)
+ cmake_parse_arguments(TF "${options}" "" "" ${ARGN})
+ if(TF_CATCH)
+ return(PROPAGATE TF_CATCH)
+ elseif(TF_GTEST)
+ return(PROPAGATE TF_GTEST)
+ elseif(TF_GUNIT)
+ return(PROPAGATE TF_GUNIT)
+ endif()
+endfunction()
+
+macro(add_unit_test)
+ detect_test_framework(${ARGN})
+ if(TF_CATCH)
+ get_catch2()
+ add_rapidcheck()
+ unset(TF_CATCH)
+ elseif(TF_GTEST)
+ get_gtest()
+ add_rapidcheck()
+ unset(TF_GTEST)
+ elseif(TF_GUNIT)
+ get_gunit()
+ add_boost_di()
+ add_rapidcheck()
+ unset(TF_GUNIT)
+ endif()
+ add_unit_test_target(${ARGN})
+endmacro()
+
+function(add_feature_test_target name)
set(singleValueArgs FEATURE)
set(multiValueArgs FILES INCLUDE_DIRECTORIES LIBRARIES SYSTEM_LIBRARIES)
cmake_parse_arguments(FEAT "${options}" "${singleValueArgs}"
@@ -127,15 +184,21 @@ function(add_feature_test name)
target_link_libraries(${name} PRIVATE sanitizers)
add_dependencies(build_unit_tests ${name})
- get_gunit()
- add_gherkin()
- add_boost_di()
target_include_directories(
${name} SYSTEM
PRIVATE ${gunit_SOURCE_DIR}/include
- ${gunit_SOURCE_DIR}/libs/json/single_include/nlohmann)
- target_link_libraries_system(${name} PRIVATE gtest_main gmock_main
- gherkin-cpp Boost.DI)
+ ${gunit_SOURCE_DIR}/libs/json/single_include/nlohmann
+ ${rapidcheck_SOURCE_DIR}/extras/gmock/include)
+ target_link_libraries_system(
+ ${name}
+ PRIVATE
+ gtest_main
+ gmock_main
+ gherkin-cpp
+ Boost.DI
+ rapidcheck
+ rapidcheck_gtest
+ rapidcheck_gmock)
set(target_test_command $ "--gtest_shuffle")
add_custom_target(all_${name} ALL DEPENDS run_${name})
@@ -152,3 +215,11 @@ function(add_feature_test name)
set_property(TEST ${name} PROPERTY ENVIRONMENT "SCENARIO=${FEATURE_FILE}")
add_dependencies(unit_tests "run_${name}")
endfunction()
+
+macro(add_feature_test)
+ get_gunit()
+ add_gherkin()
+ add_boost_di()
+ add_rapidcheck()
+ add_feature_test_target(${ARGN})
+endmacro()
diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt
index 6fd1253..f63cf86 100644
--- a/include/CMakeLists.txt
+++ b/include/CMakeLists.txt
@@ -1,3 +1,4 @@
add_library(safe_arithmetic INTERFACE)
-target_include_directories(safe_arithmetic INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
+target_include_directories(safe_arithmetic
+ INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(safe_arithmetic INTERFACE boost_mp11)
diff --git a/include/safe.hpp b/include/safe.hpp
index eb0bba7..3722100 100644
--- a/include/safe.hpp
+++ b/include/safe.hpp
@@ -1,12 +1,12 @@
#pragma once
+#include
+#include
#include
-#include
-#include
#include
-#include
+#include
#include
-#include
#include
-#include
-#include
\ No newline at end of file
+#include
+#include
+#include
diff --git a/include/safe/algorithm.hpp b/include/safe/algorithm.hpp
index 918ea56..df793ce 100644
--- a/include/safe/algorithm.hpp
+++ b/include/safe/algorithm.hpp
@@ -1,5 +1,4 @@
#pragma once
-
#include
#include
\ No newline at end of file
diff --git a/include/safe/algorithm/accumulate.hpp b/include/safe/algorithm/accumulate.hpp
index e2bf580..d09557e 100644
--- a/include/safe/algorithm/accumulate.hpp
+++ b/include/safe/algorithm/accumulate.hpp
@@ -1,21 +1,17 @@
#pragma once
-
-#include
#include
-#include
-
#include
+#include
+#include
#include
#include
-
namespace safe {
- namespace detail {
- template
- inline consteval auto fold(auto e, auto op){
- if constexpr (count > 100) {
+namespace detail {
+template inline consteval auto fold(auto e, auto op) {
+ if constexpr (count > 100) {
return safe::dsl::detail::simp(
op(op(op(op(op(op(op(op(op(op(
op(op(op(op(op(op(op(op(op(op(
@@ -39,83 +35,76 @@ namespace safe {
e), e), e), e), e), e), e), e), e), e)
);
- } else if constexpr (count > 10) {
- return safe::dsl::detail::simp(
- op(op(op(op(op(op(op(op(op(op(fold(e, op), e), e), e), e), e), e), e), e), e), e)
- );
-
- } else if constexpr (count > 1) {
+ } else if constexpr (count > 10) {
+ return safe::dsl::detail::simp(op(
+ op(op(op(op(op(op(op(op(op(fold(e, op), e), e),
+ e),
+ e),
+ e),
+ e),
+ e),
+ e),
+ e),
+ e));
+
+ } else if constexpr (count > 1) {
return safe::dsl::detail::simp(op(fold(e, op), e));
- } else {
+ } else {
return e;
- }
- }
-
- inline constexpr auto plus_op = [](auto a, auto b){return a + b;};
}
+}
+constexpr inline auto plus_op = [](auto a, auto b) { return a + b; };
+} // namespace detail
- template
- [[nodiscard]] inline constexpr auto accumulate(
- detail::iter_like auto first,
- auto last,
- auto init,
- auto op
- ) {
- constexpr auto req = decltype((*first).requirement){};
- constexpr auto sum_req = detail::fold(req, op);
+template
+[[nodiscard]] constexpr inline auto accumulate(detail::iter_like auto first,
+ auto last, auto init, auto op) {
+ constexpr auto req = decltype((*first).requirement){};
+ constexpr auto sum_req = detail::fold(req, op);
- using ret_num_t = decltype((*first).unsafe_value());
+ using ret_num_t = decltype((*first).unsafe_value());
- auto iter_count = size_t{};
- auto sum = init;
- while ((first != last) && (iter_count < max_iter)) {
- sum = op(sum, (*first).unsafe_value());
- first++;
- iter_count++;
- }
-
- return unsafe_cast>(sum);
- }
-
- template
- [[nodiscard]] inline constexpr auto accumulate(
- detail::iter_like auto first,
- auto last,
- auto init
- ) {
- return accumulate(first, last, init, detail::plus_op);
- }
-
- template
- [[nodiscard]] inline constexpr auto accumulate(
- detail::range_like auto & range,
- auto init,
- auto op
- ) {
- return accumulate(range.begin(), range.end(), init, op);
+ auto iter_count = size_t{};
+ auto sum = init;
+ while ((first != last) && (iter_count < max_iter)) {
+ sum = op(sum, (*first).unsafe_value());
+ first++;
+ iter_count++;
}
- template
- [[nodiscard]] inline constexpr auto accumulate(
- detail::range_like auto & range,
- auto init
- ) {
- return accumulate(range.begin(), range.end(), init, detail::plus_op);
- }
-
- template
- [[nodiscard]] inline constexpr auto accumulate(
- detail::range_like auto const & range,
- auto init,
- auto op
- ) {
- return accumulate(range.begin(), range.end(), init, op);
- }
-
- template
- [[nodiscard]] inline constexpr auto accumulate(auto const & range, auto init) {
- return accumulate(range.begin(), range.end(), init, detail::plus_op);
- }
-}
\ No newline at end of file
+ return unsafe_cast>(sum);
+}
+
+template
+[[nodiscard]] constexpr inline auto accumulate(detail::iter_like auto first,
+ auto last, auto init) {
+ return accumulate(first, last, init, detail::plus_op);
+}
+
+template
+[[nodiscard]] constexpr inline auto accumulate(detail::range_like auto &range,
+ auto init, auto op) {
+ return accumulate(range.begin(), range.end(), init, op);
+}
+
+template
+[[nodiscard]] constexpr inline auto accumulate(detail::range_like auto &range,
+ auto init) {
+ return accumulate(range.begin(), range.end(), init,
+ detail::plus_op);
+}
+
+template
+[[nodiscard]] constexpr inline auto
+accumulate(detail::range_like auto const &range, auto init, auto op) {
+ return accumulate(range.begin(), range.end(), init, op);
+}
+
+template
+[[nodiscard]] constexpr inline auto accumulate(auto const &range, auto init) {
+ return accumulate(range.begin(), range.end(), init,
+ detail::plus_op);
+}
+} // namespace safe
\ No newline at end of file
diff --git a/include/safe/algorithm/irange.hpp b/include/safe/algorithm/irange.hpp
index 68e4683..cd90b22 100644
--- a/include/safe/algorithm/irange.hpp
+++ b/include/safe/algorithm/irange.hpp
@@ -1,79 +1,65 @@
#pragma once
-
#include
-
namespace safe {
- template
- struct irange {
- private:
- BeginT begin_;
- EndT end_;
-
- template
- struct iterator {
- private:
- irange const * parent_;
- T value_;
- bool end_;
+template struct irange {
+ private:
+ BeginT begin_;
+ EndT end_;
- public:
- using ret_t = decltype(clamp(0, parent_->begin_, parent_->end_ - s32_<1>));
+ template struct iterator {
+ private:
+ irange const *parent_;
+ T value_;
+ bool end_;
- constexpr iterator(irange const * parent, T value, bool end)
- : parent_{parent}
- , value_{value}
- , end_{end}
- {}
+ public:
+ using ret_t =
+ decltype(clamp(0, parent_->begin_, parent_->end_ - s32_<1>));
- constexpr ret_t operator*() const {
- return unsafe_cast(value_);
- }
+ constexpr iterator(irange const *parent, T value, bool end)
+ : parent_{parent}, value_{value}, end_{end} {}
- constexpr auto operator++() {
- auto const new_unsafe_value = value_++;
+ constexpr ret_t operator*() const { return unsafe_cast(value_); }
- // FIXME: consolidate range checks between == and ++
- if (new_unsafe_value < parent_->end_.unsafe_value()) {
- value_ = new_unsafe_value;
+ constexpr auto operator++() {
+ auto const new_unsafe_value = value_++;
- } else {
- end_ = true;
- }
+ // FIXME: consolidate range checks between == and ++
+ if (new_unsafe_value < parent_->end_.unsafe_value()) {
+ value_ = new_unsafe_value;
- return *this;
+ } else {
+ end_ = true;
}
- constexpr bool operator==(iterator rhs) {
- if (end_) {
- return rhs.end_;
-
- } else {
- return
- parent_ == rhs.parent_ &&
- value_ == rhs.value_ &&
- !rhs.end_;
- }
- }
- };
-
- public:
- constexpr irange(
- BeginT begin,
- EndT end
- )
- : begin_{begin}
- , end_{end}
- {}
-
- constexpr auto begin() const {
- return iterator{this, begin_.unsafe_value(), begin_ == end_};
+ return *this;
}
- constexpr auto end() const {
- // FIXME: need to find the right value for the end
- return iterator{this, end_.unsafe_value() - 1, true};
+ constexpr bool operator==(iterator rhs) {
+ if (end_) {
+ return rhs.end_;
+
+ } else {
+ return parent_ == rhs.parent_ && value_ == rhs.value_ &&
+ !rhs.end_;
+ }
}
};
-}
\ No newline at end of file
+
+ public:
+ constexpr irange(BeginT begin, EndT end) : begin_{begin}, end_{end} {}
+
+ constexpr auto begin() const {
+ return iterator{
+ this, begin_.unsafe_value(), begin_ == end_};
+ }
+
+ constexpr auto end() const {
+ // FIXME: need to find the right value for the end
+ return iterator{
+ this, end_.unsafe_value() - 1, true};
+ }
+};
+} // namespace safe
\ No newline at end of file
diff --git a/include/safe/array.hpp b/include/safe/array.hpp
index 736ce68..0e3ef78 100644
--- a/include/safe/array.hpp
+++ b/include/safe/array.hpp
@@ -1,206 +1,167 @@
#pragma once
-#include
-#include
#include
+#include
+#include
-#include
#include
+#include
namespace safe {
- template
- struct array {
- private:
- using std_array = std::array;
- std_array storage;
-
- public:
- using value_type = typename std_array::value_type;
- using size_type = typename std_array::size_type;
- using difference_type = typename std_array::difference_type;
- using reference = typename std_array::reference;
- using const_reference = typename std_array::const_reference;
- using pointer = typename std_array::pointer;
- using const_pointer = typename std_array::const_pointer;
- using iterator = typename std_array::iterator;
- using const_iterator = typename std_array::const_iterator;
- using reverse_iterator = typename std_array::reverse_iterator;
- using const_reverse_iterator = typename std_array::const_reverse_iterator;
-
- // TODO: constructors
- template
- constexpr array(Us... values)
- : storage({values...})
- {}
-
- [[nodiscard]] constexpr reference operator[](
- var> pos
- ) {
- return storage[pos.unsafe_value()];
- }
-
- [[nodiscard]] constexpr const_reference operator[](
- var> pos
- ) const {
- return storage[pos.unsafe_value()];
- }
-
- [[nodiscard]] constexpr reference at(
- var> pos
- ) {
- return storage[pos.unsafe_value()];
- }
-
- [[nodiscard]] constexpr const_reference at(
- var> pos
- ) const {
- return storage[pos.unsafe_value()];
- }
-
- [[nodiscard]] constexpr reference front() {
- return storage.front();
- }
-
- [[nodiscard]] constexpr const_reference front() const {
- return storage.front();
- }
-
- [[nodiscard]] constexpr reference back() {
- return storage.back();
- }
-
- [[nodiscard]] constexpr const_reference back() const {
- return storage.back();
- }
-
- // NOTE: intentionally omitting data()
-
- [[nodiscard]] constexpr iterator begin() {
- return storage.begin();
- }
-
- [[nodiscard]] constexpr const_iterator begin() const {
- return storage.begin();
- }
-
- [[nodiscard]] constexpr const_iterator cbegin() const {
- return storage.cbegin();
- }
-
- [[nodiscard]] constexpr iterator end() {
- return storage.end();
- }
-
- [[nodiscard]] constexpr const_iterator end() const {
- return storage.end();
- }
-
- [[nodiscard]] constexpr const_iterator cend() const {
- return storage.cend();
- }
-
- [[nodiscard]] constexpr reverse_iterator rbegin() {
- return storage.rbegin();
- }
-
- [[nodiscard]] constexpr const_reverse_iterator rbegin() const {
- return storage.rbegin();
- }
-
- [[nodiscard]] constexpr const_reverse_iterator crbegin() const {
- return storage.crbegin();
- }
-
- [[nodiscard]] constexpr reverse_iterator rend() {
- return storage.rend();
- }
-
- [[nodiscard]] constexpr const_reverse_iterator rend() const {
- return storage.rend();
- }
-
- [[nodiscard]] constexpr const_reverse_iterator crend() const {
- return storage.crend();
- }
-
- [[nodiscard]] constexpr bool empty() const {
- return storage.empty();
- }
-
- [[nodiscard]] constexpr size_type size() const {
- return storage.size();
- }
-
- [[nodiscard]] constexpr size_type max_size() const {
- return storage.max_size();
- }
-
- constexpr void fill(T const & value) {
- storage.fill(value);
- }
-
- constexpr void swap(array & other) {
- storage.swap(other.storage);
- }
-
- [[nodiscard]] friend constexpr bool operator==(
- array const & lhs,
- array const & rhs
- ) {
- return lhs.storage == rhs.storage;
- }
-
- [[nodiscard]] friend constexpr auto operator<=>(
- array const & lhs,
- array const & rhs
- ) {
- return lhs.storage <=> rhs.storage;
- }
- };
-
- template
- array(T, U...) -> array;
-}
+template struct array {
+ private:
+ using std_array = std::array;
+ std_array storage;
+
+ public:
+ using value_type = typename std_array::value_type;
+ using size_type = typename std_array::size_type;
+ using difference_type = typename std_array::difference_type;
+ using reference = typename std_array::reference;
+ using const_reference = typename std_array::const_reference;
+ using pointer = typename std_array::pointer;
+ using const_pointer = typename std_array::const_pointer;
+ using iterator = typename std_array::iterator;
+ using const_iterator = typename std_array::const_iterator;
+ using reverse_iterator = typename std_array::reverse_iterator;
+ using const_reverse_iterator = typename std_array::const_reverse_iterator;
+
+ // TODO: constructors
+ template
+ constexpr array(Us... values) : storage({values...}) {}
+
+ [[nodiscard]] constexpr reference
+ operator[](var> pos) {
+ return storage[pos.unsafe_value()];
+ }
-namespace std {
- template
- [[nodiscard]] constexpr T & get(safe::array & a) noexcept {
- return a[safe::constant];
+ [[nodiscard]] constexpr const_reference
+ operator[](var> pos) const {
+ return storage[pos.unsafe_value()];
+ }
+
+ [[nodiscard]] constexpr reference
+ at(var> pos) {
+ return storage[pos.unsafe_value()];
+ }
+
+ [[nodiscard]] constexpr const_reference
+ at(var> pos) const {
+ return storage[pos.unsafe_value()];
}
+ [[nodiscard]] constexpr reference front() { return storage.front(); }
- template
- [[nodiscard]] constexpr T && get(safe::array && a) noexcept {
- return a[safe::constant];
+ [[nodiscard]] constexpr const_reference front() const {
+ return storage.front();
}
+ [[nodiscard]] constexpr reference back() { return storage.back(); }
- template
- [[nodiscard]] constexpr const T & get(safe::array const & a) noexcept {
- return a[safe::constant];
+ [[nodiscard]] constexpr const_reference back() const {
+ return storage.back();
}
+ // NOTE: intentionally omitting data()
- template
- [[nodiscard]] constexpr const T && get(safe::array const && a) noexcept {
- return a[safe::constant];
+ [[nodiscard]] constexpr iterator begin() { return storage.begin(); }
+
+ [[nodiscard]] constexpr const_iterator begin() const {
+ return storage.begin();
+ }
+
+ [[nodiscard]] constexpr const_iterator cbegin() const {
+ return storage.cbegin();
+ }
+
+ [[nodiscard]] constexpr iterator end() { return storage.end(); }
+
+ [[nodiscard]] constexpr const_iterator end() const { return storage.end(); }
+
+ [[nodiscard]] constexpr const_iterator cend() const {
+ return storage.cend();
}
- template
- constexpr void swap(
- safe::array & lhs,
- safe::array & rhs
- ) {
- lhs.swap(rhs);
+ [[nodiscard]] constexpr reverse_iterator rbegin() {
+ return storage.rbegin();
}
- template
- struct tuple_size>
- : std::integral_constant
- {};
+ [[nodiscard]] constexpr const_reverse_iterator rbegin() const {
+ return storage.rbegin();
+ }
+
+ [[nodiscard]] constexpr const_reverse_iterator crbegin() const {
+ return storage.crbegin();
+ }
+
+ [[nodiscard]] constexpr reverse_iterator rend() { return storage.rend(); }
+
+ [[nodiscard]] constexpr const_reverse_iterator rend() const {
+ return storage.rend();
+ }
+
+ [[nodiscard]] constexpr const_reverse_iterator crend() const {
+ return storage.crend();
+ }
+
+ [[nodiscard]] constexpr bool empty() const { return storage.empty(); }
+
+ [[nodiscard]] constexpr size_type size() const { return storage.size(); }
+
+ [[nodiscard]] constexpr size_type max_size() const {
+ return storage.max_size();
+ }
+
+ constexpr void fill(T const &value) { storage.fill(value); }
+
+ constexpr void swap(array &other) { storage.swap(other.storage); }
+
+ [[nodiscard]] friend constexpr bool operator==(array const &lhs,
+ array const &rhs) {
+ return lhs.storage == rhs.storage;
+ }
+
+ [[nodiscard]] friend constexpr auto operator<=>(array const &lhs,
+ array const &rhs) {
+ return lhs.storage <=> rhs.storage;
+ }
+};
+
+template array(T, U...) -> array;
+} // namespace safe
+
+namespace std {
+template
+[[nodiscard]] constexpr T &get(safe::array &a) noexcept {
+ return a[safe::constant];
+}
+
+template
+[[nodiscard]] constexpr T &&get(safe::array &&a) noexcept {
+ return a[safe::constant];
+}
+
+template
+[[nodiscard]] constexpr T const &get(safe::array const &a) noexcept {
+ return a[safe::constant];
+}
+
+template
+[[nodiscard]] constexpr T const &&get(safe::array const &&a) noexcept {
+ return a[safe::constant];
+}
+
+template
+constexpr void swap(safe::array &lhs, safe::array &rhs) {
+ lhs.swap(rhs);
+}
+
+template
+struct tuple_size> : std::integral_constant {
+};
- template
- struct tuple_element> {
- using type = T;
- };
-}
\ No newline at end of file
+template
+struct tuple_element> {
+ using type = T;
+};
+} // namespace std
\ No newline at end of file
diff --git a/include/safe/big_integer.hpp b/include/safe/big_integer.hpp
index 66605db..d4ae458 100644
--- a/include/safe/big_integer.hpp
+++ b/include/safe/big_integer.hpp
@@ -3,7 +3,7 @@
#include
namespace safe {
- using _big_integer::interface::big_integer;
- using _big_integer::interface::to_big_integer;
- using _big_integer::interface::common_integer_t;
-}
\ No newline at end of file
+using _big_integer::interface::big_integer;
+using _big_integer::interface::common_integer_t;
+using _big_integer::interface::to_big_integer;
+} // namespace safe
\ No newline at end of file
diff --git a/include/safe/big_integer/detail/algorithms.hpp b/include/safe/big_integer/detail/algorithms.hpp
index 234ac53..ce273d8 100644
--- a/include/safe/big_integer/detail/algorithms.hpp
+++ b/include/safe/big_integer/detail/algorithms.hpp
@@ -1,69 +1,44 @@
#pragma once
-
#include
-#include
#include
-
+#include
namespace safe::_big_integer::detail {
- [[nodiscard]] constexpr auto reverse_zip_transform(
- auto op
- ) {
- return [=](
- auto & result,
- auto const & lhs,
- auto const & rhs
- ) -> void {
- auto i = result.num_elems;
- do {
- i--;
- result.set(i, op(lhs.get(i), rhs.get(i)));
- } while (i > std::size_t{});
- };
- }
-
- [[nodiscard]] constexpr auto zip_transform(
- auto op
- ) {
- return [=](
- auto & result,
- auto const & lhs,
- auto const & rhs
- ) -> void {
- for (auto i = std::size_t{}; i < result.num_elems; i++) {
- result.set(i, op(lhs.get(i), rhs.get(i)));
- }
- };
- }
-
- [[nodiscard]] constexpr auto stateful_zip_transform(
- auto initial_value,
- auto op
- ) {
- return [=](
- auto & result,
- auto const & lhs,
- auto const & rhs
- ) -> void {
- auto state = initial_value;
- for (auto i = std::size_t{}; i < result.num_elems; i++) {
- result.set(i, op(state, lhs.get(i), rhs.get(i)));
- }
- };
- }
-
- [[nodiscard]] constexpr auto transform(
- auto op
- ) {
- return [=](
- auto & result,
- auto const & value
- ) -> void {
- for (auto i = std::size_t{}; i < result.num_elems; i++) {
- result.set(i, op(value.get(i)));
- }
- };
- }
-}
\ No newline at end of file
+[[nodiscard]] constexpr auto reverse_zip_transform(auto op) {
+ return [=](auto &result, auto const &lhs, auto const &rhs) -> void {
+ auto i = result.num_elems;
+ do {
+ i--;
+ result.set(i, op(lhs.get(i), rhs.get(i)));
+ } while (i > std::size_t{});
+ };
+}
+
+[[nodiscard]] constexpr auto zip_transform(auto op) {
+ return [=](auto &result, auto const &lhs, auto const &rhs) -> void {
+ for (auto i = std::size_t{}; i < result.num_elems; i++) {
+ result.set(i, op(lhs.get(i), rhs.get(i)));
+ }
+ };
+}
+
+[[nodiscard]] constexpr auto stateful_zip_transform(auto initial_value,
+ auto op) {
+ return [=](auto &result, auto const &lhs, auto const &rhs) -> void {
+ auto state = initial_value;
+ for (auto i = std::size_t{}; i < result.num_elems; i++) {
+ result.set(i, op(state, lhs.get(i), rhs.get(i)));
+ }
+ };
+}
+
+[[nodiscard]] constexpr auto transform(auto op) {
+ return [=](auto &result, auto const &value) -> void {
+ for (auto i = std::size_t{}; i < result.num_elems; i++) {
+ result.set(i, op(value.get(i)));
+ }
+ };
+}
+} // namespace safe::_big_integer::detail
\ No newline at end of file
diff --git a/include/safe/big_integer/detail/bitwise.hpp b/include/safe/big_integer/detail/bitwise.hpp
index 76c6fab..3e9b613 100644
--- a/include/safe/big_integer/detail/bitwise.hpp
+++ b/include/safe/big_integer/detail/bitwise.hpp
@@ -1,15 +1,13 @@
#pragma once
-
-#include
#include
+#include
#include
-
namespace safe::_big_integer::detail {
- constexpr static auto bit_and = zip_transform(std::bit_and{});
- constexpr static auto bit_or = zip_transform(std::bit_or{});
- constexpr static auto bit_xor = zip_transform(std::bit_xor{});
- constexpr static auto bit_not = transform(std::bit_not{});
-}
\ No newline at end of file
+constexpr static auto bit_and = zip_transform(std::bit_and{});
+constexpr static auto bit_or = zip_transform(std::bit_or{});
+constexpr static auto bit_xor = zip_transform(std::bit_xor{});
+constexpr static auto bit_not = transform(std::bit_not{});
+} // namespace safe::_big_integer::detail
\ No newline at end of file
diff --git a/include/safe/big_integer/detail/compare.hpp b/include/safe/big_integer/detail/compare.hpp
index 521a6d4..05d6167 100644
--- a/include/safe/big_integer/detail/compare.hpp
+++ b/include/safe/big_integer/detail/compare.hpp
@@ -1,55 +1,47 @@
#pragma once
-
-#include
#include
+#include
#include
#include
-
namespace safe::_big_integer::detail {
- template<
- std::size_t LhsNumBits,
- std::size_t RhsNumBits>
- [[nodiscard]] constexpr auto unsigned_compare(
- storage const & lhs,
- storage const & rhs
- ) -> std::strong_ordering {
- auto i = std::max(lhs.num_elems, rhs.num_elems);
- do {
- i--;
-
- if (lhs.get(i) < rhs.get(i)) {
- return std::strong_ordering::less;
-
- } else if (lhs.get(i) > rhs.get(i)) {
- return std::strong_ordering::greater;
- }
- } while (i > 0);
-
- return std::strong_ordering::equal;
- }
-
- template<
- std::size_t LhsNumBits,
- std::size_t RhsNumBits>
- [[nodiscard]] constexpr auto operator<=>(
- storage const & lhs,
- storage const & rhs
- ) -> std::strong_ordering {
- if (lhs.negative()) {
- if (rhs.negative()) {
- return unsigned_compare(lhs, rhs);
- } else {
- return std::strong_ordering::less;
- }
+template
+[[nodiscard]] constexpr auto unsigned_compare(storage const &lhs,
+ storage const &rhs)
+ -> std::strong_ordering {
+ auto i = std::max(lhs.num_elems, rhs.num_elems);
+ do {
+ i--;
+
+ if (lhs.get(i) < rhs.get(i)) {
+ return std::strong_ordering::less;
+
+ } else if (lhs.get(i) > rhs.get(i)) {
+ return std::strong_ordering::greater;
+ }
+ } while (i > 0);
+
+ return std::strong_ordering::equal;
+}
+
+template
+[[nodiscard]] constexpr auto operator<=>(storage const &lhs,
+ storage const &rhs)
+ -> std::strong_ordering {
+ if (lhs.negative()) {
+ if (rhs.negative()) {
+ return unsigned_compare(lhs, rhs);
+ } else {
+ return std::strong_ordering::less;
+ }
+ } else {
+ if (rhs.negative()) {
+ return std::strong_ordering::greater;
} else {
- if (rhs.negative()) {
- return std::strong_ordering::greater;
- } else {
- return unsigned_compare(lhs, rhs);
- }
+ return unsigned_compare(lhs, rhs);
}
}
-}
\ No newline at end of file
+}
+} // namespace safe::_big_integer::detail
\ No newline at end of file
diff --git a/include/safe/big_integer/detail/divides.hpp b/include/safe/big_integer/detail/divides.hpp
index 28b592f..c8ae9e1 100644
--- a/include/safe/big_integer/detail/divides.hpp
+++ b/include/safe/big_integer/detail/divides.hpp
@@ -1,109 +1,96 @@
#pragma once
-
-#include
#include
-#include
-#include
#include
+#include
+#include
+#include
-
-#include
#include
+#include
namespace safe::_big_integer::detail {
- template<
- std::size_t LhsNumBits,
- std::size_t RhsNumBits>
- [[nodiscard]] constexpr auto largest_doubling(
- storage a,
- storage b
- ) {
- using ret_t = storage;
-
- ret_t ret = b;
-
- auto const not_big_enough = [&]() -> bool {
- auto a_prime = a;
- minus(a_prime, a_prime, ret);
- return ret <= a_prime;
- };
-
- while (not_big_enough()) {
- bit_shift_left(ret, ret, 1);
- }
+template
+[[nodiscard]] constexpr auto largest_doubling(storage a,
+ storage b) {
+ using ret_t = storage;
- return ret;
- }
-
- constexpr static auto unsigned_divmod = [](
- auto & quotient,
- auto & remainder,
- auto const & dividend,
- auto const & divisor
- ) -> void {
- // NOTE: Algorithm is based on "Elements of Programming"
- // section 5.7 Quotient
+ ret_t ret = b;
- auto a = dividend;
- auto b = divisor;
+ auto const not_big_enough = [&]() -> bool {
+ auto a_prime = a;
+ minus(a_prime, a_prime, ret);
+ return ret <= a_prime;
+ };
- if (a < b) {
- quotient = make_storage(0);
- remainder = a;
+ while (not_big_enough()) {
+ bit_shift_left(ret, ret, 1);
+ }
- } else {
- constexpr auto one = make_storage(1);
-
- auto c = largest_doubling(a, b);
- minus(a, a, c);
- quotient = one;
- while (c != b) {
- bit_shift_left(quotient, quotient, 1);
- bit_shift_right(c, c, 1);
- if (c <= a) {
- minus(a, a, c);
- plus(quotient, quotient, one);
- }
+ return ret;
+}
+
+constexpr static auto unsigned_divmod = [](auto "ient, auto &remainder,
+ auto const ÷nd,
+ auto const &divisor) -> void {
+ // NOTE: Algorithm is based on "Elements of Programming"
+ // section 5.7 Quotient
+
+ auto a = dividend;
+ auto b = divisor;
+
+ if (a < b) {
+ quotient = make_storage(0);
+ remainder = a;
+
+ } else {
+ constexpr auto one = make_storage(1);
+
+ auto c = largest_doubling(a, b);
+ minus(a, a, c);
+ quotient = one;
+ while (c != b) {
+ bit_shift_left(quotient, quotient, 1);
+ bit_shift_right(c, c, 1);
+ if (c <= a) {
+ minus(a, a, c);
+ plus(quotient, quotient, one);
}
-
- remainder = a;
}
- };
+ remainder = a;
+ }
+};
- constexpr static auto divmod = [](
- auto & quotient,
- auto & remainder,
- auto const & dividend,
- auto const & divisor
- ) -> void {
- auto a = dividend;
- auto b = divisor;
-
- if (a.negative()) {
- if (b.negative()) {
- negate(a, a);
- negate(b, b);
- unsigned_divmod(quotient, remainder, a, b);
-
- } else {
- negate(a, a);
- unsigned_divmod(quotient, remainder, a, b);
- negate(quotient, quotient);
- }
+constexpr static auto divmod = [](auto "ient, auto &remainder,
+ auto const ÷nd,
+ auto const &divisor) -> void {
+ auto a = dividend;
+ auto b = divisor;
- negate(remainder, remainder);
+ if (a.negative()) {
+ if (b.negative()) {
+ negate(a, a);
+ negate(b, b);
+ unsigned_divmod(quotient, remainder, a, b);
} else {
- if (b.negative()) {
- negate(b, b);
- unsigned_divmod(quotient, remainder, a, b);
- negate(quotient, quotient);
+ negate(a, a);
+ unsigned_divmod(quotient, remainder, a, b);
+ negate(quotient, quotient);
+ }
- } else {
- unsigned_divmod(quotient, remainder, a, b);
- }
+ negate(remainder, remainder);
+
+ } else {
+ if (b.negative()) {
+ negate(b, b);
+ unsigned_divmod(quotient, remainder, a, b);
+ negate(quotient, quotient);
+
+ } else {
+ unsigned_divmod(quotient, remainder, a, b);
}
- };
-}
\ No newline at end of file
+ }
+};
+} // namespace safe::_big_integer::detail
\ No newline at end of file
diff --git a/include/safe/big_integer/detail/multiplies.hpp b/include/safe/big_integer/detail/multiplies.hpp
index e546cc0..fe69271 100644
--- a/include/safe/big_integer/detail/multiplies.hpp
+++ b/include/safe/big_integer/detail/multiplies.hpp
@@ -1,66 +1,62 @@
#pragma once
-
-#include
#include
-#include
#include
+#include
+#include
-#include
#include
+#include
namespace safe::_big_integer::detail {
- constexpr static auto unsigned_multiplies = [](
- auto & result,
- auto const & lhs,
- auto const & rhs
- ) -> void {
- using result_t = std::remove_cvref_t;
+constexpr static auto unsigned_multiplies = [](auto &result, auto const &lhs,
+ auto const &rhs) -> void {
+ using result_t = std::remove_cvref_t;
- for (int i = 0; i < lhs.num_elems; i++) {
- for (int j = 0; j < rhs.num_elems; j++) {
- auto const raw_partial_product =
- static_cast(lhs.get(i)) *
- static_cast(rhs.get(j));
+ for (int i = 0; i < lhs.num_elems; i++) {
+ for (int j = 0; j < rhs.num_elems; j++) {
+ auto const raw_partial_product =
+ static_cast(lhs.get(i)) *
+ static_cast(rhs.get(j));
- result_t partial_product{{
- static_cast(raw_partial_product & 0xffff'ffffu),
- static_cast(raw_partial_product >> 32)}};
+ result_t partial_product{
+ {static_cast(raw_partial_product & 0xffff'ffffu),
+ static_cast(raw_partial_product >> 32)}};
- bit_shift_left(partial_product, partial_product, (i + j) * 32);
+ bit_shift_left(partial_product, partial_product, (i + j) * 32);
- plus(result, result, partial_product);
- }
+ plus(result, result, partial_product);
}
- };
-
- constexpr static auto multiplies = [](
- auto & result,
- auto const & lhs,
- auto const & rhs
- ) -> void {
- using lhs_t = std::remove_cvref_t;
- using rhs_t = std::remove_cvref_t;
-
- if (lhs.negative()) {
- lhs_t pos_lhs{}; negate(pos_lhs, lhs);
-
- if (rhs.negative()) {
- rhs_t pos_rhs{}; negate(pos_rhs, rhs);
- unsigned_multiplies(result, pos_lhs, pos_rhs);
- } else {
- unsigned_multiplies(result, pos_lhs, rhs);
- negate(result, result);
- }
+ }
+};
+
+constexpr static auto multiplies = [](auto &result, auto const &lhs,
+ auto const &rhs) -> void {
+ using lhs_t = std::remove_cvref_t;
+ using rhs_t = std::remove_cvref_t;
+
+ if (lhs.negative()) {
+ lhs_t pos_lhs{};
+ negate(pos_lhs, lhs);
+
+ if (rhs.negative()) {
+ rhs_t pos_rhs{};
+ negate(pos_rhs, rhs);
+ unsigned_multiplies(result, pos_lhs, pos_rhs);
} else {
- if (rhs.negative()) {
- rhs_t pos_rhs{}; negate(pos_rhs, rhs);
- unsigned_multiplies(result, lhs, pos_rhs);
- negate(result, result);
+ unsigned_multiplies(result, pos_lhs, rhs);
+ negate(result, result);
+ }
+ } else {
+ if (rhs.negative()) {
+ rhs_t pos_rhs{};
+ negate(pos_rhs, rhs);
+ unsigned_multiplies(result, lhs, pos_rhs);
+ negate(result, result);
- } else {
- unsigned_multiplies(result, lhs, rhs);
- }
+ } else {
+ unsigned_multiplies(result, lhs, rhs);
}
- };
-}
\ No newline at end of file
+ }
+};
+} // namespace safe::_big_integer::detail
\ No newline at end of file
diff --git a/include/safe/big_integer/detail/operators.hpp b/include/safe/big_integer/detail/operators.hpp
index 5d59fd7..9073d78 100644
--- a/include/safe/big_integer/detail/operators.hpp
+++ b/include/safe/big_integer/detail/operators.hpp
@@ -1,9 +1,8 @@
#pragma once
-
-#include
#include
+#include
+#include
+#include
#include
#include
-#include
-#include
diff --git a/include/safe/big_integer/detail/plus.hpp b/include/safe/big_integer/detail/plus.hpp
index ae28c6a..a2340c7 100644
--- a/include/safe/big_integer/detail/plus.hpp
+++ b/include/safe/big_integer/detail/plus.hpp
@@ -1,42 +1,32 @@
#pragma once
-
-#include
#include
#include
+#include
#include
-
namespace safe::_big_integer::detail {
- constexpr static auto plus =
- stateful_zip_transform(
- elem_t{},
- [](
- elem_t & carry,
- double_elem_t const & lhs,
- double_elem_t const & rhs
- ){
- double_elem_t const result =
- lhs + rhs +
- static_cast(carry);
-
- carry = result >> 32;
- return result & 0xffff'ffffu;
- }
- );
-
- constexpr static auto negate =
- [](auto & result, auto const & value) -> void {
- std::remove_cvref_t not_value{};
- bit_not(not_value, value);
- plus(result, not_value, make_storage(1));
- };
-
- constexpr static auto minus =
- [](auto & result, auto const & lhs, auto const & rhs) -> void {
- std::remove_cvref_t negative_rhs{};
- negate(negative_rhs, rhs);
- plus(result, lhs, negative_rhs);
- };
-}
\ No newline at end of file
+constexpr static auto plus =
+ stateful_zip_transform(elem_t{}, [](elem_t &carry, double_elem_t const &lhs,
+ double_elem_t const &rhs) {
+ double_elem_t const result =
+ lhs + rhs + static_cast(carry);
+
+ carry = result >> 32;
+ return result & 0xffff'ffffu;
+ });
+
+constexpr static auto negate = [](auto &result, auto const &value) -> void {
+ std::remove_cvref_t not_value{};
+ bit_not(not_value, value);
+ plus(result, not_value, make_storage(1));
+};
+
+constexpr static auto minus = [](auto &result, auto const &lhs,
+ auto const &rhs) -> void {
+ std::remove_cvref_t negative_rhs{};
+ negate(negative_rhs, rhs);
+ plus(result, lhs, negative_rhs);
+};
+} // namespace safe::_big_integer::detail
\ No newline at end of file
diff --git a/include/safe/big_integer/detail/shift.hpp b/include/safe/big_integer/detail/shift.hpp
index 95b9c4f..2bba128 100644
--- a/include/safe/big_integer/detail/shift.hpp
+++ b/include/safe/big_integer/detail/shift.hpp
@@ -1,100 +1,71 @@
#pragma once
-
-#include
#include
#include
+#include
-#include
#include
+#include
// TODO: can we consolidate the implementations for left and right shift?
namespace safe::_big_integer::detail {
- template
- struct shift_left {
- T source;
- int32_t shift_amt;
-
- constexpr shift_left(
- T source_arg,
- int32_t shift_amt_arg
- )
- : source{source_arg}
- , shift_amt{shift_amt_arg}
- {}
-
- [[nodiscard]] constexpr auto get(int32_t i) const -> elem_t {
- return source.get(i - shift_amt);
+template struct shift_left {
+ T source;
+ int32_t shift_amt;
+
+ constexpr shift_left(T source_arg, int32_t shift_amt_arg)
+ : source{source_arg}, shift_amt{shift_amt_arg} {}
+
+ [[nodiscard]] constexpr auto get(int32_t i) const -> elem_t {
+ return source.get(i - shift_amt);
+ }
+};
+
+constexpr static auto bit_shift_left =
+ [](auto &result, auto const &lhs,
+ std::signed_integral auto const rhs) -> void {
+ auto const elem_shift_amt = rhs / 32;
+ auto const bit_shift_amt = rhs % 32;
+
+ auto const lhs_shifted_upper = shift_left(lhs, elem_shift_amt);
+ auto const lhs_shifted_lower = shift_left(lhs, elem_shift_amt + 1);
+
+ reverse_zip_transform([=](elem_t const upper, elem_t const lower) {
+ if (bit_shift_amt == 0) {
+ return upper;
+ } else {
+ return (upper << bit_shift_amt) | (lower >> (32 - bit_shift_amt));
}
- };
-
- constexpr static auto bit_shift_left = [](
- auto & result,
- auto const & lhs,
- std::signed_integral auto const rhs
- ) -> void {
- auto const elem_shift_amt = rhs / 32;
- auto const bit_shift_amt = rhs % 32;
-
- auto const lhs_shifted_upper = shift_left(lhs, elem_shift_amt);
- auto const lhs_shifted_lower = shift_left(lhs, elem_shift_amt + 1);
-
- reverse_zip_transform([=](
- elem_t const upper,
- elem_t const lower
- ){
- if (bit_shift_amt == 0) {
- return upper;
- } else {
- return
- (upper << bit_shift_amt) |
- (lower >> (32 - bit_shift_amt));
- }
-
- })(result, lhs_shifted_upper, lhs_shifted_lower);
- };
-
- template
- struct shift_right {
- T source;
- int32_t shift_amt;
-
- constexpr shift_right(
- T source_arg,
- int32_t shift_amt_arg
- )
- : source{source_arg}
- , shift_amt{shift_amt_arg}
- {}
-
- [[nodiscard]] constexpr auto get(int32_t i) const -> elem_t {
- return source.get(i + shift_amt);
+ })(result, lhs_shifted_upper, lhs_shifted_lower);
+};
+
+template struct shift_right {
+ T source;
+ int32_t shift_amt;
+
+ constexpr shift_right(T source_arg, int32_t shift_amt_arg)
+ : source{source_arg}, shift_amt{shift_amt_arg} {}
+
+ [[nodiscard]] constexpr auto get(int32_t i) const -> elem_t {
+ return source.get(i + shift_amt);
+ }
+};
+
+constexpr static auto bit_shift_right =
+ [](auto &result, auto const &lhs,
+ std::signed_integral auto const rhs) -> void {
+ auto const elem_shift_amt = rhs / 32;
+ auto const bit_shift_amt = rhs % 32;
+
+ auto const lhs_shifted_upper = shift_right(lhs, elem_shift_amt + 1);
+ auto const lhs_shifted_lower = shift_right(lhs, elem_shift_amt);
+
+ zip_transform([=](elem_t const upper, elem_t const lower) {
+ if (bit_shift_amt == 0) {
+ return lower;
+ } else {
+ return (upper << (32 - bit_shift_amt)) | (lower >> bit_shift_amt);
}
- };
-
- constexpr static auto bit_shift_right = [](
- auto & result,
- auto const & lhs,
- std::signed_integral auto const rhs
- ) -> void {
- auto const elem_shift_amt = rhs / 32;
- auto const bit_shift_amt = rhs % 32;
-
- auto const lhs_shifted_upper = shift_right(lhs, elem_shift_amt + 1);
- auto const lhs_shifted_lower = shift_right(lhs, elem_shift_amt);
-
- zip_transform([=](
- elem_t const upper,
- elem_t const lower
- ){
- if (bit_shift_amt == 0) {
- return lower;
- } else {
- return
- (upper << (32 - bit_shift_amt)) |
- (lower >> bit_shift_amt);
- }
-
- })(result, lhs_shifted_upper, lhs_shifted_lower);
- };
-}
\ No newline at end of file
+ })(result, lhs_shifted_upper, lhs_shifted_lower);
+};
+} // namespace safe::_big_integer::detail
\ No newline at end of file
diff --git a/include/safe/big_integer/detail/storage.hpp b/include/safe/big_integer/detail/storage.hpp
index 134bb80..b95dae0 100644
--- a/include/safe/big_integer/detail/storage.hpp
+++ b/include/safe/big_integer/detail/storage.hpp
@@ -1,182 +1,170 @@
#pragma once
+#include
-#include
#include
#include
+#include
#include
-#include
-
-
namespace safe::_big_integer::detail {
- using elem_t = std::uint32_t;
- using double_elem_t = std::uint64_t;
+using elem_t = std::uint32_t;
+using double_elem_t = std::uint64_t;
- template
- struct storage {
- public:
- static constexpr auto num_elems = (NumBits + 31) / 32;
- static constexpr auto num_bits = NumBits;
+template struct storage {
+ public:
+ constexpr static auto num_elems = (NumBits + 31) / 32;
+ constexpr static auto num_bits = NumBits;
- std::array elems{};
+ std::array elems{};
- constexpr storage() = default;
+ constexpr storage() = default;
- constexpr storage(std::array const & new_elems) {
- elems = new_elems;
- }
-
- template
- constexpr storage(storage const & rhs) {
- for (auto i = std::size_t{}; i < NumBits; i++) {
- set(i, rhs.get(i));
- }
- };
-
- template
- constexpr auto operator=(storage const & rhs) -> storage & {
- for (auto i = std::size_t{}; i < NumBits; i++) {
- set(i, rhs.get(i));
- }
- return *this;
- };
-
- template
- [[nodiscard]] constexpr auto operator==(
- storage const & rhs
- ) const -> bool {
- for (auto i = std::size_t{}; i < std::max(num_elems, rhs.num_elems); i++) {
- if (get(i) != rhs.get(i)) {
- return false;
- }
- }
- return true;
- }
+ constexpr storage(std::array const &new_elems) {
+ elems = new_elems;
+ }
- [[nodiscard]] constexpr bool negative() const {
- return (elems.back() >> 31) & 1;
+ template