From dcc335d726afa378069c006bc9086a1220a97a40 Mon Sep 17 00:00:00 2001 From: beached Date: Thu, 3 Jul 2025 23:06:10 -0400 Subject: [PATCH] Added math, ascii, enum help and bigfixes (#549) * Refactor: Simplify range type constraints in pipelines * Add contract validation utility with corresponding tests Introduce a `daw::contract` class for validating preconditions at runtime. Includes a failure handler * Refactor contract tests to handle exceptions conditionally. * Add support for counting leading zeros in uint128_t Introduce a constexpr function to handle leading zero count for uint128_t, ensuring compatibility with larger integers. Additionally, adjust `ToIota` initialization for consistency with type defaults. * Refactor `count_leading_zeroes` handling for better builtin usage Introduced support for `__builtin_clzg` where available, improving compatibility and performance. Removed redundant overloads and reorganized function definitions to streamline the implementation. This cleanup simplifies the logic while maintaining backward compatibility. * Fix count_leading_zeroes for zero input handling Previously, calling count_leading_zeroes with a zero input could lead to undefined behavior. This update adds a check for zero inputs and returns the bit count for the type in such cases, ensuring correct results and improved safety. * Update LLVM repo URLs in CI for Ubuntu 24.04 workflows Replaced 'jammy' with 'noble' in LLVM repository URLs to match the correct distribution for Ubuntu 24.04. * Added missing conditional for `daw::uint128` with `DAW_HAS_INT128`. * Streamline CI by removing outdated compiler toolsets * Fix incorrect handling of zero in count_leading_zeroes. * Update macro check for built-in function in count_leading_zeroes. Replaced `__has_builtin` with `DAW_HAS_BUILTIN` to ensure correct macro usage. This improves compatibility * Add ASCII utilities and corresponding tests Introduce utility functions for ASCII character checks and transformations, such as detecting digits, letters, alphanumerics, printable characters, and case conversion. Included a test file to verify the correctness of these utilities. * Fix ASCII printable check to include space character The previous logic excluded the space character (ASCII code 32) from being considered printable. This change modifies the comparison to include space, ensuring correct behavior for determining ASCII printable characters. * Add utility to convert enums to their underlying type Introduce `to_underlying_type` in `daw_to_underlying_type.h`, allowing seamless conversion of enums to their underlying integer type. This simplifies operations requiring direct manipulation of enum values. * Rename `to_underlying_type` to `to_underlying` * Refactor `function_ref` to handle null-thunk pointers as it isn't needed for fp's passed. * Fix type handling and formatting in `count_digits` and `count_leading_zeroes`. * Fix formatting in `basic_string_view` and adjust logic for conditional compilation. * Update CI for Windows to use Visual Studio 2022 toolset * Refactor Windows CI workflows: merge `ci_windows_clangcl.yml` into `ci_windows.yml`, add improved matrix configuration, and update build/test steps for better toolset coverage. * Update Windows CI workflow to build `daw-header-libraries_full` target instead of `ci_tests` * Simplify `append_hash` logic in `daw_fnv1a_hash.h` by extracting `current_char` computation. * Undid change to string_view * Ensuring msvc::no_unique_address is used for clang-cl * Add `-Wno-missing-braces` compiler option to suppress warnings * Remove unnecessary `constexpr` in `formatter::parse` signature * Refactor `append_hash` to use `array_t` for byte extraction, simplifying logic. * Change `operator""` return type from `size_t` to `unsigned long long` in `daw_size_literals` for consistency with input type. * Refine aggregate initialization in `daw_uninitialized_storage` by checking for class types. * - Move `daw_contract_test.cpp` to `CPP20_NOT_MSVC_TEST_SOURCES` in CMakeLists. - Add MSVC-friendly file handling in `daw_read_file.h` with `fopen_s` and `_wfopen_s`. --- .clang-format | 5 +- .github/workflows/ci_ubuntu.yml | 14 +-- .github/workflows/ci_windows.yml | 71 ++++++++++++-- .github/workflows/ci_windows_clangcl.yml | 18 ---- CMakeLists.txt | 2 +- ci_scripts/ci_windows_build.cmd | 22 ----- ci_scripts/ci_windows_build_clangcl.cmd | 16 --- ci_scripts/ci_windows_install_test.cmd | 20 ---- .../ci_windows_install_test_clangcl.cmd | 20 ---- ci_scripts/ci_windows_test.cmd | 6 -- include/daw/daw_ascii.h | 98 +++++++++++++++++++ include/daw/daw_attributes.h | 2 +- include/daw/daw_contract.h | 96 ++++++++++++++++++ include/daw/daw_cxmath.h | 54 ++++++---- include/daw/daw_fnv1a_hash.h | 9 +- include/daw/daw_function_ref.h | 9 +- include/daw/daw_read_file.h | 13 ++- include/daw/daw_size_literals.h | 22 ++--- include/daw/daw_string_view.h | 4 +- include/daw/daw_to_underlying_type.h | 19 ++++ include/daw/daw_uninitialized_storage.h | 2 +- include/daw/pipelines/enumerate.h | 10 +- include/daw/pipelines/every.h | 6 +- include/daw/pipelines/iota.h | 2 +- tests/CMakeLists.txt | 2 + tests/cmake/test_compiler_options.cmake | 1 + tests/daw_ascii_test.cpp | 20 ++++ tests/daw_contract_test.cpp | 28 ++++++ tests/daw_function_ref_test.cpp | 2 +- tests/daw_size_literals_test.cpp | 4 +- 30 files changed, 414 insertions(+), 183 deletions(-) delete mode 100644 .github/workflows/ci_windows_clangcl.yml delete mode 100755 ci_scripts/ci_windows_build.cmd delete mode 100755 ci_scripts/ci_windows_build_clangcl.cmd delete mode 100755 ci_scripts/ci_windows_install_test.cmd delete mode 100755 ci_scripts/ci_windows_install_test_clangcl.cmd delete mode 100755 ci_scripts/ci_windows_test.cmd create mode 100644 include/daw/daw_ascii.h create mode 100644 include/daw/daw_contract.h create mode 100644 include/daw/daw_to_underlying_type.h create mode 100644 tests/daw_ascii_test.cpp create mode 100644 tests/daw_contract_test.cpp diff --git a/.clang-format b/.clang-format index 8a50165c0..6b092066a 100644 --- a/.clang-format +++ b/.clang-format @@ -6,8 +6,9 @@ AlignTrailingComments: true AllowAllParametersOfDeclarationOnNextLine: true AllowShortBlocksOnASingleLine: Always AllowShortCaseLabelsOnASingleLine: false +AllowShortCompoundRequirementOnASingleLine: false AllowShortFunctionsOnASingleLine: Empty -AllowShortIfStatementsOnASingleLine: "false" +AllowShortIfStatementsOnASingleLine: false AllowShortLoopsOnASingleLine: false AlwaysBreakAfterDefinitionReturnType: None AlwaysBreakBeforeMultilineStrings: true @@ -42,7 +43,7 @@ PenaltyBreakString: 1000 PenaltyExcessCharacter: 1000000 PenaltyReturnTypeOnItsOwnLine: 60 PointerAlignment: Right -RequiresClausePosition: OwnLine +RequiresClausePosition: OwnLineWithBrace SpaceAfterCStyleCast: false SpaceAfterTemplateKeyword: false SpaceBeforeAssignmentOperators: true diff --git a/.github/workflows/ci_ubuntu.yml b/.github/workflows/ci_ubuntu.yml index 3fa5d68b9..5d2082aa5 100644 --- a/.github/workflows/ci_ubuntu.yml +++ b/.github/workflows/ci_ubuntu.yml @@ -25,7 +25,7 @@ jobs: cpp_version: [ 17, 20 ] build_type: [ Debug, Release ] os: [ ubuntu-24.04 ] - toolset: [ g++-12, g++-13, clang++-13, clang++-14, clang++-15, clang++-16, clang++-17, clang++-18, clang++-19, clang++-20 ] + toolset: [ g++-12, g++-13, clang++-19, clang++-20 ] exclude: - toolset: g++-12 cpp_version: 20 @@ -43,15 +43,9 @@ jobs: if: endsWith( matrix.os, '24.04' ) run: | sudo wget -O /etc/apt/trusted.gpg.d/llvm.asc https://apt.llvm.org/llvm-snapshot.gpg.key - sudo apt-add-repository 'deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy main' - sudo apt-add-repository 'deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-13 main' - sudo apt-add-repository 'deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-14 main' - sudo apt-add-repository 'deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-15 main' - sudo apt-add-repository 'deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-16 main' - sudo apt-add-repository 'deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-17 main' - sudo apt-add-repository 'deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-18 main' - sudo apt-add-repository 'deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-19 main' - sudo apt-add-repository 'deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-20 main' + sudo apt-add-repository 'deb http://apt.llvm.org/noble/ llvm-toolchain-noble main' + sudo apt-add-repository 'deb http://apt.llvm.org/noble/ llvm-toolchain-noble-19 main' + sudo apt-add-repository 'deb http://apt.llvm.org/noble/ llvm-toolchain-noble-20 main' sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test sudo apt update sudo apt install ninja-build libunwind-dev diff --git a/.github/workflows/ci_windows.yml b/.github/workflows/ci_windows.yml index 74d74c1fd..4e96f8b42 100644 --- a/.github/workflows/ci_windows.yml +++ b/.github/workflows/ci_windows.yml @@ -1,19 +1,72 @@ name: Windows - on: + schedule: + - cron: '10 5 * * *' push: - branches-ignore: dev + branches: [ release, develop ] pull_request: - branches-ignore: dev + push: + branches-ignore: develop + pull_request: + branches-ignore: develop jobs: - build: - runs-on: [windows-2019] + Windows: + permissions: + actions: none + checks: none + contents: none + deployments: none + issues: none + packages: none + pull-requests: none + repository-projects: none + security-events: none + statuses: none + defaults: + run: + shell: cmd + strategy: + fail-fast: false + matrix: + config: + - { cpp_version: 17, build_type: Debug, arch: x64, os: windows-2022, toolset: MSVC, cmake_flags: "-GNinja" } + - { cpp_version: 17, build_type: Release, arch: x64, os: windows-2022, toolset: MSVC, cmake_flags: "-GNinja" } + - { cpp_version: 20, build_type: Debug, arch: x64, os: windows-2022, toolset: MSVC, cmake_flags: "-GNinja" } + - { cpp_version: 20, build_type: Release, arch: x64, os: windows-2022, toolset: MSVC, cmake_flags: "-GNinja" } + - { cpp_version: 17, build_type: Debug, arch: Win32, os: windows-2022, toolset: MSVC, cmake_flags: "-GNinja" } + - { cpp_version: 17, build_type: Release, arch: Win32, os: windows-2022, toolset: MSVC, cmake_flags: "-GNinja" } + - { cpp_version: 20, build_type: Debug, arch: Win32, os: windows-2022, toolset: MSVC, cmake_flags: "-GNinja" } + - { cpp_version: 20, build_type: Release, arch: Win32, os: windows-2022, toolset: MSVC, cmake_flags: "-GNinja" } + - { cpp_version: 23, build_type: Debug, arch: Win32, os: windows-2022, toolset: MSVC, cmake_flags: "-GNinja" } + - { cpp_version: 23, build_type: Release, arch: Win32, os: windows-2022, toolset: MSVC, cmake_flags: "-GNinja" } + - { cpp_version: 23, build_type: Debug, arch: Win32, os: windows-2022, toolset: ClangCL, cmake_flags: " -T ClangCL -DCMAKE_C_COMPILER=clang-cl.exe -DCMAKE_CXX_COMPILER=clang-cl.exe" } + - { cpp_version: 23, build_type: Release, arch: Win32, os: windows-2022, toolset: ClangCL, cmake_flags: " -T ClangCL -DCMAKE_C_COMPILER=clang-cl.exe -DCMAKE_CXX_COMPILER=clang-cl.exe" } + runs-on: ${{ matrix.config.os }} + name: "${{ matrix.config.os }} ${{ matrix.config.toolset }} ${{ matrix.config.cpp_version }} ${{ matrix.config.arch }} ${{ matrix.config.build_type }}" + env: + DAW_BUILD_DIR: "build_${{ matrix.config.cpp_version }}_${{ matrix.config.arch }}_${{ matrix.config.build_type }}_${{ matrix.config.toolset }}" steps: - uses: actions/checkout@v1 + - uses: beached/msvc-dev-cmd@285e7c0b9b57a02c900951da93a77e656425d783 + with: + arch: ${{ matrix.config.arch }} + - name: Setup Build Environment + run: md ${{ env.DAW_BUILD_DIR }} + - name: CMake Config + run: cmake.exe ${{ matrix.config.cmake_flags }} -DCMAKE_BUILD_TYPE=${{ matrix.config.build_type }} -DCMAKE_CXX_STANDARD=${{ matrix.config.cpp_version }} -DDAW_ENABLE_TESTING=On -B${{ env.DAW_BUILD_DIR }}/ . - name: Build - run: .\ci_scripts\ci_windows_build.cmd + run: cmake.exe --build ${{ env.DAW_BUILD_DIR }}/ --target daw-header-libraries_full --config ${{ matrix.config.build_type }} + continue-on-error: true - name: Test - run: .\ci_scripts\ci_windows_test.cmd - - name: InstallTest - run: .\ci_scripts\ci_windows_install_test.cmd + run: ctest.exe -C ${{ matrix.config.build_type }} -j2 -VV --timeout 1200 --test-dir ${{ env.DAW_BUILD_DIR }}/ + - name: Archive any crashes as an artifact + uses: actions/upload-artifact@v4 + if: always( ) + with: + name: crashes + path: | + crash-* + leak-* + timeout-* + if-no-files-found: ignore diff --git a/.github/workflows/ci_windows_clangcl.yml b/.github/workflows/ci_windows_clangcl.yml deleted file mode 100644 index 25a8e13b2..000000000 --- a/.github/workflows/ci_windows_clangcl.yml +++ /dev/null @@ -1,18 +0,0 @@ -name: Windows_ClangCl - -on: - push: - branches-ignore: dev - pull_request: - branches-ignore: dev - -jobs: - build: - runs-on: [windows-2019] - steps: - - uses: actions/checkout@v1 - - name: Build - run: .\ci_scripts\ci_windows_build_clangcl.cmd - - name: Test - run: .\ci_scripts\ci_windows_test.cmd - diff --git a/CMakeLists.txt b/CMakeLists.txt index 0f1b2a525..df2c838a6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,7 +9,7 @@ cmake_minimum_required( VERSION 3.14 ) project( "daw-header-libraries" - VERSION "2.124.1" + VERSION "2.127.0" DESCRIPTION "Various headers" HOMEPAGE_URL "https://github.com/beached/header_libraries" LANGUAGES C CXX diff --git a/ci_scripts/ci_windows_build.cmd b/ci_scripts/ci_windows_build.cmd deleted file mode 100755 index 6ea9172e5..000000000 --- a/ci_scripts/ci_windows_build.cmd +++ /dev/null @@ -1,22 +0,0 @@ -@ECHO OFF - -ECHO "##############################" -ECHO "Installing Ninja" -vcpkg upgrade -REM vcpkg install ninja - -md build -cd build - -ECHO "##############################" -ECHO "Setting VCVars" -@call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" amd64 - -ECHO "##############################" -ECHO "Running cmake" -"C:/PROGRAM FILES (X86)/MICROSOFT VISUAL STUDIO/2019/ENTERPRISE/COMMON7/IDE/COMMONEXTENSIONS/MICROSOFT/CMAKE/CMake/bin/cmake.exe" -DCMAKE_BUILD_TYPE=Debug -GNinja -DCMAKE_CXX_COMPILER=cl.exe -DCMAKE_C_COMPILER=cl.exe -DDAW_ENABLE_TESTING=On .. - - -ECHO "##############################" -ECHO "Building" -"C:/PROGRAM FILES (X86)/MICROSOFT VISUAL STUDIO/2019/ENTERPRISE/COMMON7/IDE/COMMONEXTENSIONS/MICROSOFT/CMAKE/CMake/bin/cmake.exe" --build . --config Debug --target daw-header-libraries_full -j 2 -- -k 1000 diff --git a/ci_scripts/ci_windows_build_clangcl.cmd b/ci_scripts/ci_windows_build_clangcl.cmd deleted file mode 100755 index f0051cda0..000000000 --- a/ci_scripts/ci_windows_build_clangcl.cmd +++ /dev/null @@ -1,16 +0,0 @@ -@ECHO OFF - -md build -cd build - -ECHO "##############################" -ECHO "Setting VCVars" -@call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" amd64 - -ECHO "##############################" -ECHO "Running cmake" -"C:/PROGRAM FILES (X86)/MICROSOFT VISUAL STUDIO/2019/ENTERPRISE/COMMON7/IDE/COMMONEXTENSIONS/MICROSOFT/CMAKE/CMake/bin/cmake.exe" -DCMAKE_BUILD_TYPE=Debug -GNinja -DCMAKE_CXX_COMPILER="C:/Program Files (x86)/Microsoft Visual Studio/2019/Enterprise/VC/Tools/Llvm/x64/bin/clang-cl.exe" -DCMAKE_C_COMPILER="C:/Program Files (x86)/Microsoft Visual Studio/2019/Enterprise/VC/Tools/Llvm/x64/bin/clang-cl.exe" -DDAW_ENABLE_TESTING=On .. - -ECHO "##############################" -ECHO "Building" -"C:/PROGRAM FILES (X86)/MICROSOFT VISUAL STUDIO/2019/ENTERPRISE/COMMON7/IDE/COMMONEXTENSIONS/MICROSOFT/CMAKE/CMake/bin/cmake.exe" --build . --config Debug --target daw-header-libraries_full -j 2 -- -k 1000 diff --git a/ci_scripts/ci_windows_install_test.cmd b/ci_scripts/ci_windows_install_test.cmd deleted file mode 100755 index f2e1595b9..000000000 --- a/ci_scripts/ci_windows_install_test.cmd +++ /dev/null @@ -1,20 +0,0 @@ -@echo off -cd build - - -ECHO "##############################" -ECHO "Setting VCVars" -@call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" amd64 - -echo "#################################" -echo "Starting Install Tests" -cmake --install . -cd ../cmake/test_project/ -md build -cd build -"C:/PROGRAM FILES (X86)/MICROSOFT VISUAL STUDIO/2019/ENTERPRISE/COMMON7/IDE/COMMONEXTENSIONS/MICROSOFT/CMAKE/CMake/bin/cmake.exe" -DCMAKE_BUILD_TYPE=Debug -GNinja -DCMAKE_CXX_COMPILER=cl.exe -DCMAKE_C_COMPILER=cl.exe .. -IF %ERRORLEVEL% NEQ 0 EXIT %ERRORLEVEL% -"C:/PROGRAM FILES (X86)/MICROSOFT VISUAL STUDIO/2019/ENTERPRISE/COMMON7/IDE/COMMONEXTENSIONS/MICROSOFT/CMAKE/CMake/bin/cmake.exe" --build . --config Debug -IF %ERRORLEVEL% NEQ 0 EXIT %ERRORLEVEL% -"C:/PROGRAM FILES (X86)/MICROSOFT VISUAL STUDIO/2019/ENTERPRISE/COMMON7/IDE/COMMONEXTENSIONS/MICROSOFT/CMAKE/CMake/bin/ctest.exe" -C Debug -VV -IF %ERRORLEVEL% NEQ 0 EXIT %ERRORLEVEL% diff --git a/ci_scripts/ci_windows_install_test_clangcl.cmd b/ci_scripts/ci_windows_install_test_clangcl.cmd deleted file mode 100755 index 75e556cd3..000000000 --- a/ci_scripts/ci_windows_install_test_clangcl.cmd +++ /dev/null @@ -1,20 +0,0 @@ -@ECHO OFF - -cd build - -ECHO "##############################" -ECHO "Setting VCVars" -@call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" amd64 - -echo "#################################" -echo "Starting Install Tests" -cmake --install . -cd ../cmake/test_project/ -md build -cd build -"C:/PROGRAM FILES (X86)/MICROSOFT VISUAL STUDIO/2019/ENTERPRISE/COMMON7/IDE/COMMONEXTENSIONS/MICROSOFT/CMAKE/CMake/bin/cmake.exe" -DCMAKE_BUILD_TYPE=Debug -GNinja -DCMAKE_CXX_COMPILER="C:/Program Files (x86)/Microsoft Visual Studio/2019/Enterprise/VC/Tools/Llvm/x64/bin/clang-cl.exe" -DCMAKE_C_COMPILER="C:/Program Files (x86)/Microsoft Visual Studio/2019/Enterprise/VC/Tools/Llvm/x64/bin/clang-cl.exe" .. -IF %ERRORLEVEL% NEQ 0 EXIT %ERRORLEVEL% -"C:/PROGRAM FILES (X86)/MICROSOFT VISUAL STUDIO/2019/ENTERPRISE/COMMON7/IDE/COMMONEXTENSIONS/MICROSOFT/CMAKE/CMake/bin/cmake.exe" --build . --config Debug -IF %ERRORLEVEL% NEQ 0 EXIT %ERRORLEVEL% -"C:/PROGRAM FILES (X86)/MICROSOFT VISUAL STUDIO/2019/ENTERPRISE/COMMON7/IDE/COMMONEXTENSIONS/MICROSOFT/CMAKE/CMake/bin/ctest.exe" -C Debug -VV -IF %ERRORLEVEL% NEQ 0 EXIT %ERRORLEVEL% diff --git a/ci_scripts/ci_windows_test.cmd b/ci_scripts/ci_windows_test.cmd deleted file mode 100755 index 780823aa8..000000000 --- a/ci_scripts/ci_windows_test.cmd +++ /dev/null @@ -1,6 +0,0 @@ -@echo off -cd build - -ECHO "#################################3" -ECHO "Starting Tests" -"C:/PROGRAM FILES (X86)/MICROSOFT VISUAL STUDIO/2019/ENTERPRISE/COMMON7/IDE/COMMONEXTENSIONS/MICROSOFT/CMAKE/CMake/bin/ctest.exe" -C Debug --target daw-header-libraries_full -j 2 -VV --timeout 300 diff --git a/include/daw/daw_ascii.h b/include/daw/daw_ascii.h new file mode 100644 index 000000000..28750ba40 --- /dev/null +++ b/include/daw/daw_ascii.h @@ -0,0 +1,98 @@ +// Copyright (c) Darrell Wright +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/beached/header_libraries +// + +#pragma once + +#include "daw/daw_attributes.h" +#include "daw/daw_cpp_feature_check.h" +#include "daw/impl/daw_make_trait.h" + +#include + +namespace daw { + struct is_ascii_digit_t { + explicit is_ascii_digit_t( ) = default; + + template, + std::nullptr_t> = nullptr> + DAW_ATTRIB_INLINE DAW_CPP23_STATIC_CALL_OP constexpr bool + operator( )( Integer c ) DAW_CPP23_STATIC_CALL_OP_CONST { + // '0' <= c <= '9' + return Integer{ 48 } <= c and c <= Integer{ 57 }; + } + }; + inline constexpr auto is_ascii_digit = is_ascii_digit_t{ }; + + struct is_ascii_alpha_t { + explicit is_ascii_alpha_t( ) = default; + + template, + std::nullptr_t> = nullptr> + DAW_ATTRIB_INLINE DAW_CPP23_STATIC_CALL_OP constexpr bool + operator( )( Integer c ) DAW_CPP23_STATIC_CALL_OP_CONST { + // ( 'A' <= c <= 'Z' ) or ( 'a' <= c <= 'z' ) + return ( Integer{ 65 } <= c and c <= Integer{ 90 } ) or + ( Integer{ 97 } <= c and c <= Integer{ 122 } ); + } + }; + inline constexpr auto is_ascii_alpha = is_ascii_alpha_t{ }; + + struct is_ascii_alphanum_t { + explicit is_ascii_alphanum_t( ) = default; + + template, + std::nullptr_t> = nullptr> + DAW_ATTRIB_INLINE DAW_CPP23_STATIC_CALL_OP constexpr bool + operator( )( Integer c ) DAW_CPP23_STATIC_CALL_OP_CONST { + return is_ascii_digit( c ) or is_ascii_alpha( c ); + } + }; + inline constexpr auto is_ascii_alphanum = is_ascii_alphanum_t{ }; + + struct is_ascii_printable_t { + explicit is_ascii_printable_t( ) = default; + + template, + std::nullptr_t> = nullptr> + DAW_ATTRIB_INLINE DAW_CPP23_STATIC_CALL_OP constexpr bool + operator( )( Integer c ) DAW_CPP23_STATIC_CALL_OP_CONST { + return Integer{ 32 } <= c and c < Integer{ 127 }; + } + }; + inline constexpr auto is_ascii_printable = is_ascii_printable_t{ }; + + struct to_upper_ascii_t { + explicit to_upper_ascii_t( ) = default; + + template, + std::nullptr_t> = nullptr> + DAW_ATTRIB_INLINE DAW_CPP23_STATIC_CALL_OP constexpr Integer + operator( )( Integer c ) DAW_CPP23_STATIC_CALL_OP_CONST { + if( Integer{ 97 } <= c and c <= Integer{ 122 } ) { + return static_cast( c - Integer{ 32 } ); + } + return c; + } + }; + inline constexpr auto to_upper_ascii = to_upper_ascii_t{ }; + + struct to_lower_ascii_t { + explicit to_lower_ascii_t( ) = default; + + template, + std::nullptr_t> = nullptr> + DAW_ATTRIB_INLINE DAW_CPP23_STATIC_CALL_OP constexpr Integer + operator( )( Integer c ) DAW_CPP23_STATIC_CALL_OP_CONST { + if( Integer{ 65 } <= c and c <= Integer{ 90 } ) { + return static_cast( c + Integer{ 32 } ); + } + return c; + } + }; + inline constexpr auto to_lower_ascii = to_lower_ascii_t{ }; +} // namespace daw diff --git a/include/daw/daw_attributes.h b/include/daw/daw_attributes.h index 90486f533..a78491b02 100644 --- a/include/daw/daw_attributes.h +++ b/include/daw/daw_attributes.h @@ -104,7 +104,7 @@ #endif -#if defined( DAW_HAS_MSVC ) +#if defined( DAW_HAS_MSVC_LIKE ) #define DAW_NO_UNIQUE_ADDRESS [[msvc::no_unique_address]] #else #define DAW_NO_UNIQUE_ADDRESS [[no_unique_address]] diff --git a/include/daw/daw_contract.h b/include/daw/daw_contract.h new file mode 100644 index 000000000..05bf33eb6 --- /dev/null +++ b/include/daw/daw_contract.h @@ -0,0 +1,96 @@ +// Copyright (c) Darrell Wright +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/beached/header_libraries +// + +#pragma once + +#include "daw/daw_assume.h" +#include "daw/daw_attributes.h" +#include "daw/daw_check_exceptions.h" +#include "daw/daw_consteval.h" +#include "daw/daw_cpp_feature_check.h" +#include "daw/daw_function_ref.h" + +#include +#include +#include +#include +#include + +namespace daw { +#if defined( DAW_USE_EXCEPTIONS ) + struct daw_contract_violation : std::exception {}; + [[noreturn]] inline void default_contract_failure( ) { + throw daw_contract_violation{ }; + } +#else + [[noreturn]] inline void default_contract_failure( ) { + std::abort( ); + } +#endif + constinit static thread_local daw::function_ref + contract_failure_handler = default_contract_failure; + + DAW_ATTRIB_NOINLINE inline void contract_failure( ) { + contract_failure_handler( ); + } + + template + requires( std::is_invocable_r_v and... ) // + class contract { + T value; + + static constexpr bool validate( T value ) { + return ( Preconditions{ }( value ) and ... ); + } + + public: + DAW_ATTRIB_FLATINLINE constexpr contract( T v ) + : value( std::move( v ) ) { + if( not validate( value ) ) { + contract_failure( ); + } + } + + DAW_ATTRIB_FLATINLINE constexpr T extract( ) { + DAW_ASSUME( validate( value ) ); + return std::move( value ); + } + + DAW_ATTRIB_FLATINLINE constexpr T &operator*( ) { + DAW_ASSUME( validate( value ) ); + return value; + } + + DAW_ATTRIB_FLATINLINE constexpr T const &operator*( ) const { + DAW_ASSUME( validate( value ) ); + return value; + } + + DAW_ATTRIB_FLATINLINE constexpr operator T const &( ) const { + DAW_ASSUME( validate( value ) ); + return value; + } + + template + using add_precondition_t = contract; + + template + DAW_ATTRIB_FLATINLINE constexpr operator contract( ) const { + DAW_ASSUME( validate( value ) ); + return contract( value ); + } + + template + requires( std::is_invocable_r_v and... ) // + constexpr auto add_condition( Pre2s... ) const { + + DAW_ASSUME( validate( value ) ); + return contract{ value }; + } + }; +} // namespace daw diff --git a/include/daw/daw_cxmath.h b/include/daw/daw_cxmath.h index 75add3777..a8321713c 100644 --- a/include/daw/daw_cxmath.h +++ b/include/daw/daw_cxmath.h @@ -463,6 +463,16 @@ namespace daw::cxmath { } } +#if DAW_HAS_BUILTIN( __builtin_clzg ) + template, + std::nullptr_t> = nullptr> + [[nodiscard]] DAW_ATTRIB_INLINE constexpr std::uint32_t + count_leading_zeroes( Unsigned u ) { + return static_cast( + __builtin_clzg( u, static_cast( daw::bit_count_v ) ) ); + } +#else + #if DAW_HAS_BUILTIN( __builtin_clz ) [[nodiscard]] DAW_ATTRIB_INLINE constexpr unsigned count_leading_zeroes( unsigned v ) noexcept { @@ -480,11 +490,6 @@ namespace daw::cxmath { return static_cast( bit_count_v ); } - [[nodiscard]] DAW_ATTRIB_FLATINLINE inline constexpr unsigned - count_leading_zeroes( daw::UInt32 v ) noexcept { - return count_leading_zeroes( static_cast( v ) ); - } - #if DAW_HAS_BUILTIN( __builtin_clzll ) [[nodiscard]] DAW_ATTRIB_INLINE constexpr unsigned count_leading_zeroes( unsigned long long v ) noexcept { @@ -512,11 +517,6 @@ namespace daw::cxmath { #endif - [[nodiscard]] DAW_ATTRIB_FLATINLINE inline constexpr unsigned - count_leading_zeroes( daw::UInt64 v ) noexcept { - return count_leading_zeroes( static_cast( v ) ); - } - #else // Based on code from // https://graphics.stanford.edu/~seander/bithacks.html @@ -542,18 +542,32 @@ namespace daw::cxmath { return 63U - static_cast( bit_position[( v * 0x021'8a39'2cd3'd5dbf ) >> 58U] ); // [3] } +#endif +#if defined( DAW_HAS_INT128 ) + [[nodiscard]] DAW_ATTRIB_FLATTEN constexpr std::uint32_t + count_leading_zeros( daw::uint128_t v ) { + if( v == 0 ) { + return 128U; + } + auto const h = + count_leading_zeros( static_cast( v >> 64ULL ) ); + if( h == 64U ) { + return count_leading_zeros( static_cast( v ) ); + } + return h; + } +#endif +#endif + [[nodiscard]] DAW_ATTRIB_FLATINLINE inline constexpr unsigned + count_leading_zeroes( daw::UInt32 v ) noexcept { + return count_leading_zeroes( static_cast( v ) ); + } - [[nodiscard]] constexpr std::uint32_t + [[nodiscard]] DAW_ATTRIB_FLATINLINE inline constexpr unsigned count_leading_zeroes( daw::UInt64 v ) noexcept { return count_leading_zeroes( static_cast( v ) ); } - [[nodiscard]] constexpr std::uint32_t - count_leading_zeroes( daw::UInt32 v ) noexcept { - return count_leading_zeroes( static_cast( v ) << 32U ); - } -#endif - namespace cxmath_impl { [[nodiscard]] DAW_ATTRIB_INLINE constexpr std::uint32_t count_trailing_zeros_cx32( std::uint32_t v ) noexcept { @@ -1372,9 +1386,11 @@ namespace daw::cxmath { 10'000'000'000'000'000'000ull }; constexpr int count_digits( std::uint64_t value ) { - auto b = -( value > 0 ) & ( 63 - count_leading_zeroes( value ) ); + auto b = -static_cast( value > 0 ) & + ( 63 - count_leading_zeroes( value ) ); auto a = ( b * 77 ) / 256; - return static_cast( 1 + a + ( value >= powers_of_ten[a] ) ); + return static_cast( + 1 + a + static_cast( value >= powers_of_ten[a] ) ); } static_assert( count_digits( 1'000'000ULL ) == 7 ); } // namespace daw::cxmath diff --git a/include/daw/daw_fnv1a_hash.h b/include/daw/daw_fnv1a_hash.h index e7f72642b..462250026 100644 --- a/include/daw/daw_fnv1a_hash.h +++ b/include/daw/daw_fnv1a_hash.h @@ -68,11 +68,12 @@ namespace daw { std::nullptr_t> = nullptr> [[nodiscard]] static constexpr fnv1a_uint_t append_hash( fnv1a_uint_t current_hash, Value const &value ) noexcept { + struct array_t { + unsigned char values[sizeof( Value )]; + }; + auto const chars = DAW_BIT_CAST( array_t, value ); for( fnv1a_uint_t n = 0; n < sizeof( Value ); ++n ) { - current_hash ^= static_cast( - ( static_cast( value ) & - ( fnv1a_uint_t{ 0xFFU } << (n * bit_count_v)) ) >> - (n * bit_count_v)); + current_hash ^= chars.values[n]; current_hash *= fnv1a_impl::fnv_prime; } return current_hash; diff --git a/include/daw/daw_function_ref.h b/include/daw/daw_function_ref.h index 83dd4f4be..7169c3f53 100644 --- a/include/daw/daw_function_ref.h +++ b/include/daw/daw_function_ref.h @@ -84,19 +84,22 @@ namespace daw { constexpr function_ref( Result ( *ptr )( Params... ) ) noexcept : m_data( ptr ) - , m_thunk( fp_thunk ) { + , m_thunk( nullptr ) { assert( ptr ); } constexpr function_ref &operator=( Result ( *ptr )( Params... ) ) noexcept { m_data = ptr; - m_thunk = fp_thunk; + m_thunk = nullptr; assert( ptr ); return *this; } constexpr Result operator( )( Params... params ) const { - return m_thunk( m_data, params... ); + if( not m_thunk ) { + return m_data.func_ptr( std::forward( params )... ); + } + return m_thunk( m_data, std::forward( params )... ); } }; diff --git a/include/daw/daw_read_file.h b/include/daw/daw_read_file.h index c4b7a2440..40b0bd26d 100644 --- a/include/daw/daw_read_file.h +++ b/include/daw/daw_read_file.h @@ -36,10 +36,18 @@ namespace daw { } auto result = std::basic_string( static_cast( fsize ), CharT{ } ); +#if defined( _MSC_VER ) + FILE * f = nullptr; + auto err = fopen_s( &f, path.c_str( ), "rb" ); + if( err ) { + return std::nullopt; + } +#else auto *f = fopen( path.c_str( ), "rb" ); if( not f ) { return std::nullopt; } +#endif auto num_read = fread( result.data( ), sizeof( CharT ), result.size( ), f ); if( num_read != ( result.size( ) / sizeof( CharT ) ) ) { return std::nullopt; @@ -76,8 +84,9 @@ namespace daw { } auto result = std::basic_string( static_cast( fsize ), CharT{ } ); - auto *f = _wfopen( path.c_str( ), L"rb" ); - if( not f ) { + FILE * f = nullptr; + auto err = _wfopen_s( &f, path.c_str( ), L"rb" ); + if( err ) { return std::nullopt; } auto num_read = fread( result.data( ), sizeof( CharT ), result.size( ), f ); diff --git a/include/daw/daw_size_literals.h b/include/daw/daw_size_literals.h index a10d61ae1..9f1cba752 100644 --- a/include/daw/daw_size_literals.h +++ b/include/daw/daw_size_literals.h @@ -8,55 +8,53 @@ #pragma once -#include - namespace daw::size_literals { - [[nodiscard]] constexpr size_t + [[nodiscard]] constexpr unsigned long long operator""_KB( unsigned long long val ) noexcept { return val * 1024ull; } - [[nodiscard]] constexpr size_t + [[nodiscard]] constexpr unsigned long long operator""_MB( unsigned long long val ) noexcept { return val * 1024ull * 1024ull; } - [[nodiscard]] constexpr size_t + [[nodiscard]] constexpr unsigned long long operator""_GB( unsigned long long val ) noexcept { return val * 1024ull * 1024ull * 1024ull; } - [[nodiscard]] constexpr size_t + [[nodiscard]] constexpr unsigned long long operator""_TB( unsigned long long val ) noexcept { return val * 1024ull * 1024ull * 1024ull * 1024ull; } - [[nodiscard]] constexpr size_t + [[nodiscard]] constexpr unsigned long long operator""_PB( unsigned long long val ) noexcept { return val * 1024ull * 1024ull * 1024ull * 1024ull * 1024ull; } - [[nodiscard]] constexpr size_t + [[nodiscard]] constexpr unsigned long long operator""_KiB( unsigned long long val ) noexcept { return val * 1000ull; } - [[nodiscard]] constexpr size_t + [[nodiscard]] constexpr unsigned long long operator""_MiB( unsigned long long val ) noexcept { return val * 1000ull * 1000ull; } - [[nodiscard]] constexpr size_t + [[nodiscard]] constexpr unsigned long long operator""_GiB( unsigned long long val ) noexcept { return val * 1000ull * 1000ull * 1000ull; } - [[nodiscard]] constexpr size_t + [[nodiscard]] constexpr unsigned long long operator""_TiB( unsigned long long val ) noexcept { return val * 1000ull * 1000ull * 1000ull * 1000ull; } - [[nodiscard]] constexpr size_t + [[nodiscard]] constexpr unsigned long long operator""_PiB( unsigned long long val ) noexcept { return val * 1000ull * 1000ull * 1000ull * 1000ull * 1000ull; } diff --git a/include/daw/daw_string_view.h b/include/daw/daw_string_view.h index f3b5da826..b78110e75 100644 --- a/include/daw/daw_string_view.h +++ b/include/daw/daw_string_view.h @@ -536,8 +536,8 @@ namespace daw { /// refer to a constant contiguous sequence of char-like objects with the /// first element of the sequence at position zero. template - struct [[DAW_PREF_NAME( string_view ), - DAW_PREF_NAME( wstring_view )]] basic_string_view { + struct [[DAW_PREF_NAME( string_view ), DAW_PREF_NAME( wstring_view )]] + basic_string_view { using value_type = CharT; using pointer = CharT *; using const_pointer = std::add_const_t *; diff --git a/include/daw/daw_to_underlying_type.h b/include/daw/daw_to_underlying_type.h new file mode 100644 index 000000000..fa72eeec6 --- /dev/null +++ b/include/daw/daw_to_underlying_type.h @@ -0,0 +1,19 @@ +// Copyright (c) Darrell Wright +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/beached/header_libraries +// + +#pragma once + +#include + +namespace daw { + template, std::nullptr_t> = nullptr> + constexpr auto to_underlying( Enum e ) { + return static_cast>( e ); + } +} // namespace daw diff --git a/include/daw/daw_uninitialized_storage.h b/include/daw/daw_uninitialized_storage.h index f69150446..17363d8a4 100644 --- a/include/daw/daw_uninitialized_storage.h +++ b/include/daw/daw_uninitialized_storage.h @@ -39,7 +39,7 @@ namespace daw { void construct( Args &&...args ) noexcept( std::is_nothrow_constructible_v ) { - if constexpr( std::is_aggregate_v ) { + if constexpr( std::is_class_v and std::is_aggregate_v ) { new( m_data ) T{ DAW_FWD( args )... }; } else { new( m_data ) T( std ::forward( args )... ); diff --git a/include/daw/pipelines/enumerate.h b/include/daw/pipelines/enumerate.h index 83a91ea0a..2279da1c3 100644 --- a/include/daw/pipelines/enumerate.h +++ b/include/daw/pipelines/enumerate.h @@ -20,10 +20,9 @@ namespace daw::pipelines::pimpl { template struct Enumerate_t { - template + template [[nodiscard]] DAW_CPP23_STATIC_CALL_OP constexpr auto operator( )( R &&r ) DAW_CPP23_STATIC_CALL_OP_CONST { - static_assert( Range ); return zip_view, daw::remove_cvref_t>( iota_view( 0, max_value ), DAW_FWD( r ) ); } @@ -32,9 +31,8 @@ namespace daw::pipelines::pimpl { template struct EnumerateFrom_t { EnumType offset = EnumType{ }; - template + template [[nodiscard]] constexpr auto operator( )( R &&r ) const { - static_assert( Range ); return zip_view, daw::remove_cvref_t>( iota_view( offset, max_value ), DAW_FWD( r ) ); } @@ -42,7 +40,7 @@ namespace daw::pipelines::pimpl { template struct EnumerateApply_t { - template + template [[nodiscard]] DAW_CPP23_STATIC_CALL_OP constexpr auto operator( )( R &&r ) DAW_CPP23_STATIC_CALL_OP_CONST { if constexpr( RandomRange ) { @@ -59,7 +57,7 @@ namespace daw::pipelines::pimpl { template struct EnumerateApplyFrom_t { EnumType offset = EnumType{ }; - template + template [[nodiscard]] constexpr auto operator( )( R &&r ) const { if constexpr( RandomRange ) { auto const sz = static_cast( diff --git a/include/daw/pipelines/every.h b/include/daw/pipelines/every.h index d94f7c7bc..7c22d7b61 100644 --- a/include/daw/pipelines/every.h +++ b/include/daw/pipelines/every.h @@ -15,11 +15,7 @@ namespace daw::pipelines::pimpl { struct Every_t { std::size_t m_select_every; - template - [[nodiscard]] constexpr auto operator( )( R &&r ) const { - static_assert( Range, - "Every requires the previous algorithm in the pipeline " - "to return a range" ); + [[nodiscard]] constexpr auto operator( )( Range auto &&r ) const { return filter_view{ std::begin( DAW_FWD( r ) ), std::end( DAW_FWD( r ) ), [select_every = m_select_every, n = m_select_every]( auto const & ) mutable { diff --git a/include/daw/pipelines/iota.h b/include/daw/pipelines/iota.h index 3647d192e..6183f0f62 100644 --- a/include/daw/pipelines/iota.h +++ b/include/daw/pipelines/iota.h @@ -177,6 +177,6 @@ namespace daw::pipelines { iota_view( T, T ) -> iota_view; inline constexpr auto ToIota = []( I last ) { - return iota_view{ 0, last }; + return iota_view{ I{}, last }; }; } // namespace daw::pipelines diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 33c02df95..35408eedf 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -21,6 +21,7 @@ set( TEST_SOURCES daw_arith_traits_test.cpp daw_array_compare_test.cpp daw_array_test.cpp + daw_ascii_test.cpp daw_assume_test.cpp daw_attributes_test.cpp daw_benchmark_test.cpp @@ -152,6 +153,7 @@ set( CPP20_TEST_SOURCES ) set( CPP20_NOT_MSVC_TEST_SOURCES + daw_contract_test.cpp daw_pipelines_test.cpp vector_test.cpp ) diff --git a/tests/cmake/test_compiler_options.cmake b/tests/cmake/test_compiler_options.cmake index 34e857bf7..34dde0bb4 100644 --- a/tests/cmake/test_compiler_options.cmake +++ b/tests/cmake/test_compiler_options.cmake @@ -16,6 +16,7 @@ if( ${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang" OR ${CMAKE_CXX_COMPILER_ID} STREQU if( DAW_WERROR ) add_compile_options( /WX ) endif() + add_compile_options( -Wno-missing-braces ) else() message( STATUS "Clang ${CMAKE_CXX_COMPILER_VERSION} detected" ) add_compile_options( diff --git a/tests/daw_ascii_test.cpp b/tests/daw_ascii_test.cpp new file mode 100644 index 000000000..ab65233da --- /dev/null +++ b/tests/daw_ascii_test.cpp @@ -0,0 +1,20 @@ +// Copyright (c) Darrell Wright +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/beached/header_libraries +// + +#include +#include + +int main( ) { + daw_ensure( daw::is_ascii_alpha( 'a' ) ); + daw_ensure( not daw::is_ascii_alpha( '0' ) ); + daw_ensure( daw::is_ascii_digit( '0' ) ); + daw_ensure( not daw::is_ascii_digit( 'a' ) ); + daw_ensure( daw::is_ascii_alphanum( 'a' ) ); + daw_ensure( not daw::is_ascii_alphanum( ' ' ) ); + daw_ensure( daw::is_ascii_printable( '!' ) ); +} \ No newline at end of file diff --git a/tests/daw_contract_test.cpp b/tests/daw_contract_test.cpp new file mode 100644 index 000000000..b6617c5eb --- /dev/null +++ b/tests/daw_contract_test.cpp @@ -0,0 +1,28 @@ +// Copyright (c) Darrell Wright +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/beached/header_libraries +// + +#include +#include + +int main( ) { + using positive_integral = decltype( []( T const &value ) { + return value >= T{ }; + } ); + using pos_int = daw::contract; + static constexpr auto v0 = pos_int( 42 ); + constexpr int const &v0cr = v0; + (void)v0cr; +#if defined( DAW_USE_EXCEPTIONS ) + bool has_error = false; + try { + auto v1 = pos_int{ -1 }; + (void)v1; + } catch( daw::daw_contract_violation const & ) { has_error = true; } + daw_ensure( has_error ); +#endif +} diff --git a/tests/daw_function_ref_test.cpp b/tests/daw_function_ref_test.cpp index a9e1c0673..325610b18 100644 --- a/tests/daw_function_ref_test.cpp +++ b/tests/daw_function_ref_test.cpp @@ -34,7 +34,7 @@ inline constexpr int add( int a, int b, int c ) { } DAW_CONSTEVAL void test2( ) { - auto const r = func( add ); + constexpr auto const r = func( add ); daw_ensure( r == 96 ); } diff --git a/tests/daw_size_literals_test.cpp b/tests/daw_size_literals_test.cpp index ae6b95542..be0b27f69 100644 --- a/tests/daw_size_literals_test.cpp +++ b/tests/daw_size_literals_test.cpp @@ -13,8 +13,8 @@ namespace daw_size_literals_001 { static_assert( 1_KB == 1024ull ); static_assert( 1_MB == 1024ull * 1024u ); static_assert( 1_GB == 1024ull * 1024u * 1024u ); - static_assert( 1_TB == 1024ull * 1024u * 1024u * 1024u ); - static_assert( 1_PB == 1024ull * 1024u * 1024u * 1024u * 1024u ); + static_assert( 1_TB == 1024ull * 1024ull * 1024ull * 1024ull ); + static_assert( 1_PB == 1024ull * 1024ull * 1024ull * 1024ull * 1024ull ); } // namespace daw_size_literals_001 int main( ) {}