From a1a4f054d79a1a01833475d770f33665fb030ffd Mon Sep 17 00:00:00 2001 From: Ray Hamel Date: Sun, 30 May 2021 19:40:09 -0400 Subject: [PATCH 1/6] Optimize error message printing And allow the error message printing function to be configured by the user. In particular, stdio functions may not be safe to call if the user has called std::ios_base::sync_with_stdio(false) . --- include/cjdb/contracts.hpp | 71 +++++++++++++++++++++++++++++--------- 1 file changed, 55 insertions(+), 16 deletions(-) diff --git a/include/cjdb/contracts.hpp b/include/cjdb/contracts.hpp index b13c846..dae50e4 100644 --- a/include/cjdb/contracts.hpp +++ b/include/cjdb/contracts.hpp @@ -4,10 +4,48 @@ #ifndef CJDB_CONTRACTS_HPP #define CJDB_CONTRACTS_HPP -#include -#include +#include #include +#ifdef _MSC_VER + #define CJDB_PRETTY_FUNCTION __FUNCSIG__ + #define CJDB_FORCE_INLINE __forceinline +#else + #define CJDB_PRETTY_FUNCTION __PRETTY_FUNCTION__ + #define CJDB_FORCE_INLINE [[gnu::always_inline]] inline +#endif // _MSC_VER + +#ifndef CJDB_PRINT_ERROR + #ifdef CJDB_USE_STDIO + #include + + namespace cjdb::contracts_detail { + struct print_error_fn { + template + CJDB_FORCE_INLINE void operator()(char const(&message)[N]) const noexcept + { + std::fwrite(message, sizeof(char), N - 1, stderr); + } + }; + inline constexpr auto print_error = print_error_fn{}; + } // namespace cjdb::contracts_detail + #else + #include + + namespace cjdb::contracts_detail { + struct print_error_fn { + template + CJDB_FORCE_INLINE void operator()(char const(&message)[N]) const noexcept + try { + std::cerr.write(message, N - 1); + } catch(...) {} + }; + inline constexpr auto print_error = print_error_fn{}; + } // namespace cjdb::contracts_detail + #endif // CJDB_USE_STDIO + #define CJDB_PRINT_ERROR(MESSAGE) ::cjdb::contracts_detail::print_error(MESSAGE) +#endif // CJDB_PRINT_ERROR + // clang-tidy doesn't yet support this // // #ifndef __cpp_lib_is_constant_evaluated @@ -18,28 +56,30 @@ #define CJDB_ASSERT(...) CJDB_CONTRACT_IMPL("assertion", __VA_ARGS__) #define CJDB_ENSURES(...) CJDB_CONTRACT_IMPL("post-condition", __VA_ARGS__) -#ifdef _MSC_VER - #define CJDB_PRETTY_FUNCTION __FUNCSIG__ -#else - #define CJDB_PRETTY_FUNCTION __PRETTY_FUNCTION__ -#endif // _MSC_VER - namespace cjdb::contracts_detail { #ifdef NDEBUG - inline constexpr auto is_debug = false; + inline constexpr bool is_debug = false; #else - inline constexpr auto is_debug = true; + inline constexpr bool is_debug = true; #endif // NDEBUG struct contract_impl_fn { + template constexpr void operator()(bool const result, - std::string_view const message, - std::string_view const function) const noexcept + char const(&message)[N1], + char const(&function)[N2]) const noexcept { - if (not result) { + if (not result) [[unlikely]] { if (not std::is_constant_evaluated()) { if constexpr (is_debug) { - std::fprintf(stderr, "%s in `%s`\n", message.data(), function.data()); + constexpr auto& suffix = "`\n"; + constexpr auto message_size = N1 - 1, function_size = N2 - 1; + char full_message[message_size + function_size + sizeof suffix]; + auto p = full_message; + std::memcpy(p, message, message_size); + std::memcpy(p += message_size, function, function_size); + std::memcpy(p += function_size, suffix, sizeof suffix); + CJDB_PRINT_ERROR(full_message); } } #ifdef _MSC_VER @@ -69,10 +109,9 @@ namespace cjdb::contracts_detail { #define CJDB_CONTRACT_IMPL(CJDB_KIND, ...) \ ::cjdb::contracts_detail::contract_impl(::cjdb::contracts_detail::matches_bool(__VA_ARGS__), \ - __FILE__ ":" CJDB_TO_STRING(__LINE__) ": " CJDB_KIND " `" #__VA_ARGS__ "` failed", \ + __FILE__ ":" CJDB_TO_STRING(__LINE__) ": " CJDB_KIND " `" #__VA_ARGS__ "` failed in `", \ CJDB_PRETTY_FUNCTION) - #define CJDB_TO_STRING(CJDB_STRING) CJDB_TO_STRING_IMPL(CJDB_STRING) #define CJDB_TO_STRING_IMPL(CJDB_STRING) #CJDB_STRING From 0e660373e0bd80007701533d21f1ad9c54871bfe Mon Sep 17 00:00:00 2001 From: Ray Hamel Date: Sun, 30 May 2021 20:13:45 -0400 Subject: [PATCH 2/6] Fix GCC-9 error due to uninitialized array --- include/cjdb/contracts.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/cjdb/contracts.hpp b/include/cjdb/contracts.hpp index dae50e4..fb30abf 100644 --- a/include/cjdb/contracts.hpp +++ b/include/cjdb/contracts.hpp @@ -74,7 +74,7 @@ namespace cjdb::contracts_detail { if constexpr (is_debug) { constexpr auto& suffix = "`\n"; constexpr auto message_size = N1 - 1, function_size = N2 - 1; - char full_message[message_size + function_size + sizeof suffix]; + char full_message[message_size + function_size + sizeof suffix]{}; auto p = full_message; std::memcpy(p, message, message_size); std::memcpy(p += message_size, function, function_size); From 28132fe7780ce7249dbbb7c7b956378d45a58c18 Mon Sep 17 00:00:00 2001 From: Ray Hamel Date: Sun, 30 May 2021 20:20:07 -0400 Subject: [PATCH 3/6] Fix warnings-as-errors --- include/cjdb/contracts.hpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/include/cjdb/contracts.hpp b/include/cjdb/contracts.hpp index fb30abf..2e56a97 100644 --- a/include/cjdb/contracts.hpp +++ b/include/cjdb/contracts.hpp @@ -34,10 +34,10 @@ namespace cjdb::contracts_detail { struct print_error_fn { - template + template CJDB_FORCE_INLINE void operator()(char const(&message)[N]) const noexcept try { - std::cerr.write(message, N - 1); + std::cerr.write(message, static_cast(N) - 1); } catch(...) {} }; inline constexpr auto print_error = print_error_fn{}; @@ -73,7 +73,9 @@ namespace cjdb::contracts_detail { if (not std::is_constant_evaluated()) { if constexpr (is_debug) { constexpr auto& suffix = "`\n"; - constexpr auto message_size = N1 - 1, function_size = N2 - 1; + constexpr auto message_size = N1 - 1; + constexpr auto function_size = N2 - 1; + // NOLINTNEXTLINE(modernize-avoid-c-arrays) char full_message[message_size + function_size + sizeof suffix]{}; auto p = full_message; std::memcpy(p, message, message_size); From 3f05a0165a3bd17e1777d346ec7e405cbda0ca02 Mon Sep 17 00:00:00 2001 From: Ray Hamel Date: Sun, 30 May 2021 20:25:12 -0400 Subject: [PATCH 4/6] More clang-tidy suppression --- include/cjdb/contracts.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/cjdb/contracts.hpp b/include/cjdb/contracts.hpp index 2e56a97..9f0282e 100644 --- a/include/cjdb/contracts.hpp +++ b/include/cjdb/contracts.hpp @@ -21,7 +21,7 @@ namespace cjdb::contracts_detail { struct print_error_fn { - template + template // NOLINTNEXTLINE(modernize-avoid-c-arrays) CJDB_FORCE_INLINE void operator()(char const(&message)[N]) const noexcept { std::fwrite(message, sizeof(char), N - 1, stderr); @@ -34,7 +34,7 @@ namespace cjdb::contracts_detail { struct print_error_fn { - template + template // NOLINTNEXTLINE(modernize-avoid-c-arrays) CJDB_FORCE_INLINE void operator()(char const(&message)[N]) const noexcept try { std::cerr.write(message, static_cast(N) - 1); @@ -66,8 +66,8 @@ namespace cjdb::contracts_detail { struct contract_impl_fn { template constexpr void operator()(bool const result, - char const(&message)[N1], - char const(&function)[N2]) const noexcept + char const(&message)[N1], // NOLINT(modernize-avoid-c-arrays) + char const(&function)[N2]) const noexcept // NOLINT(modernize-avoid-c-arrays) { if (not result) [[unlikely]] { if (not std::is_constant_evaluated()) { From c30de9df924cdf128df92823aa0f9e7e2e9707d7 Mon Sep 17 00:00:00 2001 From: Ray Hamel Date: Sun, 30 May 2021 20:33:53 -0400 Subject: [PATCH 5/6] Suppress weird "suspicious semicolon"(??) clang-tidy warning Unless I'm missing something, this appears to be a bug in clang-tidy. --- include/cjdb/contracts.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/cjdb/contracts.hpp b/include/cjdb/contracts.hpp index 9f0282e..f99dc4a 100644 --- a/include/cjdb/contracts.hpp +++ b/include/cjdb/contracts.hpp @@ -71,7 +71,7 @@ namespace cjdb::contracts_detail { { if (not result) [[unlikely]] { if (not std::is_constant_evaluated()) { - if constexpr (is_debug) { + if constexpr (is_debug) { // NOLINT(bugprone-suspicious-semicolon) constexpr auto& suffix = "`\n"; constexpr auto message_size = N1 - 1; constexpr auto function_size = N2 - 1; From d449aa9e1c5f9bae7a6f3affa97622866ce5487a Mon Sep 17 00:00:00 2001 From: Ray Hamel Date: Sun, 30 May 2021 20:40:16 -0400 Subject: [PATCH 6/6] Suppress more weird clang-tidy warnings on same line It seems to be confused by "if constexpr" --- include/cjdb/contracts.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/cjdb/contracts.hpp b/include/cjdb/contracts.hpp index f99dc4a..e0ca735 100644 --- a/include/cjdb/contracts.hpp +++ b/include/cjdb/contracts.hpp @@ -71,7 +71,7 @@ namespace cjdb::contracts_detail { { if (not result) [[unlikely]] { if (not std::is_constant_evaluated()) { - if constexpr (is_debug) { // NOLINT(bugprone-suspicious-semicolon) + if constexpr (is_debug) { // NOLINT constexpr auto& suffix = "`\n"; constexpr auto message_size = N1 - 1; constexpr auto function_size = N2 - 1;