update boost
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2019.
|
||||
// Copyright Antony Polukhin, 2016-2023.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2019.
|
||||
// Copyright Antony Polukhin, 2016-2023.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2019.
|
||||
// Copyright Antony Polukhin, 2016-2023.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2019.
|
||||
// Copyright Antony Polukhin, 2016-2023.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
@@ -78,12 +78,12 @@ std::size_t this_thread_frames::collect(native_frame_ptr_t* out_frames, std::siz
|
||||
// NOTE: There is no way to pass "skip" count to backtrace function so we need to perform left shift operation.
|
||||
// If number of elements in result backtrace is >= max_frames_count then "skip" elements are wasted.
|
||||
if (frames_count && skip) {
|
||||
if (skip >= frames_count) {
|
||||
frames_count = 0;
|
||||
} else {
|
||||
std::copy(out_frames + skip, out_frames + frames_count, out_frames);
|
||||
frames_count -= skip;
|
||||
}
|
||||
if (skip >= frames_count) {
|
||||
frames_count = 0;
|
||||
} else {
|
||||
std::copy(out_frames + skip, out_frames + frames_count, out_frames);
|
||||
frames_count -= skip;
|
||||
}
|
||||
}
|
||||
#else
|
||||
boost::stacktrace::detail::unwind_state state = { skip, out_frames, out_frames + max_frames_count };
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2019.
|
||||
// Copyright Antony Polukhin, 2016-2023.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2019.
|
||||
// Copyright Antony Polukhin, 2016-2023.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
@@ -44,37 +44,12 @@
|
||||
|
||||
namespace boost { namespace stacktrace { namespace detail {
|
||||
|
||||
class com_global_initer: boost::noncopyable {
|
||||
bool ok_;
|
||||
|
||||
public:
|
||||
com_global_initer() BOOST_NOEXCEPT
|
||||
: ok_(false)
|
||||
{
|
||||
// COINIT_MULTITHREADED means that we must serialize access to the objects manually.
|
||||
// This is the fastest way to work. If user calls CoInitializeEx before us - we
|
||||
// can end up with other mode (which is OK for us).
|
||||
//
|
||||
// If we call CoInitializeEx befire user - user may end up with different mode, which is a problem.
|
||||
// So we need to call that initialization function as late as possible.
|
||||
const DWORD res = ::CoInitializeEx(0, COINIT_MULTITHREADED);
|
||||
ok_ = (res == S_OK || res == S_FALSE);
|
||||
}
|
||||
|
||||
~com_global_initer() BOOST_NOEXCEPT {
|
||||
if (ok_) {
|
||||
::CoUninitialize();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <class T>
|
||||
class com_holder: boost::noncopyable {
|
||||
T* holder_;
|
||||
|
||||
public:
|
||||
com_holder(const com_global_initer&) BOOST_NOEXCEPT
|
||||
com_holder() BOOST_NOEXCEPT
|
||||
: holder_(0)
|
||||
{}
|
||||
|
||||
@@ -98,7 +73,7 @@ public:
|
||||
};
|
||||
|
||||
|
||||
static std::string mingw_demangling_workaround(const std::string& s) {
|
||||
inline std::string mingw_demangling_workaround(const std::string& s) {
|
||||
#ifdef BOOST_GCC
|
||||
if (s.empty()) {
|
||||
return s;
|
||||
@@ -114,14 +89,25 @@ static std::string mingw_demangling_workaround(const std::string& s) {
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void trim_right_zeroes(std::string& s) {
|
||||
// MSVC-9 does not have back() and pop_back() functions in std::string
|
||||
while (!s.empty()) {
|
||||
const std::size_t last = static_cast<std::size_t>(s.size() - 1);
|
||||
if (s[last] != '\0') {
|
||||
break;
|
||||
}
|
||||
s.resize(last);
|
||||
}
|
||||
}
|
||||
|
||||
class debugging_symbols: boost::noncopyable {
|
||||
static void try_init_com(com_holder< ::IDebugSymbols>& idebug, const com_global_initer& com) BOOST_NOEXCEPT {
|
||||
com_holder< ::IDebugClient> iclient(com);
|
||||
static void try_init_com(com_holder< ::IDebugSymbols>& idebug) BOOST_NOEXCEPT {
|
||||
com_holder< ::IDebugClient> iclient;
|
||||
if (S_OK != ::DebugCreate(__uuidof(IDebugClient), iclient.to_void_ptr_ptr())) {
|
||||
return;
|
||||
}
|
||||
|
||||
com_holder< ::IDebugControl> icontrol(com);
|
||||
com_holder< ::IDebugControl> icontrol;
|
||||
const bool res0 = (S_OK == iclient->QueryInterface(
|
||||
__uuidof(IDebugControl),
|
||||
icontrol.to_void_ptr_ptr()
|
||||
@@ -143,20 +129,17 @@ class debugging_symbols: boost::noncopyable {
|
||||
return;
|
||||
}
|
||||
|
||||
// No cheking: QueryInterface sets the output parameter to NULL in case of error.
|
||||
// No checking: QueryInterface sets the output parameter to NULL in case of error.
|
||||
iclient->QueryInterface(__uuidof(IDebugSymbols), idebug.to_void_ptr_ptr());
|
||||
}
|
||||
|
||||
#ifndef BOOST_STACKTRACE_USE_WINDBG_CACHED
|
||||
|
||||
boost::stacktrace::detail::com_global_initer com_;
|
||||
com_holder< ::IDebugSymbols> idebug_;
|
||||
public:
|
||||
debugging_symbols() BOOST_NOEXCEPT
|
||||
: com_()
|
||||
, idebug_(com_)
|
||||
{
|
||||
try_init_com(idebug_, com_);
|
||||
try_init_com(idebug_);
|
||||
}
|
||||
|
||||
#else
|
||||
@@ -168,11 +151,10 @@ public:
|
||||
static com_holder< ::IDebugSymbols>& get_thread_local_debug_inst() BOOST_NOEXCEPT {
|
||||
// [class.mfct]: A static local variable or local type in a member function always refers to the same entity, whether
|
||||
// or not the member function is inline.
|
||||
static thread_local boost::stacktrace::detail::com_global_initer com;
|
||||
static thread_local com_holder< ::IDebugSymbols> idebug(com);
|
||||
static thread_local com_holder< ::IDebugSymbols> idebug;
|
||||
|
||||
if (!idebug.is_inited()) {
|
||||
try_init_com(idebug, com);
|
||||
try_init_com(idebug);
|
||||
}
|
||||
|
||||
return idebug;
|
||||
@@ -217,8 +199,12 @@ public:
|
||||
&size,
|
||||
0
|
||||
));
|
||||
|
||||
// According to https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/dbgeng/nf-dbgeng-idebugsymbols-getnamebyoffset
|
||||
// "This size includes the space for the '\0' terminating character."
|
||||
result.resize(size - 1);
|
||||
} else if (res) {
|
||||
result = name;
|
||||
result.assign(name, size - 1);
|
||||
}
|
||||
|
||||
if (!res) {
|
||||
@@ -301,6 +287,7 @@ public:
|
||||
&size,
|
||||
0
|
||||
));
|
||||
trim_right_zeroes(result.first);
|
||||
result.second = line_num;
|
||||
|
||||
if (!res) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2019.
|
||||
// Copyright Antony Polukhin, 2016-2023.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2019.
|
||||
// Copyright Antony Polukhin, 2016-2023.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
@@ -59,6 +59,9 @@ public:
|
||||
|
||||
std::string to_string(const frame* frames, std::size_t size) {
|
||||
std::string res;
|
||||
if (size == 0) {
|
||||
return res;
|
||||
}
|
||||
res.reserve(64 * size);
|
||||
|
||||
to_string_impl impl;
|
||||
@@ -82,6 +85,10 @@ std::string to_string(const frame* frames, std::size_t size) {
|
||||
|
||||
|
||||
std::string frame::name() const {
|
||||
if (!addr_) {
|
||||
return std::string();
|
||||
}
|
||||
|
||||
#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
|
||||
::Dl_info dli;
|
||||
const bool dl_ok = !!::dladdr(const_cast<void*>(addr_), &dli); // `dladdr` on Solaris accepts nonconst addresses
|
||||
@@ -93,6 +100,10 @@ std::string frame::name() const {
|
||||
}
|
||||
|
||||
std::string to_string(const frame& f) {
|
||||
if (!f) {
|
||||
return std::string();
|
||||
}
|
||||
|
||||
boost::stacktrace::detail::to_string_impl impl;
|
||||
return impl(f.address());
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2019.
|
||||
// Copyright Antony Polukhin, 2016-2023.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
@@ -82,31 +82,35 @@ BOOST_SYMBOL_VISIBLE inline ::backtrace_state* construct_state(const program_loc
|
||||
//
|
||||
//
|
||||
// Unfortunately, that solution segfaults when `construct_state()` function is in .so file
|
||||
// and multiple threads concurrently work with state.
|
||||
// and multiple threads concurrently work with state. I failed to localize the root cause:
|
||||
// https://gcc.gnu.org/bugzilla//show_bug.cgi?id=87653
|
||||
|
||||
#define BOOST_STACKTRACE_DETAIL_IS_MT 1
|
||||
|
||||
#ifndef BOOST_HAS_THREADS
|
||||
static
|
||||
#if !defined(BOOST_HAS_THREADS)
|
||||
# define BOOST_STACKTRACE_DETAIL_STORAGE static
|
||||
# undef BOOST_STACKTRACE_DETAIL_IS_MT
|
||||
# define BOOST_STACKTRACE_DETAIL_IS_MT 0
|
||||
#elif defined(BOOST_STACKTRACE_BACKTRACE_FORCE_STATIC)
|
||||
# define BOOST_STACKTRACE_DETAIL_STORAGE static
|
||||
#elif !defined(BOOST_NO_CXX11_THREAD_LOCAL)
|
||||
# define BOOST_STACKTRACE_DETAIL_STORAGE thread_local
|
||||
#elif defined(__GNUC__) && !defined(__clang__)
|
||||
# define BOOST_STACKTRACE_DETAIL_STORAGE static __thread
|
||||
#else
|
||||
|
||||
// Result of `construct_state()` invocation is not stored by the callers, so `thread_local`
|
||||
// gives a single `state` per thread and that state is not shared between threads in any way.
|
||||
|
||||
# ifndef BOOST_NO_CXX11_THREAD_LOCAL
|
||||
thread_local
|
||||
# elif defined(__GNUC__)
|
||||
static __thread
|
||||
# else
|
||||
/* just a local variable */
|
||||
# endif
|
||||
|
||||
# define BOOST_STACKTRACE_DETAIL_STORAGE /* just a local variable */
|
||||
#endif
|
||||
::backtrace_state* state = ::backtrace_create_state(
|
||||
|
||||
BOOST_STACKTRACE_DETAIL_STORAGE ::backtrace_state* state = ::backtrace_create_state(
|
||||
prog_location.name(),
|
||||
0,
|
||||
BOOST_STACKTRACE_DETAIL_IS_MT,
|
||||
boost::stacktrace::detail::libbacktrace_error_callback,
|
||||
0
|
||||
);
|
||||
|
||||
#undef BOOST_STACKTRACE_DETAIL_IS_MT
|
||||
#undef BOOST_STACKTRACE_DETAIL_STORAGE
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
@@ -195,6 +199,10 @@ inline std::string name_impl(const void* addr) {
|
||||
std::string frame::source_file() const {
|
||||
std::string res;
|
||||
|
||||
if (!addr_) {
|
||||
return res;
|
||||
}
|
||||
|
||||
boost::stacktrace::detail::program_location prog_location;
|
||||
::backtrace_state* state = boost::stacktrace::detail::construct_state(prog_location);
|
||||
|
||||
@@ -213,6 +221,10 @@ std::string frame::source_file() const {
|
||||
}
|
||||
|
||||
std::size_t frame::source_line() const {
|
||||
if (!addr_) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
boost::stacktrace::detail::program_location prog_location;
|
||||
::backtrace_state* state = boost::stacktrace::detail::construct_state(prog_location);
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2019.
|
||||
// Copyright Antony Polukhin, 2016-2023.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2019.
|
||||
// Copyright Antony Polukhin, 2016-2023.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2019.
|
||||
// Copyright Antony Polukhin, 2016-2023.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2019.
|
||||
// Copyright Antony Polukhin, 2016-2023.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2019.
|
||||
// Copyright Antony Polukhin, 2016-2023.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2019.
|
||||
// Copyright Antony Polukhin, 2016-2023.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2019.
|
||||
// Copyright Antony Polukhin, 2016-2023.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2019.
|
||||
// Copyright Antony Polukhin, 2016-2023.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2019.
|
||||
// Copyright Antony Polukhin, 2016-2023.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2019.
|
||||
// Copyright Antony Polukhin, 2016-2023.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Copyright 2014 Renato Tegon Forti, Antony Polukhin.
|
||||
// Copyright 2015-2019 Antony Polukhin.
|
||||
// Copyright Antony Polukhin, 2015-2023.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2019.
|
||||
// Copyright Antony Polukhin, 2016-2023.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
@@ -12,6 +12,24 @@
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/config/pragma_message.hpp>
|
||||
#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) || \
|
||||
defined(BOOST_NO_CXX11_AUTO_DECLARATIONS) || \
|
||||
defined(BOOST_NO_CXX11_CONSTEXPR) || \
|
||||
defined(BOOST_NO_CXX11_NULLPTR) || \
|
||||
defined(BOOST_NO_CXX11_NOEXCEPT) || \
|
||||
defined(BOOST_NO_CXX11_DEFAULTED_FUNCTIONS) || \
|
||||
defined(BOOST_NO_CXX11_FINAL) || \
|
||||
defined(BOOST_NO_CXX11_ALIGNOF) || \
|
||||
defined(BOOST_NO_CXX11_STATIC_ASSERT) || \
|
||||
defined(BOOST_NO_CXX11_SMART_PTR) || \
|
||||
defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) || \
|
||||
defined(BOOST_NO_CXX11_HDR_TYPE_TRAITS)
|
||||
|
||||
BOOST_PRAGMA_MESSAGE("C++03 support is deprecated in Boost.Stacktrace 1.82 and will be removed in Boost.Stacktrace 1.84.")
|
||||
|
||||
#endif
|
||||
|
||||
#include <iosfwd>
|
||||
#include <string>
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2019.
|
||||
// Copyright Antony Polukhin, 2016-2023.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2019.
|
||||
// Copyright Antony Polukhin, 2016-2023.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
@@ -13,6 +13,7 @@
|
||||
#endif
|
||||
|
||||
#include <boost/core/explicit_operator_bool.hpp>
|
||||
#include <boost/core/no_exceptions_support.hpp>
|
||||
#include <boost/container_hash/hash_fwd.hpp>
|
||||
|
||||
#include <iosfwd>
|
||||
@@ -26,6 +27,7 @@
|
||||
#include <boost/stacktrace/stacktrace_fwd.hpp>
|
||||
#include <boost/stacktrace/safe_dump_to.hpp>
|
||||
#include <boost/stacktrace/detail/frame_decl.hpp>
|
||||
#include <boost/stacktrace/frame.hpp>
|
||||
|
||||
#ifdef BOOST_INTEL
|
||||
# pragma warning(push)
|
||||
@@ -69,7 +71,7 @@ class basic_stacktrace {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
BOOST_TRY {
|
||||
{ // Fast path without additional allocations
|
||||
native_frame_ptr_t buffer[buffer_size];
|
||||
const std::size_t frames_count = boost::stacktrace::detail::this_thread_frames::collect(buffer, buffer_size < max_depth ? buffer_size : max_depth, frames_to_skip + 1);
|
||||
@@ -95,9 +97,10 @@ class basic_stacktrace {
|
||||
|
||||
buf.resize(buf.size() * 2);
|
||||
} while (buf.size() < buf.max_size()); // close to `true`, but suppresses `C4127: conditional expression is constant`.
|
||||
} catch (...) {
|
||||
} BOOST_CATCH (...) {
|
||||
// ignore exception
|
||||
}
|
||||
BOOST_CATCH_END
|
||||
}
|
||||
/// @endcond
|
||||
|
||||
@@ -132,7 +135,7 @@ public:
|
||||
///
|
||||
/// @b Async-Handler-Safety: Safe if Allocator construction, copying, Allocator::allocate and Allocator::deallocate are async signal safe.
|
||||
///
|
||||
/// @param a Allocator that would be passed to underlying storeage.
|
||||
/// @param a Allocator that would be passed to underlying storage.
|
||||
BOOST_FORCEINLINE explicit basic_stacktrace(const allocator_type& a) BOOST_NOEXCEPT
|
||||
: impl_(a)
|
||||
{
|
||||
@@ -149,7 +152,7 @@ public:
|
||||
///
|
||||
/// @param max_depth Max call sequence depth to collect.
|
||||
///
|
||||
/// @param a Allocator that would be passed to underlying storeage.
|
||||
/// @param a Allocator that would be passed to underlying storage.
|
||||
///
|
||||
/// @throws Nothing. Note that default construction of allocator may throw, however it is
|
||||
/// performed outside the constructor and exception in `allocator_type()` would not result in calling `std::terminate`.
|
||||
@@ -317,7 +320,7 @@ public:
|
||||
|
||||
/// Constructs stacktrace from raw memory dump. Terminating zero frame is discarded.
|
||||
///
|
||||
/// @param begin Begining of the memory where the stacktrace was saved using the boost::stacktrace::safe_dump_to
|
||||
/// @param begin Beginning of the memory where the stacktrace was saved using the boost::stacktrace::safe_dump_to
|
||||
///
|
||||
/// @param buffer_size_in_bytes Size of the memory. Usually the same value that was passed to the boost::stacktrace::safe_dump_to
|
||||
///
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright Antony Polukhin, 2016-2019.
|
||||
// Copyright Antony Polukhin, 2016-2023.
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
|
||||
Reference in New Issue
Block a user