diff --git a/CMakeLists.txt b/CMakeLists.txt index c4d4aad5..89728fb4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,7 +25,7 @@ include(cmake/string_catalog.cmake) add_versioned_package("gh:boostorg/mp11#boost-1.83.0") fmt_recipe(11.1.3) add_versioned_package("gh:intel/cpp-baremetal-concurrency#7c5b26c") -add_versioned_package("gh:intel/cpp-std-extensions#7725142") +add_versioned_package("gh:intel/cpp-std-extensions#01be679") add_versioned_package("gh:intel/cpp-baremetal-senders-and-receivers#0525974") set(GEN_STR_CATALOG diff --git a/include/log/log.hpp b/include/log/log.hpp index d96b53c5..77678290 100644 --- a/include/log/log.hpp +++ b/include/log/log.hpp @@ -9,6 +9,9 @@ #include #include #include +#if __cpp_pack_indexing < 202311L +#include +#endif #include #include @@ -74,14 +77,57 @@ static auto log(TArgs &&...args) -> void { #define CIB_ERROR(...) \ CIB_LOG_WITH_LEVEL(logging::level::ERROR __VA_OPT__(, ) __VA_ARGS__) +namespace logging::detail { +template +[[nodiscard]] constexpr auto panic(F file, L line, auto &&...args) { + STDX_PRAGMA(diagnostic push) +#ifdef __clang__ + STDX_PRAGMA(diagnostic ignored "-Wunknown-warning-option") + STDX_PRAGMA(diagnostic ignored "-Wc++26-extensions") +#endif + + constexpr auto N = stdx::num_fmt_specifiers; + constexpr auto sz = sizeof...(args); + using env_t = + stdx::extend_env_t; + +#if __cpp_pack_indexing >= 202311L + auto s = [&](std::index_sequence) { + return stdx::ct_format(FWD(args...[Is])...); + }(std::make_index_sequence{}); + logging::log(file, line, s); + + [&](std::index_sequence) { + stdx::panic(std::move(s).args, + FWD(args...[N + Is])...); + }(std::make_index_sequence{}); +#else + auto tup = stdx::make_tuple(FWD(args)...); + auto t = [&]( + std::index_sequence, std::index_sequence) { + return stdx::make_tuple( + stdx::make_tuple(stdx::get(std::move(tup))...), + stdx::make_tuple(stdx::get(std::move(tup))...)); + }(std::make_index_sequence{}, std::make_index_sequence{}); + + auto s = stdx::get<0>(std::move(t)).apply([](auto &&...fmt_args) { + return stdx::ct_format(FWD(fmt_args)...); + }); + logging::log(file, line, s); + + stdx::get<1>(std::move(t)).apply([&](auto &&...extra_args) { + stdx::panic(std::move(s).args, + FWD(extra_args)...); + }); +#endif + + STDX_PRAGMA(diagnostic pop) +} +} // namespace logging::detail + #define CIB_FATAL(MSG, ...) \ - [](auto &&s) { \ - CIB_LOG_ENV(logging::get_level, logging::level::FATAL); \ - logging::log(__FILE__, __LINE__, s); \ - FWD(s).args.apply([](auto &&...args) { \ - stdx::panic(FWD(args)...); \ - }); \ - }(stdx::ct_format(__VA_ARGS__)) + logging::detail::panic( \ + __FILE__, __LINE__ __VA_OPT__(, ) __VA_ARGS__) #define CIB_ASSERT(expr) \ ((expr) ? void(0) : CIB_FATAL("Assertion failure: " #expr)) diff --git a/test/log/log.cpp b/test/log/log.cpp index 62517fda..c28a2459 100644 --- a/test/log/log.cpp +++ b/test/log/log.cpp @@ -3,19 +3,21 @@ #include #include +#include #include #include +#include #include -#include #include #include +#include namespace { bool panicked{}; std::string_view expected_why{}; -std::optional expected_arg{}; +std::any expected_args{}; struct injected_handler { template @@ -24,11 +26,11 @@ struct injected_handler { CAPTURE(s); CHECK(s.ends_with(expected_why)); panicked = true; - if (expected_arg) { - CHECK(sizeof...(Args) == 1); - if constexpr (sizeof...(Args) == 1) { - CHECK(*expected_arg == (args, ...)); - } + + if (expected_args.has_value()) { + using expected_t = std::tuple...>; + CHECK(std::any_cast(expected_args) == + std::make_tuple(args...)); } } }; @@ -38,7 +40,7 @@ std::string buffer{}; auto reset_test_state() { panicked = false; expected_why = {}; - expected_arg.reset(); + expected_args.reset(); buffer.clear(); } } // namespace @@ -88,7 +90,7 @@ TEST_CASE("CIB_FATAL pre-formats arguments passed to panic", "[log]") { TEST_CASE("CIB_FATAL can format stack arguments", "[log]") { reset_test_state(); expected_why = "Hello {}"; - expected_arg = 42; + expected_args = std::make_tuple(stdx::make_tuple(42)); auto x = 42; CIB_FATAL("Hello {}", x); @@ -96,3 +98,15 @@ TEST_CASE("CIB_FATAL can format stack arguments", "[log]") { CHECK(buffer.find("Hello 42") != std::string::npos); CHECK(panicked); } + +TEST_CASE("CIB_FATAL passes extra arguments to panic", "[log]") { + reset_test_state(); + expected_why = "Hello {}"; + expected_args = std::make_tuple(stdx::make_tuple(42), 17); + + auto x = 42; + CIB_FATAL("Hello {}", x, 17); + CAPTURE(buffer); + CHECK(buffer.find("Hello 42") != std::string::npos); + CHECK(panicked); +}