From e3f9a3408643886e8faaac0a3fd7839470859726 Mon Sep 17 00:00:00 2001 From: Randalphwa <38287198+Randalphwa@users.noreply.github.com> Date: Mon, 30 Mar 2026 19:42:44 -0700 Subject: [PATCH 1/9] Add support for sccache --- CMakeLists.txt | 14 ++++++++++++++ 1 file changed, 14 insertions(+) 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 From 41cfb1c4adf99e8723bfc88609be33fc4346ca1c Mon Sep 17 00:00:00 2001 From: Randalphwa <38287198+Randalphwa@users.noreply.github.com> Date: Mon, 30 Mar 2026 19:54:04 -0700 Subject: [PATCH 2/9] Switch to #pragma once instead of conditional guards MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Every compiler that supports C++23 supports #pragma once — GCC, Clang, MSVC, and Intel have all supported it for well over a decade. --- include/frozen/algorithm.h | 5 +---- include/frozen/bits/algorithms.h | 5 +---- include/frozen/bits/basic_types.h | 5 +---- include/frozen/bits/constexpr_assert.h | 5 +---- include/frozen/bits/defines.h | 5 +---- include/frozen/bits/elsa.h | 5 +---- include/frozen/bits/elsa_std.h | 5 +---- include/frozen/bits/exceptions.h | 5 +---- include/frozen/bits/hash_string.h | 5 +---- include/frozen/bits/mpl.h | 5 +---- include/frozen/bits/pmh.h | 5 +---- include/frozen/bits/version.h | 5 +---- include/frozen/map.h | 6 ++---- include/frozen/random.h | 5 +---- include/frozen/set.h | 6 ++---- include/frozen/string.h | 8 +------- include/frozen/unordered_map.h | 5 +---- include/frozen/unordered_set.h | 6 ++---- 18 files changed, 21 insertions(+), 75 deletions(-) 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..26c8ddb 100644 --- a/include/frozen/bits/hash_string.h +++ b/include/frozen/bits/hash_string.h @@ -1,5 +1,4 @@ -#ifndef FROZEN_LETITGO_BITS_HASH_STRING_H -#define FROZEN_LETITGO_BITS_HASH_STRING_H +#pragma once #include @@ -27,5 +26,3 @@ namespace frozen } } // 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..7441f21 100644 --- a/include/frozen/bits/pmh.h +++ b/include/frozen/bits/pmh.h @@ -21,8 +21,7 @@ */ // 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" @@ -282,5 +281,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..473af37 100644 --- a/include/frozen/string.h +++ b/include/frozen/string.h @@ -1,5 +1,4 @@ -#ifndef FROZEN_LETITGO_STRING_H -#define FROZEN_LETITGO_STRING_H +#pragma once // Require C++23 or later #if defined(_MSVC_LANG) @@ -10,12 +9,9 @@ #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" #include "frozen/bits/version.h" #include -#include #include namespace frozen @@ -58,5 +54,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 From 9dc86e817693b2c67aeef18bba4b0b78f73dbdc4 Mon Sep 17 00:00:00 2001 From: Randalphwa <38287198+Randalphwa@users.noreply.github.com> Date: Mon, 30 Mar 2026 20:05:46 -0700 Subject: [PATCH 3/9] Remove unused header --- include/frozen/bits/pmh.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/frozen/bits/pmh.h b/include/frozen/bits/pmh.h index 7441f21..7591886 100644 --- a/include/frozen/bits/pmh.h +++ b/include/frozen/bits/pmh.h @@ -26,7 +26,6 @@ #include "frozen/bits/algorithms.h" #include "frozen/bits/basic_types.h" -#include #include #include #include From 3ad9ad71fb97f044da9fb28fbcbe8391e2776606 Mon Sep 17 00:00:00 2001 From: Randalphwa <38287198+Randalphwa@users.noreply.github.com> Date: Mon, 30 Mar 2026 20:06:24 -0700 Subject: [PATCH 4/9] Remove duplicate compiler check Check is in version.h --- include/frozen/string.h | 9 --------- 1 file changed, 9 deletions(-) diff --git a/include/frozen/string.h b/include/frozen/string.h index 473af37..71ad52d 100644 --- a/include/frozen/string.h +++ b/include/frozen/string.h @@ -1,14 +1,5 @@ #pragma once -// 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/version.h" #include From bc1b2fe98e68b3e4cfc162bdef2b64b733dc377b Mon Sep 17 00:00:00 2001 From: Randalphwa <38287198+Randalphwa@users.noreply.github.com> Date: Mon, 30 Mar 2026 20:06:53 -0700 Subject: [PATCH 5/9] Change variable names, replace magic numbers for clarity --- include/frozen/bits/hash_string.h | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/include/frozen/bits/hash_string.h b/include/frozen/bits/hash_string.h index 26c8ddb..f35ecbb 100644 --- a/include/frozen/bits/hash_string.h +++ b/include/frozen/bits/hash_string.h @@ -4,14 +4,24 @@ 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 @@ -19,10 +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 From b8aea5f8af6595f9fee5ec051495d1fb82586681 Mon Sep 17 00:00:00 2001 From: Randalphwa <38287198+Randalphwa@users.noreply.github.com> Date: Mon, 30 Mar 2026 20:17:05 -0700 Subject: [PATCH 6/9] Fix broken Windows CI check --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 }} From 72a2080188ba4403e538d0ca5d9a937b72c372d9 Mon Sep 17 00:00:00 2001 From: Randalphwa <38287198+Randalphwa@users.noreply.github.com> Date: Mon, 30 Mar 2026 20:29:10 -0700 Subject: [PATCH 7/9] Fix Windows CI build error Added /wd4018 alongside the existing /wd4307 in the MSVC test compile options. This suppresses the signed/unsigned warning from MSVC's system headers while leaving all other diagnostics intact. --- tests/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 60a439a..abfa5fe 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>" "$<$" ",$" ",$>" From 2b5ea5e11bf01245ca4bf990b3764820836e8995 Mon Sep 17 00:00:00 2001 From: Randalphwa <38287198+Randalphwa@users.noreply.github.com> Date: Mon, 30 Mar 2026 20:55:00 -0700 Subject: [PATCH 8/9] Fix hang in Windows CI test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Root cause: On Windows, std::abort() triggers two things that hang headless CI: CRT abort message box — a dialog requesting user input Windows Error Reporting (Watson/WER) — attempts to phone home and/or show a crash dialog The SIGABRT signal handler never fires because MSVC's abort() hits the dialog first. Fixes in no_exceptions.cpp: _set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT) — suppresses both the CRT dialog and WER, letting abort() proceed cleanly to the signal handler _CrtSetReportMode(_CRT_ASSERT/_CRT_ERROR, _CRTDBG_MODE_DEBUG) — redirects any Debug CRT assertions to the debugger (no-op in CI) instead of popping dialogs --- tests/no_exceptions.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) 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 {}; From 378b7576656e222fe94a6c9fe45ac2951df9a3e5 Mon Sep 17 00:00:00 2001 From: Randalphwa <38287198+Randalphwa@users.noreply.github.com> Date: Mon, 30 Mar 2026 20:55:44 -0700 Subject: [PATCH 9/9] Add timeout to prevent tests from hanging CI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added TIMEOUT 10 to the test properties — if anything still hangs on any platform, CTest will kill it after 10 seconds instead of blocking forever --- tests/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index abfa5fe..5f0f3b0 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -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)