Serialization

This commit is contained in:
Emil Dotchevski
2026-01-12 00:14:24 -05:00
parent 95b1ead06c
commit c1e7e3511e
14 changed files with 821 additions and 21 deletions

View File

@@ -13,6 +13,8 @@
#include <utility>
#include <string>
namespace boost { namespace exception_detail { class writer; } }
#ifndef BOOST_EXCEPTION_ENABLE_WARNINGS
#if defined(__GNUC__) && __GNUC__*100+__GNUC_MINOR__>301
#pragma GCC system_header
@@ -38,6 +40,7 @@ boost
virtual std::string name_value_string() const = 0;
virtual error_info_base * clone() const = 0;
virtual void write_to(writer &) const = 0;
virtual
~error_info_base() BOOST_NOEXCEPT_OR_NOTHROW
@@ -97,6 +100,7 @@ boost
error_info & operator=( error_info && x );
#endif
std::string name_value_string() const;
void write_to(exception_detail::writer &) const;
value_type v_;
};
}

View File

@@ -21,4 +21,4 @@ BOOST_PRAGMA_MESSAGE("C++03 support was deprecated in Boost.Exception 1.85 and w
#endif
#endif
#endif

View File

@@ -11,7 +11,17 @@
#include <boost/core/demangle.hpp>
#include <boost/current_function.hpp>
#include <string>
#include <string.h>
#include <ostream>
#include <cstring>
#include <cstddef>
#ifndef BOOST_EXCEPTION_PRETTY_FUNCTION
# if defined(_MSC_VER) && !defined(__clang__) && !defined(__GNUC__)
# define BOOST_EXCEPTION_PRETTY_FUNCTION __FUNCSIG__
# else
# define BOOST_EXCEPTION_PRETTY_FUNCTION __PRETTY_FUNCTION__
# endif
#endif
#ifndef BOOST_EXCEPTION_ENABLE_WARNINGS
#if defined(__GNUC__) && __GNUC__*100+__GNUC_MINOR__>301
@@ -73,6 +83,206 @@ boost
return a.type_!=b.type_ && strcmp(a.type_->name(), b.type_->name()) < 0;
}
};
template <int S1, int S2, int I, bool = (S1 >= S2)>
struct
cpp11_prefix
{
BOOST_FORCEINLINE static constexpr
bool
check(char const (&)[S1], char const (&)[S2]) noexcept
{
return false;
}
};
template <int S1, int S2, int I>
struct
cpp11_prefix<S1, S2, I, true>
{
BOOST_FORCEINLINE static constexpr
bool
check(char const (&str)[S1], char const (&prefix)[S2]) noexcept
{
return str[I] == prefix[I] && cpp11_prefix<S1, S2, I - 1>::check(str, prefix);
}
};
template <int S1, int S2>
struct
cpp11_prefix<S1, S2, 0, true>
{
BOOST_FORCEINLINE static constexpr
bool
check(char const (&str)[S1], char const (&prefix)[S2]) noexcept
{
return str[0] == prefix[0];
}
};
template <int S1, int S2>
BOOST_FORCEINLINE constexpr
int
check_prefix(char const (&str)[S1], char const (&prefix)[S2]) noexcept
{
return cpp11_prefix<S1, S2, S2 - 2>::check(str, prefix) ? S2 - 1 : 0;
}
template <int S1, int S2, int I1, int I2, bool = (S1 >= S2)>
struct
cpp11_suffix
{
BOOST_FORCEINLINE static constexpr
bool
check(char const (&)[S1], char const (&)[S2]) noexcept
{
return false;
}
};
template <int S1, int S2, int I1, int I2>
struct
cpp11_suffix<S1, S2, I1, I2, true>
{
BOOST_FORCEINLINE static constexpr
bool
check(char const (&str)[S1], char const (&suffix)[S2]) noexcept
{
return str[I1] == suffix[I2] && cpp11_suffix<S1, S2, I1 - 1, I2 - 1>::check(str, suffix);
}
};
template <int S1, int S2, int I1>
struct
cpp11_suffix<S1, S2, I1, 0, true>
{
BOOST_FORCEINLINE static constexpr
bool
check(char const (&str)[S1], char const (&suffix)[S2]) noexcept
{
return str[I1] == suffix[0];
}
};
template <int S1, int S2>
BOOST_FORCEINLINE constexpr
int
check_suffix(char const (&str)[S1], char const (&suffix)[S2]) noexcept
{
return cpp11_suffix<S1, S2, S1 - 2, S2 - 2>::check(str, suffix) ? S1 - S2 : 0;
}
}
namespace
n
{
struct
r
{
char const * name_not_zero_terminated_at_length;
std::size_t length;
};
#ifdef _MSC_VER
# define BOOST_EXCEPTION_CDECL __cdecl
#else
# define BOOST_EXCEPTION_CDECL
#endif
template <class T>
BOOST_FORCEINLINE
r
BOOST_EXCEPTION_CDECL
p()
{
#define BOOST_EXCEPTION_P(P) (sizeof(char[1 + exception_detail::check_prefix(BOOST_EXCEPTION_PRETTY_FUNCTION, P)]) - 1)
// clang style:
std::size_t const p01 = BOOST_EXCEPTION_P("r boost::n::p() [T = ");
std::size_t const p02 = BOOST_EXCEPTION_P("r __cdecl boost::n::p(void) [T = ");
// old clang style:
std::size_t const p03 = BOOST_EXCEPTION_P("boost::n::r boost::n::p() [T = ");
std::size_t const p04 = BOOST_EXCEPTION_P("boost::n::r __cdecl boost::n::p(void) [T = ");
// gcc style:
std::size_t const p05 = BOOST_EXCEPTION_P("boost::n::r boost::n::p() [with T = ");
std::size_t const p06 = BOOST_EXCEPTION_P("boost::n::r __cdecl boost::n::p() [with T = ");
// msvc style, struct:
std::size_t const p07 = BOOST_EXCEPTION_P("struct boost::n::r __cdecl boost::n::p<struct ");
// msvc style, class:
std::size_t const p08 = BOOST_EXCEPTION_P("struct boost::n::r __cdecl boost::n::p<class ");
// msvc style, enum:
std::size_t const p09 = BOOST_EXCEPTION_P("struct boost::n::r __cdecl boost::n::p<enum ");
// msvc style, built-in type:
std::size_t const p10 = BOOST_EXCEPTION_P("struct boost::n::r __cdecl boost::n::p<");
#undef BOOST_EXCEPTION_P
#define BOOST_EXCEPTION_S(S) (sizeof(char[1 + exception_detail::check_suffix(BOOST_EXCEPTION_PRETTY_FUNCTION, S)]) - 1)
// clang/gcc style:
std::size_t const s01 = BOOST_EXCEPTION_S("]");
// msvc style:
std::size_t const s02 = BOOST_EXCEPTION_S(">(void)");
#undef BOOST_EXCEPTION_S
char static_assert_unrecognized_pretty_function_format_please_file_github_issue[sizeof(
char[
(s01 && (1 == (!!p01 + !!p02 + !!p03 + !!p04 + !!p05 + !!p06)))
||
(s02 && (1 == (!!p07 + !!p08 + !!p09)))
||
(s02 && !!p10)
]
) * 2 - 1];
(void) static_assert_unrecognized_pretty_function_format_please_file_github_issue;
if( std::size_t const p = sizeof(char[1 + !!s01 * (p01 + p02 + p03 + p04 + p05 + p06)]) - 1 )
return { BOOST_EXCEPTION_PRETTY_FUNCTION + p, s01 - p };
if( std::size_t const p = sizeof(char[1 + !!s02 * (p07 + p08 + p09)]) - 1 )
return { BOOST_EXCEPTION_PRETTY_FUNCTION + p, s02 - p };
std::size_t const p = sizeof(char[1 + !!s02 * p10]) - 1;
return { BOOST_EXCEPTION_PRETTY_FUNCTION + p, s02 - p };
}
#undef BOOST_EXCEPTION_CDECL
}
namespace
exception_detail
{
struct
pretty_type_name
{
char const * name_not_zero_terminated_at_length;
std::size_t length;
template <class CharT, class Traits>
friend
std::basic_ostream<CharT, Traits> &
operator<<(std::basic_ostream<CharT, Traits> & os, pretty_type_name const & x)
{
return os.write(x.name_not_zero_terminated_at_length, x.length);
}
template <std::size_t S>
friend
char *
to_zstr(char (&zstr)[S], pretty_type_name const & x) noexcept
{
std::size_t n = x.length < S - 1 ? x.length : S - 1;
std::memcpy(zstr, x.name_not_zero_terminated_at_length, n);
zstr[n] = 0;
return zstr;
}
};
template <class T>
pretty_type_name
get_pretty_tag_type_name()
{
n::r parsed = n::p<T>();
return { parsed.name_not_zero_terminated_at_length, parsed.length };
}
}
}

View File

@@ -0,0 +1,114 @@
//Copyright (c) 2006-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)
#ifndef BOOST_EXCEPTION_DETAIL_WRITER_HPP_INCLUDED
#define BOOST_EXCEPTION_DETAIL_WRITER_HPP_INCLUDED
#include <boost/exception/detail/type_info.hpp>
#include <type_traits>
#include <utility>
namespace
boost
{
template <class Tag, class T> class error_info;
namespace
exception_serialization
{
struct writer_adl {};
}
namespace
exception_detail
{
template <class T>
struct first_arg;
template <class C, class R, class A1, class... A>
struct
first_arg<R(C::*)(A1, A...)>
{
using type = A1;
};
template <class C, class R, class A1, class... A>
struct
first_arg<R(C::*)(A1, A...) const>
{
using type = A1;
};
class
writer:
exception_serialization::writer_adl
{
writer(writer const &) = delete;
writer & operator=(writer const &) = delete;
core::typeinfo const * type_;
void * w_;
bool
dispatch_()
{
return false;
}
template <class F1, class... Fn>
bool
dispatch_(F1 && f1, Fn && ... fn)
{
using writer_type = typename std::decay<typename first_arg<decltype(&std::decay<F1>::type::operator())>::type>::type;
if (writer_type * w = get<writer_type>())
{
std::forward<F1>(f1)(*w);
return true;
}
return dispatch_(std::forward<Fn>(fn)...);
}
protected:
template <class Writer>
explicit
writer(Writer * w) noexcept:
type_(&BOOST_CORE_TYPEID(Writer)),
w_(w)
{
}
public:
template <class Writer>
Writer *
get() noexcept
{
return *type_ == BOOST_CORE_TYPEID(Writer) ? static_cast<Writer *>(w_) : nullptr;
}
template <class... Fn>
bool
dispatch(Fn && ... fn)
{
return dispatch_(std::forward<Fn>(fn)...);
}
};
template <class Writer>
struct
writer_adaptor:
writer
{
explicit
writer_adaptor(Writer & w) noexcept:
writer(&w)
{
}
};
}
}
#endif

View File

@@ -205,6 +205,65 @@ boost
#endif
return w;
}
namespace
exception_detail
{
template <class Writer>
void
write_diagnostic_information_to_impl_( boost::exception const * be, std::exception const * se, Writer & w )
{
if( !be && !se )
return;
#ifndef BOOST_NO_RTTI
if( !be )
be=dynamic_cast<boost::exception const *>(se);
if( !se )
se=dynamic_cast<std::exception const *>(be);
#endif
if( be )
{
if( char const * const * f=get_error_info<throw_file>(*be) )
write_nested(w, *f, "throw_file");
if( int const * l=get_error_info<throw_line>(*be) )
write_nested(w, *l, "throw_line");
if( char const * const * fn=get_error_info<throw_function>(*be) )
write_nested(w, *fn, "throw_function");
}
#ifndef BOOST_NO_RTTI
if( be || se )
write_nested(w, core::demangle((be?(BOOST_EXCEPTION_DYNAMIC_TYPEID(*be)):(BOOST_EXCEPTION_DYNAMIC_TYPEID(*se))).type_->name()).c_str(), "dynamic_exception_type");
#endif
if( se )
if( char const * wh = se->what() )
write_nested(w, wh, "std::exception::what");
if( be )
if( error_info_container * c = be->data_.get() )
{
writer_adaptor<Writer> wa(w);
c->write_to(wa);
}
}
}
template <class T, class Writer>
void
write_diagnostic_information_to( T const & e, Writer & w )
{
exception_detail::write_diagnostic_information_to_impl_(exception_detail::get_boost_exception(&e),exception_detail::get_std_exception(&e),w);
}
#ifndef BOOST_NO_EXCEPTIONS
template <class Writer>
void
write_current_exception_diagnostic_information_to( Writer & w )
{
boost::exception const * be=current_exception_cast<boost::exception const>();
std::exception const * se=current_exception_cast<std::exception const>();
if( be || se )
exception_detail::write_diagnostic_information_to_impl_(be,se,w);
}
#endif
}
#if defined(_MSC_VER) && !defined(BOOST_EXCEPTION_ENABLE_WARNINGS)

View File

@@ -11,7 +11,9 @@
#include <boost/exception/to_string_stub.hpp>
#include <boost/exception/detail/error_info_impl.hpp>
#include <boost/exception/detail/shared_ptr.hpp>
#include <boost/exception/detail/writer.hpp>
#include <map>
#include <type_traits>
#ifndef BOOST_EXCEPTION_ENABLE_WARNINGS
#if defined(__GNUC__) && __GNUC__*100+__GNUC_MINOR__>301
@@ -28,6 +30,36 @@
namespace
boost
{
namespace
exception_serialization
{
template <class Writer, class T, class... Unused>
typename std::enable_if<std::is_base_of<exception_detail::writer, Writer>::value>::type
serialize(Writer &, T const &, char const *, Unused && ...)
{
}
template <class Writer, class Tag, class T>
void
write(Writer & w, error_info<Tag, T> const & e)
{
write(w, e.value());
}
}
namespace
exception_detail
{
template <class Tag, class T>
void
serialize_(writer & w, error_info<Tag,T> const & x)
{
using namespace boost::exception_serialization;
char buf[256];
serialize(w, x.value(), to_zstr(buf, get_pretty_tag_type_name<Tag>()));
}
}
template <class Tag,class T>
inline
std::string
@@ -53,6 +85,15 @@ boost
return to_string_stub(*this);
}
template <class Tag,class T>
inline
void
error_info<Tag,T>::
write_to(exception_detail::writer & w) const
{
exception_detail::serialize_(w, *this);
}
namespace
exception_detail
{
@@ -108,6 +149,16 @@ boost
return diagnostic_info_str_.c_str();
}
void
write_to( writer & w ) const
{
for( error_info_map::const_iterator i=info_.begin(),end=info_.end(); i!=end; ++i )
{
error_info_base const & x = *i->second;
x.write_to(w);
}
}
private:
friend class boost::exception;

View File

@@ -0,0 +1,43 @@
//Copyright (c) 2006-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)
#ifndef BOOST_EXCEPTION_SERIALIZATION_NLOHMANN_WRITER_HPP_INCLUDED
#define BOOST_EXCEPTION_SERIALIZATION_NLOHMANN_WRITER_HPP_INCLUDED
#include <utility>
namespace
boost
{
namespace
exception_serialization
{
template <class Json>
struct
nlohmann_writer
{
Json & j_;
template <class T>
friend
auto
write(nlohmann_writer & w, T const & x) -> decltype(to_json(std::declval<Json &>(), x))
{
to_json(w.j_, x);
}
template <class T>
friend
void
write_nested(nlohmann_writer & w, T const & x, char const * name)
{
nlohmann_writer nested{w.j_[name]};
write(nested, x);
}
};
}
}
#endif