diff --git a/include/boost/leaf/common.hpp b/include/boost/leaf/common.hpp index 284a302f..44c154cb 100644 --- a/include/boost/leaf/common.hpp +++ b/include/boost/leaf/common.hpp @@ -11,6 +11,7 @@ #include #include +#include #if BOOST_LEAF_CFG_STD_STRING # include @@ -57,7 +58,7 @@ struct BOOST_LEAF_SYMBOL_VISIBLE e_errno template friend std::ostream & operator<<(std::basic_ostream & os, e_errno const & err) { - return print_type_str(os) << err.value << ", \"" << std::strerror(err.value) << '"'; + return os << parse_name() << ": " << err.value << ", \"" << std::strerror(err.value) << '"'; } }; @@ -101,7 +102,7 @@ namespace windows *--z = 0; if( z[-1] == '\r' ) *--z = 0; - return print_type_str(os) << err.value << ", \"" << (LPCSTR)mb.p << '"'; + return os << parse_name() << ": " << err.value << ", \"" << (LPCSTR)mb.p << '"'; } return os; } diff --git a/include/boost/leaf/config.hpp b/include/boost/leaf/config.hpp index 7b7c6cea..46308345 100644 --- a/include/boost/leaf/config.hpp +++ b/include/boost/leaf/config.hpp @@ -120,6 +120,16 @@ //////////////////////////////////////// +#ifndef BOOST_LEAF_PRETTY_FUNCTION +# if defined(_MSC_VER) && !defined(__clang__) && !defined(__GNUC__) +# define BOOST_LEAF_PRETTY_FUNCTION __FUNCSIG__ +# else +# define BOOST_LEAF_PRETTY_FUNCTION __PRETTY_FUNCTION__ +# endif +#endif + +//////////////////////////////////////// + // Configure BOOST_LEAF_NO_EXCEPTIONS, unless already #defined #ifndef BOOST_LEAF_NO_EXCEPTIONS diff --git a/include/boost/leaf/detail/demangle.hpp b/include/boost/leaf/detail/demangle.hpp index f1ded0c0..b0cf0a50 100644 --- a/include/boost/leaf/detail/demangle.hpp +++ b/include/boost/leaf/detail/demangle.hpp @@ -18,81 +18,139 @@ #include #include -#include namespace boost { namespace leaf { namespace leaf_detail { - template - BOOST_LEAF_CONSTEXPR inline int check_prefix(char const * t, char const (&prefix)[N]) noexcept + template = S2> + struct cpp11_prefix { - return std::strncmp(t, prefix, sizeof(prefix)-1) == 0 ? sizeof(prefix) - 1 : 0; + constexpr static bool check(char const (&)[S1], char const (&)[S2]) noexcept + { + return false; + } + }; + template + struct cpp11_prefix + { + constexpr static bool check(char const (&str)[S1], char const (&prefix)[S2]) noexcept + { + return str[I] == prefix[I] && cpp11_prefix::check(str, prefix); + } + }; + template + struct cpp11_prefix + { + constexpr static bool check(char const (&str)[S1], char const (&prefix)[S2]) noexcept + { + return str[0] == prefix[0]; + } + }; + template + constexpr int check_prefix(char const (&str)[S1], char const (&prefix)[S2]) noexcept + { + return cpp11_prefix::check(str, prefix) ? S2 - 1 : 0; } -} -template -inline char const * type_str() -{ -#if defined(__clang__) - BOOST_LEAF_ASSERT(leaf_detail::check_prefix(__PRETTY_FUNCTION__, "const char *boost::leaf::type_str() [Name = ") == 44); - return __PRETTY_FUNCTION__ + 44; -#elif defined(__GNUC__) - BOOST_LEAF_ASSERT(leaf_detail::check_prefix(__PRETTY_FUNCTION__, "const char* boost::leaf::type_str() [with Name = ") == 49); - return __PRETTY_FUNCTION__ + 49; -#elif defined _MSC_VER - if( char const * p = std::strstr(__FUNCSIG__, "boost::leaf::type_str<") ) - return p + 22; - else - return __FUNCSIG__; -#else - if( int clang_style = leaf_detail::check_prefix(__PRETTY_FUNCTION__, "const char *boost::leaf::type_str() [Name = ") ) - return __PRETTY_FUNCTION__ + clang_style; - else if( int gcc_style = leaf_detail::check_prefix(__PRETTY_FUNCTION__, "const char* boost::leaf::type_str() [with Name = ") ) - return __PRETTY_FUNCTION__ + gcc_style; - else - return __PRETTY_FUNCTION__; -#endif -} + //////////////////////////////////////// -template -inline std::ostream & print_type_str(std::basic_ostream & os) -{ - if( char const * t = type_str() ) - { - char const * end = std::strchr(t, 0); -#if defined(__clang__) || defined(__GNUC__) - BOOST_LEAF_ASSERT(end != t); - BOOST_LEAF_ASSERT(end[-1] == ']'); - return os.write(t, end - t - 1) << ": "; -#elif defined(_MSC_VER) - BOOST_LEAF_ASSERT(end - t > 7); - BOOST_LEAF_ASSERT(std::memcmp(end - 7, ">(void)", 7) == 0); - if( *t == 's' ) + template = S2> + struct cpp11_suffix + { + constexpr static bool check(char const (&)[S1], char const (&)[S2]) noexcept { - BOOST_LEAF_ASSERT(std::memcmp(t + 1, "truct ", 6) == 0); - t += 7; + return false; } - else if( *t == 'c' ) + }; + template + struct cpp11_suffix + { + constexpr static bool check(char const (&str)[S1], char const (&suffix)[S2]) noexcept { - BOOST_LEAF_ASSERT(std::memcmp(t + 1, "lass ", 5) == 0); - t += 6; + return str[I1] == suffix[I2] && cpp11_suffix::check(str, suffix); } - else if( *t == 'e' ) + }; + template + struct cpp11_suffix + { + constexpr static bool check(char const (&str)[S1], char const (&suffix)[S2]) noexcept { - BOOST_LEAF_ASSERT(std::memcmp(t + 1, "num ", 4) == 0); - t += 5; + return str[I1] == suffix[0]; } - return os.write(t, end - t - 7) << ": "; -#else - if( end != t && end[-1] == ']') - return os.write(t, end - t - 1) << ": "; - else - return os << t << ": "; -#endif + }; + template + constexpr int check_suffix(char const (&str)[S1], char const (&suffix)[S2]) noexcept + { + return cpp11_suffix::check(str, suffix) ? S1 - S2 : 0; + } +} + +struct parsed_name +{ + char const * name; + int len; + + parsed_name(char const * name, int len) noexcept: + name(name), + len(len) + { + } + + template + parsed_name(char const(&name)[S]) noexcept: + name(name), + len(S-1) + { + } + + bool parse_success() const noexcept + { + return name[len] != 0; + } + + template + friend std::ostream & operator<<(std::basic_ostream & os, parsed_name const & pn) + { + return os.write(pn.name, pn.len); + } +}; + +template +parsed_name parse_name() +{ + // Workaround for older gcc compilers where __PRETTY_FUNCTION__ is not constexpr. + // Instead of evaluating constexpr int x = f(__PRETTY_FUNCTION__), which fails, + // we evaluate int const x = f(__PRETTY_FUNCTION__). Then we enforce compile-time + // execution by evaluating sizeof(char[1 + x]) -1. +#define BOOST_LEAF_PARSE_PF(prefix, suffix) \ + { \ + if( int const s = leaf_detail::check_suffix(BOOST_LEAF_PRETTY_FUNCTION, suffix) ) \ + if( int const p = leaf_detail::check_prefix(BOOST_LEAF_PRETTY_FUNCTION, prefix) ) \ + return parsed_name(BOOST_LEAF_PRETTY_FUNCTION + sizeof(char[1 + p]) - 1, sizeof(char[1 + s - p]) - 1); \ } - else - return os << "no name: "; + // clang style: + BOOST_LEAF_PARSE_PF( "parsed_name boost::leaf::parse_name() [Name = ", "]"); + // old clang style: + BOOST_LEAF_PARSE_PF( "boost::leaf::parsed_name boost::leaf::parse_name() [Name = ", "]"); + // gcc style: + BOOST_LEAF_PARSE_PF( "boost::leaf::parsed_name boost::leaf::parse_name() [with Name = ", "]"); + // msvc style, __cdecl, struct/class/enum: + BOOST_LEAF_PARSE_PF( "struct boost::leaf::parsed_name __cdecl boost::leaf::parse_name(void)"); + BOOST_LEAF_PARSE_PF( "struct boost::leaf::parsed_name __cdecl boost::leaf::parse_name(void)"); + BOOST_LEAF_PARSE_PF( "struct boost::leaf::parsed_name __cdecl boost::leaf::parse_name(void)"); + // msvc style, __stdcall, struct/class/enum: + BOOST_LEAF_PARSE_PF( "struct boost::leaf::parsed_name __stdcall boost::leaf::parse_name(void)"); + BOOST_LEAF_PARSE_PF( "struct boost::leaf::parsed_name __stdcall boost::leaf::parse_name(void)"); + BOOST_LEAF_PARSE_PF( "struct boost::leaf::parsed_name __stdcall boost::leaf::parse_name(void)"); + // msvc style, __fastcall, struct/class/enum: + BOOST_LEAF_PARSE_PF( "struct boost::leaf::parsed_name __fastcall boost::leaf::parse_name(void)"); + BOOST_LEAF_PARSE_PF( "struct boost::leaf::parsed_name __fastcall boost::leaf::parse_name(void)"); + BOOST_LEAF_PARSE_PF( "struct boost::leaf::parsed_name __fastcall boost::leaf::parse_name(void)"); +#undef BOOST_LEAF_PARSE_PF + + // Unrecognized __PRETTY_FUNCTION__/__FUNSIG__ format, return as-is. Note, parsing is done at compile-time. + return parsed_name(BOOST_LEAF_PRETTY_FUNCTION); } } } diff --git a/include/boost/leaf/detail/print.hpp b/include/boost/leaf/detail/print.hpp index c0e29d5f..196503ae 100644 --- a/include/boost/leaf/detail/print.hpp +++ b/include/boost/leaf/detail/print.hpp @@ -70,7 +70,7 @@ namespace leaf_detail template static void print( std::basic_ostream & os, Wrapper const & x ) { - print_type_str(os) << x.value; + os << parse_name() << ": " << x.value; } }; @@ -82,7 +82,7 @@ namespace leaf_detail template static void print( std::basic_ostream & os, Wrapper const & ex ) { - print_type_str(os) << "std::exception::what(): " << ex.what(); + os << parse_name() << ": std::exception::what(): " << ex.what(); } }; @@ -94,7 +94,7 @@ namespace leaf_detail template static void print( std::basic_ostream & os, Wrapper const & ) { - print_type_str(os) << "{not printable}"; + os << parse_name() << ": {not printable}"; } }; @@ -106,7 +106,7 @@ namespace leaf_detail template static void print( std::basic_ostream & os, Wrapper const & w ) { - print_type_str(os) << static_cast::type>(w); + os << parse_name() << ": " << static_cast::type>(w); } }; diff --git a/include/boost/leaf/error.hpp b/include/boost/leaf/error.hpp index cf0b6e01..12262f4e 100644 --- a/include/boost/leaf/error.hpp +++ b/include/boost/leaf/error.hpp @@ -77,7 +77,7 @@ struct BOOST_LEAF_SYMBOL_VISIBLE e_source_location template friend std::ostream & operator<<( std::basic_ostream & os, e_source_location const & x ) { - return leaf::print_type_str(os) << x.file << '(' << x.line << ") in function " << x.function; + return os << leaf::parse_name() << x.file << '(' << x.line << ") in function " << x.function; } }; diff --git a/meson.build b/meson.build index 5ff57484..10eeee75 100644 --- a/meson.build +++ b/meson.build @@ -173,6 +173,7 @@ if option_enable_unit_tests 'on_error_preload_nested_success_exception_test', 'on_error_preload_nested_success_result_test', 'optional_test', + 'parse_name_test', 'print_test', 'result_bad_result_test', 'result_implicit_conversion_test', diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 651eb2a6..224d2a39 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -109,6 +109,7 @@ run on_error_preload_nested_new_error_result_test.cpp ; run on_error_preload_nested_success_exception_test.cpp ; run on_error_preload_nested_success_result_test.cpp ; run optional_test.cpp ; +run parse_name_test.cpp ; run print_test.cpp ; run result_bad_result_test.cpp ; run result_implicit_conversion_test.cpp ; diff --git a/test/parse_name_test.cpp b/test/parse_name_test.cpp new file mode 100644 index 00000000..71447f45 --- /dev/null +++ b/test/parse_name_test.cpp @@ -0,0 +1,79 @@ +// Copyright 2018-2024 Emil Dotchevski and Reverge Studios, Inc. + +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifdef BOOST_LEAF_TEST_SINGLE_HEADER +# include "leaf.hpp" +#else +# include +#endif + +#if BOOST_LEAF_CFG_STD_STRING + +namespace leaf = boost::leaf; + +#include "lightweight_test.hpp" + +namespace leaf_test +{ + class class_ { }; + struct struct_ { }; + enum enum_ { }; + template class class_template1 { }; + template struct struct_template1 { }; + template class class_template2 { }; + template struct struct_template2 { }; +} + +class class_ { }; +struct struct_ { }; +enum enum_ { }; +template class class_template1 { }; +template struct struct_template1 { }; +template class class_template2 { }; +template struct struct_template2 { }; + +namespace +{ + template + void test_name(std::string const & correct) + { + leaf::parsed_name pn = leaf::parse_name(); + BOOST_TEST(pn.parse_success()); + BOOST_TEST_EQ(std::string(pn.name, pn.len), correct); + } +} + +int main() +{ + test_name("leaf_test::class_"); + test_name("leaf_test::struct_"); + test_name("leaf_test::enum_"); + test_name>("leaf_test::class_template1<42>"); + test_name>("leaf_test::struct_template1<42>"); + test_name>("leaf_test::class_template2"); + test_name>("leaf_test::struct_template2"); + + test_name("class_"); + test_name("struct_"); + test_name("enum_"); + test_name>("class_template1<42>"); + test_name>("struct_template1<42>"); + test_name>("class_template2"); + test_name>("struct_template2"); + + return boost::report_errors(); +} + +#else + +#include + +int main() +{ + std::cout << "Unit test not applicable." << std::endl; + return 0; +} + +#endif