From d314fd6bf1149308c09cef31c58b370cf52bb903 Mon Sep 17 00:00:00 2001 From: Darrell Wright Date: Wed, 2 Sep 2026 15:17:04 -0400 Subject: [PATCH 1/6] Removed message from daw_json_ensure_exception as the stringification was triggering MSVC issues --- include/daw/daw_ensure.h | 90 ++++++++++++++++++++-------------------- 1 file changed, 44 insertions(+), 46 deletions(-) diff --git a/include/daw/daw_ensure.h b/include/daw/daw_ensure.h index bd5340769..97f7a0b24 100644 --- a/include/daw/daw_ensure.h +++ b/include/daw/daw_ensure.h @@ -44,9 +44,7 @@ namespace daw::ensure { extern void ensure_compile_error( bool ); #endif - struct daw_ensure_exception { - std::string_view msg; - }; + struct daw_ensure_exception {}; } // namespace daw::ensure #if defined( DAW_HAS_IS_CONSTANT_EVALUATED ) @@ -60,7 +58,7 @@ namespace daw::ensure { do { \ if( DAW_ENSURE_IS_CONSTANT_EVAL( ) ) { \ if( not( __VA_ARGS__ ) ) { \ - throw ::daw::ensure::daw_ensure_exception{ "" #__VA_ARGS__ }; \ + throw ::daw::ensure::daw_ensure_exception{ }; \ } \ } else { \ if( auto daw_ensure_bool_test = static_cast( __VA_ARGS__ ); \ @@ -79,56 +77,56 @@ namespace daw::ensure { #if not defined( NDEBUG ) #define daw_dbg_ensure( ... ) daw_ensure( __VA_ARGS__ ) #else -#define daw_dbg_ensure( ... ) \ - do { \ - if( DAW_ENSURE_IS_CONSTANT_EVAL( ) ) { \ - if( not( __VA_ARGS__ ) ) { \ - throw ::daw::ensure::daw_ensure_exception{ "" #__VA_ARGS__ }; \ - } \ - } else { \ - if( __builtin_constant_p( __VA_ARGS__ ) ) { \ - if( not( __VA_ARGS__ ) ) { \ - ::daw::ensure::ensure_compile_error( not( __VA_ARGS__ ) ); \ - } \ - } \ - } \ +#define daw_dbg_ensure( ... ) \ + do { \ + if( DAW_ENSURE_IS_CONSTANT_EVAL( ) ) { \ + if( not( __VA_ARGS__ ) ) { \ + throw ::daw::ensure::daw_ensure_exception{ }; \ + } \ + } else { \ + if( __builtin_constant_p( __VA_ARGS__ ) ) { \ + if( not( __VA_ARGS__ ) ) { \ + ::daw::ensure::ensure_compile_error( not( __VA_ARGS__ ) ); \ + } \ + } \ + } \ } while( false ) #endif #else -#define daw_ensure( ... ) \ - do { \ - if( DAW_ENSURE_IS_CONSTANT_EVAL( ) ) { \ - if( not( __VA_ARGS__ ) ) { \ - throw ::daw::ensure::daw_ensure_exception{ "" #__VA_ARGS__ }; \ - } \ - } else { \ - if( not( __VA_ARGS__ ) ) { \ - ::daw::ensure::ensure_error( not( __VA_ARGS__ ) ); \ - } \ - } \ +#define daw_ensure( ... ) \ + do { \ + if( DAW_ENSURE_IS_CONSTANT_EVAL( ) ) { \ + if( not( __VA_ARGS__ ) ) { \ + throw ::daw::ensure::daw_ensure_exception{ }; \ + } \ + } else { \ + if( not( __VA_ARGS__ ) ) { \ + ::daw::ensure::ensure_error( not( __VA_ARGS__ ) ); \ + } \ + } \ } while( false ) #if not defined( NDEBUG ) -#define daw_dbg_ensure( ... ) \ - do { \ - if( DAW_ENSURE_IS_CONSTANT_EVAL( ) ) { \ - if( not( __VA_ARGS__ ) ) { \ - throw ::daw::ensure::daw_ensure_exception{ "" #__VA_ARGS__ }; \ - } \ - } else { \ - if( not( __VA_ARGS__ ) ) { \ - ::daw::ensure::ensure_error( not( __VA_ARGS__ ) ); \ - } \ - } \ +#define daw_dbg_ensure( ... ) \ + do { \ + if( DAW_ENSURE_IS_CONSTANT_EVAL( ) ) { \ + if( not( __VA_ARGS__ ) ) { \ + throw ::daw::ensure::daw_ensure_exception{ }; \ + } \ + } else { \ + if( not( __VA_ARGS__ ) ) { \ + ::daw::ensure::ensure_error( not( __VA_ARGS__ ) ); \ + } \ + } \ } while( false ) #else -#define daw_dbg_ensure( ... ) \ - do { \ - if( DAW_ENSURE_IS_CONSTANT_EVAL( ) ) { \ - if( not( __VA_ARGS__ ) ) { \ - throw ::daw::ensure::daw_ensure_exception{ "" #__VA_ARGS__ }; \ - } \ - } \ +#define daw_dbg_ensure( ... ) \ + do { \ + if( DAW_ENSURE_IS_CONSTANT_EVAL( ) ) { \ + if( not( __VA_ARGS__ ) ) { \ + throw ::daw::ensure::daw_ensure_exception{ }; \ + } \ + } \ } while( false ) #endif #endif From 23bc521bd3973b333f4af4b58d03a1cd989281b4 Mon Sep 17 00:00:00 2001 From: Darrell Wright Date: Wed, 2 Sep 2026 21:18:02 -0400 Subject: [PATCH 2/6] `daw_ensure` with no longer use exceptions but will call the error handler and terminate by default. This works at compile time too. Updated dbg_ensure to do this too --- include/daw/daw_ensure.h | 88 ++++++++++++++------------------------- tests/daw_ensure_test.cpp | 12 ------ 2 files changed, 31 insertions(+), 69 deletions(-) diff --git a/include/daw/daw_ensure.h b/include/daw/daw_ensure.h index 97f7a0b24..57e191939 100644 --- a/include/daw/daw_ensure.h +++ b/include/daw/daw_ensure.h @@ -43,8 +43,6 @@ namespace daw::ensure { [[gnu::error( "Ensure check failed at compile time" )]] extern void ensure_compile_error( bool ); #endif - - struct daw_ensure_exception {}; } // namespace daw::ensure #if defined( DAW_HAS_IS_CONSTANT_EVALUATED ) @@ -54,79 +52,55 @@ namespace daw::ensure { #endif #if not defined( DAW_NO_OPT_TIME_ENSURE ) and defined( DAW_HAS_GCC_LIKE ) -#define daw_ensure( ... ) \ - do { \ - if( DAW_ENSURE_IS_CONSTANT_EVAL( ) ) { \ - if( not( __VA_ARGS__ ) ) { \ - throw ::daw::ensure::daw_ensure_exception{ }; \ - } \ - } else { \ - if( auto daw_ensure_bool_test = static_cast( __VA_ARGS__ ); \ - __builtin_constant_p( daw_ensure_bool_test ) ) { \ - if( not( daw_ensure_bool_test ) ) { \ - ::daw::ensure::ensure_compile_error( not( __VA_ARGS__ ) ); \ - } \ - } else { \ - if( not( daw_ensure_bool_test ) ) { \ - ::daw::ensure::ensure_error( not( __VA_ARGS__ ) ); \ - } \ - } \ - } \ +#define daw_ensure( ... ) \ + do { \ + if( auto daw_ensure_bool_test = static_cast( __VA_ARGS__ ); \ + __builtin_constant_p( daw_ensure_bool_test ) ) { \ + if( not( daw_ensure_bool_test ) ) { \ + ::daw::ensure::ensure_compile_error( not( __VA_ARGS__ ) ); \ + } \ + } else { \ + if( not( daw_ensure_bool_test ) ) { \ + ::daw::ensure::ensure_error( not( __VA_ARGS__ ) ); \ + } \ + } \ } while( false ) #if not defined( NDEBUG ) #define daw_dbg_ensure( ... ) daw_ensure( __VA_ARGS__ ) #else -#define daw_dbg_ensure( ... ) \ - do { \ - if( DAW_ENSURE_IS_CONSTANT_EVAL( ) ) { \ - if( not( __VA_ARGS__ ) ) { \ - throw ::daw::ensure::daw_ensure_exception{ }; \ - } \ - } else { \ - if( __builtin_constant_p( __VA_ARGS__ ) ) { \ - if( not( __VA_ARGS__ ) ) { \ - ::daw::ensure::ensure_compile_error( not( __VA_ARGS__ ) ); \ - } \ - } \ - } \ +#define daw_dbg_ensure( ... ) \ + do { \ + if( __builtin_constant_p( __VA_ARGS__ ) ) { \ + if( not( __VA_ARGS__ ) ) { \ + ::daw::ensure::ensure_compile_error( not( __VA_ARGS__ ) ); \ + } \ + } \ } while( false ) #endif #else -#define daw_ensure( ... ) \ - do { \ - if( DAW_ENSURE_IS_CONSTANT_EVAL( ) ) { \ - if( not( __VA_ARGS__ ) ) { \ - throw ::daw::ensure::daw_ensure_exception{ }; \ - } \ - } else { \ - if( not( __VA_ARGS__ ) ) { \ - ::daw::ensure::ensure_error( not( __VA_ARGS__ ) ); \ - } \ - } \ +#define daw_ensure( ... ) \ + do { \ + if( not( __VA_ARGS__ ) ) { \ + ::daw::ensure::ensure_error( not( __VA_ARGS__ ) ); \ + } \ } while( false ) #if not defined( NDEBUG ) +#define daw_dbg_ensure( ... ) \ + do { \ + if( not( __VA_ARGS__ ) ) { \ + ::daw::ensure::ensure_error( not( __VA_ARGS__ ) ); \ + } \ + } while( false ) +#else #define daw_dbg_ensure( ... ) \ do { \ if( DAW_ENSURE_IS_CONSTANT_EVAL( ) ) { \ - if( not( __VA_ARGS__ ) ) { \ - throw ::daw::ensure::daw_ensure_exception{ }; \ - } \ - } else { \ if( not( __VA_ARGS__ ) ) { \ ::daw::ensure::ensure_error( not( __VA_ARGS__ ) ); \ } \ } \ } while( false ) -#else -#define daw_dbg_ensure( ... ) \ - do { \ - if( DAW_ENSURE_IS_CONSTANT_EVAL( ) ) { \ - if( not( __VA_ARGS__ ) ) { \ - throw ::daw::ensure::daw_ensure_exception{ }; \ - } \ - } \ - } while( false ) #endif #endif diff --git a/tests/daw_ensure_test.cpp b/tests/daw_ensure_test.cpp index 798dedd62..3bef18b88 100644 --- a/tests/daw_ensure_test.cpp +++ b/tests/daw_ensure_test.cpp @@ -19,18 +19,6 @@ namespace { static_assert( constant_evaluation_success( ) ); -#if defined( __cpp_constexpr_exceptions ) and \ - __cpp_constexpr_exceptions >= 202411L - constexpr bool constant_evaluation_failure( bool condition ) { - try { - daw_ensure( condition ); - } catch( ... ) { return true; } - return false; - } - - static_assert( constant_evaluation_failure( false ) ); -#endif - DAW_ATTRIB_NOINLINE void runtime_check( bool condition ) { daw_ensure( condition ); } From 036e4e9acb8b862ed82ef5c640a18fac23afbe3a Mon Sep 17 00:00:00 2001 From: Darrell Wright Date: Thu, 3 Sep 2026 01:26:26 -0400 Subject: [PATCH 3/6] Improve feature detection macros and refine `daw_ensure` for better compile-time checks and GCC attribute handling. --- include/daw/daw_attributes.h | 10 ++++++++-- include/daw/daw_ensure.h | 4 ++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/include/daw/daw_attributes.h b/include/daw/daw_attributes.h index e995596c9..723fbac8d 100644 --- a/include/daw/daw_attributes.h +++ b/include/daw/daw_attributes.h @@ -14,7 +14,12 @@ #ifdef __has_cpp_attribute #define DAW_HAS_ATTRIBUTE( Attrib ) __has_cpp_attribute( Attrib ) #else -#define DAW_HAS_ATTRIBUTE( Attrib ) false +#define DAW_HAS_ATTRIBUTE( Attrib ) 0 +#defien __has_cpp_attribute( Attrib ) 0 +#endif + +#ifndef __has_attribute +#define __has_attribute( Attrib ) 0 #endif #if DAW_HAS_ATTRIBUTE( clang::lifetimebound ) @@ -148,6 +153,7 @@ #if defined( DAW_HAS_CLANG ) #if __has_attribute( enable_if ) -#define DAW_ATTRIB_ENABLE_IF(...) __attribute__((enable_if(__VA_ARGS__))) +#define DAW_ATTRIB_ENABLE_IF( ... ) \ + __attribute__( ( enable_if( __VA_ARGS__ ) ) ) #endif #endif \ No newline at end of file diff --git a/include/daw/daw_ensure.h b/include/daw/daw_ensure.h index 57e191939..420c9646f 100644 --- a/include/daw/daw_ensure.h +++ b/include/daw/daw_ensure.h @@ -39,7 +39,7 @@ namespace daw::ensure { } #endif -#if defined( DAW_HAS_GCC_LIKE ) +#if __has_attribute( error ) [[gnu::error( "Ensure check failed at compile time" )]] extern void ensure_compile_error( bool ); #endif @@ -51,7 +51,7 @@ namespace daw::ensure { #define DAW_ENSURE_IS_CONSTANT_EVAL( ) false #endif -#if not defined( DAW_NO_OPT_TIME_ENSURE ) and defined( DAW_HAS_GCC_LIKE ) +#if not defined( DAW_NO_OPT_TIME_ENSURE ) and __has_attribute( error ) #define daw_ensure( ... ) \ do { \ if( auto daw_ensure_bool_test = static_cast( __VA_ARGS__ ); \ From 100baac4cfc72918c6d03f8ef443cd4cf02a948e Mon Sep 17 00:00:00 2001 From: Darrell Wright Date: Thu, 3 Sep 2026 11:14:27 -0400 Subject: [PATCH 4/6] Refine `DAW_LIKELY` and `DAW_UNLIKELY` macros to respect `DAW_NOLIKELY` and simplify fallback definitions. --- include/daw/daw_likely.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/daw/daw_likely.h b/include/daw/daw_likely.h index 51a49ccd8..6731e6b8b 100644 --- a/include/daw/daw_likely.h +++ b/include/daw/daw_likely.h @@ -10,15 +10,15 @@ #include "daw_cpp_feature_check.h" -#if DAW_HAS_BUILTIN( __builtin_expect ) +#if not defined( DAW_NOLIKELY ) and DAW_HAS_BUILTIN( __builtin_expect ) #define DAW_LIKELY( ... ) ( __builtin_expect( !!( __VA_ARGS__ ), 1 ) ) #define DAW_UNLIKELY( ... ) ( __builtin_expect( !!( __VA_ARGS__ ), 0 ) ) #else -#define DAW_LIKELY( ... ) !!( __VA_ARGS__ ) -#define DAW_UNLIKELY( ... ) !!( __VA_ARGS__ ) +#define DAW_LIKELY( ... ) __VA_ARGS__ +#define DAW_UNLIKELY( ... ) __VA_ARGS__ #endif #if __has_cpp_attribute( likely ) From edd989b6e52961addaac0408ba418914675fabff Mon Sep 17 00:00:00 2001 From: Darrell Wright Date: Thu, 3 Sep 2026 11:17:44 -0400 Subject: [PATCH 5/6] Fix typo in `DAW_NO_LIKELY` macro definition guard --- include/daw/daw_likely.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/daw/daw_likely.h b/include/daw/daw_likely.h index 6731e6b8b..c2d72e101 100644 --- a/include/daw/daw_likely.h +++ b/include/daw/daw_likely.h @@ -10,7 +10,7 @@ #include "daw_cpp_feature_check.h" -#if not defined( DAW_NOLIKELY ) and DAW_HAS_BUILTIN( __builtin_expect ) +#if not defined( DAW_NO_LIKELY ) and DAW_HAS_BUILTIN( __builtin_expect ) #define DAW_LIKELY( ... ) ( __builtin_expect( !!( __VA_ARGS__ ), 1 ) ) #define DAW_UNLIKELY( ... ) ( __builtin_expect( !!( __VA_ARGS__ ), 0 ) ) From f1e1873e30f91340238272dbf1a1b0b72dddc911 Mon Sep 17 00:00:00 2001 From: Darrell Wright Date: Thu, 3 Sep 2026 11:28:04 -0400 Subject: [PATCH 6/6] Refine debug and precondition check macros for improved readability and consistency, and adjust zero-terminated string view constructors accordingly. --- include/daw/daw_string_view.h | 69 +++++++++++++++++++---------------- 1 file changed, 37 insertions(+), 32 deletions(-) diff --git a/include/daw/daw_string_view.h b/include/daw/daw_string_view.h index 1a12a5adf..46cd3abe3 100644 --- a/include/daw/daw_string_view.h +++ b/include/daw/daw_string_view.h @@ -56,12 +56,13 @@ #define DAW_STRING_VIEW_DBG_RNG_CHECK( Bool, ... ) \ do { \ } while( false ) -#elif not defined( NDEBUG ) or defined( DEBUG ) -#define DAW_STRING_VIEW_DBG_RNG_CHECK( Bool, ... ) \ - if( DAW_UNLIKELY( not( Bool ) ) ) { \ - DAW_THROW_OR_TERMINATE( std::out_of_range, __VA_ARGS__ ); \ - } \ - do { \ +#elif not defined( DAW_NO_SV_CHECKS ) and not defined( NDEBUG ) or \ + defined( DEBUG ) +#define DAW_STRING_VIEW_DBG_RNG_CHECK( Bool, ... ) \ + do { \ + if( DAW_UNLIKELY( not( Bool ) ) ) { \ + DAW_THROW_OR_TERMINATE( std::out_of_range, __VA_ARGS__ ); \ + } \ } while( false ) #else #define DAW_STRING_VIEW_DBG_RNG_CHECK( Bool, ... ) \ @@ -69,13 +70,14 @@ } while( false ) #endif -#if not defined( NDEBUG ) or defined( DEBUG ) -#define DAW_STRING_VIEW_DBG_ZERO_CHECK( ) \ - if( DAW_UNLIKELY( *( f + static_cast( l ) ) != \ - CharT{ } ) ) { \ - DAW_THROW_OR_TERMINATE_NA( std::exception ); \ - } \ - do { \ +#if not defined( DAW_NO_SV_CHECKS ) and not defined( NDEBUG ) or \ + defined( DEBUG ) +#define DAW_STRING_VIEW_DBG_ZERO_CHECK( ) \ + do { \ + if( DAW_UNLIKELY( *( f + static_cast( l ) ) != \ + CharT{ } ) ) { \ + DAW_THROW_OR_TERMINATE_NA( std::exception ); \ + } \ } while( false ) #else #define DAW_STRING_VIEW_DBG_ZERO_CHECK( ) \ @@ -83,19 +85,20 @@ } while( false ) #endif -#if not defined( DAW_NO_STRING_VIEW_PRECOND_CHECKS ) +#if not defined( DAW_NO_SV_CHECKS ) and \ + not defined( DAW_NO_STRING_VIEW_PRECOND_CHECKS ) #define DAW_STRING_VIEW_PRECOND_CHECK( Bool, ... ) \ - if( DAW_UNLIKELY( not( Bool ) ) ) { \ - std::terminate( ); \ - } \ do { \ + if( DAW_UNLIKELY( not( Bool ) ) ) { \ + std::terminate( ); \ + } \ } while( false ) -#define DAW_STRING_VIEW_RNG_CHECK( Bool, ... ) \ - if( DAW_UNLIKELY( not( Bool ) ) ) { \ - DAW_THROW_OR_TERMINATE( std::out_of_range, __VA_ARGS__ ); \ - } \ - do { \ +#define DAW_STRING_VIEW_RNG_CHECK( Bool, ... ) \ + do { \ + if( DAW_UNLIKELY( not( Bool ) ) ) { \ + DAW_THROW_OR_TERMINATE( std::out_of_range, __VA_ARGS__ ); \ + } \ } while( false ) #else #define DAW_STRING_VIEW_PRECOND_CHECK( Bool, ... ) \ @@ -107,16 +110,16 @@ } while( false ) #endif -#if not defined( NDEBUG ) +#if not defined( DAW_NO_SV_CHECKS ) and not defined( NDEBUG ) #define DAW_DBG_STRING_VIEW_PRECOND_CHECK( Bool, ... ) \ - if( DAW_UNLIKELY( not( Bool ) ) ) { \ - std::terminate( ); \ - } \ - do { \ + do { \ + if( DAW_UNLIKELY( not( Bool ) ) ) { \ + std::terminate( ); \ + } \ } while( false ) #else #define DAW_DBG_STRING_VIEW_PRECOND_CHECK( Bool, ... ) \ - do { \ + do { \ } while( false ) #endif @@ -687,8 +690,8 @@ namespace daw { /// string_view DAW_ATTRIB_INLINE constexpr basic_string_view( std::nullptr_t, size_type n ) { - DAW_DBG_STRING_VIEW_PRECOND_CHECK( n == 0, - "nullptr can only form an empty range" ); + DAW_DBG_STRING_VIEW_PRECOND_CHECK( + n == 0, "nullptr can only form an empty range" ); (void)n; } @@ -703,7 +706,8 @@ namespace daw { const_pointer s DAW_LIFETIME_BOUND, size_type count ) noexcept : m_first( s ) , m_last( count ) { - DAW_DBG_STRING_VIEW_PRECOND_CHECK( s != nullptr or count == 0, "When s is null, count must be zero" ); + DAW_DBG_STRING_VIEW_PRECOND_CHECK( + s != nullptr or count == 0, "When s is null, count must be zero" ); } /// @brief Construct a zero terminated string_view @@ -718,7 +722,8 @@ namespace daw { zero_terminated_t ) noexcept : m_first( s ) , m_last( count ) { - DAW_DBG_PRECONDITION_CHECK( s != nullptr or count == 0, "[s, s+counbt) must be a valid range" ); + DAW_DBG_PRECONDITION_CHECK( s != nullptr or count == 0, + "[s, s+counbt) must be a valid range" ); m_last = set_zero_terminated( m_first, m_last ); }