Serialization for error info objects to Boost JSON and nlohmann/json

This commit is contained in:
Emil Dotchevski
2026-01-24 21:39:23 -05:00
parent ff24294368
commit 4c3e9427bf
17 changed files with 1450 additions and 89 deletions
+19
View File
@@ -238,6 +238,10 @@ jobs:
cp -r $GITHUB_WORKSPACE/* libs/$LIBRARY
git submodule update --init tools/boostdep
python3 tools/boostdep/depinst/depinst.py --git_args "--jobs 3" $LIBRARY
cd libs/throw_exception
git fetch origin feature/serialization
git checkout feature/serialization
cd ../..
./bootstrap.sh
./b2 -d0 headers
@@ -246,6 +250,11 @@ jobs:
run: |
echo "using ${{matrix.toolset}} : : ${{matrix.compiler}} ;" > ~/user-config.jam
- name: Download nlohmann/json
run: |
cd ../boost-root/libs/$LIBRARY
python3 scripts/download_nlohmann_json.py
- name: Run tests
run: |
cd ../boost-root
@@ -293,9 +302,19 @@ jobs:
xcopy /s /e /q %GITHUB_WORKSPACE% libs\%LIBRARY%\
git submodule update --init tools/boostdep
python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" %LIBRARY%
cd libs\throw_exception
git fetch origin feature/serialization
git checkout feature/serialization
cd ..\..
cmd /c bootstrap
b2 -d0 headers
- name: Download nlohmann/json
shell: cmd
run: |
cd ../boost-root/libs/%LIBRARY%
python3 scripts/download_nlohmann_json.py
- name: Run tests
shell: cmd
run: |
+1
View File
@@ -2,3 +2,4 @@
/.vscode/settings.json
.DS_Store
doc/html/index.html
/test/nlohmann/
+101
View File
@@ -0,0 +1,101 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "Download nlohmann/json.hpp",
"type": "shell",
"command": "python scripts/download_nlohmann_json.py",
"options": {
"cwd": "${workspaceFolder}"
},
"problemMatcher": []
},
{
"label": "b2: Run all tests (default)",
"type": "shell",
"dependsOn": ["Download nlohmann/json.hpp"],
"command": "../../b2 test",
"options": {
"cwd": "${workspaceFolder}"
},
"group": "test",
"problemMatcher": {
"base": "$gcc",
"fileLocation": ["relative", "${workspaceFolder}"]
},
"windows": {
"command": "..\\..\\b2 test",
"problemMatcher": {
"base": "$msCompile",
"fileLocation": ["relative", "${workspaceFolder}"]
}
}
},
{
"label": "b2: Run all tests (release)",
"type": "shell",
"dependsOn": ["Download nlohmann/json.hpp"],
"command": "../../b2 test variant=release",
"options": {
"cwd": "${workspaceFolder}"
},
"group": "test",
"problemMatcher": {
"base": "$gcc",
"fileLocation": ["relative", "${workspaceFolder}"]
},
"windows": {
"command": "..\\..\\b2 test variant=release",
"problemMatcher": {
"base": "$msCompile",
"fileLocation": ["relative", "${workspaceFolder}"]
}
}
},
{
"label": "b2: Run all tests (all configs)",
"type": "shell",
"dependsOn": ["Download nlohmann/json.hpp"],
"command": "../../b2 test exception-handling=on,off rtti=on,off variant=debug,release link=static,shared",
"options": {
"cwd": "${workspaceFolder}"
},
"group": "test",
"problemMatcher": {
"base": "$gcc",
"fileLocation": ["relative", "${workspaceFolder}"]
},
"windows": {
"command": "..\\..\\b2 test exception-handling=on,off rtti=on,off variant=debug,release link=static,shared",
"problemMatcher": {
"base": "$msCompile",
"fileLocation": ["relative", "${workspaceFolder}"]
}
}
},
{
"label": "b2: Run test for current editor file",
"type": "shell",
"dependsOn": ["Download nlohmann/json.hpp"],
"command": "../../b2 test ${fileBasenameNoExtension}.test",
"options": {
"cwd": "${workspaceFolder}"
},
"group": {
"kind": "test",
"isDefault": true
},
"problemMatcher": {
"base": "$gcc",
"fileLocation": ["relative", "${workspaceFolder}"]
},
"windows": {
"command": "..\\..\\b2 test ${fileBasenameNoExtension}.test",
"problemMatcher": {
"base": "$msCompile",
"fileLocation": ["relative", "${workspaceFolder}"]
}
}
}
]
}
+400 -46
View File
@@ -453,6 +453,164 @@ std::exception::what: example_io error
[struct boost::errinfo_file_open_mode_ *] = rb
----
[[tutorial_serialization]]
=== Serialization
Boost Exception provides a serialization API that enables exporting diagnostic information into different formats, such as JSON. This is useful for structured logging, remote debugging, or integrating with monitoring systems.
To serialize diagnostic information, use the following functions:
* `<<serialize_diagnostic_information_to,serialize_diagnostic_information_to>>` -- serializes diagnostic information for a given exception.
* `<<serialize_current_exception_diagnostic_information_to,serialize_current_exception_diagnostic_information_to>>` -- serializes diagnostic information for the current exception.
The serialization system uses `output` and `output_at` functions found via ADL:
* `output(enc, x)` serializes value `x` directly to encoder `enc`.
* `output_at(enc, x, name)` serializes value `x` to encoder `enc` as a named field.
[[custom-encoders]]
==== Custom Encoders
To support exporting to a specific format, users define an encoder class with associated `output` and `output_at` function templates:
[source,c++]
----
struct my_encoder
{
template <class T>
friend void output(my_encoder & enc, T const & x)
{
// output value x to enc
}
template <class T>
friend void output_at(my_encoder & enc, T const & x, char const * name)
{
// output x to enc as a named field
}
};
----
The `output_at` function typically creates a nested scope (e.g. a JSON object) and then calls `output` to serialize the value.
To enable serialization to a custom encoder type, define a `<<serialize,serialize>>` function template in the `boost::exception_serialization` namespace:
[source,c++]
----
namespace boost { namespace exception_serialization {
template <class Handle, class T>
void serialize(Handle & h, T const & x, char const * name)
{
h.dispatch([&](my_encoder & enc) {
output_at(enc, x, name);
});
}
} }
----
The `<<serialize,serialize>>` function template takes a handle reference `h` (of unspecified type) that holds an encoder, the object to be serialized, and its type name. Call `h.dispatch` with a single-argument function F to detect the encoder type based on F's argument type; F is called only if the handle contains an encoder of that type.
To support multiple output formats, pass multiple functions to `h.dispatch`:
[source,c++]
----
h.dispatch(
[&](json_encoder & enc) { output_at(enc, x, name); },
[&](xml_encoder & enc) { output_at(enc, x, name); }
);
----
==== JSON Serialization
Boost Exception provides two JSON encoders:
* `<<boost_json_encoder,boost_json_encoder>>` for https://www.boost.org/doc/libs/release/libs/json/[Boost.JSON]
* `<<nlohmann_json_encoder,nlohmann_json_encoder>>` based on ADL calls to `to_json` (compatible with https://github.com/nlohmann/json[nlohmann/json])
Below is an example using `nlohmann_json_encoder` with nlohmann/json. We just need to define the required `<<serialize,serialize>>` function template (see <<custom-encoders>>):
[source,c++]
----
#include <boost/exception/serialization/nlohmann_json_encoder.hpp>
#include "nlohmann/json.hpp"
using nlohmann_json_encoder = boost::exception_serialization::nlohmann_json_encoder<nlohmann::json>;
namespace boost { namespace exception_serialization {
template <class Handle, class T>
void serialize(Handle & h, T const & x, char const * name)
{
h.dispatch([&](nlohmann_json_encoder & enc) {
output_at(enc, x, name);
});
}
} }
----
With this in place, we can output diagnostic information to JSON:
[source,c++]
----
#include <boost/exception/diagnostic_information.hpp>
#include <boost/throw_exception.hpp>
#include <iostream>
struct api_response
{
int status;
std::string message;
template <class Json>
friend void to_json(Json & j, api_response const & e)
{
j["status"] = e.status;
j["message"] = e.message;
}
};
typedef boost::error_info<struct errinfo_api_response_, api_response> errinfo_api_response;
typedef boost::error_info<struct errinfo_request_url_, std::string> errinfo_request_url;
struct api_error : virtual boost::exception, virtual std::exception { };
....
nlohmann::json j;
try
{
BOOST_THROW_EXCEPTION(api_error()
<< errinfo_api_response({403, "Access denied"})
<< errinfo_request_url("/api/admin/settings"));
}
catch(boost::exception & e)
{
nlohmann_json_encoder enc{j};
boost::serialize_diagnostic_information_to(enc, e);
}
std::cout << j.dump(2) << std::endl;
----
.Output:
[source,json]
----
{
"errinfo_api_response_": {
"status": 403,
"message": "Access denied"
},
"errinfo_request_url_": "/api/admin/settings"
}
----
[.text-right]
<<serialize_diagnostic_information_to>> | <<nlohmann_json_encoder>>
NOTE: In the example above, `api_response` uses an unqualified call to `to_json` for serialization. This is to demonstrate that `nlohmann_json_encoder` handles third party types with suitable `to_json` overloads automatically. If instead we defined a function `output` compatible with the Boost Exception serialization API, it would make `api_response` compatible with any Boost Exception encoder.
[[synopsis]]
== Synopsis
@@ -604,11 +762,17 @@ namespace boost
char const * diagnostic_information_what( boost::exception const & e, bool verbose=true ) throw();
std::string current_exception_diagnostic_information();
template <class Encoder, class E>
void serialize_diagnostic_information_to( Encoder & enc, E const & e );
template <class Encoder>
void serialize_current_exception_diagnostic_information_to( Encoder & enc );
}
----
[.text-right]
Reference: <<diagnostic_information>> | <<diagnostic_information_what>> | <<current_exception_diagnostic_information>>
Reference: <<diagnostic_information>> | <<diagnostic_information_what>> | <<current_exception_diagnostic_information>> | <<serialize_diagnostic_information_to>> | <<serialize_current_exception_diagnostic_information_to>>
====
[[synopsis-current_exception_cast]]
@@ -904,6 +1068,67 @@ Reference: <<errinfo_type_info_name>>
This header includes all Boost Exception headers except `<<synopsis-exception_ptr,boost/exception_ptr.hpp>>` (unless BOOST_NO_EXCEPTIONS is defined.)
====
[[synopsis-serialization]]
=== Serialization
[[synopsis-boost_json_encoder]]
==== `boost_json_encoder.hpp`
====
.#include <boost/exception/serialization/boost_json_encoder.hpp>
[source,c++]
----
namespace boost { namespace exception_serialization {
struct boost_json_encoder
{
boost::json::value & v_;
// Enabled if x is assignable to boost::json::value, or
// if tag_invoke is defined for boost::json::value_from_tag.
template <class T>
friend void output( boost_json_encoder &, T const & x );
template <class T>
friend void output_at( boost_json_encoder &, T const &, char const * name );
};
} }
----
[.text-right]
Reference: <<boost_json_encoder>>
====
[[synopsis-nlohmann_json_encoder]]
==== `nlohmann_json_encoder.hpp`
====
.#include <boost/exception/serialization/nlohmann_json_encoder.hpp>
[source,c++]
----
namespace boost { namespace exception_serialization {
template <class Json>
struct nlohmann_json_encoder
{
Json & j_;
// Enabled if to_json is available for Json and T.
template <class T>
friend void output( nlohmann_json_encoder &, T const & x );
template <class T>
friend void output_at( nlohmann_json_encoder &, T const &, char const * name );
};
} }
----
[.text-right]
Reference: <<nlohmann_json_encoder>>
====
[[reference]]
== Reference
@@ -919,60 +1144,36 @@ endif::[]
[[types]]
=== Types
[[exception]]
==== `exception`
[[boost_json_encoder]]
==== `boost_json_encoder`
.#include <boost/exception/exception.hpp>
.#include <boost/exception/serialization/boost_json_encoder.hpp>
[source,c++]
----
namespace boost
namespace boost { namespace exception_serialization {
struct boost_json_encoder
{
class exception
{
protected:
boost::json::value & v_;
exception();
exception( exception const & x );
~exception();
};
}
// Enabled if x is assignable to boost::json::value, or
// if tag_invoke is defined for boost::json::value_from_tag.
template <class T>
friend void output( boost_json_encoder &, T const & x );
template <class T>
friend void output_at( boost_json_encoder &, T const &, char const * name );
};
} }
----
Class `boost::exception` is designed to be used as a universal base for user-defined exception types.
The `boost_json_encoder` type serializes objects to JSON format using https://www.boost.org/doc/libs/release/libs/json/[Boost.JSON]. The `output` function is enabled for:
An object of any type deriving from `boost::exception` can store data of arbitrary types, using the `<<error_info,error_info>>` wrapper and `<<exception_operator_shl,operator<<>>`.
* Types directly assignable to `boost::json::value`
* Types for which a `tag_invoke` overload for `value_from_tag` can be found via ADL
To retrieve data from a `boost::exception` object, use the `<<get_error_info,get_error_info>>` function template.
[[exception_constructors]]
===== `exception::exception`
[source,c++]
----
exception();
exception( exception const & x );
----
Effects: ::
+
--
* Default constructor: initializes an empty `boost::exception` object.
* Copy constructor: initializes a `boost::exception` object which shares with x the pointers to all currently stored data. Subsequently, data can be added to or retrieved from both exception objects interchangeably, however doing so concurrently from multiple threads is undefined behavior.
--
Throws: :: Nothing.
[[exception_destructor]]
===== `exception::~exception`
[source,c++]
----
~exception();
----
Effects: :: Releases all resources associated with the `boost::exception` object.
Throws: :: Nothing.
See <<tutorial_serialization>>.
'''
@@ -1288,6 +1489,63 @@ This type is designed to be used as a standard `<<error_info,error_info>>` insta
'''
[[exception]]
==== `exception`
.#include <boost/exception/exception.hpp>
[source,c++]
----
namespace boost
{
class exception
{
protected:
exception();
exception( exception const & x );
~exception();
};
}
----
Class `boost::exception` is designed to be used as a universal base for user-defined exception types.
An object of any type deriving from `boost::exception` can store data of arbitrary types, using the `<<error_info,error_info>>` wrapper and `<<exception_operator_shl,operator<<>>`.
To retrieve data from a `boost::exception` object, use the `<<get_error_info,get_error_info>>` function template.
[[exception_constructors]]
===== `exception::exception`
[source,c++]
----
exception();
exception( exception const & x );
----
Effects: ::
+
--
* Default constructor: initializes an empty `boost::exception` object.
* Copy constructor: initializes a `boost::exception` object which shares with x the pointers to all currently stored data. Subsequently, data can be added to or retrieved from both exception objects interchangeably, however doing so concurrently from multiple threads is undefined behavior.
--
Throws: :: Nothing.
[[exception_destructor]]
===== `exception::~exception`
[source,c++]
----
~exception();
----
Effects: :: Releases all resources associated with the `boost::exception` object.
Throws: :: Nothing.
'''
[[exception_ptr]]
==== `exception_ptr`
@@ -1321,6 +1579,34 @@ Nesting of exceptions: :: An `exception_ptr` can be added as `<<error_info,error
'''
[[nlohmann_json_encoder]]
==== `nlohmann_json_encoder`
.#include <boost/exception/serialization/nlohmann_json_encoder.hpp>
[source,c++]
----
namespace boost { namespace exception_serialization {
template <class Json>
struct nlohmann_json_encoder
{
Json & j_;
// Enabled if to_json is available for Json and T.
template <class T>
friend void output( nlohmann_json_encoder &, T const & x );
template <class T>
friend void output_at( nlohmann_json_encoder &, T const &, char const * name );
};
} }
----
The `nlohmann_json_encoder` type serializes objects to JSON format based on ADL calls to `to_json`. This is compatible with https://github.com/nlohmann/json[nlohmann/json]. See <<tutorial_serialization>>.
'''
[[original_exception_type]]
==== `original_exception_type`
@@ -1720,6 +2006,74 @@ Throws: :: The exception to which ep refers.
'''
[[serialize]]
==== `serialize`
[source,c++]
----
namespace boost { namespace exception_serialization {
template <class Handle, class E>
void serialize( Handle & h, E const & x, char const * name );
} }
----
The `serialize` function template is a user-defined customization point. If provided, it is called by the serialization system to output objects to an encoder; see <<custom-encoders>>.
'''
[[serialize_current_exception_diagnostic_information_to]]
==== `serialize_current_exception_diagnostic_information_to`
.#include <boost/exception/diagnostic_information.hpp>
[source,c++]
----
namespace boost
{
template <class Encoder>
void serialize_current_exception_diagnostic_information_to( Encoder & enc );
}
----
Requirements: :: This function must not be called outside of a catch block.
Effects: :: Serializes diagnostic information for the current exception to the encoder `enc`. Equivalent to calling `<<serialize_diagnostic_information_to,serialize_diagnostic_information_to>>` with the current exception object.
See <<tutorial_serialization>>.
'''
[[serialize_diagnostic_information_to]]
==== `serialize_diagnostic_information_to`
.#include <boost/exception/diagnostic_information.hpp>
[source,c++]
----
namespace boost
{
template <class Encoder, class E>
void serialize_diagnostic_information_to( Encoder & enc, E const & e );
}
----
Serializes diagnostic information for the exception `e` to the encoder `enc`.
Requirements: :: E must be convertible to either `boost::<<exception,exception>> const &` or `std::exception const &`.
Effects: :: Outputs diagnostic information about the exception to the encoder, including:
+
--
* Throw location (file, line, function) if available
* Dynamic exception type (if RTTI is enabled)
* `std::exception::what()` if available
* All `<<error_info,error_info>>` objects stored in the exception
--
See <<tutorial_serialization>>.
'''
[[throw_exception]]
==== `throw_exception`
+114
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_ENCODER_HPP_INCLUDED
#define BOOST_EXCEPTION_DETAIL_ENCODER_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 encoder_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
encoder:
exception_serialization::encoder_adl
{
encoder(encoder const &) = delete;
encoder & operator=(encoder const &) = delete;
core::typeinfo const * type_;
void * e_;
bool
dispatch_()
{
return false;
}
template <class F1, class... Fn>
bool
dispatch_(F1 && f1, Fn && ... fn)
{
using encoder_type = typename std::decay<typename first_arg<decltype(&std::decay<F1>::type::operator())>::type>::type;
if (encoder_type * e = get<encoder_type>())
{
std::forward<F1>(f1)(*e);
return true;
}
return dispatch_(std::forward<Fn>(fn)...);
}
protected:
template <class Encoder>
explicit
encoder(Encoder * e) noexcept:
type_(&BOOST_CORE_TYPEID(Encoder)),
e_(e)
{
}
public:
template <class Encoder>
Encoder *
get() noexcept
{
return *type_ == BOOST_CORE_TYPEID(Encoder) ? static_cast<Encoder *>(e_) : nullptr;
}
template <class... Fn>
bool
dispatch(Fn && ... fn)
{
return dispatch_(std::forward<Fn>(fn)...);
}
};
template <class Encoder>
struct
encoder_adaptor:
encoder
{
explicit
encoder_adaptor(Encoder & e) noexcept:
encoder(&e)
{
}
};
}
}
#endif
@@ -13,6 +13,8 @@
#include <utility>
#include <string>
namespace boost { namespace exception_detail { class encoder; } }
#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 serialize_to(encoder &) 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 serialize_to(exception_detail::encoder &) const;
value_type v_;
};
}
@@ -21,4 +21,4 @@ BOOST_PRAGMA_MESSAGE("C++03 support was deprecated in Boost.Exception 1.85 and w
#endif
#endif
#endif
+211 -1
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 };
}
}
}
@@ -205,6 +205,65 @@ boost
#endif
return w;
}
namespace
exception_detail
{
template <class Encoder>
void
serialize_diagnostic_information_to_impl_( boost::exception const * be, std::exception const * se, Encoder & e )
{
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) )
output_at(e, *f, "throw_file");
if( int const * l=get_error_info<throw_line>(*be) )
output_at(e, *l, "throw_line");
if( char const * const * fn=get_error_info<throw_function>(*be) )
output_at(e, *fn, "throw_function");
}
#ifndef BOOST_NO_RTTI
if( be || se )
output_at(e, 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() )
output_at(e, wh, "std::exception::what");
if( be )
if( error_info_container * c = be->data_.get() )
{
encoder_adaptor<Encoder> ea(e);
c->serialize_to(ea);
}
}
}
template <class T, class Encoder>
void
serialize_diagnostic_information_to( T const & e, Encoder & enc )
{
exception_detail::serialize_diagnostic_information_to_impl_(exception_detail::get_boost_exception(&e),exception_detail::get_std_exception(&e),enc);
}
#ifndef BOOST_NO_EXCEPTIONS
template <class Encoder>
void
serialize_current_exception_diagnostic_information_to( Encoder & e )
{
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::serialize_diagnostic_information_to_impl_(be,se,e);
}
#endif
}
#if defined(_MSC_VER) && !defined(BOOST_EXCEPTION_ENABLE_WARNINGS)
+34
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/encoder.hpp>
#include <map>
#include <type_traits>
#ifndef BOOST_EXCEPTION_ENABLE_WARNINGS
#if defined(__GNUC__) && __GNUC__*100+__GNUC_MINOR__>301
@@ -28,6 +30,17 @@
namespace
boost
{
namespace
exception_serialization
{
// Stub
template <class Encoder, class T, class... Deprioritize>
typename std::enable_if<std::is_base_of<exception_detail::encoder, Encoder>::value>::type
serialize(Encoder &, T const &, char const *, Deprioritize...)
{
}
}
template <class Tag,class T>
inline
std::string
@@ -53,6 +66,17 @@ boost
return to_string_stub(*this);
}
template <class Tag,class T>
inline
void
error_info<Tag,T>::
serialize_to(exception_detail::encoder & e) const
{
char buf[256];
using namespace exception_serialization;
serialize(e, value(), to_zstr(buf, exception_detail::get_pretty_tag_type_name<Tag>()));
}
namespace
exception_detail
{
@@ -108,6 +132,16 @@ boost
return diagnostic_info_str_.c_str();
}
void
serialize_to( encoder & e ) const
{
for( error_info_map::const_iterator i=info_.begin(),end=info_.end(); i!=end; ++i )
{
error_info_base const & x = *i->second;
x.serialize_to(e);
}
}
private:
friend class boost::exception;
@@ -0,0 +1,64 @@
//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_BOOST_JSON_ENCODER_HPP_INCLUDED
#define BOOST_EXCEPTION_SERIALIZATION_BOOST_JSON_ENCODER_HPP_INCLUDED
#include <utility>
namespace
boost
{
namespace
json
{
class value;
struct value_from_tag;
}
namespace
exception_serialization
{
// Baast.JSON does not provide ADL interface for serializing user-defined types.
// This limits the functionality of boost_json_encoder to only types that provide tag_invoke.
template <class Value = boost::json::value, class ValueFromTag = boost::json::value_from_tag>
struct
boost_json_encoder_
{
Value & v_;
template <class T>
friend
auto
output(boost_json_encoder_ & e, T const & x) -> decltype(std::declval<Value &>() = x, void())
{
e.v_ = x;
}
template <class T>
friend
auto
output(boost_json_encoder_ & e, T const & x) -> decltype(tag_invoke(std::declval<ValueFromTag>(), std::declval<Value &>(), x), void())
{
tag_invoke(ValueFromTag{}, e.v_, x);
}
template <class T>
friend
void
output_at(boost_json_encoder_ & e, T const & x, char const * name)
{
if( e.v_.is_null() )
e.v_.emplace_object();
boost_json_encoder_ nested{e.v_.as_object()[name]};
output(nested, x);
}
};
using boost_json_encoder = boost_json_encoder_<>;
}
}
#endif
@@ -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_JSON_ENCODER_HPP_INCLUDED
#define BOOST_EXCEPTION_SERIALIZATION_NLOHMANN_JSON_ENCODER_HPP_INCLUDED
#include <utility>
namespace
boost
{
namespace
exception_serialization
{
template <class Json>
struct
nlohmann_json_encoder
{
Json & j_;
template <class T>
friend
auto
output(nlohmann_json_encoder & e, T const & x) -> decltype(to_json(std::declval<Json &>(), x))
{
to_json(e.j_, x);
}
template <class T>
friend
void
output_at(nlohmann_json_encoder & e, T const & x, char const * name)
{
nlohmann_json_encoder nested{e.j_[name]};
output(nested, x);
}
};
}
}
#endif
+33
View File
@@ -0,0 +1,33 @@
"""
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)
This program downloads the nlohmann/json single header distribution.
Usage:
python3 download_nlohmann_json.py
"""
import urllib.request
import os
url = "https://github.com/nlohmann/json/releases/download/v3.11.3/json.hpp"
output_dir = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "test", "nlohmann")
output_file = os.path.join(output_dir, "json.hpp")
def _main():
if os.path.exists(output_file):
print(f"{output_file} already exists, skipping download")
return
os.makedirs(output_dir, exist_ok=True)
print(f"Downloading {url}...")
urllib.request.urlretrieve(url, output_file)
print(f"Saved to {output_file}")
if __name__ == "__main__":
_main()
+25 -22
View File
@@ -11,10 +11,11 @@ project : requirements <library>/boost/exception//boost_exception ;
#to_string
run is_output_streamable_test.cpp ;
run has_to_string_test.cpp ;
run to_string_test.cpp ;
run is_output_streamable_test.cpp ;
run to_string_stub_test.cpp ;
run to_string_test.cpp ;
compile-fail to_string_fail.cpp ;
#exception
@@ -23,47 +24,42 @@ run 1-throw_exception_test.cpp : : : <exception-handling>on ;
run 2-throw_exception_no_exceptions_test.cpp : : : <exception-handling>off ;
run 3-throw_exception_no_integration_test.cpp : : : <exception-handling>on ;
run 4-throw_exception_no_both_test.cpp : : : <exception-handling>off ;
run boost_json_test.cpp /boost/json//boost_json : : : <exception-handling>on ;
run cloning_test.cpp : : : <exception-handling>on ;
run copy_exception_test.cpp ../../thread/src/tss_null.cpp /boost/thread//boost_thread : : : <threading>multi <exception-handling>on ;
run copy_exception_no_exceptions_test.cpp : : : <exception-handling>off <rtti>on ;
run unknown_exception_test.cpp : : : <exception-handling>on ;
run exception_test.cpp : : : <exception-handling>on ;
run copy_exception_test.cpp ../../thread/src/tss_null.cpp /boost/thread//boost_thread : : : <threading>multi <exception-handling>on ;
run current_exception_cast_test.cpp : : : <exception-handling>on ;
run diagnostic_information_test.cpp : : : <exception-handling>on ;
run enable_error_info_test.cpp helper1.cpp : : : <exception-handling>on ;
run throw_exception_test.cpp helper2.cpp : : : <exception-handling>on ;
run errno_test.cpp : : : <exception-handling>on ;
run error_info_basic_test.cpp : : : <exception-handling>on ;
run error_info_lv_test.cpp : : : <exception-handling>on ;
run error_info_lv_const_test.cpp : : : <exception-handling>on ;
run error_info_rv_test.cpp : : : <exception-handling>on ;
run error_info_lv_test.cpp : : : <exception-handling>on ;
run error_info_rv_const_test.cpp : : : <exception-handling>on ;
run diagnostic_information_test.cpp : : : <exception-handling>on ;
run refcount_ptr_test.cpp ;
run current_exception_cast_test.cpp : : : <exception-handling>on ;
run no_exceptions_test.cpp : : : <exception-handling>off ;
run error_info_rv_test.cpp : : : <exception-handling>on ;
run errinfos_test.cpp : : : <exception-handling>on ;
run exception_ptr_test.cpp/<define>BOOST_ENABLE_NON_INTRUSIVE_EXCEPTION_PTR ../../thread/src/tss_null.cpp /boost/exception//boost_exception /boost/thread//boost_thread : : : <threading>multi <exception-handling>on : non_intrusive_exception_ptr_test ;
run exception_ptr_test.cpp ../../thread/src/tss_null.cpp /boost/thread//boost_thread : : : <threading>multi <exception-handling>on ;
run exception_ptr_test.cpp/<define>BOOST_ENABLE_NON_INTRUSIVE_EXCEPTION_PTR ../../thread/src/tss_null.cpp /boost/exception//boost_exception /boost/thread//boost_thread : : : <threading>multi <exception-handling>on : non_intrusive_exception_ptr_test ;
run exception_ptr_test2.cpp ;
run exception_test.cpp : : : <exception-handling>on ;
run nlohmann_json_test.cpp : : : <exception-handling>on <toolset>clang,<target-os>linux,<cxxstd>2b:<build>no <toolset>clang,<target-os>linux,<cxxstd>23:<build>no ;
run no_exceptions_test.cpp : : : <exception-handling>off ;
run refcount_ptr_test.cpp ;
run throw_exception_test.cpp helper2.cpp : : : <exception-handling>on ;
run unknown_exception_test.cpp : : : <exception-handling>on ;
lib visibility_test_lib : visibility_test_lib.cpp : <visibility>hidden <exception-handling>on ;
run visibility_test.cpp visibility_test_lib/<link>shared : : : <visibility>hidden <exception-handling>on ;
compile-fail error_info_const_fail.cpp ;
compile-fail exception_fail.cpp ;
compile-fail throw_exception_fail.cpp ;
compile-fail error_info_const_fail.cpp ;
#headers
compile exception_ptr_hpp_test.cpp ;
compile diagnostic_information_hpp_test.cpp ;
compile error_info_hpp_test.cpp ;
compile get_error_info_hpp_test.cpp ;
compile info_hpp_test.cpp ;
compile info_tuple_hpp_test.cpp ;
compile to_string_hpp_test.cpp ;
compile to_string_stub_hpp_test.cpp ;
compile all_hpp_test.cpp ;
compile current_exception_cast_hpp_test.cpp ;
compile diagnostic_information_hpp_test.cpp ;
compile errinfo_api_function_hpp_test.cpp ;
compile errinfo_at_line_hpp_test.cpp ;
compile errinfo_errno_hpp_test.cpp ;
@@ -72,3 +68,10 @@ compile errinfo_file_name_hpp_test.cpp ;
compile errinfo_file_open_mode_hpp_test.cpp ;
compile errinfo_nested_exception_hpp_test.cpp ;
compile errinfo_type_info_name_hpp_test.cpp ;
compile error_info_hpp_test.cpp ;
compile exception_ptr_hpp_test.cpp ;
compile get_error_info_hpp_test.cpp ;
compile info_hpp_test.cpp ;
compile info_tuple_hpp_test.cpp ;
compile to_string_hpp_test.cpp ;
compile to_string_stub_hpp_test.cpp ;
+148
View File
@@ -0,0 +1,148 @@
//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)
#include <boost/config.hpp>
#if defined( BOOST_NO_EXCEPTIONS )
# error This program requires exception handling.
#endif
#include <boost/exception/diagnostic_information.hpp>
#include <boost/exception/serialization/boost_json_encoder.hpp>
#include <boost/throw_exception.hpp>
#include <boost/json.hpp>
#include <boost/detail/lightweight_test.hpp>
#include <iomanip>
#include <iostream>
#include <exception>
using output_encoder = boost::exception_serialization::boost_json_encoder;
namespace
boost
{
namespace
exception_serialization
{
template <class Handle, class E>
void
serialize(Handle & h, E const & e, char const * name)
{
h.dispatch(
[&](boost_json_encoder & enc) { output_at(enc, e, name); } );
}
}
}
typedef boost::error_info<struct my_error1_, int> my_error1;
typedef boost::error_info<struct my_error2_, std::string> my_error2;
struct
my_info
{
int code;
char const * message;
friend
void
tag_invoke(boost::json::value_from_tag, boost::json::value & v, my_info const & e)
{
v = {
{"code", e.code},
{"message", e.message}
};
}
};
typedef boost::error_info<struct my_error3_, my_info> my_error3;
struct
test_exception:
virtual boost::exception,
virtual std::exception
{
char const *
what() const noexcept override
{
return "test_exception::what";
}
};
void
check_output(boost::json::value const & j, bool has_source_location)
{
auto const & obj = j.as_object();
if( has_source_location )
{
BOOST_TEST(obj.contains("throw_file"));
BOOST_TEST(obj.contains("throw_line"));
BOOST_TEST(obj.contains("throw_function"));
}
#ifndef BOOST_NO_RTTI
BOOST_TEST(obj.contains("dynamic_exception_type"));
#endif
BOOST_TEST(obj.contains("std::exception::what"));
BOOST_TEST_EQ(obj.at("std::exception::what").as_string(), "test_exception::what");
BOOST_TEST(obj.contains("my_error1_"));
BOOST_TEST_EQ(obj.at("my_error1_").as_int64(), 42);
BOOST_TEST(obj.contains("my_error2_"));
BOOST_TEST_EQ(obj.at("my_error2_").as_string(), "hello");
BOOST_TEST(obj.contains("my_error3_"));
auto const & mij = obj.at("my_error3_").as_object();
BOOST_TEST_EQ(mij.at("code").as_int64(), 1);
BOOST_TEST_EQ(mij.at("message").as_string(), "error one");
}
int
main()
{
{
std::cout << "Testing serialize_diagnostic_information_to:\n";
boost::json::value j;
try
{
test_exception e;
e <<
my_error1(42) <<
my_error2("hello") <<
my_error3({1, "error one"});
BOOST_THROW_EXCEPTION(e);
}
catch( test_exception & e )
{
output_encoder enc{j};
boost::serialize_diagnostic_information_to(e, enc);
}
std::cout << j << std::endl;
check_output(j, true);
}
{
std::cout << "\nTesting serialize_current_exception_diagnostic_information_to:\n";
boost::json::value j;
try
{
test_exception e;
e <<
my_error1(42) <<
my_error2("hello") <<
my_error3({1, "error one"});
BOOST_THROW_EXCEPTION(e);
}
catch( ... )
{
output_encoder enc{j};
boost::serialize_current_exception_diagnostic_information_to(enc);
}
std::cout << j << std::endl;
check_output(j, true);
}
return boost::report_errors();
}
+35 -19
View File
@@ -13,6 +13,7 @@
#include <boost/exception/info.hpp>
#include <boost/detail/lightweight_test.hpp>
#include <boost/detail/workaround.hpp>
#include <iostream>
#if BOOST_WORKAROUND(BOOST_CODEGEARC, BOOST_TESTED_AT(0x610))
struct test_tag1 {};
@@ -141,9 +142,11 @@ main()
catch(
error1 & x )
{
std::string di1=boost::diagnostic_information(x);
std::string di1 = diagnostic_information(x);
std::cout << __LINE__ << " ------------------\n" << di1;
x << tagged_int1(2) << tagged_int2(2);
std::string di2 = diagnostic_information(x);
std::cout << "\n" << di2 << std::endl;
test1(di1,di2);
}
try
@@ -155,9 +158,11 @@ main()
catch(
error1 & x )
{
std::string di1=boost::current_exception_diagnostic_information();
std::string di1 = current_exception_diagnostic_information();
std::cout << __LINE__ << " ------------------\n" << di1;
x << tagged_int1(2) << tagged_int2(2);
std::string di2 = current_exception_diagnostic_information();
std::cout << "\n" << di2 << std::endl;
test1(di1,di2);
}
try
@@ -170,8 +175,10 @@ main()
error2 & x )
{
std::string di1 = diagnostic_information(x);
std::cout << __LINE__ << " ------------------\n" << di1;
x << tagged_int1(2) << tagged_int2(2);
std::string di2 = diagnostic_information(x);
std::cout << "\n" << di2 << std::endl;
test2(di1,di2);
}
try
@@ -184,23 +191,27 @@ main()
error2 & x )
{
std::string di1 = current_exception_diagnostic_information();
BOOST_TEST(di1==boost::diagnostic_information_what(x));
std::cout << __LINE__ << " ------------------\n" << di1;
BOOST_TEST(di1 == diagnostic_information_what(x));
x << tagged_int1(2) << tagged_int2(2);
std::string di2 = current_exception_diagnostic_information();
BOOST_TEST(di2==boost::diagnostic_information_what(x));
std::cout << "\n" << di2 << std::endl;
BOOST_TEST(di2 == diagnostic_information_what(x));
test2(di1,di2);
}
try
{
error3 x;
std::string di=diagnostic_information(x);
std::string di = diagnostic_information(x);
std::cout << __LINE__ << " ------------------\n" << di << std::endl;
test3(di);
throw x;
}
catch(
... )
{
std::string di=current_exception_diagnostic_information();
std::string di = current_exception_diagnostic_information();
std::cout << __LINE__ << " ------------------\n" << di << std::endl;
test3(di);
}
try
@@ -210,9 +221,10 @@ main()
catch(
error4 & x )
{
std::string di1=boost::diagnostic_information(x);
std::string wh1=x.what();
BOOST_TEST(wh1==di1);
std::string di1 = diagnostic_information(x);
std::cout << __LINE__ << " ------------------\n" << di1 << std::endl;
std::string wh1 = x.what();
BOOST_TEST(wh1 == di1);
}
try
{
@@ -222,13 +234,15 @@ main()
catch(
error4 & x )
{
std::string di1=boost::diagnostic_information(x);
std::string wh1=x.what();
BOOST_TEST(wh1==di1);
std::string di1 = diagnostic_information(x);
std::cout << __LINE__ << " ------------------\n" << di1;
std::string wh1 = x.what();
BOOST_TEST(wh1 == di1);
x << tagged_int1(2) << tagged_int2(2);
std::string di2 = diagnostic_information(x);
std::string wh2=x.what();
BOOST_TEST(wh2==di2);
std::cout << "\n" << di2 << std::endl;
std::string wh2 = x.what();
BOOST_TEST(wh2 == di2);
test4(di1,di2);
}
try
@@ -239,13 +253,15 @@ main()
catch(
error4 & x )
{
std::string di1=boost::current_exception_diagnostic_information();
std::string wh1=x.what();
BOOST_TEST(wh1==di1);
std::string di1 = current_exception_diagnostic_information();
std::cout << __LINE__ << " ------------------\n" << di1;
std::string wh1 = x.what();
BOOST_TEST(wh1 == di1);
x << tagged_int1(2) << tagged_int2(2);
std::string di2 = current_exception_diagnostic_information();
std::string wh2=x.what();
BOOST_TEST(wh2==di2);
std::cout << "\n" << di2 << std::endl;
std::string wh2 = x.what();
BOOST_TEST(wh2 == di2);
test4(di1,di2);
}
return boost::report_errors();
+158
View File
@@ -0,0 +1,158 @@
//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)
#include <boost/config.hpp>
#if defined( BOOST_NO_EXCEPTIONS )
# error This program requires exception handling.
#endif
#include <boost/exception/diagnostic_information.hpp>
#include <boost/exception/serialization/nlohmann_json_encoder.hpp>
#include <boost/throw_exception.hpp>
#include "nlohmann/json.hpp"
#include <boost/detail/lightweight_test.hpp>
#include <iomanip>
#include <iostream>
#include <exception>
#include <vector>
using output_encoder = boost::exception_serialization::nlohmann_json_encoder<nlohmann::ordered_json>;
namespace
boost
{
namespace
exception_serialization
{
template <class Handle, class E>
void
serialize(Handle & h, E const & e, char const * name)
{
h.dispatch(
[&](nlohmann_json_encoder<nlohmann::json> & enc) { output_at(enc, e, name); },
[&](nlohmann_json_encoder<nlohmann::ordered_json> & enc) { output_at(enc, e, name); } );
}
}
}
typedef boost::error_info<struct my_error1_, int> my_error1;
typedef boost::error_info<struct my_error2_, std::string> my_error2;
typedef boost::error_info<struct my_error4_, std::vector<int>> my_error4;
struct
my_info
{
int code;
char const * message;
template <class Json>
friend
void
to_json(Json & j, my_info const & e)
{
j["code"] = e.code;
j["message"] = e.message;
}
};
typedef boost::error_info<struct my_error3_, my_info> my_error3;
struct
test_exception:
virtual boost::exception,
virtual std::exception
{
char const *
what() const noexcept override
{
return "test_exception::what";
}
};
void
check_output(nlohmann::ordered_json const & j, bool has_source_location)
{
if( has_source_location )
{
BOOST_TEST(j.contains("throw_file"));
BOOST_TEST(j.contains("throw_line"));
BOOST_TEST(j.contains("throw_function"));
}
#ifndef BOOST_NO_RTTI
BOOST_TEST(j.contains("dynamic_exception_type"));
#endif
BOOST_TEST(j.contains("std::exception::what"));
BOOST_TEST_EQ(j["std::exception::what"].get<std::string>(), "test_exception::what");
BOOST_TEST(j.contains("my_error1_"));
BOOST_TEST_EQ(j["my_error1_"].get<int>(), 42);
BOOST_TEST(j.contains("my_error2_"));
BOOST_TEST_EQ(j["my_error2_"].get<std::string>(), "hello");
BOOST_TEST(j.contains("my_error3_"));
auto const & mij = j["my_error3_"];
BOOST_TEST_EQ(mij["code"].get<int>(), 1);
BOOST_TEST_EQ(mij["message"].get<std::string>(), "error one");
BOOST_TEST(j.contains("my_error4_"));
auto const & vec = j["my_error4_"];
BOOST_TEST_EQ(vec.size(), 3u);
BOOST_TEST_EQ(vec[0].get<int>(), 1);
BOOST_TEST_EQ(vec[1].get<int>(), 2);
BOOST_TEST_EQ(vec[2].get<int>(), 3);
}
int
main()
{
{
std::cout << "Testing serialize_diagnostic_information_to:\n";
nlohmann::ordered_json j;
try
{
test_exception e;
e <<
my_error1(42) <<
my_error2("hello") <<
my_error3({1, "error one"}) <<
my_error4({1, 2, 3});
BOOST_THROW_EXCEPTION(e);
}
catch( test_exception & e )
{
output_encoder enc{j};
boost::serialize_diagnostic_information_to(e, enc);
}
std::cout << std::setw(2) << j << std::endl;
check_output(j, true);
}
{
std::cout << "\nTesting serialize_current_exception_diagnostic_information_to:\n";
nlohmann::ordered_json j;
try
{
test_exception e;
e <<
my_error1(42) <<
my_error2("hello") <<
my_error3({1, "error one"}) <<
my_error4({1, 2, 3});
BOOST_THROW_EXCEPTION(e);
}
catch( ... )
{
output_encoder enc{j};
boost::serialize_current_exception_diagnostic_information_to(enc);
}
std::cout << std::setw(2) << j << std::endl;
check_output(j, true);
}
return boost::report_errors();
}