Skip to content

Commit 3797a19

Browse files
committed
diagnostics refactor
1 parent dff40ee commit 3797a19

19 files changed

+545
-612
lines changed

include/boost/leaf/context.hpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
77

88
#include <boost/leaf/config.hpp>
9+
#include <boost/leaf/detail/diagnostics_writer.hpp>
910
#include <boost/leaf/error.hpp>
1011

1112
#if !defined(BOOST_LEAF_NO_THREADS) && !defined(NDEBUG)
@@ -375,10 +376,10 @@ class context
375376
template <class CharT, class Traits>
376377
friend std::ostream & operator<<( std::basic_ostream<CharT, Traits> & os, context const & ctx )
377378
{
378-
char const * prefix = "Contents:";
379-
ostream_writer w(os, prefix, BOOST_LEAF_CFG_DIAGNOSTICS_DELIMITER);
379+
detail::diagnostics_writer w(os);
380+
w.set_prefix("Contents:");
380381
ctx.write_to(w);
381-
return os << '\n';
382+
return os;
382383
}
383384

384385
template <class T>

include/boost/leaf/detail/all.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,5 @@
1111
#include <boost/leaf/on_error.hpp>
1212
#include <boost/leaf/pred.hpp>
1313
#include <boost/leaf/result.hpp>
14-
#include <boost/leaf/serialize.hpp>
1514
#include <boost/leaf/to_variant.hpp>
15+
#include <boost/leaf/writer.hpp>

include/boost/leaf/detail/capture_list.hpp

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
77

88
#include <boost/leaf/config.hpp>
9-
#include <boost/leaf/serialize.hpp>
9+
#include <boost/leaf/writer.hpp>
1010

1111
#if BOOST_LEAF_CFG_CAPTURE
1212

@@ -27,9 +27,7 @@ namespace detail
2727
friend class capture_list;
2828

2929
virtual void unload( int err_id ) = 0;
30-
#if BOOST_LEAF_CFG_DIAGNOSTICS
3130
virtual void write_to(writer &, error_id const &) const = 0;
32-
#endif
3331

3432
protected:
3533

@@ -92,7 +90,6 @@ namespace detail
9290

9391
void write_to(writer & w, error_id const & id) const
9492
{
95-
#if BOOST_LEAF_CFG_DIAGNOSTICS
9693
if( first_ )
9794
{
9895
for_each(
@@ -101,10 +98,6 @@ namespace detail
10198
n.write_to(w, id);
10299
} );
103100
}
104-
#else
105-
(void) w;
106-
(void) id;
107-
#endif
108101
}
109102
}; // class capture_list
110103

include/boost/leaf/detail/demangle.hpp

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -135,13 +135,6 @@ namespace n
135135
{
136136
return os.write(pn.name, pn.len);
137137
}
138-
139-
#if BOOST_LEAF_CFG_STD_STRING
140-
friend std::string to_string(r const & pn)
141-
{
142-
return std::string(pn.name, pn.len);
143-
}
144-
#endif
145138
};
146139

147140
template <class T>
Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
#ifndef BOOST_LEAF_DETAIL_DIAGNOSTICS_WRITER_HPP_INCLUDED
2+
#define BOOST_LEAF_DETAIL_DIAGNOSTICS_WRITER_HPP_INCLUDED
3+
4+
// Copyright 2018-2025 Emil Dotchevski and Reverge Studios, Inc.
5+
// Distributed under the Boost Software License, Version 1.0. (See accompanying
6+
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7+
8+
#include <boost/leaf/writer.hpp>
9+
#include <boost/leaf/detail/exception_base.hpp>
10+
11+
#include <iosfwd>
12+
13+
namespace boost { namespace leaf {
14+
15+
namespace detail
16+
{
17+
template <class T, class E = void>
18+
struct is_printable: std::false_type
19+
{
20+
};
21+
22+
template <class T>
23+
struct is_printable<T, decltype(std::declval<std::ostream&>()<<std::declval<T const &>(), void())>: show_in_diagnostics<T>
24+
{
25+
};
26+
27+
template <class T, class E = void>
28+
struct has_printable_member_value: std::false_type
29+
{
30+
};
31+
32+
template <class T>
33+
struct has_printable_member_value<T, decltype(std::declval<std::ostream&>()<<std::declval<T const &>().value, void())>: show_in_diagnostics<T>
34+
{
35+
};
36+
37+
template <class T, class E = void>
38+
struct has_member_value: std::false_type
39+
{
40+
};
41+
42+
template <class T>
43+
struct has_member_value<T, decltype((void)std::declval<T const &>().value)>: std::true_type
44+
{
45+
};
46+
47+
////////////////////////////////////////
48+
49+
class diagnostics_writer: public writer
50+
{
51+
diagnostics_writer(diagnostics_writer const &) = delete;
52+
diagnostics_writer & operator=(diagnostics_writer const &) = delete;
53+
54+
void (*print_lf_)(std::ostream &);
55+
std::ostream & os_;
56+
char const * prefix_;
57+
char const * const delimiter_;
58+
59+
template <class T, class CharT, class Traits>
60+
static void print_name(std::basic_ostream<CharT, Traits> & os, char const * & prefix, char const * delimiter)
61+
{
62+
static_assert(show_in_diagnostics<T>::value, "show_in_diagnostics violation");
63+
BOOST_LEAF_ASSERT(delimiter);
64+
char const * p = prefix;
65+
prefix = nullptr;
66+
os << (p ? p : delimiter) << parse<T>();
67+
}
68+
69+
template <class T, class PrintableInfo, class CharT, class Traits>
70+
static bool print_impl(std::basic_ostream<CharT, Traits> & os, char const * & prefix, char const * delimiter, char const * mid, PrintableInfo const & x)
71+
{
72+
print_name<T>(os, prefix, delimiter);
73+
if( mid )
74+
os << mid << x;
75+
return true;
76+
}
77+
78+
template <class T, class PrintableInfo, class CharT, class Traits>
79+
static bool print_impl(std::basic_ostream<CharT, Traits> & os, char const * & prefix, char const * delimiter, char const * mid, PrintableInfo const * x)
80+
{
81+
print_name<T>(os, prefix, delimiter);
82+
if( mid )
83+
{
84+
os << mid;
85+
if( x )
86+
os << x;
87+
else
88+
os << "<nullptr>";
89+
}
90+
return true;
91+
}
92+
93+
template <
94+
class Wrapper,
95+
bool ShowInDiagnostics = show_in_diagnostics<Wrapper>::value,
96+
bool WrapperPrintable = is_printable<Wrapper>::value,
97+
bool ValuePrintable = has_printable_member_value<Wrapper>::value,
98+
bool IsException = std::is_base_of<std::exception,Wrapper>::value,
99+
bool IsEnum = std::is_enum<Wrapper>::value>
100+
struct diagnostic;
101+
102+
public:
103+
104+
template <class CharT, class Traits>
105+
explicit diagnostics_writer(std::basic_ostream<CharT, Traits> & os, char const * delimiter = BOOST_LEAF_CFG_DIAGNOSTICS_DELIMITER) noexcept:
106+
writer(this),
107+
print_lf_([](std::basic_ostream<CharT, Traits> & os) { os << '\n'; }),
108+
os_(os),
109+
prefix_(nullptr),
110+
delimiter_(delimiter)
111+
{
112+
}
113+
114+
template <class CharT, class Traits, class ErrorId, class SourceLocation, class Exception>
115+
diagnostics_writer(std::basic_ostream<CharT, Traits> & os, ErrorId id, SourceLocation const * loc, Exception const * ex) noexcept:
116+
writer(this),
117+
print_lf_([](std::basic_ostream<CharT, Traits> & os) { os << '\n'; }),
118+
os_(os),
119+
prefix_(nullptr),
120+
delimiter_(BOOST_LEAF_CFG_DIAGNOSTICS_DELIMITER)
121+
{
122+
os << "Error with serial #" << id;
123+
if( loc )
124+
os << " reported at " << *loc;
125+
#ifndef BOOST_LEAF_NO_EXCEPTIONS
126+
if( ex )
127+
{
128+
os << "\nCaught:" BOOST_LEAF_CFG_DIAGNOSTICS_FIRST_DELIMITER;
129+
if( auto eb = dynamic_cast<exception_base const *>(ex) )
130+
os << eb->type_name();
131+
else
132+
os << demangler(typeid(*ex).name()).get();
133+
os << ": \"" << ex->what() << '"';
134+
}
135+
else
136+
#endif
137+
{
138+
prefix_ = "\nCaught:" BOOST_LEAF_CFG_DIAGNOSTICS_FIRST_DELIMITER;
139+
}
140+
(void) ex;
141+
}
142+
143+
~diagnostics_writer() noexcept
144+
{
145+
print_lf_(os_);
146+
}
147+
148+
void set_prefix(char const * prefix) noexcept
149+
{
150+
prefix_ = prefix;
151+
}
152+
153+
template <class E>
154+
void write(E const & e)
155+
{
156+
diagnostic<E>::print(os_, prefix_, delimiter_, e);
157+
}
158+
}; // class diagnostics_writer
159+
160+
////////////////////////////////////////
161+
162+
template <class Wrapper, bool WrapperPrintable, bool ValuePrintable, bool IsException, bool IsEnum>
163+
struct diagnostics_writer::diagnostic<Wrapper, false, WrapperPrintable, ValuePrintable, IsException, IsEnum>
164+
{
165+
template <class CharT, class Traits>
166+
static bool print(std::basic_ostream<CharT, Traits> &, char const * &, char const *, Wrapper const &) noexcept
167+
{
168+
return false;
169+
}
170+
};
171+
172+
template <class Wrapper, bool ValuePrintable, bool IsEnum>
173+
struct diagnostics_writer::diagnostic<Wrapper, true, true, ValuePrintable, false, IsEnum>
174+
{
175+
template <class CharT, class Traits>
176+
static bool print(std::basic_ostream<CharT, Traits> & os, char const * & prefix, char const * delimiter, Wrapper const & x)
177+
{
178+
return print_impl<Wrapper>(os, prefix, delimiter, ": ", x);
179+
}
180+
};
181+
182+
template <class Wrapper>
183+
struct diagnostics_writer::diagnostic<Wrapper, true, false, true, false, false>
184+
{
185+
template <class CharT, class Traits>
186+
static bool print(std::basic_ostream<CharT, Traits> & os, char const * & prefix, char const * delimiter, Wrapper const & x)
187+
{
188+
return print_impl<Wrapper>(os, prefix, delimiter, ": ", x.value);
189+
}
190+
};
191+
192+
template <class Exception, bool WrapperPrintable, bool ValuePrintable>
193+
struct diagnostics_writer::diagnostic<Exception, true, WrapperPrintable, ValuePrintable, true, false>
194+
{
195+
template <class CharT, class Traits>
196+
static bool print(std::basic_ostream<CharT, Traits> & os, char const * & prefix, char const * delimiter, Exception const & ex)
197+
{
198+
if( print_impl<Exception>(os, prefix, delimiter, ": \"", static_cast<std::exception const &>(ex).what()) )
199+
{
200+
os << '"';
201+
return true;
202+
}
203+
return false;
204+
}
205+
};
206+
207+
template <class Wrapper>
208+
struct diagnostics_writer::diagnostic<Wrapper, true, false, false, false, false>
209+
{
210+
template <class CharT, class Traits>
211+
static bool print(std::basic_ostream<CharT, Traits> & os, char const * & prefix, char const * delimiter, Wrapper const &)
212+
{
213+
return print_impl<Wrapper>(os, prefix, delimiter, nullptr, 0);
214+
}
215+
};
216+
217+
template <class Enum>
218+
struct diagnostics_writer::diagnostic<Enum, true, false, false, false, true>
219+
{
220+
template <class CharT, class Traits>
221+
static bool print(std::basic_ostream<CharT, Traits> & os, char const * & prefix, char const * delimiter, Enum const & enum_)
222+
{
223+
return print_impl<Enum>(os, prefix, delimiter, ": ", static_cast<typename std::underlying_type<Enum>::type>(enum_));
224+
}
225+
};
226+
227+
} // namespace detail
228+
229+
} } // namespace boost::leaf
230+
231+
#endif // #ifndef BOOST_LEAF_DETAIL_DIAGNOSTICS_WRITER_HPP_INCLUDED
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#ifndef BOOST_LEAF_DETAIL_EXCEPTION_BASE_HPP_INCLUDED
2+
#define BOOST_LEAF_DETAIL_EXCEPTION_BASE_HPP_INCLUDED
3+
4+
// Copyright 2018-2025 Emil Dotchevski and Reverge Studios, Inc.
5+
// Distributed under the Boost Software License, Version 1.0. (See accompanying
6+
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7+
8+
#include <boost/leaf/detail/demangle.hpp>
9+
10+
namespace boost { namespace leaf {
11+
12+
class error_id;
13+
14+
namespace detail
15+
{
16+
class exception_base
17+
{
18+
public:
19+
virtual error_id get_error_id() const noexcept = 0;
20+
virtual parsed type_name() const = 0;
21+
protected:
22+
exception_base() noexcept { }
23+
~exception_base() noexcept { }
24+
};
25+
} // namespace detail
26+
27+
} } // namespace boost::leaf
28+
29+
#endif // #ifndef BOOST_LEAF_DETAIL_EXCEPTION_BASE_HPP_INCLUDED

0 commit comments

Comments
 (0)