#ifndef BOOST_LEAF_DETAIL_DIAGNOSTICS_WRITER_HPP_INCLUDED #define BOOST_LEAF_DETAIL_DIAGNOSTICS_WRITER_HPP_INCLUDED // Copyright 2018-2026 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) #include #include #include #include #if BOOST_LEAF_CFG_DIAGNOSTICS # include #else # include #endif #ifndef BOOST_LEAF_NO_EXCEPTIONS # include #endif namespace boost { namespace leaf { template struct show_in_diagnostics: std::integral_constant { }; namespace detail { template struct is_printable: std::false_type { }; template struct is_printable()<(), void())>: std::true_type { }; template struct has_printable_member_value: std::false_type { }; template struct has_printable_member_value()<().value, void())>: std::true_type { }; //////////////////////////////////////// class diagnostics_writer: public encoder { diagnostics_writer(diagnostics_writer const &) = delete; diagnostics_writer & operator=(diagnostics_writer const &) = delete; std::ostream & os_; char const * prefix_; char const * delimiter_; void (* const print_suffix_)(std::ostream &); template static void print_name(std::basic_ostream & os, char const * & prefix, char const * delimiter) { static_assert(show_in_diagnostics::value, "show_in_diagnostics violation"); BOOST_LEAF_ASSERT(delimiter); char const * p = prefix; prefix = nullptr; os << (p ? p : delimiter) << detail::get_type_name(); } template static bool print_impl(std::basic_ostream & os, char const * & prefix, char const * delimiter, char const * mid, PrintableInfo const & x) { print_name(os, prefix, delimiter); if( mid ) os << mid << x; return true; } template static bool print_impl(std::basic_ostream & os, char const * & prefix, char const * delimiter, char const * mid, PrintableInfo const * x) { print_name(os, prefix, delimiter); if( mid ) { os << mid; if( x ) os << x; else os << ""; } return true; } template < class Wrapper, bool ShowInDiagnostics = show_in_diagnostics::value, bool WrapperPrintable = is_printable::value, bool ValuePrintable = has_printable_member_value::value, bool IsException = std::is_base_of::value, bool IsEnum = std::is_enum::value> struct diagnostic; public: template explicit diagnostics_writer(std::basic_ostream & os) noexcept: encoder(this), os_(os), prefix_(BOOST_LEAF_CFG_DIAGNOSTICS_FIRST_DELIMITER), delimiter_(BOOST_LEAF_CFG_DIAGNOSTICS_DELIMITER), print_suffix_([](std::basic_ostream &) { }) { } template diagnostics_writer(std::basic_ostream & os, error_id const & id, e_source_location const * loc, std::exception const * ex) noexcept: encoder(this), os_(os), prefix_(BOOST_LEAF_CFG_DIAGNOSTICS_FIRST_DELIMITER), delimiter_(BOOST_LEAF_CFG_DIAGNOSTICS_DELIMITER), print_suffix_([](std::basic_ostream & os) { os << '\n'; }) { os << "Error with serial #" << id; if( loc ) os << " reported at " << *loc; #ifndef BOOST_LEAF_NO_EXCEPTIONS if( ex ) { os << "\nCaught:" BOOST_LEAF_CFG_DIAGNOSTICS_FIRST_DELIMITER; if( auto eb = dynamic_cast(ex) ) os << eb->get_type_name(); else os << detail::demangler(typeid(*ex).name()).get(); os << ": \"" << ex->what() << '"'; } else #endif { prefix_ = "\nCaught:" BOOST_LEAF_CFG_DIAGNOSTICS_FIRST_DELIMITER; } (void) ex; } ~diagnostics_writer() noexcept { print_suffix_(os_); } void set_prefix(char const * prefix) noexcept { prefix_ = prefix; } void set_delimiter(char const * delimiter) noexcept { delimiter_ = delimiter; } template void write(T const & x) { diagnostic::print(os_, prefix_, delimiter_, x); } }; // class diagnostics_writer //////////////////////////////////////// template struct diagnostics_writer::diagnostic { template static bool print(std::basic_ostream &, char const * &, char const *, Wrapper const &) noexcept { return false; } }; template struct diagnostics_writer::diagnostic { template static bool print(std::basic_ostream & os, char const * & prefix, char const * delimiter, Wrapper const & x) { return print_impl(os, prefix, delimiter, ": ", x); } }; template struct diagnostics_writer::diagnostic { template static bool print(std::basic_ostream & os, char const * & prefix, char const * delimiter, Wrapper const & x) { return print_impl(os, prefix, delimiter, ": ", x.value); } }; template struct diagnostics_writer::diagnostic { template static bool print(std::basic_ostream & os, char const * & prefix, char const * delimiter, Exception const & ex) { if( print_impl(os, prefix, delimiter, ": \"", static_cast(ex).what()) ) { os << '"'; return true; } return false; } }; template struct diagnostics_writer::diagnostic { template static bool print(std::basic_ostream & os, char const * & prefix, char const * delimiter, Wrapper const &) { return print_impl(os, prefix, delimiter, nullptr, 0); } }; template struct diagnostics_writer::diagnostic { template static bool print(std::basic_ostream & os, char const * & prefix, char const * delimiter, Enum const & enum_) { return print_impl(os, prefix, delimiter, ": ", static_cast::type>(enum_)); } }; } // namespace detail } } // namespace boost::leaf #endif // #ifndef BOOST_LEAF_DETAIL_DIAGNOSTICS_WRITER_HPP_INCLUDED