2
0
mirror of https://github.com/boostorg/leaf.git synced 2026-02-03 09:12:18 +00:00

Significant refactoring:

- Support for error objects crossing DLL boundaries on Windows via BOOST_LEAF_CFG_WIN32=2.
- Internal TLS interface improvements, separating logical allocation from reading.
- Dynamic allocations (if enabled) for on_error objects now happens before stack unwinding begins.
- BOOST_LEAF_SYMBOL_VISIBLE declarations now separated in config/visibility.hpp.
This commit is contained in:
Emil Dotchevski
2025-12-23 17:31:52 -05:00
parent d8e4a84080
commit 56b247d71a
95 changed files with 2332 additions and 903 deletions

View File

@@ -1,10 +1,10 @@
#ifndef BOOST_LEAF_HPP_INCLUDED
#define BOOST_LEAF_HPP_INCLUDED
// Copyright 2018-2024 Emil Dotchevski and Reverge Studios, Inc.
// Copyright 2018-2025 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/leaf/detail/all.hpp>
#endif
#endif // #ifndef BOOST_LEAF_HPP_INCLUDED

View File

@@ -1,7 +1,7 @@
#ifndef BOOST_LEAF_COMMON_HPP_INCLUDED
#define BOOST_LEAF_COMMON_HPP_INCLUDED
// Copyright 2018-2024 Emil Dotchevski and Reverge Studios, Inc.
// Copyright 2018-2025 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)
@@ -18,7 +18,6 @@
#if BOOST_LEAF_CFG_WIN32
# include <windows.h>
# include <cstring>
# ifdef min
# undef min
# endif
@@ -29,18 +28,18 @@
namespace boost { namespace leaf {
struct BOOST_LEAF_SYMBOL_VISIBLE e_api_function { char const * value; };
struct e_api_function { char const * value; };
#if BOOST_LEAF_CFG_STD_STRING
struct BOOST_LEAF_SYMBOL_VISIBLE e_file_name
struct e_file_name
{
std::string value;
};
#else
struct BOOST_LEAF_SYMBOL_VISIBLE e_file_name
struct e_file_name
{
char const * value = "<unavailable>";
BOOST_LEAF_CONSTEXPR explicit e_file_name( char const * ) { }
@@ -48,7 +47,7 @@ struct BOOST_LEAF_SYMBOL_VISIBLE e_file_name
#endif
struct BOOST_LEAF_SYMBOL_VISIBLE e_errno
struct e_errno
{
int value;
@@ -61,9 +60,9 @@ struct BOOST_LEAF_SYMBOL_VISIBLE e_errno
}
};
struct BOOST_LEAF_SYMBOL_VISIBLE e_type_info_name { char const * value; };
struct e_type_info_name { char const * value; };
struct BOOST_LEAF_SYMBOL_VISIBLE e_at_line { int value; };
struct e_at_line { int value; };
namespace windows
{
@@ -97,18 +96,18 @@ namespace windows
{
BOOST_LEAF_ASSERT(mb.p != nullptr);
char * z = std::strchr((LPSTR)mb.p,0);
if( z[-1] == '\n' )
if( z != (LPSTR)mb.p && z[-1] == '\n' )
*--z = 0;
if( z[-1] == '\r' )
if( z != (LPSTR)mb.p && z[-1] == '\r' )
*--z = 0;
return os << err.value << ", \"" << (LPCSTR)mb.p << '"';
}
return os;
}
#endif
#endif // #if BOOST_LEAF_CFG_WIN32
};
}
} // namespace windows
} }
} } // namespace boost::leaf
#endif // BOOST_LEAF_COMMON_HPP_INCLUDED
#endif // #ifndef BOOST_LEAF_COMMON_HPP_INCLUDED

View File

@@ -1,10 +1,13 @@
#ifndef BOOST_LEAF_CONFIG_HPP_INCLUDED
#define BOOST_LEAF_CONFIG_HPP_INCLUDED
// Copyright 2018-2024 Emil Dotchevski and Reverge Studios, Inc.
// Copyright 2018-2025 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 <utility>
#include <exception>
#ifdef BOOST_LEAF_TLS_FREERTOS
# ifndef BOOST_LEAF_EMBEDDED
# define BOOST_LEAF_EMBEDDED
@@ -24,7 +27,7 @@
# ifndef BOOST_LEAF_CFG_CAPTURE
# define BOOST_LEAF_CFG_CAPTURE 0
# endif
#endif
#endif // #ifdef BOOST_LEAF_EMBEDDED
////////////////////////////////////////
@@ -87,8 +90,13 @@
# error BOOST_LEAF_CFG_CAPTURE must be 0 or 1.
#endif
#if BOOST_LEAF_CFG_WIN32 != 0 && BOOST_LEAF_CFG_WIN32 != 1
# error BOOST_LEAF_CFG_WIN32 must be 0 or 1.
#if BOOST_LEAF_CFG_WIN32 != 0 && BOOST_LEAF_CFG_WIN32 != 1 && BOOST_LEAF_CFG_WIN32 != 2
# error BOOST_LEAF_CFG_WIN32 must be 0 or 1 or 2.
#endif
#if BOOST_LEAF_CFG_WIN32 && !defined(_WIN32)
# warning "Ignoring BOOST_LEAF_CFG_WIN32 because _WIN32 is not defined"
# define BOOST_LEAF_CFG_WIN32 0
#endif
#if BOOST_LEAF_CFG_GNUC_STMTEXPR != 0 && BOOST_LEAF_CFG_GNUC_STMTEXPR != 1
@@ -154,7 +162,7 @@
# endif
# endif
#endif
#endif // #ifndef BOOST_LEAF_NO_EXCEPTIONS
////////////////////////////////////////
@@ -203,7 +211,6 @@
////////////////////////////////////////
#ifndef BOOST_LEAF_NO_EXCEPTIONS
# include <exception>
# if (defined(__cpp_lib_uncaught_exceptions) && __cpp_lib_uncaught_exceptions >= 201411L) || (defined(_MSC_VER) && _MSC_VER >= 1900)
# define BOOST_LEAF_STD_UNCAUGHT_EXCEPTIONS 1
# else
@@ -219,6 +226,8 @@
# define BOOST_LEAF_SYMBOL_VISIBLE
#endif
#include <boost/leaf/config/visibility.hpp>
////////////////////////////////////////
#if defined(__GNUC__) && !(defined(__clang__) || defined(__INTEL_COMPILER) || defined(__ICL) || defined(__ICC) || defined(__ECC)) && (__GNUC__ * 100 + __GNUC_MINOR__) < 409
@@ -229,7 +238,36 @@
////////////////////////////////////////
#ifdef _MSC_VER
# define BOOST_LEAF_UNREACHABLE __assume(0)
#else
# define BOOST_LEAF_UNREACHABLE __builtin_unreachable()
#endif
////////////////////////////////////////
namespace boost
{
[[noreturn]] void throw_exception( std::exception const & ); // user defined
}
namespace boost { namespace leaf {
template <class T>
[[noreturn]] void throw_exception_( T && e )
{
#ifdef BOOST_LEAF_NO_EXCEPTIONS
::boost::throw_exception(std::move(e));
#else
throw std::move(e);
#endif
}
} }
////////////////////////////////////////
// Configure TLS access
#include <boost/leaf/config/tls.hpp>
#endif // BOOST_LEAF_CONFIG_HPP_INCLUDED
#endif // #ifndef BOOST_LEAF_CONFIG_HPP_INCLUDED

View File

@@ -1,12 +1,68 @@
#ifndef BOOST_LEAF_CONFIG_TLS_HPP_INCLUDED
#define BOOST_LEAF_CONFIG_TLS_HPP_INCLUDED
// Copyright 2018-2024 Emil Dotchevski and Reverge Studios, Inc.
// Copyright 2018-2025 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)
namespace boost { namespace leaf {
// The following declarations specify the thread local storage API used
// internally by LEAF. To port LEAF to a new TLS API, provide definitions for
// each of these functions.
namespace tls
{
// Generate the next unique error_id. Values start at 1 and increment by 4.
// Error ids must be unique for the lifetime of the process, and this
// function must be thread-safe. Postcondition: (id & 3) == 1 && id != 0.
//
// This function may not fail.
unsigned generate_next_error_id() noexcept;
// Write x to the TLS for the current error_id. The initial value for each
// thread must be 0. Precondition: x == 0 or (x & 3) == 1.
//
// This function may not fail.
void write_current_error_id( unsigned x ) noexcept;
// Read the current error_id for this thread. The initial value for each
// thread must be 0.
//
// This function may not fail.
unsigned read_current_error_id() noexcept;
// Reserve TLS storage for T. The TLS may be allocated dynamically on the
// first call to reserve_ptr<T>, but subsequent calls must reuse the same
// TLS. On platforms where allocation is not needed, this function is
// still defined but does nothing.
//
// This function may throw on allocation failure.
template <class T>
void reserve_ptr();
// Write p to the TLS previously reserved for T by a call to reserve_ptr<T>.
// It is illegal to call write_ptr<T> without a prior successful call to
// reserve_ptr<T>.
//
// This function may not fail.
template <class T>
void write_ptr( T * p ) noexcept;
// Read the T * value previously written in the TLS for T. Returns nullptr
// if TLS for T has not yet been reserved.
//
// This function may not fail.
template <class T>
T * read_ptr() noexcept;
} // namespace tls
} } // namespace boost::leaf
#if defined(BOOST_LEAF_TLS_FREERTOS)
# include <boost/leaf/config/tls_freertos.hpp>
# ifndef BOOST_LEAF_USE_TLS_ARRAY
# define BOOST_LEAF_USE_TLS_ARRAY
# endif
#endif
#ifndef BOOST_LEAF_USE_TLS_ARRAY
@@ -23,10 +79,12 @@
#if defined BOOST_LEAF_USE_TLS_ARRAY
# include <boost/leaf/config/tls_array.hpp>
#elif BOOST_LEAF_CFG_WIN32 == 2
# include <boost/leaf/config/tls_win32.hpp>
#elif defined(BOOST_LEAF_NO_THREADS)
# include <boost/leaf/config/tls_globals.hpp>
#else
# include <boost/leaf/config/tls_cpp11.hpp>
#endif
#endif // BOOST_LEAF_CONFIG_TLS_HPP_INCLUDED
#endif // #ifndef BOOST_LEAF_CONFIG_TLS_HPP_INCLUDED

View File

@@ -1,16 +1,15 @@
#ifndef BOOST_LEAF_CONFIG_TLS_ARRAY_HPP_INCLUDED
#define BOOST_LEAF_CONFIG_TLS_ARRAY_HPP_INCLUDED
// Copyright 2018-2024 Emil Dotchevski and Reverge Studios, Inc.
// Copyright 2018-2025 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)
// Copyright (c) 2022 Khalil Estell
// LEAF requires thread local storage support for pointers and for uin32_t values.
// This header implements thread local storage for pointers and for unsigned int
// values for platforms that support thread local pointers by index.
// This header implements the TLS API specified in tls.hpp for platforms that
// provide TLS by indexing an array (this is typical for embedded platforms).
// The array is accessed via user-defined functions.
namespace boost { namespace leaf {
@@ -26,8 +25,8 @@ namespace tls
////////////////////////////////////////
#include <limits>
#include <atomic>
#include <limits>
#include <cstdint>
#include <type_traits>
@@ -56,19 +55,25 @@ namespace boost { namespace leaf {
namespace detail
{
using atomic_unsigned_int = std::atomic<unsigned int>;
}
namespace tls
{
template <class=void>
struct BOOST_LEAF_SYMBOL_VISIBLE id_factory
{
static atomic_unsigned_int counter;
};
template <class T>
atomic_unsigned_int id_factory<T>::counter(1);
template <class=void>
class BOOST_LEAF_SYMBOL_VISIBLE index_counter
{
static int c_;
static BOOST_LEAF_CFG_TLS_INDEX_TYPE next_() noexcept
BOOST_LEAF_ALWAYS_INLINE static BOOST_LEAF_CFG_TLS_INDEX_TYPE next_() noexcept
{
int idx = ++c_;
BOOST_LEAF_ASSERT(idx > (BOOST_LEAF_CFG_TLS_ARRAY_START_INDEX));
BOOST_LEAF_ASSERT(idx > (BOOST_LEAF_CFG_TLS_ARRAY_START_INDEX + 1));
BOOST_LEAF_ASSERT(idx < (BOOST_LEAF_CFG_TLS_ARRAY_SIZE));
return idx;
}
@@ -76,12 +81,15 @@ namespace tls
public:
template <class T>
static BOOST_LEAF_CFG_TLS_INDEX_TYPE next() noexcept
BOOST_LEAF_ALWAYS_INLINE static BOOST_LEAF_CFG_TLS_INDEX_TYPE next() noexcept
{
return next_(); // Set breakpoint here to monitor TLS index allocation for T.
return next_();
}
};
template <class T>
int index_counter<T>::c_ = BOOST_LEAF_CFG_TLS_ARRAY_START_INDEX + 1;
template <class T>
struct BOOST_LEAF_SYMBOL_VISIBLE tls_index
{
@@ -89,58 +97,72 @@ namespace tls
};
template <class T>
struct BOOST_LEAF_SYMBOL_VISIBLE alloc_tls_index
BOOST_LEAF_CFG_TLS_INDEX_TYPE tls_index<T>::idx = BOOST_LEAF_CFG_TLS_ARRAY_START_INDEX + 1;
template <class T>
struct BOOST_LEAF_SYMBOL_VISIBLE reserve_tls_index
{
static BOOST_LEAF_CFG_TLS_INDEX_TYPE const idx;
};
template <class T>
int index_counter<T>::c_ = BOOST_LEAF_CFG_TLS_ARRAY_START_INDEX;
BOOST_LEAF_CFG_TLS_INDEX_TYPE const reserve_tls_index<T>::idx = tls_index<T>::idx = index_counter<>::next<T>();
} // namespace detail
template <class T>
BOOST_LEAF_CFG_TLS_INDEX_TYPE tls_index<T>::idx = BOOST_LEAF_CFG_TLS_ARRAY_START_INDEX;
} } // namespace boost::leaf
template <class T>
BOOST_LEAF_CFG_TLS_INDEX_TYPE const alloc_tls_index<T>::idx = tls_index<T>::idx = index_counter<>::next<T>();
////////////////////////////////////////
////////////////////////////////////////
namespace boost { namespace leaf {
template <class T>
T * read_ptr() noexcept
namespace tls
{
BOOST_LEAF_ALWAYS_INLINE unsigned generate_next_error_id() noexcept
{
int tls_idx = tls_index<T>::idx;
if( tls_idx == (BOOST_LEAF_CFG_TLS_ARRAY_START_INDEX) )
return nullptr;
--tls_idx;
return reinterpret_cast<T *>(read_void_ptr(tls_idx));
unsigned id = (detail::id_factory<>::counter += 4);
BOOST_LEAF_ASSERT((id&3) == 1);
return id;
}
BOOST_LEAF_ALWAYS_INLINE void write_current_error_id( unsigned x ) noexcept
{
static_assert(sizeof(std::intptr_t) >= sizeof(unsigned), "Incompatible tls_array implementation");
write_void_ptr(BOOST_LEAF_CFG_TLS_ARRAY_START_INDEX, (void *) (std::intptr_t) x);
}
BOOST_LEAF_ALWAYS_INLINE unsigned read_current_error_id() noexcept
{
static_assert(sizeof(std::intptr_t) >= sizeof(unsigned), "Incompatible tls_array implementation");
return (unsigned) (std::intptr_t) read_void_ptr(BOOST_LEAF_CFG_TLS_ARRAY_START_INDEX);
}
template <class T>
void write_ptr( T * p ) noexcept
BOOST_LEAF_ALWAYS_INLINE void reserve_ptr()
{
int tls_idx = alloc_tls_index<T>::idx;
(void) detail::reserve_tls_index<T>::idx;
}
template <class T>
BOOST_LEAF_ALWAYS_INLINE void write_ptr( T * p ) noexcept
{
int tls_idx = detail::tls_index<T>::idx;
BOOST_LEAF_ASSERT(tls_idx != (BOOST_LEAF_CFG_TLS_ARRAY_START_INDEX + 1));
--tls_idx;
write_void_ptr(tls_idx, p);
BOOST_LEAF_ASSERT(read_void_ptr(tls_idx) == p);
}
////////////////////////////////////////
template <class Tag>
unsigned read_uint() noexcept
template <class T>
BOOST_LEAF_ALWAYS_INLINE T * read_ptr() noexcept
{
static_assert(sizeof(std::intptr_t) >= sizeof(unsigned), "Incompatible tls_array implementation");
return (unsigned) (std::intptr_t) (void *) read_ptr<Tag>();
int tls_idx = detail::tls_index<T>::idx;
if( tls_idx == (BOOST_LEAF_CFG_TLS_ARRAY_START_INDEX + 1) )
return nullptr;
--tls_idx;
return reinterpret_cast<T *>(read_void_ptr(tls_idx));
}
} // namespace tls
template <class Tag>
void write_uint( unsigned x ) noexcept
{
static_assert(sizeof(std::intptr_t) >= sizeof(unsigned), "Incompatible tls_array implementation");
write_ptr<Tag>((Tag *) (void *) (std::intptr_t) x);
}
}
} } // namespace boost::leaf
} }
#endif // BOOST_LEAF_CONFIG_TLS_ARRAY_HPP_INCLUDED
#endif // #ifndef BOOST_LEAF_CONFIG_TLS_ARRAY_HPP_INCLUDED

View File

@@ -1,27 +1,34 @@
#ifndef BOOST_LEAF_CONFIG_TLS_CPP11_HPP_INCLUDED
#define BOOST_LEAF_CONFIG_TLS_CPP11_HPP_INCLUDED
// Copyright 2018-2024 Emil Dotchevski and Reverge Studios, Inc.
// Copyright 2018-2025 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)
// LEAF requires thread local storage support for pointers and for uin32_t values.
// This header implements the TLS API specified in tls.hpp using the C++11
// built-in thread_local storage class specifier. On Windows, this
// implementation does not allow error objects to cross DLL boundaries. If this
// is required, define BOOST_LEAF_CFG_WIN32=2 before including any LEAF headers
// to enable the alternative implementation defined in tls_win32.hpp.
// This header implements thread local storage for pointers and for unsigned int
// values using the C++11 built-in thread_local storage class specifier.
#include <cstdint>
#include <atomic>
#include <cstdint>
namespace boost { namespace leaf {
namespace detail
{
using atomic_unsigned_int = std::atomic<unsigned int>;
}
namespace tls
{
template <class=void>
struct BOOST_LEAF_SYMBOL_VISIBLE id_factory
{
static atomic_unsigned_int counter;
};
template <class T>
atomic_unsigned_int id_factory<T>::counter(1);
template <class T>
struct BOOST_LEAF_SYMBOL_VISIBLE ptr
{
@@ -31,42 +38,59 @@ namespace tls
template <class T>
thread_local T * ptr<T>::p;
template <class T>
T * read_ptr() noexcept
{
return ptr<T>::p;
}
template <class T>
void write_ptr( T * p ) noexcept
{
ptr<T>::p = p;
}
////////////////////////////////////////
template <class Tag>
struct BOOST_LEAF_SYMBOL_VISIBLE tagged_uint
template <class=void>
struct BOOST_LEAF_SYMBOL_VISIBLE current_error_id_storage
{
static thread_local unsigned x;
};
template <class Tag>
thread_local unsigned tagged_uint<Tag>::x;
template <class T>
thread_local unsigned current_error_id_storage<T>::x;
} // namespace detail
template <class Tag>
unsigned read_uint() noexcept
} } // namespace boost::leaf
////////////////////////////////////////
namespace boost { namespace leaf {
namespace tls
{
BOOST_LEAF_ALWAYS_INLINE unsigned generate_next_error_id() noexcept
{
return tagged_uint<Tag>::x;
unsigned id = (detail::id_factory<>::counter += 4);
BOOST_LEAF_ASSERT((id&3) == 1);
return id;
}
template <class Tag>
void write_uint( unsigned x ) noexcept
BOOST_LEAF_ALWAYS_INLINE void write_current_error_id( unsigned x ) noexcept
{
tagged_uint<Tag>::x = x;
detail::current_error_id_storage<>::x = x;
}
}
} }
BOOST_LEAF_ALWAYS_INLINE unsigned read_current_error_id() noexcept
{
return detail::current_error_id_storage<>::x;
}
#endif // BOOST_LEAF_CONFIG_TLS_CPP11_HPP_INCLUDED
template <class T>
BOOST_LEAF_ALWAYS_INLINE void reserve_ptr()
{
}
template <class T>
BOOST_LEAF_ALWAYS_INLINE void write_ptr( T * p ) noexcept
{
detail::ptr<T>::p = p;
}
template <class T>
BOOST_LEAF_ALWAYS_INLINE T * read_ptr() noexcept
{
return detail::ptr<T>::p;
}
} // namespace tls
} } // namespace boost::leaf
#endif // #ifndef BOOST_LEAF_CONFIG_TLS_CPP11_HPP_INCLUDED

View File

@@ -1,23 +1,18 @@
#ifndef BOOST_LEAF_CONFIG_TLS_FREERTOS_HPP_INCLUDED
#define BOOST_LEAF_CONFIG_TLS_FREERTOS_HPP_INCLUDED
// Copyright 2018-2024 Emil Dotchevski and Reverge Studios, Inc.
// Copyright 2018-2025 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)
// Copyright (c) 2022 Khalil Estell
// LEAF requires thread local storage support for pointers and for uin32_t values.
// This header implements "thread local" storage via FreeTOS functions
// This header implements the TLS API specified in tls.hpp via the FreeTOS
// pvTaskGetThreadLocalStoragePointer / pvTaskSetThreadLocalStoragePointer
// functions, using the more general implementation defined in tls_array.hpp.
#include <task.h>
#ifndef BOOST_LEAF_USE_TLS_ARRAY
# define BOOST_LEAF_USE_TLS_ARRAY
#endif
#ifndef BOOST_LEAF_CFG_TLS_ARRAY_SIZE
# define BOOST_LEAF_CFG_TLS_ARRAY_SIZE configNUM_THREAD_LOCAL_STORAGE_POINTERS
#endif
@@ -31,12 +26,12 @@ namespace tls
{
// See https://www.freertos.org/thread-local-storage-pointers.html.
inline void * read_void_ptr( int tls_index ) noexcept
BOOST_LEAF_ALWAYS_INLINE void * read_void_ptr( int tls_index ) noexcept
{
return pvTaskGetThreadLocalStoragePointer(0, tls_index);
}
inline void write_void_ptr( int tls_index, void * p ) noexcept
BOOST_LEAF_ALWAYS_INLINE void write_void_ptr( int tls_index, void * p ) noexcept
{
vTaskSetThreadLocalStoragePointer(0, tls_index, p);
}
@@ -44,4 +39,4 @@ namespace tls
} }
#endif // BOOST_LEAF_CONFIG_TLS_FREERTOS_HPP_INCLUDED
#endif // #ifndef BOOST_LEAF_CONFIG_TLS_FREERTOS_HPP_INCLUDED

View File

@@ -1,14 +1,12 @@
#ifndef BOOST_LEAF_CONFIG_TLS_GLOBALS_HPP_INCLUDED
#define BOOST_LEAF_CONFIG_TLS_GLOBALS_HPP_INCLUDED
// Copyright 2018-2024 Emil Dotchevski and Reverge Studios, Inc.
// Copyright 2018-2025 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)
// LEAF requires thread local storage support for pointers and for uin32_t values.
// This header implements "thread local" storage for pointers and for unsigned int
// values using globals, which is suitable for single thread environments.
// This header implements the TLS API specified in tls.hpp using globals, which
// is suitable for single thread environments.
#include <cstdint>
@@ -17,10 +15,16 @@ namespace boost { namespace leaf {
namespace detail
{
using atomic_unsigned_int = unsigned int;
}
namespace tls
{
template <class=void>
struct BOOST_LEAF_SYMBOL_VISIBLE id_factory
{
static atomic_unsigned_int counter;
};
template <class T>
atomic_unsigned_int id_factory<T>::counter = 1;
template <class T>
struct BOOST_LEAF_SYMBOL_VISIBLE ptr
{
@@ -30,42 +34,59 @@ namespace tls
template <class T>
T * ptr<T>::p;
template <class T>
T * read_ptr() noexcept
{
return ptr<T>::p;
}
template <class T>
void write_ptr( T * p ) noexcept
{
ptr<T>::p = p;
}
////////////////////////////////////////
template <class Tag>
struct BOOST_LEAF_SYMBOL_VISIBLE tagged_uint
template <class=void>
struct BOOST_LEAF_SYMBOL_VISIBLE current_error_id_storage
{
static unsigned x;
};
template <class Tag>
unsigned tagged_uint<Tag>::x;
template <class T>
unsigned current_error_id_storage<T>::x = 0;
} // namespace detail
template <class Tag>
unsigned read_uint() noexcept
} } // namespace boost::leaf
////////////////////////////////////////
namespace boost { namespace leaf {
namespace tls
{
BOOST_LEAF_ALWAYS_INLINE unsigned generate_next_error_id() noexcept
{
return tagged_uint<Tag>::x;
unsigned id = (detail::id_factory<>::counter += 4);
BOOST_LEAF_ASSERT((id&3) == 1);
return id;
}
template <class Tag>
void write_uint( unsigned x ) noexcept
BOOST_LEAF_ALWAYS_INLINE void write_current_error_id( unsigned v ) noexcept
{
tagged_uint<Tag>::x = x;
detail::current_error_id_storage<>::x = v;
}
}
} }
BOOST_LEAF_ALWAYS_INLINE unsigned read_current_error_id() noexcept
{
return detail::current_error_id_storage<>::x;
}
#endif // BOOST_LEAF_CONFIG_TLS_GLOBALS_HPP_INCLUDED
template <class T>
BOOST_LEAF_ALWAYS_INLINE void reserve_ptr()
{
}
template <class T>
BOOST_LEAF_ALWAYS_INLINE void write_ptr( T * p ) noexcept
{
detail::ptr<T>::p = p;
}
template <class T>
BOOST_LEAF_ALWAYS_INLINE T * read_ptr() noexcept
{
return detail::ptr<T>::p;
}
} // namespace tls
} } // namespace boost::leaf
#endif // #ifndef BOOST_LEAF_CONFIG_TLS_GLOBALS_HPP_INCLUDED

View File

@@ -0,0 +1,495 @@
#ifndef BOOST_LEAF_CONFIG_TLS_WIN32_HPP_INCLUDED
#define BOOST_LEAF_CONFIG_TLS_WIN32_HPP_INCLUDED
// Copyright 2025 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 header implements the TLS API specified in tls.hpp using Win32 TLS
// functions, allowing error objects to cross DLL boundaries on Windows. This
// implementation is enabled by defining BOOST_LEAF_CFG_WIN32=2 before including
// any LEAF headers.
#ifndef _WIN32
# error "This header is only for Windows"
#endif
#include <atomic>
#include <unordered_map>
#include <cstdint>
#include <new>
#include <stdexcept>
#include <windows.h>
#ifdef min
# undef min
#endif
#ifdef max
# undef max
#endif
namespace boost { namespace leaf {
// Thrown on TLS allocation failure.
class win32_tls_error:
public std::runtime_error
{
public:
explicit win32_tls_error(char const * what) noexcept:
std::runtime_error(what)
{
}
};
namespace detail
{
__declspec(noreturn) inline void raise_fail_fast(NTSTATUS status) noexcept
{
EXCEPTION_RECORD rec = {};
rec.ExceptionCode = status;
rec.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
RaiseFailFastException(&rec, nullptr, 0);
BOOST_LEAF_UNREACHABLE;
}
template <class T, class... Args>
T * heap_new(Args && ... args) noexcept
{
void * mem = HeapAlloc(GetProcessHeap(), 0, sizeof(T));
if (!mem)
{
raise_fail_fast(STATUS_NO_MEMORY);
BOOST_LEAF_UNREACHABLE;
}
return new (mem) T(static_cast<Args &&>(args)...);
}
template <class T>
void heap_delete(T * p) noexcept
{
if (p)
{
p->~T();
BOOL r = HeapFree(GetProcessHeap(), 0, p);
BOOST_LEAF_ASSERT(r), (void) r;
}
}
template <class T>
class heap_allocator
{
public:
using value_type = T;
heap_allocator() noexcept = default;
template <class U>
heap_allocator(heap_allocator<U> const &) noexcept
{
}
T * allocate(std::size_t n) noexcept
{
if (void * p = HeapAlloc(GetProcessHeap(), 0, n * sizeof(T)))
return static_cast<T *>(p);
raise_fail_fast(STATUS_NO_MEMORY);
BOOST_LEAF_UNREACHABLE;
}
void deallocate(T * p, std::size_t) noexcept
{
BOOL r = HeapFree(GetProcessHeap(), 0, p);
BOOST_LEAF_ASSERT(r), (void) r;
}
friend bool operator==(heap_allocator const &, heap_allocator const &) noexcept { return true; }
friend bool operator!=(heap_allocator const &, heap_allocator const &) noexcept { return false; }
};
class critical_section_lock
{
critical_section_lock(critical_section_lock const &) = delete;
critical_section_lock & operator=(critical_section_lock const &) = delete;
CRITICAL_SECTION & cs_;
public:
explicit critical_section_lock(CRITICAL_SECTION & cs) noexcept:
cs_(cs)
{
EnterCriticalSection(&cs_);
}
~critical_section_lock() noexcept
{
LeaveCriticalSection(&cs_);
}
};
using atomic_unsigned_int = std::atomic<unsigned int>;
template <int N, int I>
struct cpp11_hash_step
{
BOOST_LEAF_ALWAYS_INLINE constexpr static std::uint32_t compute(char const (&str)[N], std::uint32_t hash) noexcept
{
return cpp11_hash_step<N, I - 1>::compute(str, (hash ^ static_cast<std::uint32_t>(str[I])) * 16777619u);
}
};
template <int N>
struct cpp11_hash_step<N, -1>
{
BOOST_LEAF_ALWAYS_INLINE constexpr static std::uint32_t compute(char const (&)[N], std::uint32_t hash) noexcept
{
return hash;
}
};
template <int N>
BOOST_LEAF_ALWAYS_INLINE constexpr std::uint32_t cpp11_hash_string(char const (&str)[N]) noexcept
{
return cpp11_hash_step<N, N - 2>::compute(str, 2166136261u); // str[N-2] is the last character before the \0.
}
} // namespace detail
namespace n
{
template <class T>
BOOST_LEAF_ALWAYS_INLINE constexpr std::uint32_t __cdecl h() noexcept
{
return detail::cpp11_hash_string(BOOST_LEAF_PRETTY_FUNCTION);
}
}
namespace detail
{
template<class T>
BOOST_LEAF_ALWAYS_INLINE constexpr std::uint32_t type_hash() noexcept
{
return n::h<T>();
}
}
} } // namespace boost::leaf
////////////////////////////////////////
namespace boost { namespace leaf {
namespace detail
{
class slot_map
{
slot_map(slot_map const &) = delete;
slot_map & operator=(slot_map const &) = delete;
class tls_slot_index
{
tls_slot_index(tls_slot_index const &) = delete;
tls_slot_index & operator=(tls_slot_index const &) = delete;
tls_slot_index & operator=(tls_slot_index &&) = delete;
DWORD idx_;
public:
BOOST_LEAF_ALWAYS_INLINE tls_slot_index():
idx_(TlsAlloc())
{
if (idx_ == TLS_OUT_OF_INDEXES)
throw_exception_(win32_tls_error("TLS_OUT_OF_INDEXES"));
}
BOOST_LEAF_ALWAYS_INLINE ~tls_slot_index() noexcept
{
if (idx_ == TLS_OUT_OF_INDEXES)
return;
BOOL r = TlsFree(idx_);
BOOST_LEAF_ASSERT(r), (void) r;
}
BOOST_LEAF_ALWAYS_INLINE tls_slot_index(tls_slot_index && other) noexcept:
idx_(other.idx_)
{
other.idx_ = TLS_OUT_OF_INDEXES;
}
BOOST_LEAF_ALWAYS_INLINE DWORD get() const noexcept
{
BOOST_LEAF_ASSERT(idx_ != TLS_OUT_OF_INDEXES);
return idx_;
}
};
int refcount_;
HANDLE const mapping_;
tls_slot_index const error_id_slot_;
mutable CRITICAL_SECTION cs_;
std::unordered_map<
std::uint32_t,
tls_slot_index,
std::hash<std::uint32_t>,
std::equal_to<std::uint32_t>,
heap_allocator<std::pair<std::uint32_t const, tls_slot_index>>> map_;
atomic_unsigned_int error_id_storage_;
public:
explicit slot_map(HANDLE mapping) noexcept:
refcount_(1),
mapping_(mapping),
error_id_storage_(1)
{
BOOST_LEAF_ASSERT(mapping != INVALID_HANDLE_VALUE);
InitializeCriticalSection(&cs_);
}
~slot_map() noexcept
{
DeleteCriticalSection(&cs_);
BOOL r = CloseHandle(mapping_);
BOOST_LEAF_ASSERT(r), (void) r;
}
BOOST_LEAF_ALWAYS_INLINE void add_ref() noexcept
{
BOOST_LEAF_ASSERT(refcount_ >= 1);
++refcount_;
}
BOOST_LEAF_ALWAYS_INLINE void release() noexcept
{
--refcount_;
BOOST_LEAF_ASSERT(refcount_ >= 0);
if (refcount_ == 0)
heap_delete(this);
}
DWORD check(std::uint32_t type_hash) const noexcept
{
critical_section_lock lock(cs_);
auto it = map_.find(type_hash);
return (it != map_.end()) ? it->second.get() : TLS_OUT_OF_INDEXES;
}
DWORD get(std::uint32_t type_hash)
{
critical_section_lock lock(cs_);
DWORD idx = map_[type_hash].get();
BOOST_LEAF_ASSERT(idx != TLS_OUT_OF_INDEXES);
return idx;
}
BOOST_LEAF_ALWAYS_INLINE DWORD error_id_slot() const noexcept
{
return error_id_slot_.get();
}
BOOST_LEAF_ALWAYS_INLINE atomic_unsigned_int & error_id_storage() noexcept
{
return error_id_storage_;
}
}; // class slot_map
class module_state
{
module_state(module_state const &) = delete;
module_state & operator=(module_state const &) = delete;
static constexpr unsigned tls_failure_create_mapping = 0x01;
static constexpr unsigned tls_failure_map_view = 0x02;
void * hinstance_;
unsigned tls_failures_;
slot_map * sm_;
public:
constexpr module_state() noexcept:
hinstance_(nullptr),
tls_failures_(0),
sm_(nullptr)
{
}
BOOST_LEAF_ALWAYS_INLINE slot_map & sm() const noexcept
{
BOOST_LEAF_ASSERT(hinstance_);
BOOST_LEAF_ASSERT(!(tls_failures_ & tls_failure_create_mapping));
BOOST_LEAF_ASSERT(!(tls_failures_ & tls_failure_map_view));
BOOST_LEAF_ASSERT(sm_);
return *sm_;
}
BOOST_LEAF_ALWAYS_INLINE void update(PVOID hinstDLL, DWORD dwReason) noexcept
{
if (dwReason == DLL_PROCESS_ATTACH)
{
hinstance_ = hinstDLL;
char name[32] = "Local\\boost_leaf_";
{
constexpr static char const hex[] = "0123456789ABCDEF";
DWORD pid = GetCurrentProcessId();
for (int i = 7; i >= 0; --i)
{
name[17 + i] = hex[pid & 0xf];
pid >>= 4;
}
name[25] = '\0';
}
HANDLE mapping = CreateFileMappingA(INVALID_HANDLE_VALUE, nullptr, PAGE_READWRITE, 0, sizeof(slot_map *), name);
DWORD mapping_status = GetLastError();
if (!mapping)
{
tls_failures_ |= tls_failure_create_mapping;
return;
}
BOOST_LEAF_ASSERT(mapping_status == ERROR_ALREADY_EXISTS || mapping_status == ERROR_SUCCESS);
bool is_first_module = (mapping_status == ERROR_SUCCESS);
slot_map * * mapped_ptr = static_cast<slot_map * *>(MapViewOfFile(mapping, FILE_MAP_WRITE, 0, 0, sizeof(slot_map *)));
if (!mapped_ptr)
{
tls_failures_ |= tls_failure_map_view;
BOOL r = CloseHandle(mapping);
BOOST_LEAF_ASSERT(r), (void) r;
return;
}
if (is_first_module)
sm_ = *mapped_ptr = heap_new<slot_map>(mapping);
else
{
sm_ = *mapped_ptr;
sm_->add_ref();
BOOL r = CloseHandle(mapping);
BOOST_LEAF_ASSERT(r), (void) r;
}
UnmapViewOfFile(mapped_ptr);
}
else if (dwReason == DLL_PROCESS_DETACH)
{
BOOST_LEAF_ASSERT(sm_ || tls_failures_);
if (sm_)
{
sm_->release();
sm_ = nullptr;
}
}
}
}; // class module_state
template<int = 0>
struct module
{
static module_state state;
};
template<int N>
module_state module<N>::state;
BOOST_LEAF_ALWAYS_INLINE unsigned generate_next_error_id() noexcept
{
static atomic_unsigned_int & counter = module<>::state.sm().error_id_storage();
unsigned id = (counter += 4);
BOOST_LEAF_ASSERT((id&3) == 1);
return id;
}
inline void NTAPI tls_callback(PVOID hinstDLL, DWORD dwReason, PVOID) noexcept
{
module<>::state.update(hinstDLL, dwReason);
}
#ifdef _MSC_VER
# pragma section(".CRT$XLB", long, read)
# pragma data_seg(push, ".CRT$XLB")
extern "C" __declspec(selectany) PIMAGE_TLS_CALLBACK boost_leaf_tls_callback = tls_callback;
# pragma data_seg(pop)
# ifdef _WIN64
# pragma comment(linker, "/INCLUDE:boost_leaf_tls_callback")
# else
# pragma comment(linker, "/INCLUDE:_boost_leaf_tls_callback")
# endif
#elif defined(__GNUC__)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wattributes"
extern "C" __attribute__((used, selectany)) PIMAGE_TLS_CALLBACK boost_leaf_tls_callback __attribute__((section(".CRT$XLB"))) = tls_callback;
# pragma GCC diagnostic pop
#else
# error Unknown compiler, unable to define .CRT$XLB section
#endif
} // namespace detail
} } // namespace boost::leaf
////////////////////////////////////////
namespace boost { namespace leaf {
namespace tls
{
BOOST_LEAF_ALWAYS_INLINE unsigned generate_next_error_id() noexcept
{
return detail::generate_next_error_id();
}
BOOST_LEAF_ALWAYS_INLINE void write_current_error_id(unsigned x) noexcept
{
using namespace detail;
DWORD slot = module<>::state.sm().error_id_slot();
BOOL r = TlsSetValue(slot, reinterpret_cast<void *>(static_cast<std::uintptr_t>(x)));
BOOST_LEAF_ASSERT(r), (void) r;
}
BOOST_LEAF_ALWAYS_INLINE unsigned read_current_error_id() noexcept
{
using namespace detail;
DWORD slot = module<>::state.sm().error_id_slot();
LPVOID value = TlsGetValue(slot);
BOOST_LEAF_ASSERT(GetLastError() == ERROR_SUCCESS);
return static_cast<unsigned>(reinterpret_cast<std::uintptr_t>(value));
}
template <class T>
BOOST_LEAF_ALWAYS_INLINE void reserve_ptr()
{
using namespace detail;
thread_local DWORD const cached_slot = module<>::state.sm().get(type_hash<T>());
BOOST_LEAF_ASSERT(cached_slot != TLS_OUT_OF_INDEXES), (void) cached_slot;
}
template <class T>
BOOST_LEAF_ALWAYS_INLINE void write_ptr(T * p) noexcept
{
using namespace detail;
thread_local DWORD const cached_slot = module<>::state.sm().check(type_hash<T>());
DWORD slot = cached_slot;
BOOST_LEAF_ASSERT(slot != TLS_OUT_OF_INDEXES);
BOOL r = TlsSetValue(slot, p);
BOOST_LEAF_ASSERT(r), (void) r;
}
template <class T>
BOOST_LEAF_ALWAYS_INLINE T * read_ptr() noexcept
{
using namespace detail;
thread_local DWORD cached_slot = TLS_OUT_OF_INDEXES;
if (cached_slot == TLS_OUT_OF_INDEXES)
cached_slot = module<>::state.sm().check(type_hash<T>());
DWORD slot = cached_slot;
if (slot == TLS_OUT_OF_INDEXES)
return nullptr;
LPVOID value = TlsGetValue(slot);
BOOST_LEAF_ASSERT(GetLastError() == ERROR_SUCCESS);
return static_cast<T *>(value);
}
} // namespace tls
} } // namespace boost::leaf
#endif // #ifndef BOOST_LEAF_CONFIG_TLS_WIN32_HPP_INCLUDED

View File

@@ -0,0 +1,45 @@
#ifndef BOOST_LEAF_CONFIG_VISIBILITY_HPP_INCLUDED
#define BOOST_LEAF_CONFIG_VISIBILITY_HPP_INCLUDED
// Copyright 2018-2024 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)
namespace boost { namespace leaf {
class BOOST_LEAF_SYMBOL_VISIBLE error_id;
class BOOST_LEAF_SYMBOL_VISIBLE error_info;
class BOOST_LEAF_SYMBOL_VISIBLE diagnostic_info;
class BOOST_LEAF_SYMBOL_VISIBLE diagnostic_details;
struct BOOST_LEAF_SYMBOL_VISIBLE e_api_function;
struct BOOST_LEAF_SYMBOL_VISIBLE e_file_name;
struct BOOST_LEAF_SYMBOL_VISIBLE e_errno;
struct BOOST_LEAF_SYMBOL_VISIBLE e_type_info_name;
struct BOOST_LEAF_SYMBOL_VISIBLE e_at_line;
struct BOOST_LEAF_SYMBOL_VISIBLE e_source_location;
class BOOST_LEAF_SYMBOL_VISIBLE bad_result;
template <class> class BOOST_LEAF_SYMBOL_VISIBLE result;
namespace detail
{
template <class> class BOOST_LEAF_SYMBOL_VISIBLE slot;
class BOOST_LEAF_SYMBOL_VISIBLE exception_base;
template <class> class BOOST_LEAF_SYMBOL_VISIBLE exception;
#if BOOST_LEAF_CFG_CAPTURE
class BOOST_LEAF_SYMBOL_VISIBLE dynamic_allocator;
#endif
#if BOOST_LEAF_CFG_STD_SYSTEM_ERROR
class BOOST_LEAF_SYMBOL_VISIBLE leaf_error_category;
template <class> struct BOOST_LEAF_SYMBOL_VISIBLE get_leaf_error_category;
#endif
}
} } // namespace boost::leaf
#endif // BOOST_LEAF_CONFIG_VISIBILITY_HPP_INCLUDED

View File

@@ -1,7 +1,7 @@
#ifndef BOOST_LEAF_CONTEXT_HPP_INCLUDED
#define BOOST_LEAF_CONTEXT_HPP_INCLUDED
// Copyright 2018-2024 Emil Dotchevski and Reverge Studios, Inc.
// Copyright 2018-2025 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)
@@ -130,7 +130,7 @@ namespace detail
{
static_assert(sizeof(E) == 0, "Error handlers must take this type by value");
};
}
} // namespace detail
////////////////////////////////////////
@@ -171,7 +171,7 @@ namespace detail
else
return find_in_tuple<T, I+1, Tp...>(t);
}
}
} // namespace detail
////////////////////////////////////////
@@ -227,7 +227,7 @@ namespace detail
{
tuple_for_each<std::tuple_size<Tup>::value, Tup>::print(os, tup, to_print, prefix);
}
}
} // namespace detail
////////////////////////////////////////
@@ -262,7 +262,7 @@ namespace detail
template <class... E>
using deduce_e_tuple = typename deduce_e_tuple_impl<typename deduce_e_type_list<leaf_detail_mp11::mp_list<E...>>::type>::type;
}
} // namespace detail
////////////////////////////////////////
@@ -292,11 +292,13 @@ class context
if( ctx_ )
ctx_->activate();
}
#if __cplusplus < 201703L
BOOST_LEAF_CONSTEXPR BOOST_LEAF_ALWAYS_INLINE raii_deactivator( raii_deactivator && x ) noexcept:
ctx_(x.ctx_)
{
x.ctx_ = nullptr;
}
#endif
BOOST_LEAF_ALWAYS_INLINE ~raii_deactivator() noexcept
{
if( ctx_ && ctx_->is_active() )
@@ -313,7 +315,7 @@ public:
BOOST_LEAF_ASSERT(!x.is_active());
}
BOOST_LEAF_CONSTEXPR context() noexcept:
BOOST_LEAF_CONSTEXPR context():
is_active_(false)
{
}
@@ -398,7 +400,7 @@ public:
{
return raii_deactivator(ctx);
}
};
}; // template context
////////////////////////////////////////
@@ -439,7 +441,7 @@ namespace detail
{
using type = deduce_context<leaf_detail_mp11::mp_append<typename fn_mp_args_fwd<H>::type...>>;
};
}
} // namespace detail
template <class... H>
using context_type_from_handlers = typename detail::context_type_from_handlers_impl<H...>::type;
@@ -458,6 +460,6 @@ BOOST_LEAF_CONSTEXPR inline context_type_from_handlers<H...> make_context( H &&
return { };
}
} }
} } // namespace boost::leaf
#endif // BOOST_LEAF_CONTEXT_HPP_INCLUDED
#endif // #ifndef BOOST_LEAF_CONTEXT_HPP_INCLUDED

View File

@@ -1,4 +1,4 @@
// Copyright 2018-2024 Emil Dotchevski and Reverge Studios, Inc.
// Copyright 2018-2025 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)

View File

@@ -1,7 +1,7 @@
#ifndef BOOST_LEAF_DETAIL_CAPTURE_LIST_HPP_INCLUDED
#define BOOST_LEAF_DETAIL_CAPTURE_LIST_HPP_INCLUDED
// Copyright 2018-2024 Emil Dotchevski and Reverge Studios, Inc.
// Copyright 2018-2025 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)
@@ -14,11 +14,8 @@
namespace boost { namespace leaf {
class error_id;
namespace detail
{
struct BOOST_LEAF_SYMBOL_VISIBLE tls_tag_id_factory_current_id;
class capture_list
{
@@ -87,7 +84,7 @@ namespace detail
{
capture_list moved(first_);
first_ = nullptr;
tls::write_uint<detail::tls_tag_id_factory_current_id>(unsigned(err_id));
tls::write_current_error_id(unsigned(err_id));
moved.for_each(
[err_id]( node & n )
{
@@ -113,12 +110,12 @@ namespace detail
(void) to_print;
#endif
}
};
}; // class capture_list
}
} // namespace detail
} }
} } // namespace boost::leaf
#endif
#endif // #if BOOST_LEAF_CFG_CAPTURE
#endif // BOOST_LEAF_DETAIL_CAPTURE_LIST_HPP_INCLUDED
#endif // #ifndef BOOST_LEAF_DETAIL_CAPTURE_LIST_HPP_INCLUDED

View File

@@ -1,7 +1,7 @@
#ifndef BOOST_LEAF_DETAIL_DEMANGLE_HPP_INCLUDED
#define BOOST_LEAF_DETAIL_DEMANGLE_HPP_INCLUDED
// Copyright 2018-2024 Emil Dotchevski and Reverge Studios, Inc.
// Copyright 2018-2025 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)
@@ -41,14 +41,14 @@
# endif
#endif
#endif
#endif // #if BOOST_LEAF_CFG_DIAGNOSTICS
namespace boost { namespace leaf {
namespace detail
{
// The functions below are C++11 constexpr, but we use BOOST_LEAF_ALWAYS_INLINE to control object file
// section count / template bleat. Evidently this makes a difference on gcc / windows at least.
// section count / template bloat.
template <int S1, int S2, int I, bool = S1 >= S2>
struct cpp11_prefix
@@ -111,7 +111,7 @@ namespace detail
{
return cpp11_suffix<S1, S2, S1 - 2, S2 - 2>::check(str, suffix) ? S1 - S2 : 0;
}
}
} // namespace detail
namespace n
{
@@ -205,7 +205,7 @@ namespace n
int const p = sizeof(char[1 + !!s02 * (p22 + p23 + p24)]) - 1; // p is not zero, we've static asserted the hell out of it
return { BOOST_LEAF_PRETTY_FUNCTION + p, s02 - p };
}
}
} // namespace n
using parsed = n::r;
@@ -215,7 +215,7 @@ parsed parse()
return n::p<T>();
}
} }
} } // namespace boost::leaf
////////////////////////////////////////
@@ -243,11 +243,11 @@ namespace detail
} d(mangled_name);
if( d.demangled_name )
return os << d.demangled_name;
#endif
#endif // #if defined(BOOST_LEAF_CFG_DIAGNOSTICS) && defined(BOOST_LEAF_HAS_CXXABI_H)
return os << mangled_name;
}
}
} // namespace detail
} }
} } // namespace boost::leaf
#endif // BOOST_LEAF_DETAIL_DEMANGLE_HPP_INCLUDED
#endif // #ifndef BOOST_LEAF_DETAIL_DEMANGLE_HPP_INCLUDED

View File

@@ -1,7 +1,7 @@
#ifndef BOOST_LEAF_DETAIL_FUNCTION_TRAITS_HPP_INCLUDED
#define BOOST_LEAF_DETAIL_FUNCTION_TRAITS_HPP_INCLUDED
// Copyright 2018-2024 Emil Dotchevski and Reverge Studios, Inc.
// Copyright 2018-2025 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)
@@ -92,8 +92,8 @@ namespace detail
template <class F>
using fn_mp_args = typename function_traits<F>::mp_args;
}
} // namespace detail
} }
} } // namespace boost::leaf
#endif // BOOST_LEAF_DETAIL_FUNCTION_TRAITS_HPP_INCLUDED
#endif // #ifndef BOOST_LEAF_DETAIL_FUNCTION_TRAITS_HPP_INCLUDED

View File

@@ -2,7 +2,7 @@
#define BOOST_LEAF_DETAIL_MP11_HPP_INCLUDED
// Copyright 2015-2017 Peter Dimov.
// Copyright 2018-2024 Emil Dotchevski and Reverge Studios, Inc.
// Copyright 2018-2025 Emil Dotchevski and Reverge Studios, Inc.
//
// Distributed under the Boost Software License, Version 1.0.
//
@@ -300,4 +300,4 @@ template<template<class...> class F, class... T> using mp_valid = typename detai
} } }
#endif // BOOST_LEAF_DETAIL_MP11_HPP_INCLUDED
#endif // #ifndef BOOST_LEAF_DETAIL_MP11_HPP_INCLUDED

View File

@@ -1,13 +1,11 @@
#ifndef BOOST_LEAF_DETAIL_OPTIONAL_HPP_INCLUDED
#define BOOST_LEAF_DETAIL_OPTIONAL_HPP_INCLUDED
// Copyright 2018-2024 Emil Dotchevski and Reverge Studios, Inc.
// Copyright 2018-2025 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/leaf/config.hpp>
#include <utility>
#include <new>
namespace boost { namespace leaf {
@@ -133,16 +131,6 @@ namespace detail
return value_;
}
BOOST_LEAF_CONSTEXPR T const * has_value_any_key() const noexcept
{
return key_ ? &value_ : nullptr;
}
BOOST_LEAF_CONSTEXPR T * has_value_any_key() noexcept
{
return key_ ? &value_ : nullptr;
}
BOOST_LEAF_CONSTEXPR T const * has_value(int key) const noexcept
{
BOOST_LEAF_ASSERT(key);
@@ -184,18 +172,10 @@ namespace detail
reset();
return tmp;
}
}; // template optional
BOOST_LEAF_CONSTEXPR T & value_or_default(int key) noexcept
{
if( T * v = has_value(key) )
return *v;
else
return load(key);
}
};
} // namespace detail
}
} } // namespace boost::leaf
} }
#endif // BOOST_LEAF_DETAIL_OPTIONAL_HPP_INCLUDED
#endif // #ifndef BOOST_LEAF_DETAIL_OPTIONAL_HPP_INCLUDED

View File

@@ -1,7 +1,7 @@
#ifndef BOOST_LEAF_DETAIL_PRINT_HPP_INCLUDED
#define BOOST_LEAF_DETAIL_PRINT_HPP_INCLUDED
// Copyright 2018-2024 Emil Dotchevski and Reverge Studios, Inc.
// Copyright 2018-2025 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)
@@ -9,9 +9,7 @@
#include <boost/leaf/detail/demangle.hpp>
#include <type_traits>
#include <exception>
#include <iosfwd>
#include <cstring>
namespace boost { namespace leaf {
@@ -155,8 +153,8 @@ namespace detail
return print_impl<Enum>(os, prefix, delimiter, ": ", static_cast<typename std::underlying_type<Enum>::type>(enum_));
}
};
}
} // namespace detail
} }
} } // namespace boost::leaf
#endif // BOOST_LEAF_DETAIL_PRINT_HPP_INCLUDED
#endif // #ifndef BOOST_LEAF_DETAIL_PRINT_HPP_INCLUDED

View File

@@ -1,7 +1,7 @@
#ifndef BOOST_LEAF_DIAGNOSTICS_HPP_INCLUDED
#define BOOST_LEAF_DIAGNOSTICS_HPP_INCLUDED
// Copyright 2018-2024 Emil Dotchevski and Reverge Studios, Inc.
// Copyright 2018-2025 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)
@@ -44,7 +44,7 @@ protected:
x.print_diagnostic_info(os);
return os << '\n';
}
};
}; // class diagnostic_info
namespace detail
{
@@ -68,7 +68,7 @@ namespace detail
};
}
#else
#else // #if BOOST_LEAF_CFG_DIAGNOSTICS
class diagnostic_info: public error_info
{
@@ -94,7 +94,7 @@ protected:
x.print_diagnostic_info(os);
return os << "\n";
}
};
}; // class diagnostic_info
namespace detail
{
@@ -117,7 +117,7 @@ namespace detail
};
}
#endif
#endif // #else (#if BOOST_LEAF_CFG_DIAGNOSTICS)
////////////////////////////////////////
@@ -157,7 +157,7 @@ protected:
x.print_diagnostic_details(os);
return os << '\n';
}
};
}; // class diagnostic_details
namespace detail
{
@@ -177,12 +177,12 @@ namespace detail
BOOST_LEAF_CONSTEXPR static diagnostic_details_ get( Tup const & tup, error_info const & ei ) noexcept
{
slot<dynamic_allocator> const * da = find_in_tuple<slot<dynamic_allocator>>(tup);
return diagnostic_details_(ei, tup, da ? da->has_value_any_key() : nullptr );
return diagnostic_details_(ei, tup, da ? &da->get() : nullptr );
}
};
}
#else
#else // #if BOOST_LEAF_CFG_CAPTURE
class diagnostic_details: public diagnostic_info
{
@@ -209,7 +209,7 @@ protected:
x.print_diagnostic_details(os);
return os << "\n";
}
};
}; // class diagnostic_details
namespace detail
{
@@ -233,9 +233,9 @@ namespace detail
};
}
#endif
#endif // #else (#if BOOST_LEAF_CFG_CAPTURE)
#else
#else // #if BOOST_LEAF_CFG_DIAGNOSTICS
class diagnostic_details: public diagnostic_info
{
@@ -284,10 +284,10 @@ namespace detail
};
}
#endif
#endif // #else (#if BOOST_LEAF_CFG_DIAGNOSTICS)
using verbose_diagnostic_info = diagnostic_details;
} }
} } // namespace boost::leaf
#endif // BOOST_LEAF_DIAGNOSTICS_HPP_INCLUDED
#endif // #ifndef BOOST_LEAF_DIAGNOSTICS_HPP_INCLUDED

View File

@@ -1,7 +1,7 @@
#ifndef BOOST_LEAF_ERROR_HPP_INCLUDED
#define BOOST_LEAF_ERROR_HPP_INCLUDED
// Copyright 2018-2024 Emil Dotchevski and Reverge Studios, Inc.
// Copyright 2018-2025 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)
@@ -45,7 +45,7 @@
std::move(BOOST_LEAF_TMP);\
}).value()
#else
#else // #if BOOST_LEAF_CFG_GNUC_STMTEXPR
#define BOOST_LEAF_CHECK(r)\
{\
@@ -56,13 +56,13 @@
return BOOST_LEAF_TMP.error();\
}
#endif
#endif // #else (#if BOOST_LEAF_CFG_GNUC_STMTEXPR)
#define BOOST_LEAF_NEW_ERROR ::boost::leaf::detail::inject_loc{__FILE__,__LINE__,__FUNCTION__}+::boost::leaf::new_error
namespace boost { namespace leaf {
struct BOOST_LEAF_SYMBOL_VISIBLE e_source_location
struct e_source_location
{
char const * file;
int line;
@@ -82,11 +82,9 @@ struct show_in_diagnostics<e_source_location>: std::false_type
////////////////////////////////////////
class BOOST_LEAF_SYMBOL_VISIBLE error_id;
namespace detail
{
class BOOST_LEAF_SYMBOL_VISIBLE exception_base
class exception_base
{
public:
virtual error_id get_error_id() const noexcept = 0;
@@ -104,9 +102,10 @@ namespace detail
namespace detail
{
template <class E>
class BOOST_LEAF_SYMBOL_VISIBLE slot:
class slot:
optional<E>
{
static_assert(std::is_same<E, typename std::decay<E>::type>::value, "E must be decayed for slot<E>");
slot( slot const & ) = delete;
slot & operator=( slot const & ) = delete;
@@ -115,9 +114,18 @@ namespace detail
public:
BOOST_LEAF_CONSTEXPR slot() noexcept:
BOOST_LEAF_CONSTEXPR slot():
prev_(nullptr)
{
tls::reserve_ptr<slot<E>>();
}
template <class T>
BOOST_LEAF_CONSTEXPR slot( int key, T && e ):
optional<E>(key, std::forward<T>(e)),
prev_(nullptr)
{
tls::reserve_ptr<slot<E>>();
}
BOOST_LEAF_CONSTEXPR slot( slot && x ) noexcept:
@@ -159,11 +167,9 @@ namespace detail
using impl::load;
using impl::has_value;
using impl::has_value_any_key;
using impl::value;
using impl::value_or_default;
};
}
}; // template slot
} // namespace detail
////////////////////////////////////////
@@ -171,12 +177,22 @@ namespace detail
namespace detail
{
class BOOST_LEAF_SYMBOL_VISIBLE dynamic_allocator:
class preloaded_base;
template <class E>
struct capturing_slot_node_allocator;
class dynamic_allocator:
capture_list
{
dynamic_allocator( dynamic_allocator const & ) = delete;
dynamic_allocator & operator=( dynamic_allocator const & ) = delete;
template <class>
friend struct capturing_slot_node_allocator;
preloaded_base * preloaded_list_;
class capturing_node:
public capture_list::node
{
@@ -192,54 +208,60 @@ namespace detail
};
template <class E>
class capturing_slot_node:
public capturing_node,
public slot<E>
class capturing_slot_node final:
public slot<E>,
public capturing_node
{
using impl = slot<E>;
capturing_slot_node( capturing_slot_node const & ) = delete;
capturing_slot_node & operator=( capturing_slot_node const & ) = delete;
void deactivate() const noexcept final override
void deactivate() const noexcept override
{
impl::deactivate();
}
void unload( int err_id ) final override
void unload( int err_id ) override
{
impl::unload(err_id);
}
#if BOOST_LEAF_CFG_DIAGNOSTICS
void print(std::ostream & os, error_id const & to_print, char const * & prefix) const final override
void print(std::ostream & os, error_id const & to_print, char const * & prefix) const override
{
impl::print(os, to_print, prefix);
}
#endif
public:
template <class T>
BOOST_LEAF_CONSTEXPR capturing_slot_node( capture_list::node * * & last, int err_id, T && e ):
BOOST_LEAF_CONSTEXPR explicit capturing_slot_node( capture_list::node * * & last ):
capturing_node(last)
{
BOOST_LEAF_ASSERT(last == &next_);
BOOST_LEAF_ASSERT(next_ == nullptr);
}
template <class T>
BOOST_LEAF_CONSTEXPR capturing_slot_node( capture_list::node * * & last, int err_id, T && e ):
slot<E>(err_id, std::forward<T>(e)),
capturing_node(last)
{
BOOST_LEAF_ASSERT(last == &next_);
BOOST_LEAF_ASSERT(next_ == nullptr);
impl::load(err_id, std::forward<T>(e));
}
};
#ifndef BOOST_LEAF_NO_EXCEPTIONS
class capturing_exception_node:
class capturing_exception_node final:
public capturing_node
{
capturing_exception_node( capturing_exception_node const & ) = delete;
capturing_exception_node & operator=( capturing_exception_node const & ) = delete;
void deactivate() const noexcept final override
void deactivate() const noexcept override
{
BOOST_LEAF_ASSERT(0);
}
void unload( int ) final override
void unload( int ) override
{
std::rethrow_exception(ex_);
}
#if BOOST_LEAF_CFG_DIAGNOSTICS
void print(std::ostream &, error_id const &, char const * &) const final override
void print(std::ostream &, error_id const &, char const * &) const override
{
}
#endif
@@ -253,7 +275,7 @@ namespace detail
BOOST_LEAF_ASSERT(ex_);
}
};
#endif
#endif // #ifndef BOOST_LEAF_NO_EXCEPTIONS
node * * last_;
@@ -261,6 +283,7 @@ namespace detail
dynamic_allocator() noexcept:
capture_list(nullptr),
preloaded_list_(nullptr),
last_(&first_)
{
BOOST_LEAF_ASSERT(first_ == nullptr);
@@ -268,24 +291,52 @@ namespace detail
dynamic_allocator( dynamic_allocator && other ) noexcept:
capture_list(std::move(other)),
preloaded_list_(nullptr),
last_(other.last_ == &other.first_? &first_ : other.last_)
{
BOOST_LEAF_ASSERT(last_ != nullptr);
BOOST_LEAF_ASSERT(*last_ == nullptr);
BOOST_LEAF_ASSERT(other.first_ == nullptr);
BOOST_LEAF_ASSERT(other.preloaded_list_ == nullptr);
other.last_ = &other.first_;
}
template <class E>
typename std::decay<E>::type & dynamic_load(int err_id, E && e)
preloaded_base * preloaded_list() const noexcept
{
return preloaded_list_;
}
preloaded_base * link_preloaded_item(preloaded_base * pb) noexcept
{
BOOST_LEAF_ASSERT(pb != nullptr);
preloaded_base * next = preloaded_list_;
preloaded_list_ = pb;
return next;
}
void unlink_preloaded_item(preloaded_base * next) noexcept
{
preloaded_list_ = next;
}
template <class E>
slot<E> * alloc()
{
using T = typename std::decay<E>::type;
BOOST_LEAF_ASSERT(last_ != nullptr);
BOOST_LEAF_ASSERT(*last_ == nullptr);
BOOST_LEAF_ASSERT(tls::read_ptr<slot<T>>() == nullptr);
capturing_slot_node<T> * csn = new capturing_slot_node<T>(last_, err_id, std::forward<E>(e));
BOOST_LEAF_ASSERT(tls::read_ptr<slot<E>>() == nullptr);
capturing_slot_node<E> * csn = capturing_slot_node_allocator<E>::new_(last_);
csn->activate();
return csn->value(err_id);
return csn;
}
template <class E>
slot<E> * reserve()
{
if( slot<E> * p = tls::read_ptr<slot<E>>() )
return p;
else
return alloc<E>();
}
void deactivate() const noexcept
@@ -312,180 +363,165 @@ namespace detail
using capture_list::unload;
using capture_list::print;
}; // class dynamic_allocator
template <class E>
struct capturing_slot_node_allocator
{
template <class... A>
static dynamic_allocator::capturing_slot_node<E> * new_( A && ... a )
{
return new dynamic_allocator::capturing_slot_node<E>(std::forward<A>(a)...);
}
static void delete_( dynamic_allocator::capturing_slot_node<E> * p ) noexcept
{
delete p;
}
};
template <>
inline void slot<dynamic_allocator>::deactivate() const noexcept
class slot<dynamic_allocator>
{
if( dynamic_allocator const * c = this->has_value_any_key() )
c->deactivate();
tls::write_ptr<slot<dynamic_allocator>>(prev_);
}
slot( slot const & ) = delete;
slot & operator=( slot const & ) = delete;
template <>
inline void slot<dynamic_allocator>::unload( int err_id ) noexcept(false)
{
BOOST_LEAF_ASSERT(err_id);
if( dynamic_allocator * da1 = this->has_value_any_key() )
da1->unload(err_id);
}
dynamic_allocator da_;
slot * prev_;
template <class E>
inline void dynamic_load_( int err_id, E && e )
{
if( slot<dynamic_allocator> * sl = tls::read_ptr<slot<dynamic_allocator>>() )
public:
slot() noexcept:
prev_(nullptr)
{
if( dynamic_allocator * c = sl->has_value_any_key() )
c->dynamic_load(err_id, std::forward<E>(e));
else
sl->load(err_id).dynamic_load(err_id, std::forward<E>(e));
tls::reserve_ptr<slot<dynamic_allocator>>();
}
}
template <class E, class F>
inline void dynamic_accumulate_( int err_id, F && f )
{
if( slot<dynamic_allocator> * sl = tls::read_ptr<slot<dynamic_allocator>>() )
slot( slot && x ) noexcept:
da_(std::move(x.da_)),
prev_(nullptr)
{
if( dynamic_allocator * c = sl->has_value(err_id) )
(void) std::forward<F>(f)(c->dynamic_load(err_id, E{}));
else
(void) std::forward<F>(f)(sl->load(err_id).dynamic_load(err_id, E{}));
BOOST_LEAF_ASSERT(x.prev_ == nullptr);
}
}
template <bool OnError, class E>
inline void dynamic_load( int err_id, E && e ) noexcept(OnError)
{
if( OnError )
~slot() noexcept
{
#ifndef BOOST_LEAF_NO_EXCEPTIONS
try
{
#endif
dynamic_load_(err_id, std::forward<E>(e));
#ifndef BOOST_LEAF_NO_EXCEPTIONS
}
catch(...)
{
}
#endif
BOOST_LEAF_ASSERT(tls::read_ptr<slot<dynamic_allocator>>() != this);
}
else
dynamic_load_(err_id, std::forward<E>(e));
}
template <bool OnError, class E, class F>
inline void dynamic_load_accumulate( int err_id, F && f ) noexcept(OnError)
{
if( OnError )
dynamic_allocator const & get() const noexcept
{
#ifndef BOOST_LEAF_NO_EXCEPTIONS
try
{
#endif
dynamic_accumulate_<E>(err_id, std::forward<F>(f));
#ifndef BOOST_LEAF_NO_EXCEPTIONS
}
catch(...)
{
}
#endif
return da_;
}
else
dynamic_accumulate_<E>(err_id, std::forward<F>(f));
}
}
template <>
struct show_in_diagnostics<detail::dynamic_allocator>: std::false_type
{
};
dynamic_allocator & get() noexcept
{
return da_;
}
void activate() noexcept
{
prev_ = tls::read_ptr<slot<dynamic_allocator>>();
tls::write_ptr<slot<dynamic_allocator>>(this);
}
void deactivate() const noexcept
{
da_.deactivate();
tls::write_ptr<slot<dynamic_allocator>>(prev_);
}
void unload( int err_id )
{
BOOST_LEAF_ASSERT(err_id);
da_.unload(err_id);
}
#if BOOST_LEAF_CFG_DIAGNOSTICS
template <class CharT, class Traits, class ErrorID>
void print(std::basic_ostream<CharT, Traits> &, ErrorID, char const * &) const
{
}
#endif
}; // slot specialization for dynamic_allocator
} // namespace detail
#endif // #if BOOST_LEAF_CFG_CAPTURE
////////////////////////////////////////
namespace detail
{
#if BOOST_LEAF_CFG_CAPTURE
inline dynamic_allocator * get_dynamic_allocator() noexcept
{
if( slot<dynamic_allocator> * sl = tls::read_ptr<slot<dynamic_allocator>>() )
return &sl->get();
return nullptr;
}
#endif
template <class E>
inline slot<E> * get_slot() noexcept(!BOOST_LEAF_CFG_CAPTURE)
{
static_assert(!std::is_pointer<E>::value, "Error objects of pointer types are not allowed");
static_assert(!std::is_same<E, error_id>::value, "Error objects of type error_id are not allowed");
if( slot<E> * p = tls::read_ptr<slot<E>>() )
return p;
#if BOOST_LEAF_CFG_CAPTURE
if( dynamic_allocator * da = get_dynamic_allocator() )
return da->alloc<E>();
#endif
return nullptr;
}
template <class E>
inline void slot<E>::unload( int err_id ) noexcept(!BOOST_LEAF_CFG_CAPTURE)
{
BOOST_LEAF_ASSERT(err_id);
if( this->key() != err_id )
return;
if( impl * p = tls::read_ptr<slot<E>>() )
{
if( impl * p = get_slot<E>() )
if( !p->has_value(err_id) )
*p = std::move(*this);
}
#if BOOST_LEAF_CFG_CAPTURE
else
dynamic_load<false>(err_id, std::move(*this).value(err_id));
#endif
}
template <bool OnError, class E>
BOOST_LEAF_CONSTEXPR inline int load_slot( int err_id, E && e ) noexcept(OnError)
template <class E>
BOOST_LEAF_CONSTEXPR inline int load_slot( int err_id, E && e ) noexcept(!BOOST_LEAF_CFG_CAPTURE)
{
using T = typename std::decay<E>::type;
static_assert(!std::is_pointer<T>::value, "Error objects of pointer types are not allowed");
static_assert(!std::is_same<T, error_id>::value, "Error objects of type error_id are not allowed");
using E_decayed = typename std::decay<E>::type;
BOOST_LEAF_ASSERT((err_id&3) == 1);
if( slot<T> * p = tls::read_ptr<slot<T>>() )
{
if( !OnError || !p->has_value(err_id) )
(void) p->load(err_id, std::forward<E>(e));
}
#if BOOST_LEAF_CFG_CAPTURE
else
dynamic_load<OnError>(err_id, std::forward<E>(e));
#endif
if( slot<E_decayed> * p = get_slot<E_decayed>() )
(void) p->load(err_id, std::forward<E>(e));
return 0;
}
template <bool OnError, class F>
BOOST_LEAF_CONSTEXPR inline int load_slot_deferred( int err_id, F && f ) noexcept(OnError)
template <class F>
BOOST_LEAF_CONSTEXPR inline int load_slot_deferred( int err_id, F && f )
{
using E = typename function_traits<F>::return_type;
using T = typename std::decay<E>::type;
static_assert(!std::is_pointer<T>::value, "Error objects of pointer types are not allowed");
static_assert(!std::is_same<T, error_id>::value, "Error objects of type error_id are not allowed");
using E_decayed = typename std::decay<E>::type;
BOOST_LEAF_ASSERT((err_id&3) == 1);
if( slot<T> * p = tls::read_ptr<slot<T>>() )
{
if( !OnError || !p->has_value(err_id) )
(void) p->load(err_id, std::forward<F>(f)());
}
#if BOOST_LEAF_CFG_CAPTURE
else
dynamic_load<OnError>(err_id, std::forward<F>(f)());
#endif
if( slot<E_decayed> * p = get_slot<E_decayed>() )
(void) p->load(err_id, std::forward<F>(f)());
return 0;
}
template <bool OnError, class F>
BOOST_LEAF_CONSTEXPR inline int load_slot_accumulate( int err_id, F && f ) noexcept(OnError)
template <class F>
BOOST_LEAF_CONSTEXPR inline int load_slot_accumulate( int err_id, F && f )
{
static_assert(function_traits<F>::arity == 1, "Lambdas passed to accumulate must take a single e-type argument by reference");
using E = typename std::decay<fn_arg_type<F,0>>::type;
using T = typename std::decay<E>::type;
static_assert(!std::is_pointer<T>::value, "Error objects of pointer types are not allowed");
using E = fn_arg_type<F,0>;
using E_decayed = typename std::decay<E>::type;
BOOST_LEAF_ASSERT((err_id&3) == 1);
if( auto sl = tls::read_ptr<slot<E>>() )
{
if( auto v = sl->has_value(err_id) )
if( slot<E_decayed> * p = get_slot<E_decayed>() )
if( E_decayed * v = p->has_value(err_id) )
(void) std::forward<F>(f)(*v);
else
(void) std::forward<F>(f)(sl->load(err_id,E()));
}
#if BOOST_LEAF_CFG_CAPTURE
else
dynamic_load_accumulate<OnError, E>(err_id, std::forward<F>(f));
#endif
(void) std::forward<F>(f)(p->load(err_id, E_decayed()));
return 0;
}
}
} // namespace detail
////////////////////////////////////////
@@ -500,27 +536,27 @@ namespace detail
template <class E>
struct load_item<E, -1>
{
BOOST_LEAF_CONSTEXPR static int load_( int err_id, E && e ) noexcept
BOOST_LEAF_CONSTEXPR static int load_( int err_id, E && e )
{
return load_slot<false>(err_id, std::forward<E>(e));
return load_slot(err_id, std::forward<E>(e));
}
};
template <class F>
struct load_item<F, 0>
{
BOOST_LEAF_CONSTEXPR static int load_( int err_id, F && f ) noexcept
BOOST_LEAF_CONSTEXPR static int load_( int err_id, F && f )
{
return load_slot_deferred<false>(err_id, std::forward<F>(f));
return load_slot_deferred(err_id, std::forward<F>(f));
}
};
template <class F>
struct load_item<F, 1>
{
BOOST_LEAF_CONSTEXPR static int load_( int err_id, F && f ) noexcept
BOOST_LEAF_CONSTEXPR static int load_( int err_id, F && f )
{
return load_slot_accumulate<false>(err_id, std::forward<F>(f));
return load_slot_accumulate(err_id, std::forward<F>(f));
}
};
}
@@ -529,38 +565,63 @@ namespace detail
namespace detail
{
struct BOOST_LEAF_SYMBOL_VISIBLE tls_tag_id_factory_current_id;
template <class=void>
struct BOOST_LEAF_SYMBOL_VISIBLE id_factory
#if BOOST_LEAF_CFG_CAPTURE
class preloaded_base
{
static atomic_unsigned_int counter;
protected:
BOOST_LEAF_CONSTEXPR static unsigned generate_next_id() noexcept
preloaded_base() noexcept:
next_(
[]( preloaded_base * this_ ) -> preloaded_base *
{
if( dynamic_allocator * da = get_dynamic_allocator() )
return da->link_preloaded_item(this_);
return nullptr;
}(this))
{
auto id = (counter+=4);
BOOST_LEAF_ASSERT((id&3) == 1);
return id;
}
};
template <class T>
atomic_unsigned_int id_factory<T>::counter(1);
~preloaded_base() noexcept
{
if( dynamic_allocator * da = get_dynamic_allocator() )
da->unlink_preloaded_item(next_);
else
BOOST_LEAF_ASSERT(next_ == nullptr);
}
public:
preloaded_base * const next_;
virtual void reserve( dynamic_allocator & ) const = 0;
};
#endif // #if BOOST_LEAF_CFG_CAPTURE
inline int current_id() noexcept
{
unsigned id = tls::read_uint<tls_tag_id_factory_current_id>();
unsigned id = tls::read_current_error_id();
BOOST_LEAF_ASSERT(id == 0 || (id&3) == 1);
return int(id);
}
inline int new_id() noexcept
{
unsigned id = id_factory<>::generate_next_id();
tls::write_uint<tls_tag_id_factory_current_id>(id);
unsigned id = tls::generate_next_error_id();
tls::write_current_error_id(id);
return int(id);
}
inline int start_new_error()
{
int id = new_id();
#if BOOST_LEAF_CFG_CAPTURE
if( dynamic_allocator * da = get_dynamic_allocator() )
for( preloaded_base const * e = da->preloaded_list(); e; e = e->next_ )
e->reserve(*da);
#endif
return id;
}
struct inject_loc
{
char const * file;
@@ -568,26 +629,27 @@ namespace detail
char const * fn;
template <class T>
friend T operator+( inject_loc loc, T && x ) noexcept
friend T operator+( inject_loc loc, T && x ) noexcept(!BOOST_LEAF_CFG_CAPTURE)
{
x.load_source_location_(loc.file, loc.line, loc.fn);
return std::move(x);
}
};
}
} // namespace detail
#if BOOST_LEAF_CFG_STD_SYSTEM_ERROR
namespace detail
{
class leaf_error_category final: public std::error_category
class leaf_error_category final:
public std::error_category
{
bool equivalent( int, std::error_condition const & ) const noexcept final override { return false; }
bool equivalent( std::error_code const &, int ) const noexcept final override { return false; }
char const * name() const noexcept final override { return "LEAF error"; }
std::string message( int ) const final override { return name(); }
bool equivalent( int, std::error_condition const & ) const noexcept override { return false; }
bool equivalent( std::error_code const &, int ) const noexcept override { return false; }
char const * name() const noexcept override { return "LEAF error"; }
std::string message( int ) const override { return name(); }
public:
~leaf_error_category() noexcept final override { }
~leaf_error_category() noexcept override { }
};
template <class=void>
@@ -599,7 +661,7 @@ namespace detail
template <class T>
leaf_error_category get_leaf_error_category<T>::cat;
inline int import_error_code( std::error_code const & ec ) noexcept
inline int import_error_code( std::error_code const & ec ) noexcept(!BOOST_LEAF_CFG_CAPTURE)
{
if( int err_id = ec.value() )
{
@@ -611,15 +673,15 @@ namespace detail
}
else
{
err_id = new_id();
(void) load_slot<false>(err_id, ec);
err_id = start_new_error();
(void) load_slot(err_id, ec);
return (err_id&~3)|1;
}
}
else
return 0;
}
}
} // namespace detail
inline bool is_error_id( std::error_code const & ec ) noexcept
{
@@ -628,7 +690,7 @@ inline bool is_error_id( std::error_code const & ec ) noexcept
return res;
}
#endif
#endif // #if BOOST_LEAF_CFG_STD_SYSTEM_ERROR
////////////////////////////////////////
@@ -637,7 +699,7 @@ namespace detail
BOOST_LEAF_CONSTEXPR error_id make_error_id(int) noexcept;
}
class BOOST_LEAF_SYMBOL_VISIBLE error_id
class error_id
{
friend error_id BOOST_LEAF_CONSTEXPR detail::make_error_id(int) noexcept;
@@ -657,14 +719,14 @@ public:
}
#if BOOST_LEAF_CFG_STD_SYSTEM_ERROR
explicit error_id( std::error_code const & ec ) noexcept:
explicit error_id( std::error_code const & ec ) noexcept(!BOOST_LEAF_CFG_CAPTURE):
value_(detail::import_error_code(std::error_code(ec)))
{
BOOST_LEAF_ASSERT(!value_ || ((value_&3) == 1));
}
template <class Enum>
error_id( Enum e, typename std::enable_if<std::is_error_code_enum<Enum>::value, int>::type = 0 ) noexcept:
error_id( Enum e, typename std::enable_if<std::is_error_code_enum<Enum>::value, int>::type = 0 ) noexcept(!BOOST_LEAF_CFG_CAPTURE):
value_(detail::import_error_code(e))
{
}
@@ -674,7 +736,7 @@ public:
{
return std::error_code(value_, detail::get_leaf_error_category<>::cat);
}
#endif
#endif // #if BOOST_LEAF_CFG_STD_SYSTEM_ERROR
BOOST_LEAF_CONSTEXPR error_id load() const noexcept
{
@@ -682,7 +744,7 @@ public:
}
template <class Item>
BOOST_LEAF_CONSTEXPR error_id load(Item && item) const noexcept
BOOST_LEAF_CONSTEXPR error_id load(Item && item) const
{
if (int err_id = value())
{
@@ -693,7 +755,7 @@ public:
}
template <class... Item>
BOOST_LEAF_CONSTEXPR error_id load( Item && ... item ) const noexcept
BOOST_LEAF_CONSTEXPR error_id load( Item && ... item ) const
{
if( int err_id = value() )
{
@@ -735,7 +797,7 @@ public:
return os << (x.value_ / 4);
}
BOOST_LEAF_CONSTEXPR void load_source_location_( char const * file, int line, char const * function ) const noexcept
BOOST_LEAF_CONSTEXPR void load_source_location_( char const * file, int line, char const * function ) const noexcept(!BOOST_LEAF_CFG_CAPTURE)
{
BOOST_LEAF_ASSERT(file&&*file);
BOOST_LEAF_ASSERT(line>0);
@@ -743,7 +805,7 @@ public:
BOOST_LEAF_ASSERT(value_);
(void) load(e_source_location {file,line,function});
}
};
}; // class error_id
namespace detail
{
@@ -754,15 +816,15 @@ namespace detail
}
}
inline error_id new_error() noexcept
inline error_id new_error()
{
return detail::make_error_id(detail::new_id());
return detail::make_error_id(detail::start_new_error());
}
template <class... Item>
inline error_id new_error( Item && ... item ) noexcept
inline error_id new_error( Item && ... item )
{
return detail::make_error_id(detail::new_id()).load(std::forward<Item>(item)...);
return detail::make_error_id(detail::start_new_error()).load(std::forward<Item>(item)...);
}
inline error_id current_error() noexcept
@@ -782,6 +844,6 @@ struct is_result_type<R const>: is_result_type<R>
{
};
} }
} } // namespace boost::leaf
#endif // BOOST_LEAF_ERROR_HPP_INCLUDED
#endif // #ifndef BOOST_LEAF_ERROR_HPP_INCLUDED

View File

@@ -1,52 +1,14 @@
#ifndef BOOST_LEAF_EXCEPTION_HPP_INCLUDED
#define BOOST_LEAF_EXCEPTION_HPP_INCLUDED
// Copyright 2018-2024 Emil Dotchevski and Reverge Studios, Inc.
// Copyright 2018-2025 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/leaf/config.hpp>
#include <boost/leaf/error.hpp>
#include <exception>
#include <typeinfo>
#ifdef BOOST_LEAF_NO_EXCEPTIONS
namespace boost
{
[[noreturn]] void throw_exception( std::exception const & ); // user defined
}
namespace boost { namespace leaf {
namespace detail
{
template <class T>
[[noreturn]] void throw_exception_impl( T && e )
{
::boost::throw_exception(std::move(e));
}
}
} }
#else
namespace boost { namespace leaf {
namespace detail
{
template <class T>
[[noreturn]] void throw_exception_impl( T && e )
{
throw std::move(e);
}
}
} }
#endif
////////////////////////////////////////
#define BOOST_LEAF_THROW_EXCEPTION ::boost::leaf::detail::throw_with_loc{__FILE__,__LINE__,__FUNCTION__}+::boost::leaf::detail::make_exception
@@ -65,7 +27,7 @@ namespace detail
[[noreturn]] friend void operator+( throw_with_loc loc, Ex && ex )
{
ex.load_source_location_(loc.file, loc.line, loc.fn);
::boost::leaf::detail::throw_exception_impl(std::move(ex));
::boost::leaf::throw_exception_(std::move(ex));
}
};
}
@@ -77,7 +39,7 @@ namespace detail
inline void enforce_std_exception( std::exception const & ) noexcept { }
template <class Ex>
class BOOST_LEAF_SYMBOL_VISIBLE exception:
class exception final:
public Ex,
public exception_base,
public error_id
@@ -86,17 +48,17 @@ namespace detail
bool is_current_exception() const noexcept
{
return tls::read_uint<detail::tls_tag_id_factory_current_id>() == unsigned(error_id::value());
return tls::read_current_error_id() == unsigned(error_id::value());
}
error_id get_error_id() const noexcept final override
error_id get_error_id() const noexcept override
{
clear_current_error_ = false;
return *this;
}
#if BOOST_LEAF_CFG_DIAGNOSTICS && !defined(BOOST_LEAF_NO_EXCEPTIONS)
void print_type_name(std::ostream & os) const final override
void print_type_name(std::ostream & os) const override
{
detail::demangle_and_print(os, typeid(Ex).name());
}
@@ -148,9 +110,9 @@ namespace detail
~exception() noexcept
{
if( clear_current_error_ && is_current_exception() )
tls::write_uint<detail::tls_tag_id_factory_current_id>(0);
tls::write_current_error_id(0);
}
};
}; // template exception
template <class... T>
struct at_least_one_derives_from_std_exception;
@@ -167,7 +129,7 @@ namespace detail
template <class Ex, class... E>
inline
typename std::enable_if<std::is_base_of<std::exception,typename std::remove_reference<Ex>::type>::value, exception<typename std::remove_reference<Ex>::type>>::type
make_exception( error_id err, Ex && ex, E && ... e ) noexcept
make_exception( error_id err, Ex && ex, E && ... e ) noexcept(!BOOST_LEAF_CFG_CAPTURE)
{
static_assert(!at_least_one_derives_from_std_exception<E...>::value, "Error objects passed to leaf::exception may not derive from std::exception");
return exception<typename std::remove_reference<Ex>::type>( err.load(std::forward<E>(e)...), std::forward<Ex>(ex) );
@@ -176,7 +138,7 @@ namespace detail
template <class E1, class... E>
inline
typename std::enable_if<!std::is_base_of<std::exception,typename std::remove_reference<E1>::type>::value, exception<std::exception>>::type
make_exception( error_id err, E1 && car, E && ... cdr ) noexcept
make_exception( error_id err, E1 && car, E && ... cdr ) noexcept(!BOOST_LEAF_CFG_CAPTURE)
{
static_assert(!at_least_one_derives_from_std_exception<E...>::value, "Error objects passed to leaf::exception may not derive from std::exception");
return exception<std::exception>( err.load(std::forward<E1>(car), std::forward<E>(cdr)...) );
@@ -190,7 +152,7 @@ namespace detail
template <class Ex, class... E>
inline
typename std::enable_if<std::is_base_of<std::exception,typename std::remove_reference<Ex>::type>::value, exception<typename std::remove_reference<Ex>::type>>::type
make_exception( Ex && ex, E && ... e ) noexcept
make_exception( Ex && ex, E && ... e ) noexcept(!BOOST_LEAF_CFG_CAPTURE)
{
static_assert(!at_least_one_derives_from_std_exception<E...>::value, "Error objects passed to leaf::exception may not derive from std::exception");
return exception<typename std::remove_reference<Ex>::type>( new_error().load(std::forward<E>(e)...), std::forward<Ex>(ex) );
@@ -199,7 +161,7 @@ namespace detail
template <class E1, class... E>
inline
typename std::enable_if<!std::is_base_of<std::exception,typename std::remove_reference<E1>::type>::value, exception<std::exception>>::type
make_exception( E1 && car, E && ... cdr ) noexcept
make_exception( E1 && car, E && ... cdr ) noexcept(!BOOST_LEAF_CFG_CAPTURE)
{
static_assert(!at_least_one_derives_from_std_exception<E...>::value, "Error objects passed to leaf::exception may not derive from std::exception");
return exception<std::exception>( new_error().load(std::forward<E1>(car), std::forward<E>(cdr)...) );
@@ -209,7 +171,7 @@ namespace detail
{
return exception<std::exception>(leaf::new_error());
}
}
} // namespace detail
template <class... E>
[[noreturn]] void throw_exception( E && ... e )
@@ -217,17 +179,14 @@ template <class... E>
// Warning: setting a breakpoint here will not intercept exceptions thrown
// via BOOST_LEAF_THROW_EXCEPTION or originating in the few other throw
// points elsewhere in LEAF. To intercept all of those exceptions as well,
// set a breakpoint inside boost::leaf::detail::throw_exception_impl.
detail::throw_exception_impl(detail::make_exception(std::forward<E>(e)...));
// set a breakpoint inside boost::leaf::throw_exception_.
throw_exception_(detail::make_exception(std::forward<E>(e)...));
}
////////////////////////////////////////
#ifndef BOOST_LEAF_NO_EXCEPTIONS
template <class T>
class BOOST_LEAF_SYMBOL_VISIBLE result;
namespace detail
{
inline error_id catch_exceptions_helper( std::exception const &, leaf_detail_mp11::mp_list<> )
@@ -258,12 +217,12 @@ namespace detail
template <class T>
using deduce_exception_to_result_return_type = typename deduce_exception_to_result_return_type_impl<T>::type;
}
} // namespace detail
template <class... Ex, class F>
inline
detail::deduce_exception_to_result_return_type<detail::fn_return_type<F>>
exception_to_result( F && f ) noexcept
exception_to_result( F && f ) noexcept(!BOOST_LEAF_CFG_CAPTURE)
{
try
{
@@ -279,8 +238,8 @@ exception_to_result( F && f ) noexcept
}
}
#endif
#endif // #ifndef BOOST_LEAF_NO_EXCEPTIONS
} }
} } // namespace boost::leaf
#endif // BOOST_LEAF_EXCEPTION_HPP_INCLUDED
#endif // #ifndef BOOST_LEAF_EXCEPTION_HPP_INCLUDED

View File

@@ -1,7 +1,7 @@
#ifndef BOOST_LEAF_HANDLE_ERRORS_HPP_INCLUDED
#define BOOST_LEAF_HANDLE_ERRORS_HPP_INCLUDED
// Copyright 2018-2024 Emil Dotchevski and Reverge Studios, Inc.
// Copyright 2018-2025 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)
@@ -11,9 +11,6 @@
namespace boost { namespace leaf {
template <class T>
class BOOST_LEAF_SYMBOL_VISIBLE result;
////////////////////////////////////////
#ifndef BOOST_LEAF_NO_EXCEPTIONS
@@ -30,11 +27,11 @@ namespace detail
}
}
#endif
#endif // #ifndef BOOST_LEAF_NO_EXCEPTIONS
////////////////////////////////////////
class BOOST_LEAF_SYMBOL_VISIBLE error_info
class error_info
{
error_info & operator=( error_info const & ) = delete;
@@ -97,7 +94,7 @@ public:
detail::demangle_and_print(os, typeid(*ex_).name());
os << ": \"" << ex_->what() << '"';
}
#endif
#endif // #ifndef BOOST_LEAF_NO_EXCEPTIONS
}
template <class CharT, class Traits>
@@ -106,7 +103,7 @@ public:
x.print_error_info(os);
return os << '\n';
}
};
}; // class error_info
namespace detail
{
@@ -202,7 +199,7 @@ namespace detail
return nullptr;
}
};
#endif
#endif // #if BOOST_LEAF_CFG_STD_SYSTEM_ERROR
template <class E>
struct peek_exception<E, true>
@@ -222,7 +219,7 @@ namespace detail
}
};
#endif
#endif // #ifndef BOOST_LEAF_NO_EXCEPTIONS
template <class E, bool = does_not_participate_in_context_deduction<E>::value>
struct peek_tuple;
@@ -292,7 +289,7 @@ namespace detail
}
return nullptr;
}
}
} // namespace detail
////////////////////////////////////////
@@ -347,7 +344,7 @@ namespace detail
return handler_argument_traits<Car>::check(tup, ei) && check_arguments<Tup, Cdr...>::check(tup, ei);
}
};
}
} // namespace detail
////////////////////////////////////////
@@ -472,7 +469,7 @@ namespace detail
std::forward<Car>(car),
std::forward<Cdr>(cdr)...);
}
}
} // namespace detail
////////////////////////////////////////
@@ -570,7 +567,7 @@ try_catch( TryBlock && try_block, H && ... ) noexcept
return std::forward<TryBlock>(try_block)();
}
#else
#else // #ifdef BOOST_LEAF_NO_EXCEPTIONS
namespace detail
{
@@ -610,7 +607,7 @@ namespace detail
} );
}
}
}
} // namespace detail
template <class TryBlock, class... H>
inline
@@ -701,7 +698,7 @@ try_catch( TryBlock && try_block, H && ... h )
}
}
#endif
#endif // #else (#ifdef BOOST_LEAF_NO_EXCEPTIONS)
#if BOOST_LEAF_CFG_CAPTURE
@@ -716,7 +713,7 @@ namespace detail
inline
static
leaf_result
try_capture_all_( TryBlock && try_block ) noexcept
try_capture_all_( TryBlock && try_block )
{
detail::slot<detail::dynamic_allocator> sl;
sl.activate();
@@ -733,7 +730,7 @@ namespace detail
{
sl.deactivate();
int const err_id = error_id(r.error()).value();
return leaf_result(sl.value_or_default(err_id).template extract_capture_list<leaf_result>(err_id));
return leaf_result(sl.get().template extract_capture_list<leaf_result>(err_id));
}
}
#ifndef BOOST_LEAF_NO_EXCEPTIONS
@@ -741,15 +738,15 @@ namespace detail
{
sl.deactivate();
int err_id = unpack_error_id(ex).value();
return sl.value_or_default(err_id).template extract_capture_list<leaf_result>(err_id);
return sl.get().template extract_capture_list<leaf_result>(err_id);
}
catch(...)
{
sl.deactivate();
int err_id = current_error().value();
return sl.value_or_default(err_id).template extract_capture_list<leaf_result>(err_id);
return sl.get().template extract_capture_list<leaf_result>(err_id);
}
#endif
#endif // #ifndef BOOST_LEAF_NO_EXCEPTIONS
}
};
@@ -777,7 +774,7 @@ namespace detail
inline
static
leaf_result
try_capture_all_( TryBlock && try_block ) noexcept
try_capture_all_( TryBlock && try_block )
{
detail::slot<detail::dynamic_allocator> sl;
sl.activate();
@@ -793,18 +790,18 @@ namespace detail
{
sl.deactivate();
int err_id = unpack_error_id(ex).value();
return sl.value_or_default(err_id).template extract_capture_list<leaf_result>(err_id);
return sl.get().template extract_capture_list<leaf_result>(err_id);
}
catch(...)
{
sl.deactivate();
int err_id = current_error().value();
return sl.value_or_default(err_id).template extract_capture_list<leaf_result>(err_id);
return sl.get().template extract_capture_list<leaf_result>(err_id);
}
#endif
#endif // #ifndef BOOST_LEAF_NO_EXCEPTIONS
}
};
}
} // namespace detail
template <class TryBlock>
inline
@@ -813,9 +810,10 @@ try_capture_all( TryBlock && try_block ) noexcept
{
return detail::try_capture_all_dispatch<decltype(std::declval<TryBlock>()())>::try_capture_all_(std::forward<TryBlock>(try_block));
}
#endif
} }
#endif // #if BOOST_LEAF_CFG_CAPTURE
} } // namespace boost::leaf
// Boost Exception Integration
@@ -875,8 +873,8 @@ namespace detail
template <class Tag, class T> struct handler_argument_traits<boost::error_info<Tag, T> const *>: handler_argument_traits_require_by_value<boost::error_info<Tag, T>> { };
template <class Tag, class T> struct handler_argument_traits<boost::error_info<Tag, T> &>: handler_argument_traits_require_by_value<boost::error_info<Tag, T>> { };
template <class Tag, class T> struct handler_argument_traits<boost::error_info<Tag, T> *>: handler_argument_traits_require_by_value<boost::error_info<Tag, T>> { };
}
} // namespace detail
} }
} } // namespace boost::leaf
#endif // BOOST_LEAF_HANDLE_ERRORS_HPP_INCLUDED
#endif // #ifndef BOOST_LEAF_HANDLE_ERRORS_HPP_INCLUDED

View File

@@ -1,7 +1,7 @@
#ifndef BOOST_LEAF_ON_ERROR_HPP_INCLUDED
#define BOOST_LEAF_ON_ERROR_HPP_INCLUDED
// Copyright 2018-2024 Emil Dotchevski and Reverge Studios, Inc.
// Copyright 2018-2025 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)
@@ -40,7 +40,7 @@ public:
# else
if( std::uncaught_exception() )
# endif
return detail::new_id();
return detail::start_new_error();
#endif
return 0;
}
@@ -64,7 +64,7 @@ public:
{
return detail::make_error_id(get_id());
}
};
}; // class error_monitor
////////////////////////////////////////
@@ -79,19 +79,31 @@ namespace detail
tuple_for_each_preload<I-1,Tup>::trigger(tup,err_id);
std::get<I-1>(tup).trigger(err_id);
}
#if BOOST_LEAF_CFG_CAPTURE
static void reserve( Tup const & tup, dynamic_allocator & da )
{
tuple_for_each_preload<I-1,Tup>::reserve(tup,da);
std::get<I-1>(tup).reserve(da);
}
#endif
};
template <class Tup>
struct tuple_for_each_preload<0, Tup>
{
BOOST_LEAF_CONSTEXPR static void trigger( Tup const &, int ) noexcept { }
#if BOOST_LEAF_CFG_CAPTURE
static void reserve( Tup const &, dynamic_allocator & ) { }
#endif
};
template <class E>
class preloaded_item
{
using decay_E = typename std::decay<E>::type;
decay_E e_;
using E_decayed = typename std::decay<E>::type;
E_decayed e_;
public:
@@ -102,26 +114,57 @@ namespace detail
BOOST_LEAF_CONSTEXPR void trigger( int err_id ) noexcept
{
(void) load_slot<true>(err_id, std::move(e_));
if( slot<E_decayed> * p = tls::read_ptr<slot<E_decayed>>() )
if( !p->has_value(err_id) )
(void) p->load(err_id, std::move(e_));
}
#if BOOST_LEAF_CFG_CAPTURE
void reserve( dynamic_allocator & da ) const
{
da.reserve<E_decayed>();
}
#endif
};
template <class F, class ReturnType = typename function_traits<F>::return_type>
class deferred_item
{
using E_decayed = typename std::decay<ReturnType>::type;
F f_;
public:
BOOST_LEAF_CONSTEXPR deferred_item( F && f ) noexcept:
BOOST_LEAF_CONSTEXPR deferred_item( F && f ):
f_(std::forward<F>(f))
{
}
BOOST_LEAF_CONSTEXPR void trigger( int err_id ) noexcept
void trigger( int err_id ) noexcept
{
(void) load_slot_deferred<true>(err_id, f_);
if( slot<E_decayed> * p = tls::read_ptr<slot<E_decayed>>() )
if( !p->has_value(err_id) )
{
#ifndef BOOST_LEAF_NO_EXCEPTIONS
try
{
#endif
(void) p->load(err_id, f_());
#ifndef BOOST_LEAF_NO_EXCEPTIONS
}
catch(...)
{
}
#endif
}
}
#if BOOST_LEAF_CFG_CAPTURE
void reserve( dynamic_allocator & da ) const
{
da.reserve<E_decayed>();
}
#endif
};
template <class F>
@@ -136,10 +179,26 @@ namespace detail
{
}
BOOST_LEAF_CONSTEXPR void trigger( int ) noexcept
void trigger( int ) noexcept
{
f_();
#ifndef BOOST_LEAF_NO_EXCEPTIONS
try
{
#endif
f_();
#ifndef BOOST_LEAF_NO_EXCEPTIONS
}
catch(...)
{
}
#endif
}
#if BOOST_LEAF_CFG_CAPTURE
void reserve( dynamic_allocator & ) const
{
}
#endif
};
template <class F, class A0 = fn_arg_type<F,0>, int arity = function_traits<F>::arity>
@@ -148,50 +207,89 @@ namespace detail
template <class F, class A0>
class accumulating_item<F, A0 &, 1>
{
using E_decayed = typename std::decay<A0>::type;
F f_;
public:
BOOST_LEAF_CONSTEXPR accumulating_item( F && f ) noexcept:
BOOST_LEAF_CONSTEXPR accumulating_item( F && f ):
f_(std::forward<F>(f))
{
}
BOOST_LEAF_CONSTEXPR void trigger( int err_id ) noexcept
void trigger( int err_id ) noexcept
{
load_slot_accumulate<true>(err_id, std::move(f_));
if( slot<E_decayed> * p = tls::read_ptr<slot<E_decayed>>() )
{
#ifndef BOOST_LEAF_NO_EXCEPTIONS
try
{
#endif
if( E_decayed * v = p->has_value(err_id) )
(void) std::move(f_)(*v);
else
(void) std::move(f_)(p->load(err_id, E_decayed()));
#ifndef BOOST_LEAF_NO_EXCEPTIONS
}
catch(...)
{
}
#endif
}
}
#if BOOST_LEAF_CFG_CAPTURE
void reserve( dynamic_allocator & da ) const
{
da.reserve<E_decayed>();
}
#endif
};
template <class... Item>
class preloaded
#if BOOST_LEAF_CFG_CAPTURE
: preloaded_base
#endif
{
preloaded( preloaded const & ) = delete;
preloaded & operator=( preloaded const & ) = delete;
std::tuple<Item...> p_;
bool moved_;
error_monitor id_;
#if __cplusplus < 201703L
bool moved_ = false;
#endif
#if BOOST_LEAF_CFG_CAPTURE
void reserve( dynamic_allocator & da ) const override
{
tuple_for_each_preload<sizeof...(Item),decltype(p_)>::reserve(p_,da);
}
#endif
public:
BOOST_LEAF_CONSTEXPR explicit preloaded( Item && ... i ):
p_(std::forward<Item>(i)...),
moved_(false)
p_(std::forward<Item>(i)...)
{
}
#if __cplusplus < 201703L
BOOST_LEAF_CONSTEXPR preloaded( preloaded && x ) noexcept:
p_(std::move(x.p_)),
moved_(false),
id_(std::move(x.id_))
{
x.moved_ = true;
}
#endif
~preloaded() noexcept
{
#if __cplusplus < 201703L
if( moved_ )
return;
#endif
if( auto id = id_.check_id() )
tuple_for_each_preload<sizeof...(Item),decltype(p_)>::trigger(p_,id);
}
@@ -217,7 +315,7 @@ namespace detail
{
using type = accumulating_item<F>;
};
}
} // namespace detail
template <class... Item>
BOOST_LEAF_ATTRIBUTE_NODISCARD BOOST_LEAF_CONSTEXPR inline
@@ -227,6 +325,6 @@ on_error( Item && ... i )
return detail::preloaded<typename detail::deduce_item_type<Item>::type...>(std::forward<Item>(i)...);
}
} }
} } // namespace boost::leaf
#endif // BOOST_LEAF_ON_ERROR_HPP_INCLUDED
#endif // #ifndef BOOST_LEAF_ON_ERROR_HPP_INCLUDED

View File

@@ -1,7 +1,7 @@
#ifndef BOOST_LEAF_PRED_HPP_INCLUDED
#define BOOST_LEAF_PRED_HPP_INCLUDED
// Copyright 2018-2024 Emil Dotchevski and Reverge Studios, Inc.
// Copyright 2018-2025 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)
@@ -33,7 +33,7 @@ namespace detail
BOOST_LEAF_ASSERT(P != nullptr);
return P(e);
}
#endif
#endif // #if __cplusplus >= 201703L
template <class MatchType, class V>
BOOST_LEAF_CONSTEXPR BOOST_LEAF_ALWAYS_INLINE bool cmp_value_pack( MatchType const & e, V v )
@@ -46,7 +46,7 @@ namespace detail
{
return cmp_value_pack(e, car) || cmp_value_pack(e, cdr...);
}
}
} // namespace detail
////////////////////////////////////////
@@ -71,7 +71,7 @@ BOOST_LEAF_CONSTEXPR inline bool category( std::error_code const & ec )
return &ec.category() == &std::error_code(ErrorCodeEnum{}).category();
}
#endif
#endif
#endif // #if BOOST_LEAF_CFG_STD_SYSTEM_ERROR
////////////////////////////////////////
@@ -95,7 +95,7 @@ namespace detail
{
static_assert(sizeof(Enum) == 0, "leaf::condition<E, Enum> should be used with leaf::match_value<>, not with leaf::match<>");
};
#endif
#endif // #if BOOST_LEAF_CFG_STD_SYSTEM_ERROR
}
template <class E, BOOST_LEAF_MATCH_ARGS(match_enum_type<E>, V1, V)>
@@ -123,7 +123,7 @@ struct match<condition<Enum, Enum>, V1, V...>
return detail::cmp_value_pack(e, V1, V...);
}
};
#endif
#endif // #if BOOST_LEAF_CFG_STD_SYSTEM_ERROR
template <class E, BOOST_LEAF_MATCH_ARGS(match_enum_type<E>, V1, V)>
struct is_predicate<match<E, V1, V...>>: std::true_type
@@ -152,7 +152,7 @@ namespace detail
{
static_assert(sizeof(Enum) == 0, "leaf::condition<Enum> should be used with leaf::match<>, not with leaf::match_value<>");
};
#endif
#endif // #if BOOST_LEAF_CFG_STD_SYSTEM_ERROR
}
template <class E, BOOST_LEAF_MATCH_ARGS(match_value_enum_type<E>, V1, V)>
@@ -179,7 +179,7 @@ struct match_value<condition<E, Enum>, V1, V...>
return detail::cmp_value_pack(e.value, V1, V...);
}
};
#endif
#endif // #if BOOST_LEAF_CFG_STD_SYSTEM_ERROR
template <class E, BOOST_LEAF_MATCH_ARGS(match_value_enum_type<E>, V1, V)>
struct is_predicate<match_value<E, V1, V...>>: std::true_type
@@ -208,7 +208,7 @@ template <auto P, auto V1, auto... V>
struct is_predicate<match_member<P, V1, V...>>: std::true_type
{
};
#endif
#endif // #if __cplusplus >= 201703L
////////////////////////////////////////
@@ -289,8 +289,8 @@ struct is_predicate<catch_<Ex...>>: std::true_type
{
};
#endif
#endif // #ifndef BOOST_LEAF_NO_EXCEPTIONS
} }
} } // namespace boost::leaf
#endif // BOOST_LEAF_PRED_HPP_INCLUDED
#endif // #ifndef BOOST_LEAF_PRED_HPP_INCLUDED

View File

@@ -1,7 +1,7 @@
#ifndef BOOST_LEAF_RESULT_HPP_INCLUDED
#define BOOST_LEAF_RESULT_HPP_INCLUDED
// Copyright 2018-2024 Emil Dotchevski and Reverge Studios, Inc.
// Copyright 2018-2025 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)
@@ -10,19 +10,16 @@
#include <boost/leaf/detail/capture_list.hpp>
#include <boost/leaf/exception.hpp>
#include <climits>
#include <functional>
namespace boost { namespace leaf {
namespace detail { class dynamic_allocator; }
////////////////////////////////////////
class bad_result:
public std::exception
{
char const * what() const noexcept final override
char const * what() const noexcept override
{
return "boost::leaf::bad_result";
}
@@ -60,7 +57,7 @@ namespace detail
{
result_value_printer<T>::print(s, x);
}
}
} // namespace detail
////////////////////////////////////////
@@ -158,20 +155,19 @@ namespace detail
BOOST_LEAF_ASSERT(kind() == err_id_zero || kind() == err_id || kind() == err_id_capture_list);
return make_error_id(int((state_&~3)|1));
}
};
}
}; // class result_discriminant
} // namespace detail
////////////////////////////////////////
template <class T>
class BOOST_LEAF_SYMBOL_VISIBLE BOOST_LEAF_ATTRIBUTE_NODISCARD result
class BOOST_LEAF_ATTRIBUTE_NODISCARD result
{
template <class U>
friend class result;
friend class detail::dynamic_allocator;
#if BOOST_LEAF_CFG_CAPTURE
friend class detail::dynamic_allocator;
using capture_list = detail::capture_list;
#endif
@@ -223,6 +219,7 @@ class BOOST_LEAF_SYMBOL_VISIBLE BOOST_LEAF_ATTRIBUTE_NODISCARD result
#endif
default:
BOOST_LEAF_ASSERT(k == result_discriminant::err_id);
(void) k;
case result_discriminant::err_id_zero:
return result<U>(what.get_error_id());
}
@@ -243,6 +240,7 @@ class BOOST_LEAF_SYMBOL_VISIBLE BOOST_LEAF_ATTRIBUTE_NODISCARD result
{
default:
BOOST_LEAF_ASSERT(k == result_discriminant::err_id);
(void) k;
case result_discriminant::err_id_zero:
break;
case result_discriminant::err_id_capture_list:
@@ -265,6 +263,7 @@ class BOOST_LEAF_SYMBOL_VISIBLE BOOST_LEAF_ATTRIBUTE_NODISCARD result
{
default:
BOOST_LEAF_ASSERT(k == result_discriminant::err_id);
(void) k;
case result_discriminant::err_id_zero:
break;
case result_discriminant::err_id_capture_list:
@@ -412,7 +411,7 @@ public:
{
}
#else
#else // #if defined(BOOST_STRICT_CONFIG) || !defined(__clang__)
private:
static int init_T_with_A( T && );
@@ -426,7 +425,7 @@ public:
{
}
#endif
#endif // #else (#if defined(BOOST_STRICT_CONFIG) || !defined(__clang__))
#if BOOST_LEAF_CFG_STD_SYSTEM_ERROR
result( std::error_code const & ec ) noexcept:
@@ -439,7 +438,7 @@ public:
what_(error_id(e))
{
}
#endif
#endif // #if BOOST_LEAF_CFG_STD_SYSTEM_ERROR
~result() noexcept
{
@@ -490,7 +489,7 @@ public:
return stored_;
}
#else
#else // #ifdef BOOST_LEAF_NO_CXX11_REF_QUALIFIERS
value_cref value() const &
{
@@ -516,7 +515,7 @@ public:
return std::move(stored_);
}
#endif
#endif // #else (#ifdef BOOST_LEAF_NO_CXX11_REF_QUALIFIERS)
value_no_ref_const * operator->() const noexcept
{
@@ -544,7 +543,7 @@ public:
return *p;
}
#else
#else // #ifdef BOOST_LEAF_NO_CXX11_REF_QUALIFIERS
value_cref operator*() const & noexcept
{
@@ -574,7 +573,7 @@ public:
return std::move(*p);
}
#endif
#endif // #else (#ifdef BOOST_LEAF_NO_CXX11_REF_QUALIFIERS)
error_result error() noexcept
{
@@ -582,7 +581,7 @@ public:
}
template <class... Item>
error_id load( Item && ... item ) noexcept
error_id load( Item && ... item ) noexcept(!BOOST_LEAF_CFG_CAPTURE)
{
return error_id(error()).load(std::forward<Item>(item)...);
}
@@ -604,7 +603,7 @@ public:
r.print_error_result(os);
return os;
}
};
}; // template result
////////////////////////////////////////
@@ -614,19 +613,19 @@ namespace detail
}
template <>
class BOOST_LEAF_SYMBOL_VISIBLE BOOST_LEAF_ATTRIBUTE_NODISCARD result<void>:
class BOOST_LEAF_ATTRIBUTE_NODISCARD result<void>:
result<detail::void_>
{
template <class U>
friend class result;
friend class detail::dynamic_allocator;
using result_discriminant = detail::result_discriminant;
using void_ = detail::void_;
using base = result<void_>;
#if BOOST_LEAF_CFG_CAPTURE
friend class detail::dynamic_allocator;
result( int err_id, detail::capture_list && cap ) noexcept:
base(err_id, std::move(cap))
{
@@ -663,7 +662,7 @@ public:
base(e)
{
}
#endif
#endif // #if BOOST_LEAF_CFG_STD_SYSTEM_ERROR
~result() noexcept
{
@@ -712,7 +711,7 @@ public:
using base::error;
using base::load;
using base::unload;
};
}; // result specialization for void
////////////////////////////////////////
@@ -724,6 +723,6 @@ struct is_result_type<result<T>>: std::true_type
{
};
} }
} } // namespace boost::leaf
#endif // BOOST_LEAF_RESULT_HPP_INCLUDED
#endif // #ifndef BOOST_LEAF_RESULT_HPP_INCLUDED

View File

@@ -1,7 +1,7 @@
#ifndef BOOST_LEAF_TO_VARIANT_HPP_INCLUDED
#define BOOST_LEAF_TO_VARIANT_HPP_INCLUDED
// Copyright 2018-2024 Emil Dotchevski and Reverge Studios, Inc.
// Copyright 2018-2025 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)
@@ -42,8 +42,8 @@ to_variant( TryBlock && try_block )
} );
}
} }
} } // namespace boost::leaf
#endif
#endif // #if __cplusplus >= 201703L
#endif // BOOST_LEAF_TO_VARIANT_HPP_INCLUDED
#endif // #ifndef BOOST_LEAF_TO_VARIANT_HPP_INCLUDED