diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ef3b5f2..3850ad9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -47,7 +47,7 @@ jobs: cmake -B build -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_STANDARD=23 - -Dfrozen.tests=ON + "-Dfrozen.tests=ON" -DCMAKE_VERBOSE_MAKEFILE=ON ${{ matrix.cmake_args }} diff --git a/CMakeLists.txt b/CMakeLists.txt index 8c01481..fcffc18 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,6 +22,20 @@ include(CTest) include(GNUInstallDirs) include(cmake/detect_cxx_version.cmake) +# ###################### sccache ####################### +find_program(SCCACHE_PROGRAM sccache) +if(SCCACHE_PROGRAM) + message(STATUS "sccache found: ${SCCACHE_PROGRAM}") + set(CMAKE_C_COMPILER_LAUNCHER "${SCCACHE_PROGRAM}") + set(CMAKE_CXX_COMPILER_LAUNCHER "${SCCACHE_PROGRAM}") +else() + message(STATUS "sccache not found; building without a compiler cache") +endif() + +if(MSVC) + set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT "$<$:Embedded>") +endif() + # # The `frozen.testing`, `frozen.benchmark`, and `frozen.coverage` options # only appear as cmake-gui and ccmake options iff frozen is the highest diff --git a/include/frozen/algorithm.h b/include/frozen/algorithm.h index ffcbcc9..a538f7c 100644 --- a/include/frozen/algorithm.h +++ b/include/frozen/algorithm.h @@ -20,8 +20,7 @@ * under the License. */ -#ifndef FROZEN_LETITGO_ALGORITHM_H -#define FROZEN_LETITGO_ALGORITHM_H +#pragma once // Require C++23 or later #if defined(_MSVC_LANG) @@ -270,5 +269,3 @@ namespace frozen } } // namespace frozen - -#endif diff --git a/include/frozen/bits/algorithms.h b/include/frozen/bits/algorithms.h index 50d2eec..310c31d 100644 --- a/include/frozen/bits/algorithms.h +++ b/include/frozen/bits/algorithms.h @@ -20,8 +20,7 @@ * under the License. */ -#ifndef FROZEN_LETITGO_BITS_ALGORITHMS_H -#define FROZEN_LETITGO_BITS_ALGORITHMS_H +#pragma once #include "frozen/bits/basic_types.h" @@ -266,5 +265,3 @@ namespace frozen::bits } } // namespace frozen::bits - -#endif diff --git a/include/frozen/bits/basic_types.h b/include/frozen/bits/basic_types.h index e1bf0d4..817908f 100644 --- a/include/frozen/bits/basic_types.h +++ b/include/frozen/bits/basic_types.h @@ -20,8 +20,7 @@ * under the License. */ -#ifndef FROZEN_LETITGO_BASIC_TYPES_H -#define FROZEN_LETITGO_BASIC_TYPES_H +#pragma once #include "frozen/bits/constexpr_assert.h" #include "frozen/bits/exceptions.h" @@ -247,5 +246,3 @@ namespace frozen::bits }; } // namespace frozen::bits - -#endif diff --git a/include/frozen/bits/constexpr_assert.h b/include/frozen/bits/constexpr_assert.h index 95543f3..d69c25f 100644 --- a/include/frozen/bits/constexpr_assert.h +++ b/include/frozen/bits/constexpr_assert.h @@ -20,8 +20,7 @@ * under the License. */ -#ifndef FROZEN_LETITGO_CONSTEXPR_ASSERT_H -#define FROZEN_LETITGO_CONSTEXPR_ASSERT_H +#pragma once #include #include @@ -29,5 +28,3 @@ inline void constexpr_assert_failed() {} #define constexpr_assert(cond, msg) ((void) ((cond) ? 0 : (constexpr_assert_failed(), 0))) - -#endif diff --git a/include/frozen/bits/defines.h b/include/frozen/bits/defines.h index d9aa2d1..c3f6740 100644 --- a/include/frozen/bits/defines.h +++ b/include/frozen/bits/defines.h @@ -20,8 +20,7 @@ * under the License. */ -#ifndef FROZEN_LETITGO_DEFINES_H -#define FROZEN_LETITGO_DEFINES_H +#pragma once // C++23 guarantees all previously-detected features: // - string_view (C++17) @@ -31,5 +30,3 @@ // The feature-detection macros have been removed. This header // is here only for backward compatibility to the original // frozen implementation. - -#endif // FROZEN_LETITGO_DEFINES_H diff --git a/include/frozen/bits/elsa.h b/include/frozen/bits/elsa.h index c07ccfd..f26b3a9 100644 --- a/include/frozen/bits/elsa.h +++ b/include/frozen/bits/elsa.h @@ -20,8 +20,7 @@ * under the License. */ -#ifndef FROZEN_LETITGO_ELSA_H -#define FROZEN_LETITGO_ELSA_H +#pragma once #include #include @@ -64,5 +63,3 @@ namespace frozen template using anna = elsa; } // namespace frozen - -#endif diff --git a/include/frozen/bits/elsa_std.h b/include/frozen/bits/elsa_std.h index 84bcad6..f2640f0 100644 --- a/include/frozen/bits/elsa_std.h +++ b/include/frozen/bits/elsa_std.h @@ -1,5 +1,4 @@ -#ifndef FROZEN_LETITGO_BITS_ELSA_STD_H -#define FROZEN_LETITGO_BITS_ELSA_STD_H +#pragma once #include "elsa.h" #include "hash_string.h" @@ -39,5 +38,3 @@ namespace frozen }; } // namespace frozen - -#endif // FROZEN_LETITGO_BITS_ELSA_STD_H diff --git a/include/frozen/bits/exceptions.h b/include/frozen/bits/exceptions.h index 9c71346..86db84f 100644 --- a/include/frozen/bits/exceptions.h +++ b/include/frozen/bits/exceptions.h @@ -20,8 +20,7 @@ * under the License. */ -#ifndef FROZEN_LETITGO_EXCEPTIONS_H -#define FROZEN_LETITGO_EXCEPTIONS_H +#pragma once #if defined(FROZEN_NO_EXCEPTIONS) || (defined(_MSC_VER) && !defined(_CPPUNWIND)) || \ (!defined(_MSC_VER) && !defined(__cpp_exceptions)) @@ -35,5 +34,3 @@ #define FROZEN_THROW_OR_ABORT(err) throw err #endif - -#endif diff --git a/include/frozen/bits/hash_string.h b/include/frozen/bits/hash_string.h index 43ee83c..f35ecbb 100644 --- a/include/frozen/bits/hash_string.h +++ b/include/frozen/bits/hash_string.h @@ -1,18 +1,27 @@ -#ifndef FROZEN_LETITGO_BITS_HASH_STRING_H -#define FROZEN_LETITGO_BITS_HASH_STRING_H +#pragma once #include namespace frozen { + // djb2 hash constants + constexpr std::size_t djb2_initial = 5381; + constexpr std::size_t djb2_multiplier = 33; + + // FNV-1 hash constants (32-bit) + constexpr std::size_t fnv_offset_basis = 0x811c9dc5; + constexpr std::size_t fnv_prime = 0x01000193; + constexpr std::size_t fnv_shift_bits = 8; template constexpr std::size_t hash_string(const String& value) { - std::size_t d = 5381; - for (const auto& c: value) - d = d * 33 + static_cast(c); - return d; + std::size_t hash = djb2_initial; + for (const auto& chr: value) + { + hash = (hash * djb2_multiplier) + static_cast(chr); + } + return hash; } // https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function @@ -20,12 +29,12 @@ namespace frozen template constexpr std::size_t hash_string(const String& value, std::size_t seed) { - std::size_t d = (0x811c9dc5 ^ seed) * static_cast(0x01000193); - for (const auto& c: value) - d = (d ^ static_cast(c)) * static_cast(0x01000193); - return d >> 8; + std::size_t hash = (fnv_offset_basis ^ seed) * static_cast(fnv_prime); + for (const auto& chr: value) + { + hash = (hash ^ static_cast(chr)) * static_cast(fnv_prime); + } + return hash >> fnv_shift_bits; } } // namespace frozen - -#endif // FROZEN_LETITGO_BITS_HASH_STRING_H diff --git a/include/frozen/bits/mpl.h b/include/frozen/bits/mpl.h index 1f405b2..7f0d808 100644 --- a/include/frozen/bits/mpl.h +++ b/include/frozen/bits/mpl.h @@ -20,8 +20,7 @@ * under the License. */ -#ifndef FROZEN_LETITGO_BITS_MPL_H -#define FROZEN_LETITGO_BITS_MPL_H +#pragma once #include @@ -53,5 +52,3 @@ namespace frozen::bits using remove_cv_t = typename remove_cv::type; } // namespace frozen::bits - -#endif diff --git a/include/frozen/bits/pmh.h b/include/frozen/bits/pmh.h index e7864be..7591886 100644 --- a/include/frozen/bits/pmh.h +++ b/include/frozen/bits/pmh.h @@ -21,13 +21,11 @@ */ // inspired from http://stevehanov.ca/blog/index.php?id=119 -#ifndef FROZEN_LETITGO_PMH_H -#define FROZEN_LETITGO_PMH_H +#pragma once #include "frozen/bits/algorithms.h" #include "frozen/bits/basic_types.h" -#include #include #include #include @@ -282,5 +280,3 @@ namespace frozen::bits } } // namespace frozen::bits - -#endif diff --git a/include/frozen/bits/version.h b/include/frozen/bits/version.h index cc6f1e7..a6278df 100644 --- a/include/frozen/bits/version.h +++ b/include/frozen/bits/version.h @@ -20,8 +20,7 @@ * under the License. */ -#ifndef FROZEN_LETITGO_VERSION_H -#define FROZEN_LETITGO_VERSION_H +#pragma once // Require C++23 or later #if defined(_MSVC_LANG) @@ -35,5 +34,3 @@ #define FROZEN_MAJOR_VERSION 2 #define FROZEN_MINOR_VERSION 0 #define FROZEN_PATCH_VERSION 0 - -#endif diff --git a/include/frozen/map.h b/include/frozen/map.h index dc203c9..733b51a 100644 --- a/include/frozen/map.h +++ b/include/frozen/map.h @@ -20,8 +20,7 @@ * under the License. */ -#ifndef FROZEN_LETITGO_MAP_H -#define FROZEN_LETITGO_MAP_H +#pragma once // Require C++23 or later #if defined(_MSVC_LANG) @@ -38,6 +37,7 @@ #include "frozen/bits/mpl.h" #include "frozen/bits/version.h" +#include #include #include @@ -456,5 +456,3 @@ namespace frozen } } // namespace frozen - -#endif diff --git a/include/frozen/random.h b/include/frozen/random.h index 5a57c35..1d41232 100644 --- a/include/frozen/random.h +++ b/include/frozen/random.h @@ -20,8 +20,7 @@ * under the License. */ -#ifndef FROZEN_LETITGO_RANDOM_H -#define FROZEN_LETITGO_RANDOM_H +#pragma once // Require C++23 or later #if defined(_MSVC_LANG) @@ -104,5 +103,3 @@ namespace frozen using default_prg_t = minstd_rand; } // namespace frozen - -#endif diff --git a/include/frozen/set.h b/include/frozen/set.h index 184e202..2ee4195 100644 --- a/include/frozen/set.h +++ b/include/frozen/set.h @@ -20,8 +20,7 @@ * under the License. */ -#ifndef FROZEN_SET_H -#define FROZEN_SET_H +#pragma once // Require C++23 or later #if defined(_MSVC_LANG) @@ -36,6 +35,7 @@ #include "frozen/bits/basic_types.h" #include "frozen/bits/version.h" +#include #include #include @@ -315,5 +315,3 @@ namespace frozen set(T, Args...) -> set; } // namespace frozen - -#endif diff --git a/include/frozen/string.h b/include/frozen/string.h index 560fc6f..71ad52d 100644 --- a/include/frozen/string.h +++ b/include/frozen/string.h @@ -1,21 +1,8 @@ -#ifndef FROZEN_LETITGO_STRING_H -#define FROZEN_LETITGO_STRING_H - -// Require C++23 or later -#if defined(_MSVC_LANG) - #if _MSVC_LANG < 202302L - #error "frozen/string.h requires C++23 or later. Compile with /std:c++latest or /std:c++23." - #endif -#elif __cplusplus < 202302L - #error "frozen/string.h requires C++23 or later. Compile with -std=c++23 or later." -#endif - -#include "frozen/bits/elsa.h" -#include "frozen/bits/hash_string.h" +#pragma once + #include "frozen/bits/version.h" #include -#include #include namespace frozen @@ -58,5 +45,3 @@ namespace frozen } // namespace string_literals } // namespace frozen - -#endif diff --git a/include/frozen/unordered_map.h b/include/frozen/unordered_map.h index 4fadde8..cacea20 100644 --- a/include/frozen/unordered_map.h +++ b/include/frozen/unordered_map.h @@ -20,8 +20,7 @@ * under the License. */ -#ifndef FROZEN_LETITGO_UNORDERED_MAP_H -#define FROZEN_LETITGO_UNORDERED_MAP_H +#pragma once // Require C++23 or later #if defined(_MSVC_LANG) @@ -253,5 +252,3 @@ namespace frozen } } // namespace frozen - -#endif diff --git a/include/frozen/unordered_set.h b/include/frozen/unordered_set.h index 5d7236f..4d19112 100644 --- a/include/frozen/unordered_set.h +++ b/include/frozen/unordered_set.h @@ -20,8 +20,7 @@ * under the License. */ -#ifndef FROZEN_LETITGO_UNORDERED_SET_H -#define FROZEN_LETITGO_UNORDERED_SET_H +#pragma once // Require C++23 or later #if defined(_MSVC_LANG) @@ -39,6 +38,7 @@ #include "frozen/bits/version.h" #include "frozen/random.h" +#include #include namespace frozen @@ -211,5 +211,3 @@ namespace frozen unordered_set(T, Args...) -> unordered_set; } // namespace frozen - -#endif diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 60a439a..5f0f3b0 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -25,7 +25,7 @@ target_sources(frozen.tests PRIVATE string(CONCAT generator # msvc gives invalid integral overflow warning for unsigned type - "$<$:/W3;/WX;/wd4307>" + "$<$:/W3;/WX;/wd4307;/wd4018>" "$<$" ",$" ",$>" @@ -57,4 +57,4 @@ target_compile_options(test_no_expections PUBLIC $<$>:-fno-exceptions>) add_test(no_exceptions test_no_expections) -set_tests_properties(no_exceptions PROPERTIES WILL_FAIL TRUE) +set_tests_properties(no_exceptions PROPERTIES WILL_FAIL TRUE TIMEOUT 10) diff --git a/tests/no_exceptions.cpp b/tests/no_exceptions.cpp index fd5e0b0..2db89b2 100644 --- a/tests/no_exceptions.cpp +++ b/tests/no_exceptions.cpp @@ -3,6 +3,10 @@ #include #include +#ifdef _MSC_VER + #include +#endif + // https://discourse.cmake.org/t/tests-that-are-meant-to-abort/537/3 // This is a hack to implement death tests in CTest. extern "C" void error_test_handle_abort(int) @@ -12,7 +16,17 @@ extern "C" void error_test_handle_abort(int) struct test_override_abort { - test_override_abort() noexcept { std::signal(SIGABRT, error_test_handle_abort); } + test_override_abort() noexcept + { +#ifdef _MSC_VER + // Prevent abort() from showing a dialog or invoking Windows Error + // Reporting — either of which hangs headless CI environments. + _set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT); + _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG); + _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG); +#endif + std::signal(SIGABRT, error_test_handle_abort); + } }; test_override_abort handler {};