update boost

This commit is contained in:
2023-11-24 12:56:13 -06:00
parent cfc99971af
commit 19d727037a
9260 changed files with 849256 additions and 299957 deletions

View File

@@ -0,0 +1,80 @@
/* Tells C++ coroutines about Outcome's result
(C) 2019-2023 Niall Douglas <http://www.nedproductions.biz/> (12 commits)
File Created: Oct 2019
Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#ifndef BOOST_OUTCOME_EXPERIMENTAL_COROUTINE_SUPPORT_HPP
#define BOOST_OUTCOME_EXPERIMENTAL_COROUTINE_SUPPORT_HPP
#include "../config.hpp"
#define BOOST_OUTCOME_COROUTINE_SUPPORT_NAMESPACE_BEGIN \
BOOST_OUTCOME_V2_NAMESPACE_BEGIN namespace experimental \
{ \
namespace awaitables \
{
//
#define BOOST_OUTCOME_COROUTINE_SUPPORT_NAMESPACE_EXPORT_BEGIN \
BOOST_OUTCOME_V2_NAMESPACE_EXPORT_BEGIN namespace experimental \
{ \
namespace awaitables \
{
//
#define BOOST_OUTCOME_COROUTINE_SUPPORT_NAMESPACE_END \
} \
} \
BOOST_OUTCOME_V2_NAMESPACE_END
#ifndef BOOST_NO_EXCEPTIONS
#if !BOOST_OUTCOME_USE_SYSTEM_STATUS_CODE && __has_include("status-code/status-code/system_code_from_exception.hpp")
#include "status-code/status-code/system_code_from_exception.hpp"
#else
#include <status-code/system_code_from_exception.hpp>
#endif
BOOST_OUTCOME_V2_NAMESPACE_BEGIN
namespace awaitables
{
namespace detail
{
inline bool error_is_set(BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::system_code &sc) noexcept { return sc.failure(); }
inline BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::system_code error_from_exception(std::exception_ptr &&ep = std::current_exception(), BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::system_code not_matched = BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::generic_code(BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::errc::resource_unavailable_try_again)) noexcept
{
return BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::system_code_from_exception(static_cast<std::exception_ptr &&>(ep), static_cast<BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::system_code &&>(not_matched));
}
} // namespace detail
} // namespace awaitables
BOOST_OUTCOME_V2_NAMESPACE_END
#endif
#include "../detail/coroutine_support.ipp"
#undef BOOST_OUTCOME_COROUTINE_SUPPORT_NAMESPACE_BEGIN
#undef BOOST_OUTCOME_COROUTINE_SUPPORT_NAMESPACE_EXPORT_BEGIN
#undef BOOST_OUTCOME_COROUTINE_SUPPORT_NAMESPACE_END
#endif

View File

@@ -1,5 +1,5 @@
/* C interface for result
(C) 2017-2019 Niall Douglas <http://www.nedproductions.biz/> (59 commits)
(C) 2017-2023 Niall Douglas <http://www.nedproductions.biz/> (6 commits)
File Created: Aug 2017
@@ -33,12 +33,20 @@ DEALINGS IN THE SOFTWARE.
#include <stdint.h> // for intptr_t
#define BOOST_OUTCOME_C_DECLARE_RESULT(ident, R, S) \
struct cxx_result_##ident \
{ \
R value; \
unsigned flags; \
S error; \
#ifdef __cplusplus
extern "C"
{
#endif
#define BOOST_OUTCOME_C_DECLARE_RESULT(ident, R, S) \
struct cxx_result_##ident \
{ \
union \
{ \
R value; \
S error; \
}; \
unsigned flags; \
}
#define BOOST_OUTCOME_C_RESULT(ident) struct cxx_result_##ident
@@ -51,32 +59,46 @@ DEALINGS IN THE SOFTWARE.
#define BOOST_OUTCOME_C_RESULT_ERROR_IS_ERRNO(r) (((r).flags & (1U << 4U)) == (1U << 4U))
/***************************** <system_error2> support ******************************/
/***************************** <system_error2> support ******************************/
#define BOOST_OUTCOME_C_DECLARE_STATUS_CODE(ident, value_type) \
struct cxx_status_code_##ident \
{ \
void *domain; \
value_type value; \
#define BOOST_OUTCOME_C_DECLARE_STATUS_CODE(ident, value_type) \
struct cxx_status_code_##ident \
{ \
void *domain; \
value_type value; \
};
#define BOOST_OUTCOME_C_STATUS_CODE(ident) struct cxx_status_code_##ident
#define BOOST_OUTCOME_C_DECLARE_RESULT_STATUS_CODE(ident, R, S) \
struct cxx_result_status_code_##ident \
{ \
R value; \
unsigned flags; \
S error; \
}
struct cxx_status_code_posix
{
void *domain;
int value;
};
#define BOOST_OUTCOME_C_DECLARE_RESULT_ERRNO(ident, R) BOOST_OUTCOME_C_DECLARE_RESULT(posix_##ident, R, struct cxx_status_code_posix)
#define BOOST_OUTCOME_C_RESULT_ERRNO(ident) BOOST_OUTCOME_C_RESULT(posix_##ident)
#define BOOST_OUTCOME_C_RESULT_STATUS_CODE(ident) struct cxx_result_status_code_##ident
struct cxx_status_code_system
{
void *domain;
intptr_t value;
};
#define BOOST_OUTCOME_C_DECLARE_RESULT_SYSTEM(ident, R) BOOST_OUTCOME_C_DECLARE_RESULT(system_##ident, R, struct cxx_status_code_system)
#define BOOST_OUTCOME_C_RESULT_SYSTEM(ident) BOOST_OUTCOME_C_RESULT(system_##ident)
struct cxx_status_code_posix
{
void *domain;
int value;
};
#define BOOST_OUTCOME_C_DECLARE_RESULT_ERRNO(ident, R) BOOST_OUTCOME_C_DECLARE_RESULT_STATUS_CODE(posix_##ident, R, struct cxx_status_code_posix)
#define BOOST_OUTCOME_C_RESULT_ERRNO(ident) BOOST_OUTCOME_C_RESULT_STATUS_CODE(posix_##ident)
struct cxx_status_code_system
{
void *domain;
intptr_t value;
};
#define BOOST_OUTCOME_C_DECLARE_RESULT_SYSTEM(ident, R) BOOST_OUTCOME_C_DECLARE_RESULT_STATUS_CODE(system_##ident, R, struct cxx_status_code_system)
#define BOOST_OUTCOME_C_RESULT_SYSTEM(ident) BOOST_OUTCOME_C_RESULT_STATUS_CODE(system_##ident)
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -1,261 +0,0 @@
/* Proposed SG14 status_code
(C) 2018-2019 Niall Douglas <http://www.nedproductions.biz/> (5 commits)
File Created: Feb 2018
Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#ifndef BOOST_OUTCOME_SYSTEM_ERROR2_CONFIG_HPP
#define BOOST_OUTCOME_SYSTEM_ERROR2_CONFIG_HPP
// < 0.1 each
#include <cassert>
#include <cstddef> // for size_t
#include <cstdlib> // for free
// 0.22
#include <type_traits>
// 0.29
#include <atomic>
// 0.28 (0.15 of which is exception_ptr)
#include <exception> // for std::exception
// <new> includes <exception>, <exception> includes <new>
#include <new>
// 0.01
#include <initializer_list>
#ifndef BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR14
#if defined(BOOST_OUTCOME_STANDARDESE_IS_IN_THE_HOUSE) || __cplusplus >= 201400 || _MSC_VER >= 1910 /* VS2017 */
//! Defined to be `constexpr` when on C++ 14 or better compilers. Usually automatic, can be overriden.
#define BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR14 constexpr
#else
#define BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR14
#endif
#endif
#ifndef BOOST_OUTCOME_SYSTEM_ERROR2_NORETURN
#if defined(BOOST_OUTCOME_STANDARDESE_IS_IN_THE_HOUSE) || (_HAS_CXX17 && _MSC_VER >= 1911 /* VS2017.3 */)
#define BOOST_OUTCOME_SYSTEM_ERROR2_NORETURN [[noreturn]]
#endif
#endif
#if !defined(BOOST_OUTCOME_SYSTEM_ERROR2_NORETURN)
#ifdef __has_cpp_attribute
#if __has_cpp_attribute(noreturn)
#define BOOST_OUTCOME_SYSTEM_ERROR2_NORETURN [[noreturn]]
#endif
#endif
#endif
#if !defined(BOOST_OUTCOME_SYSTEM_ERROR2_NORETURN)
#if defined(_MSC_VER)
#define BOOST_OUTCOME_SYSTEM_ERROR2_NORETURN __declspec(noreturn)
#elif defined(__GNUC__)
#define BOOST_OUTCOME_SYSTEM_ERROR2_NORETURN __attribute__((__noreturn__))
#else
#define BOOST_OUTCOME_SYSTEM_ERROR2_NORETURN
#endif
#endif
// GCCs before 7 don't grok [[noreturn]] virtual functions, and warn annoyingly
#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 7
#undef BOOST_OUTCOME_SYSTEM_ERROR2_NORETURN
#define BOOST_OUTCOME_SYSTEM_ERROR2_NORETURN
#endif
#ifndef BOOST_OUTCOME_SYSTEM_ERROR2_NODISCARD
#if defined(BOOST_OUTCOME_STANDARDESE_IS_IN_THE_HOUSE) || (_HAS_CXX17 && _MSC_VER >= 1911 /* VS2017.3 */)
#define BOOST_OUTCOME_SYSTEM_ERROR2_NODISCARD [[nodiscard]]
#endif
#endif
#ifndef BOOST_OUTCOME_SYSTEM_ERROR2_NODISCARD
#ifdef __has_cpp_attribute
#if __has_cpp_attribute(nodiscard)
#define BOOST_OUTCOME_SYSTEM_ERROR2_NODISCARD [[nodiscard]]
#endif
#elif defined(__clang__)
#define BOOST_OUTCOME_SYSTEM_ERROR2_NODISCARD __attribute__((warn_unused_result))
#elif defined(_MSC_VER)
// _Must_inspect_result_ expands into this
#define BOOST_OUTCOME_SYSTEM_ERROR2_NODISCARD \
__declspec("SAL_name" \
"(" \
"\"_Must_inspect_result_\"" \
"," \
"\"\"" \
"," \
"\"2\"" \
")") __declspec("SAL_begin") __declspec("SAL_post") __declspec("SAL_mustInspect") __declspec("SAL_post") __declspec("SAL_checkReturn") __declspec("SAL_end")
#endif
#endif
#ifndef BOOST_OUTCOME_SYSTEM_ERROR2_NODISCARD
#define BOOST_OUTCOME_SYSTEM_ERROR2_NODISCARD
#endif
#ifndef BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE
//! The system_error2 namespace name.
#define BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE system_error2
//! Begins the system_error2 namespace.
#define BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_BEGIN \
namespace system_error2 \
{
//! Ends the system_error2 namespace.
#define BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_END }
#endif
//! Namespace for the library
BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_BEGIN
//! Namespace for user specialised traits
namespace traits
{
/*! Specialise to true if you guarantee that a type is move relocating (i.e.
its move constructor equals copying bits from old to new, old is left in a
default constructed state, and calling the destructor on a default constructed
instance is trivial). All trivially copyable types are move relocating by
definition, and that is the unspecialised implementation.
*/
template <class T> struct is_move_relocating
{
static constexpr bool value = std::is_trivially_copyable<T>::value;
};
} // namespace traits
namespace detail
{
inline BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR14 size_t cstrlen(const char *str)
{
const char *end = nullptr;
for(end = str; *end != 0; ++end) // NOLINT
;
return end - str;
}
/* A partially compliant implementation of C++20's std::bit_cast function contributed
by Jesse Towner. TODO FIXME Replace with C++ 20 bit_cast when available.
Our bit_cast is only guaranteed to be constexpr when both the input and output
arguments are either integrals or enums. However, this covers most use cases
since the vast majority of status_codes have an underlying type that is either
an integral or enum.
*/
template <class T> using is_integral_or_enum = std::integral_constant<bool, std::is_integral<T>::value || std::is_enum<T>::value>;
template <class To, class From> using is_static_castable = std::integral_constant<bool, is_integral_or_enum<To>::value && is_integral_or_enum<From>::value>;
template <class To, class From> using is_bit_castable = std::integral_constant<bool, sizeof(To) == sizeof(From) && traits::is_move_relocating<To>::value && traits::is_move_relocating<From>::value>;
template <class To, class From> union bit_cast_union {
From source;
To target;
};
template <class To, class From, typename std::enable_if<is_bit_castable<To, From>::value && is_static_castable<To, From>::value, bool>::type = true> constexpr To bit_cast(const From &from) noexcept { return static_cast<To>(from); }
template <class To, class From, typename std::enable_if<is_bit_castable<To, From>::value && !is_static_castable<To, From>::value, bool>::type = true> constexpr To bit_cast(const From &from) noexcept { return bit_cast_union<To, From>{from}.target; }
/* erasure_cast performs a bit_cast with additional rules to handle types
of differing sizes. For integral & enum types, it may perform a narrowing
or widing conversion with static_cast if necessary, before doing the final
conversion with bit_cast. When casting to or from non-integral, non-enum
types it may insert the value into another object with extra padding bytes
to satisfy bit_cast's preconditions that both types have the same size. */
template <class To, class From> using is_erasure_castable = std::integral_constant<bool, traits::is_move_relocating<To>::value && traits::is_move_relocating<From>::value>;
template <class T, bool = std::is_enum<T>::value> struct identity_or_underlying_type
{
using type = T;
};
template <class T> struct identity_or_underlying_type<T, true>
{
using type = typename std::underlying_type<T>::type;
};
template <class OfSize, class OfSign>
using erasure_integer_type = typename std::conditional<std::is_signed<typename identity_or_underlying_type<OfSign>::type>::value, typename std::make_signed<typename identity_or_underlying_type<OfSize>::type>::type, typename std::make_unsigned<typename identity_or_underlying_type<OfSize>::type>::type>::type;
template <class ErasedType, std::size_t N> struct padded_erasure_object
{
static_assert(traits::is_move_relocating<ErasedType>::value, "ErasedType must be TriviallyCopyable or MoveRelocating");
static_assert(alignof(ErasedType) <= sizeof(ErasedType), "ErasedType must not be over-aligned");
ErasedType value;
char padding[N];
constexpr explicit padded_erasure_object(const ErasedType &v) noexcept
: value(v)
, padding{}
{
}
};
template <class To, class From, typename std::enable_if<is_erasure_castable<To, From>::value && (sizeof(To) == sizeof(From)), bool>::type = true> constexpr To erasure_cast(const From &from) noexcept { return bit_cast<To>(from); }
template <class To, class From, typename std::enable_if<is_erasure_castable<To, From>::value && is_static_castable<To, From>::value && (sizeof(To) < sizeof(From)), bool>::type = true> constexpr To erasure_cast(const From &from) noexcept { return static_cast<To>(bit_cast<erasure_integer_type<From, To>>(from)); }
template <class To, class From, typename std::enable_if<is_erasure_castable<To, From>::value && is_static_castable<To, From>::value && (sizeof(To) > sizeof(From)), bool>::type = true> constexpr To erasure_cast(const From &from) noexcept { return bit_cast<To>(static_cast<erasure_integer_type<To, From>>(from)); }
template <class To, class From, typename std::enable_if<is_erasure_castable<To, From>::value && !is_static_castable<To, From>::value && (sizeof(To) < sizeof(From)), bool>::type = true> constexpr To erasure_cast(const From &from) noexcept
{
return bit_cast<padded_erasure_object<To, sizeof(From) - sizeof(To)>>(from).value;
}
template <class To, class From, typename std::enable_if<is_erasure_castable<To, From>::value && !is_static_castable<To, From>::value && (sizeof(To) > sizeof(From)), bool>::type = true> constexpr To erasure_cast(const From &from) noexcept
{
return bit_cast<To>(padded_erasure_object<From, sizeof(To) - sizeof(From)>{from});
}
} // namespace detail
BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_END
#ifndef BOOST_OUTCOME_SYSTEM_ERROR2_FATAL
#include <cstdlib> // for abort
#ifdef __APPLE__
#include <unistd.h> // for write
#endif
BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_BEGIN
namespace detail
{
namespace avoid_stdio_include
{
#ifndef __APPLE__
extern "C" ptrdiff_t write(int, const void *, size_t);
#endif
}
inline void do_fatal_exit(const char *msg)
{
using namespace avoid_stdio_include;
write(2 /*stderr*/, msg, cstrlen(msg));
write(2 /*stderr*/, "\n", 1);
abort();
}
} // namespace detail
BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_END
//! Prints msg to stderr, and calls `std::terminate()`. Can be overriden via predefinition.
#define BOOST_OUTCOME_SYSTEM_ERROR2_FATAL(msg) ::BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::detail::do_fatal_exit(msg)
#endif
#endif

View File

@@ -1,342 +0,0 @@
/* Proposed SG14 status_code
(C) 2018-2019 Niall Douglas <http://www.nedproductions.biz/> (5 commits)
File Created: Jun 2018
Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#ifndef BOOST_OUTCOME_SYSTEM_ERROR2_ERRORED_STATUS_CODE_HPP
#define BOOST_OUTCOME_SYSTEM_ERROR2_ERRORED_STATUS_CODE_HPP
#include "generic_code.hpp"
#include "status_code_ptr.hpp"
BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_BEGIN
/*! A `status_code` which is always a failure. The closest equivalent to
`std::error_code`, except it cannot be modified, and is templated.
Differences from `status_code`:
- Never successful (this contract is checked on construction, if fails then it
terminates the process).
- Is immutable.
*/
template <class DomainType> class errored_status_code : public status_code<DomainType>
{
using _base = status_code<DomainType>;
using _base::clear;
using _base::success;
void _check()
{
if(_base::success())
{
std::terminate();
}
}
public:
//! The type of the erased error code.
using typename _base::value_type;
//! The type of a reference to a message string.
using typename _base::string_ref;
//! Default constructor.
errored_status_code() = default;
//! Copy constructor.
errored_status_code(const errored_status_code &) = default;
//! Move constructor.
errored_status_code(errored_status_code &&) = default; // NOLINT
//! Copy assignment.
errored_status_code &operator=(const errored_status_code &) = default;
//! Move assignment.
errored_status_code &operator=(errored_status_code &&) = default; // NOLINT
~errored_status_code() = default;
//! Explicitly construct from any similarly erased status code
explicit errored_status_code(const _base &o) noexcept(std::is_nothrow_copy_constructible<_base>::value)
: _base(o)
{
_check();
}
//! Explicitly construct from any similarly erased status code
explicit errored_status_code(_base &&o) noexcept(std::is_nothrow_move_constructible<_base>::value)
: _base(static_cast<_base &&>(o))
{
_check();
}
/***** KEEP THESE IN SYNC WITH STATUS_CODE *****/
//! Implicit construction from any type where an ADL discovered `make_status_code(T, Args ...)` returns a `status_code`.
template <class T, class... Args, //
class MakeStatusCodeResult = typename detail::safe_get_make_status_code_result<T, Args...>::type, // Safe ADL lookup of make_status_code(), returns void if not found
typename std::enable_if<!std::is_same<typename std::decay<T>::type, errored_status_code>::value // not copy/move of self
&& !std::is_same<typename std::decay<T>::type, in_place_t>::value // not in_place_t
&& is_status_code<MakeStatusCodeResult>::value // ADL makes a status code
&& std::is_constructible<errored_status_code, MakeStatusCodeResult>::value, // ADLed status code is compatible
bool>::type = true>
errored_status_code(T &&v, Args &&... args) noexcept(noexcept(make_status_code(std::declval<T>(), std::declval<Args>()...))) // NOLINT
: errored_status_code(make_status_code(static_cast<T &&>(v), static_cast<Args &&>(args)...))
{
_check();
}
//! Explicit in-place construction.
template <class... Args>
explicit errored_status_code(in_place_t _, Args &&... args) noexcept(std::is_nothrow_constructible<value_type, Args &&...>::value)
: _base(_, static_cast<Args &&>(args)...)
{
_check();
}
//! Explicit in-place construction from initialiser list.
template <class T, class... Args>
explicit errored_status_code(in_place_t _, std::initializer_list<T> il, Args &&... args) noexcept(std::is_nothrow_constructible<value_type, std::initializer_list<T>, Args &&...>::value)
: _base(_, il, static_cast<Args &&>(args)...)
{
_check();
}
//! Explicit copy construction from a `value_type`.
explicit errored_status_code(const value_type &v) noexcept(std::is_nothrow_copy_constructible<value_type>::value)
: _base(v)
{
_check();
}
//! Explicit move construction from a `value_type`.
explicit errored_status_code(value_type &&v) noexcept(std::is_nothrow_move_constructible<value_type>::value)
: _base(static_cast<value_type &&>(v))
{
_check();
}
/*! Explicit construction from an erased status code. Available only if
`value_type` is trivially destructible and `sizeof(status_code) <= sizeof(status_code<erased<>>)`.
Does not check if domains are equal.
*/
template <class ErasedType, //
typename std::enable_if<detail::type_erasure_is_safe<ErasedType, value_type>::value, bool>::type = true>
explicit errored_status_code(const status_code<erased<ErasedType>> &v) noexcept(std::is_nothrow_copy_constructible<value_type>::value)
: errored_status_code(detail::erasure_cast<value_type>(v.value())) // NOLINT
{
assert(v.domain() == this->domain()); // NOLINT
_check();
}
//! Return a const reference to the `value_type`.
constexpr const value_type &value() const &noexcept { return this->_value; }
};
namespace traits
{
template <class DomainType> struct is_move_relocating<errored_status_code<DomainType>>
{
static constexpr bool value = is_move_relocating<typename DomainType::value_type>::value;
};
} // namespace traits
template <class ErasedType> class errored_status_code<erased<ErasedType>> : public status_code<erased<ErasedType>>
{
using _base = status_code<erased<ErasedType>>;
using _base::success;
void _check()
{
if(_base::success())
{
std::terminate();
}
}
public:
using value_type = typename _base::value_type;
using string_ref = typename _base::string_ref;
//! Default construction to empty
errored_status_code() = default;
//! Copy constructor
errored_status_code(const errored_status_code &) = default;
//! Move constructor
errored_status_code(errored_status_code &&) = default; // NOLINT
//! Copy assignment
errored_status_code &operator=(const errored_status_code &) = default;
//! Move assignment
errored_status_code &operator=(errored_status_code &&) = default; // NOLINT
~errored_status_code() = default;
//! Explicitly construct from any similarly erased status code
explicit errored_status_code(const _base &o) noexcept(std::is_nothrow_copy_constructible<_base>::value)
: _base(o)
{
_check();
}
//! Explicitly construct from any similarly erased status code
explicit errored_status_code(_base &&o) noexcept(std::is_nothrow_move_constructible<_base>::value)
: _base(static_cast<_base &&>(o))
{
_check();
}
/***** KEEP THESE IN SYNC WITH STATUS_CODE *****/
//! Implicit copy construction from any other status code if its value type is trivially copyable and it would fit into our storage
template <class DomainType, //
typename std::enable_if<!detail::is_erased_status_code<status_code<DomainType>>::value //
&& std::is_trivially_copyable<typename DomainType::value_type>::value //
&& detail::type_erasure_is_safe<value_type, typename DomainType::value_type>::value,
bool>::type = true>
errored_status_code(const status_code<DomainType> &v) noexcept : _base(v) // NOLINT
{
_check();
}
//! Implicit move construction from any other status code if its value type is trivially copyable or move relocating and it would fit into our storage
template <class DomainType, //
typename std::enable_if<detail::type_erasure_is_safe<value_type, typename DomainType::value_type>::value,
bool>::type = true>
errored_status_code(status_code<DomainType> &&v) noexcept : _base(static_cast<status_code<DomainType> &&>(v)) // NOLINT
{
_check();
}
//! Implicit construction from any type where an ADL discovered `make_status_code(T, Args ...)` returns a `status_code`.
template <class T, class... Args, //
class MakeStatusCodeResult = typename detail::safe_get_make_status_code_result<T, Args...>::type, // Safe ADL lookup of make_status_code(), returns void if not found
typename std::enable_if<!std::is_same<typename std::decay<T>::type, errored_status_code>::value // not copy/move of self
&& !std::is_same<typename std::decay<T>::type, value_type>::value // not copy/move of value type
&& is_status_code<MakeStatusCodeResult>::value // ADL makes a status code
&& std::is_constructible<errored_status_code, MakeStatusCodeResult>::value, // ADLed status code is compatible
bool>::type = true>
errored_status_code(T &&v, Args &&... args) noexcept(noexcept(make_status_code(std::declval<T>(), std::declval<Args>()...))) // NOLINT
: errored_status_code(make_status_code(static_cast<T &&>(v), static_cast<Args &&>(args)...))
{
_check();
}
//! Return the erased `value_type` by value.
constexpr value_type value() const noexcept { return this->_value; }
};
namespace traits
{
template <class ErasedType> struct is_move_relocating<errored_status_code<erased<ErasedType>>>
{
static constexpr bool value = true;
};
} // namespace traits
//! True if the status code's are semantically equal via `equivalent()`.
template <class DomainType1, class DomainType2> inline bool operator==(const errored_status_code<DomainType1> &a, const errored_status_code<DomainType2> &b) noexcept
{
return a.equivalent(static_cast<const status_code<DomainType2> &>(b));
}
//! True if the status code's are semantically equal via `equivalent()`.
template <class DomainType1, class DomainType2> inline bool operator==(const status_code<DomainType1> &a, const errored_status_code<DomainType2> &b) noexcept
{
return a.equivalent(static_cast<const status_code<DomainType2> &>(b));
}
//! True if the status code's are semantically equal via `equivalent()`.
template <class DomainType1, class DomainType2> inline bool operator==(const errored_status_code<DomainType1> &a, const status_code<DomainType2> &b) noexcept
{
return static_cast<const status_code<DomainType1> &>(a).equivalent(b);
}
//! True if the status code's are not semantically equal via `equivalent()`.
template <class DomainType1, class DomainType2> inline bool operator!=(const errored_status_code<DomainType1> &a, const errored_status_code<DomainType2> &b) noexcept
{
return !a.equivalent(static_cast<const status_code<DomainType2> &>(b));
}
//! True if the status code's are not semantically equal via `equivalent()`.
template <class DomainType1, class DomainType2> inline bool operator!=(const status_code<DomainType1> &a, const errored_status_code<DomainType2> &b) noexcept
{
return !a.equivalent(static_cast<const status_code<DomainType2> &>(b));
}
//! True if the status code's are not semantically equal via `equivalent()`.
template <class DomainType1, class DomainType2> inline bool operator!=(const errored_status_code<DomainType1> &a, const status_code<DomainType2> &b) noexcept
{
return !static_cast<const status_code<DomainType1> &>(a).equivalent(b);
}
//! True if the status code's are semantically equal via `equivalent()` to `make_status_code(T)`.
template <class DomainType1, class T, //
class MakeStatusCodeResult = typename detail::safe_get_make_status_code_result<const T &>::type, // Safe ADL lookup of make_status_code(), returns void if not found
typename std::enable_if<is_status_code<MakeStatusCodeResult>::value, bool>::type = true> // ADL makes a status code
inline bool
operator==(const errored_status_code<DomainType1> &a, const T &b)
{
return a.equivalent(make_status_code(b));
}
//! True if the status code's are semantically equal via `equivalent()` to `make_status_code(T)`.
template <class T, class DomainType1, //
class MakeStatusCodeResult = typename detail::safe_get_make_status_code_result<const T &>::type, // Safe ADL lookup of make_status_code(), returns void if not found
typename std::enable_if<is_status_code<MakeStatusCodeResult>::value, bool>::type = true> // ADL makes a status code
inline bool
operator==(const T &a, const errored_status_code<DomainType1> &b)
{
return b.equivalent(make_status_code(a));
}
//! True if the status code's are not semantically equal via `equivalent()` to `make_status_code(T)`.
template <class DomainType1, class T, //
class MakeStatusCodeResult = typename detail::safe_get_make_status_code_result<const T &>::type, // Safe ADL lookup of make_status_code(), returns void if not found
typename std::enable_if<is_status_code<MakeStatusCodeResult>::value, bool>::type = true> // ADL makes a status code
inline bool
operator!=(const errored_status_code<DomainType1> &a, const T &b)
{
return !a.equivalent(make_status_code(b));
}
//! True if the status code's are semantically equal via `equivalent()` to `make_status_code(T)`.
template <class T, class DomainType1, //
class MakeStatusCodeResult = typename detail::safe_get_make_status_code_result<const T &>::type, // Safe ADL lookup of make_status_code(), returns void if not found
typename std::enable_if<is_status_code<MakeStatusCodeResult>::value, bool>::type = true> // ADL makes a status code
inline bool
operator!=(const T &a, const errored_status_code<DomainType1> &b)
{
return !b.equivalent(make_status_code(a));
}
namespace detail
{
template <class T> struct is_errored_status_code
{
static constexpr bool value = false;
};
template <class T> struct is_errored_status_code<errored_status_code<T>>
{
static constexpr bool value = true;
};
template <class T> struct is_erased_errored_status_code
{
static constexpr bool value = false;
};
template <class T> struct is_erased_errored_status_code<errored_status_code<erased<T>>>
{
static constexpr bool value = true;
};
} // namespace detail
//! Trait returning true if the type is an errored status code.
template <class T> struct is_errored_status_code
{
static constexpr bool value = detail::is_errored_status_code<typename std::decay<T>::type>::value || detail::is_erased_errored_status_code<typename std::decay<T>::type>::value;
};
BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_END
#endif

View File

@@ -1,378 +0,0 @@
/* Proposed SG14 status_code
(C) 2018-2019 Niall Douglas <http://www.nedproductions.biz/> (5 commits)
File Created: Feb 2018
Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#ifndef BOOST_OUTCOME_SYSTEM_ERROR2_GENERIC_CODE_HPP
#define BOOST_OUTCOME_SYSTEM_ERROR2_GENERIC_CODE_HPP
#include "status_error.hpp"
#include <cerrno> // for error constants
BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_BEGIN
//! The generic error coding (POSIX)
enum class errc : int
{
success = 0,
unknown = -1,
address_family_not_supported = EAFNOSUPPORT,
address_in_use = EADDRINUSE,
address_not_available = EADDRNOTAVAIL,
already_connected = EISCONN,
argument_list_too_long = E2BIG,
argument_out_of_domain = EDOM,
bad_address = EFAULT,
bad_file_descriptor = EBADF,
bad_message = EBADMSG,
broken_pipe = EPIPE,
connection_aborted = ECONNABORTED,
connection_already_in_progress = EALREADY,
connection_refused = ECONNREFUSED,
connection_reset = ECONNRESET,
cross_device_link = EXDEV,
destination_address_required = EDESTADDRREQ,
device_or_resource_busy = EBUSY,
directory_not_empty = ENOTEMPTY,
executable_format_error = ENOEXEC,
file_exists = EEXIST,
file_too_large = EFBIG,
filename_too_long = ENAMETOOLONG,
function_not_supported = ENOSYS,
host_unreachable = EHOSTUNREACH,
identifier_removed = EIDRM,
illegal_byte_sequence = EILSEQ,
inappropriate_io_control_operation = ENOTTY,
interrupted = EINTR,
invalid_argument = EINVAL,
invalid_seek = ESPIPE,
io_error = EIO,
is_a_directory = EISDIR,
message_size = EMSGSIZE,
network_down = ENETDOWN,
network_reset = ENETRESET,
network_unreachable = ENETUNREACH,
no_buffer_space = ENOBUFS,
no_child_process = ECHILD,
no_link = ENOLINK,
no_lock_available = ENOLCK,
no_message = ENOMSG,
no_protocol_option = ENOPROTOOPT,
no_space_on_device = ENOSPC,
no_stream_resources = ENOSR,
no_such_device_or_address = ENXIO,
no_such_device = ENODEV,
no_such_file_or_directory = ENOENT,
no_such_process = ESRCH,
not_a_directory = ENOTDIR,
not_a_socket = ENOTSOCK,
not_a_stream = ENOSTR,
not_connected = ENOTCONN,
not_enough_memory = ENOMEM,
not_supported = ENOTSUP,
operation_canceled = ECANCELED,
operation_in_progress = EINPROGRESS,
operation_not_permitted = EPERM,
operation_not_supported = EOPNOTSUPP,
operation_would_block = EWOULDBLOCK,
owner_dead = EOWNERDEAD,
permission_denied = EACCES,
protcol_error = EPROTO,
protocol_not_supported = EPROTONOSUPPORT,
read_only_file_system = EROFS,
resource_deadlock_would_occur = EDEADLK,
resource_unavailable_try_again = EAGAIN,
result_out_of_range = ERANGE,
state_not_recoverable = ENOTRECOVERABLE,
stream_timeout = ETIME,
text_file_busy = ETXTBSY,
timed_out = ETIMEDOUT,
too_many_files_open_in_system = ENFILE,
too_many_files_open = EMFILE,
too_many_links = EMLINK,
too_many_symbolic_link_levels = ELOOP,
value_too_large = EOVERFLOW,
wrong_protocol_type = EPROTOTYPE
};
namespace detail
{
struct generic_code_messages
{
// libc++ defines missing errc macros to integers in the 9xxx range
// As much as 10,000 seems wasteful, bear in mind this is all constexpr
// and on C++ 14 or later this entire construct disappears.
const char *msgs[(ETIME >= 256) ? 10000 : 256];
BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR14 size_t size() const { return sizeof(msgs) / sizeof(*msgs); } // NOLINT
BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR14 const char *operator[](int i) const { return (i < 0 || i >= static_cast<int>(size()) || nullptr == msgs[i]) ? "unknown" : msgs[i]; } // NOLINT
BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR14 generic_code_messages()
: msgs{}
{
msgs[0] = "Success";
msgs[EAFNOSUPPORT] = "Address family not supported by protocol";
msgs[EADDRINUSE] = "Address already in use";
msgs[EADDRNOTAVAIL] = "Cannot assign requested address";
msgs[EISCONN] = "Transport endpoint is already connected";
msgs[E2BIG] = "Argument list too long";
msgs[EDOM] = "Numerical argument out of domain";
msgs[EFAULT] = "Bad address";
msgs[EBADF] = "Bad file descriptor";
msgs[EBADMSG] = "Bad message";
msgs[EPIPE] = "Broken pipe";
msgs[ECONNABORTED] = "Software caused connection abort";
msgs[EALREADY] = "Operation already in progress";
msgs[ECONNREFUSED] = "Connection refused";
msgs[ECONNRESET] = "Connection reset by peer";
msgs[EXDEV] = "Invalid cross-device link";
msgs[EDESTADDRREQ] = "Destination address required";
msgs[EBUSY] = "Device or resource busy";
msgs[ENOTEMPTY] = "Directory not empty";
msgs[ENOEXEC] = "Exec format error";
msgs[EEXIST] = "File exists";
msgs[EFBIG] = "File too large";
msgs[ENAMETOOLONG] = "File name too long";
msgs[ENOSYS] = "Function not implemented";
msgs[EHOSTUNREACH] = "No route to host";
msgs[EIDRM] = "Identifier removed";
msgs[EILSEQ] = "Invalid or incomplete multibyte or wide character";
msgs[ENOTTY] = "Inappropriate ioctl for device";
msgs[EINTR] = "Interrupted system call";
msgs[EINVAL] = "Invalid argument";
msgs[ESPIPE] = "Illegal seek";
msgs[EIO] = "Input/output error";
msgs[EISDIR] = "Is a directory";
msgs[EMSGSIZE] = "Message too long";
msgs[ENETDOWN] = "Network is down";
msgs[ENETRESET] = "Network dropped connection on reset";
msgs[ENETUNREACH] = "Network is unreachable";
msgs[ENOBUFS] = "No buffer space available";
msgs[ECHILD] = "No child processes";
msgs[ENOLINK] = "Link has been severed";
msgs[ENOLCK] = "No locks available";
msgs[ENOMSG] = "No message of desired type";
msgs[ENOPROTOOPT] = "Protocol not available";
msgs[ENOSPC] = "No space left on device";
msgs[ENOSR] = "Out of streams resources";
msgs[ENXIO] = "No such device or address";
msgs[ENODEV] = "No such device";
msgs[ENOENT] = "No such file or directory";
msgs[ESRCH] = "No such process";
msgs[ENOTDIR] = "Not a directory";
msgs[ENOTSOCK] = "Socket operation on non-socket";
msgs[ENOSTR] = "Device not a stream";
msgs[ENOTCONN] = "Transport endpoint is not connected";
msgs[ENOMEM] = "Cannot allocate memory";
msgs[ENOTSUP] = "Operation not supported";
msgs[ECANCELED] = "Operation canceled";
msgs[EINPROGRESS] = "Operation now in progress";
msgs[EPERM] = "Operation not permitted";
msgs[EOPNOTSUPP] = "Operation not supported";
msgs[EWOULDBLOCK] = "Resource temporarily unavailable";
msgs[EOWNERDEAD] = "Owner died";
msgs[EACCES] = "Permission denied";
msgs[EPROTO] = "Protocol error";
msgs[EPROTONOSUPPORT] = "Protocol not supported";
msgs[EROFS] = "Read-only file system";
msgs[EDEADLK] = "Resource deadlock avoided";
msgs[EAGAIN] = "Resource temporarily unavailable";
msgs[ERANGE] = "Numerical result out of range";
msgs[ENOTRECOVERABLE] = "State not recoverable";
msgs[ETIME] = "Timer expired";
msgs[ETXTBSY] = "Text file busy";
msgs[ETIMEDOUT] = "Connection timed out";
msgs[ENFILE] = "Too many open files in system";
msgs[EMFILE] = "Too many open files";
msgs[EMLINK] = "Too many links";
msgs[ELOOP] = "Too many levels of symbolic links";
msgs[EOVERFLOW] = "Value too large for defined data type";
msgs[EPROTOTYPE] = "Protocol wrong type for socket";
}
};
} // namespace detail
/*! The implementation of the domain for generic status codes, those mapped by `errc` (POSIX).
*/
class _generic_code_domain : public status_code_domain
{
template <class> friend class status_code;
template <class StatusCode> friend class detail::indirecting_domain;
using _base = status_code_domain;
public:
//! The value type of the generic code, which is an `errc` as per POSIX.
using value_type = errc;
using string_ref = _base::string_ref;
public:
//! Default constructor
constexpr explicit _generic_code_domain(typename _base::unique_id_type id = 0x746d6354f4f733e9) noexcept : _base(id) {}
_generic_code_domain(const _generic_code_domain &) = default;
_generic_code_domain(_generic_code_domain &&) = default;
_generic_code_domain &operator=(const _generic_code_domain &) = default;
_generic_code_domain &operator=(_generic_code_domain &&) = default;
~_generic_code_domain() = default;
//! Constexpr singleton getter. Returns the constexpr generic_code_domain variable.
static inline constexpr const _generic_code_domain &get();
virtual _base::string_ref name() const noexcept override { return string_ref("generic domain"); } // NOLINT
protected:
virtual bool _do_failure(const status_code<void> &code) const noexcept override // NOLINT
{
assert(code.domain() == *this); // NOLINT
return static_cast<const generic_code &>(code).value() != errc::success; // NOLINT
}
virtual bool _do_equivalent(const status_code<void> &code1, const status_code<void> &code2) const noexcept override // NOLINT
{
assert(code1.domain() == *this); // NOLINT
const auto &c1 = static_cast<const generic_code &>(code1); // NOLINT
if(code2.domain() == *this)
{
const auto &c2 = static_cast<const generic_code &>(code2); // NOLINT
return c1.value() == c2.value();
}
return false;
}
virtual generic_code _generic_code(const status_code<void> &code) const noexcept override // NOLINT
{
assert(code.domain() == *this); // NOLINT
return static_cast<const generic_code &>(code); // NOLINT
}
virtual _base::string_ref _do_message(const status_code<void> &code) const noexcept override // NOLINT
{
assert(code.domain() == *this); // NOLINT
const auto &c = static_cast<const generic_code &>(code); // NOLINT
static BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR14 detail::generic_code_messages msgs;
return string_ref(msgs[static_cast<int>(c.value())]);
}
#if defined(_CPPUNWIND) || defined(__EXCEPTIONS) || defined(BOOST_OUTCOME_STANDARDESE_IS_IN_THE_HOUSE)
BOOST_OUTCOME_SYSTEM_ERROR2_NORETURN virtual void _do_throw_exception(const status_code<void> &code) const override // NOLINT
{
assert(code.domain() == *this); // NOLINT
const auto &c = static_cast<const generic_code &>(code); // NOLINT
throw status_error<_generic_code_domain>(c);
}
#endif
};
//! A specialisation of `status_error` for the generic code domain.
using generic_error = status_error<_generic_code_domain>;
//! A constexpr source variable for the generic code domain, which is that of `errc` (POSIX). Returned by `_generic_code_domain::get()`.
constexpr _generic_code_domain generic_code_domain;
inline constexpr const _generic_code_domain &_generic_code_domain::get()
{
return generic_code_domain;
}
// Enable implicit construction of generic_code from errc
BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR14 inline generic_code make_status_code(errc c) noexcept
{
return generic_code(in_place, c);
}
/*************************************************************************************************************/
template <class T> inline bool status_code<void>::equivalent(const status_code<T> &o) const noexcept
{
if(_domain && o._domain)
{
if(_domain->_do_equivalent(*this, o))
{
return true;
}
if(o._domain->_do_equivalent(o, *this))
{
return true;
}
generic_code c1 = o._domain->_generic_code(o);
if(c1.value() != errc::unknown && _domain->_do_equivalent(*this, c1))
{
return true;
}
generic_code c2 = _domain->_generic_code(*this);
if(c2.value() != errc::unknown && o._domain->_do_equivalent(o, c2))
{
return true;
}
}
// If we are both empty, we are equivalent, otherwise not equivalent
return (!_domain && !o._domain);
}
//! True if the status code's are semantically equal via `equivalent()`.
template <class DomainType1, class DomainType2> inline bool operator==(const status_code<DomainType1> &a, const status_code<DomainType2> &b) noexcept
{
return a.equivalent(b);
}
//! True if the status code's are not semantically equal via `equivalent()`.
template <class DomainType1, class DomainType2> inline bool operator!=(const status_code<DomainType1> &a, const status_code<DomainType2> &b) noexcept
{
return !a.equivalent(b);
}
//! True if the status code's are semantically equal via `equivalent()` to `make_status_code(T)`.
template <class DomainType1, class T, //
class MakeStatusCodeResult = typename detail::safe_get_make_status_code_result<const T &>::type, // Safe ADL lookup of make_status_code(), returns void if not found
typename std::enable_if<is_status_code<MakeStatusCodeResult>::value, bool>::type = true> // ADL makes a status code
inline bool
operator==(const status_code<DomainType1> &a, const T &b)
{
return a.equivalent(make_status_code(b));
}
//! True if the status code's are semantically equal via `equivalent()` to `make_status_code(T)`.
template <class T, class DomainType1, //
class MakeStatusCodeResult = typename detail::safe_get_make_status_code_result<const T &>::type, // Safe ADL lookup of make_status_code(), returns void if not found
typename std::enable_if<is_status_code<MakeStatusCodeResult>::value, bool>::type = true> // ADL makes a status code
inline bool
operator==(const T &a, const status_code<DomainType1> &b)
{
return b.equivalent(make_status_code(a));
}
//! True if the status code's are not semantically equal via `equivalent()` to `make_status_code(T)`.
template <class DomainType1, class T, //
class MakeStatusCodeResult = typename detail::safe_get_make_status_code_result<const T &>::type, // Safe ADL lookup of make_status_code(), returns void if not found
typename std::enable_if<is_status_code<MakeStatusCodeResult>::value, bool>::type = true> // ADL makes a status code
inline bool
operator!=(const status_code<DomainType1> &a, const T &b)
{
return !a.equivalent(make_status_code(b));
}
//! True if the status code's are semantically equal via `equivalent()` to `make_status_code(T)`.
template <class T, class DomainType1, //
class MakeStatusCodeResult = typename detail::safe_get_make_status_code_result<const T &>::type, // Safe ADL lookup of make_status_code(), returns void if not found
typename std::enable_if<is_status_code<MakeStatusCodeResult>::value, bool>::type = true> // ADL makes a status code
inline bool
operator!=(const T &a, const status_code<DomainType1> &b)
{
return !b.equivalent(make_status_code(a));
}
BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_END
#endif

View File

@@ -0,0 +1,335 @@
/* Proposed SG14 status_code
(C) 2018 - 2022 Niall Douglas <http://www.nedproductions.biz/> (5 commits)
File Created: Mar 2022
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License in the accompanying file
Licence.txt or at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Distributed under the Boost Software License, Version 1.0.
(See accompanying file Licence.txt or copy at
http://www.boost.org/LICENSE_1_0.txt)
*/
#ifndef BOOST_OUTCOME_SYSTEM_ERROR2_BOOST_ERROR_CODE_HPP
#define BOOST_OUTCOME_SYSTEM_ERROR2_BOOST_ERROR_CODE_HPP
#ifndef BOOST_OUTCOME_SYSTEM_ERROR2_NOT_POSIX
#include "posix_code.hpp"
#endif
#if defined(_WIN32) || defined(BOOST_OUTCOME_STANDARDESE_IS_IN_THE_HOUSE)
#include "win32_code.hpp"
#endif
#include "std_error_code.hpp"
#include <boost/system/error_code.hpp>
#include <boost/system/system_error.hpp>
#include <system_error>
BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_BEGIN
class _boost_error_code_domain;
//! A `status_code` representing exactly a `boost::system::error_code`
using boost_error_code = status_code<_boost_error_code_domain>;
namespace mixins
{
template <class Base> struct mixin<Base, _boost_error_code_domain> : public Base
{
using Base::Base;
//! Implicit constructor from a `boost::system::error_code`
inline mixin(boost::system::error_code ec);
//! Returns the error code category
inline const boost::system::error_category &category() const noexcept;
};
} // namespace mixins
/*! The implementation of the domain for `boost::system::error_code` error codes.
*/
class _boost_error_code_domain final : public status_code_domain
{
template <class DomainType> friend class status_code;
template <class StatusCode, class Allocator> friend class detail::indirecting_domain;
using _base = status_code_domain;
using _error_code_type = boost::system::error_code;
using _error_category_type = boost::system::error_category;
std::string _name;
static _base::string_ref _make_string_ref(_error_code_type c) noexcept
{
#if defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)
try
#endif
{
std::string msg = c.message();
auto *p = static_cast<char *>(malloc(msg.size() + 1)); // NOLINT
if(p == nullptr)
{
return _base::string_ref("failed to allocate message");
}
memcpy(p, msg.c_str(), msg.size() + 1);
return _base::atomic_refcounted_string_ref(p, msg.size());
}
#if defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)
catch(...)
{
return _base::string_ref("failed to allocate message");
}
#endif
}
public:
//! The value type of the `boost::system::error_code` code, which stores the `int` from the `boost::system::error_code`
using value_type = int;
using _base::string_ref;
//! Returns the error category singleton pointer this status code domain represents
const _error_category_type &error_category() const noexcept
{
auto ptr = 0x0ea88ff382d94915 ^ this->id();
return *reinterpret_cast<const _error_category_type *>(ptr);
}
//! Default constructor
explicit _boost_error_code_domain(const _error_category_type &category) noexcept
: _base(0x0ea88ff382d94915 ^ reinterpret_cast<_base::unique_id_type>(&category))
, _name("boost_error_code_domain(")
{
_name.append(category.name());
_name.push_back(')');
}
_boost_error_code_domain(const _boost_error_code_domain &) = default;
_boost_error_code_domain(_boost_error_code_domain &&) = default;
_boost_error_code_domain &operator=(const _boost_error_code_domain &) = default;
_boost_error_code_domain &operator=(_boost_error_code_domain &&) = default;
~_boost_error_code_domain() = default;
static inline const _boost_error_code_domain *get(_error_code_type ec);
virtual string_ref name() const noexcept override { return string_ref(_name.c_str(), _name.size()); } // NOLINT
virtual payload_info_t payload_info() const noexcept override
{
return {sizeof(value_type), sizeof(status_code_domain *) + sizeof(value_type),
(alignof(value_type) > alignof(status_code_domain *)) ? alignof(value_type) : alignof(status_code_domain *)};
}
protected:
virtual bool _do_failure(const status_code<void> &code) const noexcept override;
virtual bool _do_equivalent(const status_code<void> &code1, const status_code<void> &code2) const noexcept override;
virtual generic_code _generic_code(const status_code<void> &code) const noexcept override;
virtual string_ref _do_message(const status_code<void> &code) const noexcept override;
#if defined(_CPPUNWIND) || defined(__EXCEPTIONS) || defined(BOOST_OUTCOME_STANDARDESE_IS_IN_THE_HOUSE)
BOOST_OUTCOME_SYSTEM_ERROR2_NORETURN virtual void _do_throw_exception(const status_code<void> &code) const override;
#endif
};
namespace detail
{
extern inline _boost_error_code_domain *boost_error_code_domain_from_category(const boost::system::error_category &category)
{
static constexpr size_t max_items = 64;
static struct storage_t
{
std::atomic<unsigned> _lock;
union item_t
{
int _init;
_boost_error_code_domain domain;
constexpr item_t()
: _init(0)
{
}
~item_t() {}
} items[max_items];
size_t count{0};
void lock()
{
while(_lock.exchange(1, std::memory_order_acquire) != 0)
;
}
void unlock() { _lock.store(0, std::memory_order_release); }
storage_t() {}
~storage_t()
{
lock();
for(size_t n = 0; n < count; n++)
{
items[n].domain.~_boost_error_code_domain();
}
unlock();
}
_boost_error_code_domain *add(const boost::system::error_category &category)
{
_boost_error_code_domain *ret = nullptr;
lock();
for(size_t n = 0; n < count; n++)
{
if(items[n].domain.error_category() == category)
{
ret = &items[n].domain;
break;
}
}
if(ret == nullptr && count < max_items)
{
ret = new(BOOST_OUTCOME_SYSTEM_ERROR2_ADDRESS_OF(items[count++].domain)) _boost_error_code_domain(category);
}
unlock();
return ret;
}
} storage;
return storage.add(category);
}
} // namespace detail
namespace mixins
{
template <class Base>
inline mixin<Base, _boost_error_code_domain>::mixin(boost::system::error_code ec)
: Base(typename Base::_value_type_constructor{}, _boost_error_code_domain::get(ec), ec.value())
{
}
template <class Base> inline const boost::system::error_category &mixin<Base, _boost_error_code_domain>::category() const noexcept
{
const auto &domain = static_cast<const _boost_error_code_domain &>(this->domain());
return domain.error_category();
};
} // namespace mixins
inline const _boost_error_code_domain *_boost_error_code_domain::get(boost::system::error_code ec)
{
auto *p = detail::boost_error_code_domain_from_category(ec.category());
assert(p != nullptr);
if(p == nullptr)
{
abort();
}
return p;
}
inline bool _boost_error_code_domain::_do_failure(const status_code<void> &code) const noexcept
{
assert(code.domain() == *this);
return static_cast<const boost_error_code &>(code).value() != 0; // NOLINT
}
inline bool _boost_error_code_domain::_do_equivalent(const status_code<void> &code1, const status_code<void> &code2) const noexcept
{
assert(code1.domain() == *this);
const auto &c1 = static_cast<const boost_error_code &>(code1); // NOLINT
const auto &cat1 = c1.category();
// Are we comparing to another wrapped error_code?
if(code2.domain() == *this)
{
const auto &c2 = static_cast<const boost_error_code &>(code2); // NOLINT
const auto &cat2 = c2.category();
// If the error code categories are identical, do literal comparison
if(cat1 == cat2)
{
return c1.value() == c2.value();
}
// Otherwise fall back onto the _generic_code comparison, which uses default_error_condition()
return false;
}
// Am I an error code with generic category?
if(cat1 == boost::system::generic_category())
{
// Convert to generic code, and compare that
generic_code _c1(static_cast<errc>(c1.value()));
return _c1 == code2;
}
// Am I an error code with system category?
if(cat1 == boost::system::system_category())
{
// Convert to POSIX or Win32 code, and compare that
#ifdef _WIN32
win32_code _c1((win32::DWORD) c1.value());
return _c1 == code2;
#elif !defined(BOOST_OUTCOME_SYSTEM_ERROR2_NOT_POSIX)
posix_code _c1(c1.value());
return _c1 == code2;
#endif
}
return false;
}
inline generic_code _boost_error_code_domain::_generic_code(const status_code<void> &code) const noexcept
{
assert(code.domain() == *this);
const auto &c = static_cast<const boost_error_code &>(code); // NOLINT
// Ask my embedded error code for its mapping to boost::system::errc, which is a subset of our generic_code errc.
boost::system::error_condition cond(c.category().default_error_condition(c.value()));
if(cond.category() == boost::system::generic_category())
{
return generic_code(static_cast<errc>(cond.value()));
}
#if !defined(BOOST_OUTCOME_SYSTEM_ERROR2_NOT_POSIX) && !defined(_WIN32)
if(cond.category() == boost::system::system_category())
{
return generic_code(static_cast<errc>(cond.value()));
}
#endif
return errc::unknown;
}
inline _boost_error_code_domain::string_ref _boost_error_code_domain::_do_message(const status_code<void> &code) const noexcept
{
assert(code.domain() == *this);
const auto &c = static_cast<const boost_error_code &>(code); // NOLINT
return _make_string_ref(_error_code_type(c.value(), c.category()));
}
#if defined(_CPPUNWIND) || defined(__EXCEPTIONS) || defined(BOOST_OUTCOME_STANDARDESE_IS_IN_THE_HOUSE)
BOOST_OUTCOME_SYSTEM_ERROR2_NORETURN inline void _boost_error_code_domain::_do_throw_exception(const status_code<void> &code) const
{
assert(code.domain() == *this);
const auto &c = static_cast<const boost_error_code &>(code); // NOLINT
throw boost::system::system_error(boost::system::error_code(c.value(), c.category()));
}
#endif
static_assert(sizeof(boost_error_code) <= sizeof(void *) * 2, "boost_error_code does not fit into a system_code!");
BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_END
// Enable implicit construction of `boost_error_code` from `boost::system::error_code`.
namespace boost
{
namespace system
{
inline BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::erased_status_code<int> make_status_code(error_code c) noexcept
{
if(c.category() == detail::interop_category())
{
// This is actually a wrap of std::error_code. If this fails to compile, your Boost is too old.
return std::make_status_code(std::error_code(c));
}
return BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::boost_error_code(c);
}
} // namespace system
} // namespace boost
#endif

View File

@@ -1,5 +1,5 @@
/* Proposed SG14 status_code
(C) 2018-2019 Niall Douglas <http://www.nedproductions.biz/> (5 commits)
(C) 2018-2023 Niall Douglas <http://www.nedproductions.biz/> (5 commits)
File Created: Feb 2018
@@ -46,10 +46,10 @@ BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_BEGIN
class _com_code_domain;
/*! (Windows only) A COM error code. Note semantic equivalence testing is only implemented for `FACILITY_WIN32`
and `FACILITY_NT_BIT`. As you can see at [https://blogs.msdn.microsoft.com/eldar/2007/04/03/a-lot-of-hresult-codes/](https://blogs.msdn.microsoft.com/eldar/2007/04/03/a-lot-of-hresult-codes/),
there are an awful lot of COM error codes, and keeping mapping tables for all of them would be impractical
(for the Win32 and NT facilities, we actually reuse the mapping tables in `win32_code` and `nt_code`).
You can, of course, inherit your own COM code domain from this one and override the `_do_equivalent()` function
and `FACILITY_NT_BIT`. As you can see at
[https://blogs.msdn.microsoft.com/eldar/2007/04/03/a-lot-of-hresult-codes/](https://blogs.msdn.microsoft.com/eldar/2007/04/03/a-lot-of-hresult-codes/), there
are an awful lot of COM error codes, and keeping mapping tables for all of them would be impractical (for the Win32 and NT facilities, we actually reuse the
mapping tables in `win32_code` and `nt_code`). You can, of course, inherit your own COM code domain from this one and override the `_do_equivalent()` function
to add semantic equivalence testing for whichever extra COM codes that your application specifically needs.
*/
using com_code = status_code<_com_code_domain>;
@@ -57,15 +57,19 @@ using com_code = status_code<_com_code_domain>;
using com_error = status_error<_com_code_domain>;
/*! (Windows only) The implementation of the domain for COM error codes and/or `IErrorInfo`.
*/
*/
class _com_code_domain : public status_code_domain
{
template <class DomainType> friend class status_code;
template <class StatusCode> friend class detail::indirecting_domain;
template <class StatusCode, class Allocator> friend class detail::indirecting_domain;
using _base = status_code_domain;
//! Construct from a `HRESULT` error code
#ifdef _COMDEF_NOT_WINAPI_FAMILY_DESKTOP_APP
static _base::string_ref _make_string_ref(HRESULT c, wchar_t *perrinfo = nullptr) noexcept
#else
static _base::string_ref _make_string_ref(HRESULT c, IErrorInfo *perrinfo = nullptr) noexcept
#endif
{
_com_error ce(c, perrinfo);
#ifdef _UNICODE
@@ -83,7 +87,7 @@ class _com_code_domain : public status_code_domain
{
return _base::string_ref("failed to get message from system");
}
bytes = win32::WideCharToMultiByte(65001 /*CP_UTF8*/, 0, ce.ErrorMessage(), wlen + 1, p, allocation, nullptr, nullptr);
bytes = win32::WideCharToMultiByte(65001 /*CP_UTF8*/, 0, ce.ErrorMessage(), (int) (wlen + 1), p, (int) allocation, nullptr, nullptr);
if(bytes != 0)
{
char *end = strchr(p, 0);
@@ -127,7 +131,10 @@ public:
public:
//! Default constructor
constexpr explicit _com_code_domain(typename _base::unique_id_type id = 0xdc8275428b4effac) noexcept : _base(id) {}
constexpr explicit _com_code_domain(typename _base::unique_id_type id = 0xdc8275428b4effac) noexcept
: _base(id)
{
}
_com_code_domain(const _com_code_domain &) = default;
_com_code_domain(_com_code_domain &&) = default;
_com_code_domain &operator=(const _com_code_domain &) = default;
@@ -138,6 +145,13 @@ public:
static inline constexpr const _com_code_domain &get();
virtual string_ref name() const noexcept override { return string_ref("COM domain"); } // NOLINT
virtual payload_info_t payload_info() const noexcept override
{
return {sizeof(value_type), sizeof(status_code_domain *) + sizeof(value_type),
(alignof(value_type) > alignof(status_code_domain *)) ? alignof(value_type) : alignof(status_code_domain *)};
}
protected:
virtual bool _do_failure(const status_code<void> &code) const noexcept override // NOLINT
{
@@ -145,7 +159,7 @@ protected:
return static_cast<const com_code &>(code).value() < 0; // NOLINT
}
/*! Note semantic equivalence testing is only implemented for `FACILITY_WIN32` and `FACILITY_NT_BIT`.
*/
*/
virtual bool _do_equivalent(const status_code<void> &code1, const status_code<void> &code2) const noexcept override // NOLINT
{
assert(code1.domain() == *this);

View File

@@ -0,0 +1,459 @@
/* Proposed SG14 status_code
(C) 2018 - 2021 Niall Douglas <http://www.nedproductions.biz/> (5 commits)
File Created: Feb 2018
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License in the accompanying file
Licence.txt or at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Distributed under the Boost Software License, Version 1.0.
(See accompanying file Licence.txt or copy at
http://www.boost.org/LICENSE_1_0.txt)
*/
#ifndef BOOST_OUTCOME_SYSTEM_ERROR2_CONFIG_HPP
#define BOOST_OUTCOME_SYSTEM_ERROR2_CONFIG_HPP
// < 0.1 each
#include <cassert>
#include <cstddef> // for size_t
#include <cstdlib> // for free
// 0.22
#include <type_traits>
// 0.29
#include <atomic>
// 0.28 (0.15 of which is exception_ptr)
#include <exception> // for std::exception
// <new> includes <exception>, <exception> includes <new>
#include <new>
// 0.01
#include <initializer_list>
#ifndef BOOST_OUTCOME_SYSTEM_ERROR2_HAVE_BIT_CAST
#ifdef __has_include
#if __has_include(<bit>) && (__cplusplus >= 202002L || _HAS_CXX20)
#define BOOST_OUTCOME_SYSTEM_ERROR2_HAVE_BIT_CAST 1
#endif
#elif __cplusplus >= 202002L
#define BOOST_OUTCOME_SYSTEM_ERROR2_HAVE_BIT_CAST 1
#endif
#ifndef BOOST_OUTCOME_SYSTEM_ERROR2_HAVE_BIT_CAST
#define BOOST_OUTCOME_SYSTEM_ERROR2_HAVE_BIT_CAST 0
#endif
#endif
#if BOOST_OUTCOME_SYSTEM_ERROR2_HAVE_BIT_CAST
#include <bit>
#if __cpp_lib_bit_cast < 201806L
#undef BOOST_OUTCOME_SYSTEM_ERROR2_HAVE_BIT_CAST
#define BOOST_OUTCOME_SYSTEM_ERROR2_HAVE_BIT_CAST 0
#endif
#endif
#if BOOST_OUTCOME_SYSTEM_ERROR2_USE_STD_ADDRESSOF
#include <memory> // for std::addressof
#define BOOST_OUTCOME_SYSTEM_ERROR2_ADDRESS_OF(...) std::addressof(__VA_ARGS__)
#else
#define BOOST_OUTCOME_SYSTEM_ERROR2_ADDRESS_OF(...) (&__VA_ARGS__)
#endif
#ifndef BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR14
#if defined(BOOST_OUTCOME_STANDARDESE_IS_IN_THE_HOUSE) || __cplusplus >= 201400 || _MSC_VER >= 1910 /* VS2017 */
//! Defined to be `constexpr` when on C++ 14 or better compilers. Usually automatic, can be overriden.
#define BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR14 constexpr
#else
#define BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR14
#endif
#endif
#ifndef BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR20
#if defined(BOOST_OUTCOME_STANDARDESE_IS_IN_THE_HOUSE) || __cplusplus >= 202000 || _HAS_CXX20
//! Defined to be `constexpr` when on C++ 20 or better compilers. Usually automatic, can be overriden.
#define BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR20 constexpr
#else
#define BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR20
#endif
#endif
#ifndef BOOST_OUTCOME_SYSTEM_ERROR2_NORETURN
#if defined(BOOST_OUTCOME_STANDARDESE_IS_IN_THE_HOUSE) || (_HAS_CXX17 && _MSC_VER >= 1911 /* VS2017.3 */)
#define BOOST_OUTCOME_SYSTEM_ERROR2_NORETURN [[noreturn]]
#endif
#endif
#if !defined(BOOST_OUTCOME_SYSTEM_ERROR2_NORETURN)
#ifdef __has_cpp_attribute
#if __has_cpp_attribute(noreturn)
#define BOOST_OUTCOME_SYSTEM_ERROR2_NORETURN [[noreturn]]
#endif
#endif
#endif
#if !defined(BOOST_OUTCOME_SYSTEM_ERROR2_NORETURN)
#if defined(_MSC_VER)
#define BOOST_OUTCOME_SYSTEM_ERROR2_NORETURN __declspec(noreturn)
#elif defined(__GNUC__)
#define BOOST_OUTCOME_SYSTEM_ERROR2_NORETURN __attribute__((__noreturn__))
#else
#define BOOST_OUTCOME_SYSTEM_ERROR2_NORETURN
#endif
#endif
// GCCs before 7 don't grok [[noreturn]] virtual functions, and warn annoyingly
#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 7
#undef BOOST_OUTCOME_SYSTEM_ERROR2_NORETURN
#define BOOST_OUTCOME_SYSTEM_ERROR2_NORETURN
#endif
#ifndef BOOST_OUTCOME_SYSTEM_ERROR2_NODISCARD
#if defined(BOOST_OUTCOME_STANDARDESE_IS_IN_THE_HOUSE) || (_HAS_CXX17 && _MSC_VER >= 1911 /* VS2017.3 */)
#define BOOST_OUTCOME_SYSTEM_ERROR2_NODISCARD [[nodiscard]]
#endif
#endif
#ifndef BOOST_OUTCOME_SYSTEM_ERROR2_NODISCARD
#ifdef __has_cpp_attribute
#if __has_cpp_attribute(nodiscard)
#define BOOST_OUTCOME_SYSTEM_ERROR2_NODISCARD [[nodiscard]]
#endif
#elif defined(__clang__)
#define BOOST_OUTCOME_SYSTEM_ERROR2_NODISCARD __attribute__((warn_unused_result))
#elif defined(_MSC_VER)
// _Must_inspect_result_ expands into this
#define BOOST_OUTCOME_SYSTEM_ERROR2_NODISCARD \
__declspec( \
"SAL_name" \
"(" \
"\"_Must_inspect_result_\"" \
"," \
"\"\"" \
"," \
"\"2\"" \
")") __declspec("SAL_begin") __declspec("SAL_post") __declspec("SAL_mustInspect") __declspec("SAL_post") __declspec("SAL_checkReturn") __declspec("SAL_end")
#endif
#endif
#ifndef BOOST_OUTCOME_SYSTEM_ERROR2_NODISCARD
#define BOOST_OUTCOME_SYSTEM_ERROR2_NODISCARD
#endif
#ifndef BOOST_OUTCOME_SYSTEM_ERROR2_TRIVIAL_ABI
#if defined(BOOST_OUTCOME_STANDARDESE_IS_IN_THE_HOUSE) || (__clang_major__ >= 7 && !defined(__APPLE__))
//! Defined to be `[[clang::trivial_abi]]` when on a new enough clang compiler. Usually automatic, can be overriden.
#define BOOST_OUTCOME_SYSTEM_ERROR2_TRIVIAL_ABI [[clang::trivial_abi]]
#else
#define BOOST_OUTCOME_SYSTEM_ERROR2_TRIVIAL_ABI
#endif
#endif
#if defined(__cpp_concepts) && !defined(BOOST_OUTCOME_SYSTEM_ERROR2_DISABLE_CONCEPTS_SUPPORT)
#define BOOST_OUTCOME_SYSTEM_ERROR2_GLUE(x, y) x y
#define BOOST_OUTCOME_SYSTEM_ERROR2_RETURN_ARG_COUNT(_1_, _2_, _3_, _4_, _5_, _6_, _7_, _8_, count, ...) count
#define BOOST_OUTCOME_SYSTEM_ERROR2_EXPAND_ARGS(args) BOOST_OUTCOME_SYSTEM_ERROR2_RETURN_ARG_COUNT args
#define BOOST_OUTCOME_SYSTEM_ERROR2_COUNT_ARGS_MAX8(...) BOOST_OUTCOME_SYSTEM_ERROR2_EXPAND_ARGS((__VA_ARGS__, 8, 7, 6, 5, 4, 3, 2, 1, 0))
#define BOOST_OUTCOME_SYSTEM_ERROR2_OVERLOAD_MACRO2(name, count) name##count
#define BOOST_OUTCOME_SYSTEM_ERROR2_OVERLOAD_MACRO1(name, count) BOOST_OUTCOME_SYSTEM_ERROR2_OVERLOAD_MACRO2(name, count)
#define BOOST_OUTCOME_SYSTEM_ERROR2_OVERLOAD_MACRO(name, count) BOOST_OUTCOME_SYSTEM_ERROR2_OVERLOAD_MACRO1(name, count)
#define BOOST_OUTCOME_SYSTEM_ERROR2_CALL_OVERLOAD(name, ...) BOOST_OUTCOME_SYSTEM_ERROR2_GLUE(BOOST_OUTCOME_SYSTEM_ERROR2_OVERLOAD_MACRO(name, BOOST_OUTCOME_SYSTEM_ERROR2_COUNT_ARGS_MAX8(__VA_ARGS__)), (__VA_ARGS__))
#define BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES_EXPAND8(a, b, c, d, e, f, g, h) a &&BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES_EXPAND7(b, c, d, e, f, g, h)
#define BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES_EXPAND7(a, b, c, d, e, f, g) a &&BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES_EXPAND6(b, c, d, e, f, g)
#define BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES_EXPAND6(a, b, c, d, e, f) a &&BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES_EXPAND5(b, c, d, e, f)
#define BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES_EXPAND5(a, b, c, d, e) a &&BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES_EXPAND4(b, c, d, e)
#define BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES_EXPAND4(a, b, c, d) a &&BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES_EXPAND3(b, c, d)
#define BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES_EXPAND3(a, b, c) a &&BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES_EXPAND2(b, c)
#define BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES_EXPAND2(a, b) a &&BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES_EXPAND1(b)
#define BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES_EXPAND1(a) a
//! Expands into a && b && c && ...
#define BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(...) requires BOOST_OUTCOME_SYSTEM_ERROR2_CALL_OVERLOAD(BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES_EXPAND, __VA_ARGS__)
#define BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(...) template <__VA_ARGS__>
#define BOOST_OUTCOME_SYSTEM_ERROR2_TEXPR(...) \
requires { (__VA_ARGS__); }
#define BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(...) (__VA_ARGS__)
#if !defined(_MSC_VER) || _MSC_FULL_VER >= 192400000 // VS 2019 16.3 is broken here
#define BOOST_OUTCOME_SYSTEM_ERROR2_REQUIRES(...) requires(__VA_ARGS__)
#else
#define BOOST_OUTCOME_SYSTEM_ERROR2_REQUIRES(...)
#endif
#else
#define BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(...) template <__VA_ARGS__
#define BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(...) , __VA_ARGS__ >
#define BOOST_OUTCOME_SYSTEM_ERROR2_TEXPR(...) typename = decltype(__VA_ARGS__)
#ifdef _MSC_VER
// MSVC gives an error if every specialisation of a template is always ill-formed, so
// the more powerful SFINAE form below causes pukeage :(
#define BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(...) typename = typename std::enable_if<(__VA_ARGS__)>::type
#else
#define BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(...) typename std::enable_if<(__VA_ARGS__), bool>::type = true
#endif
#define BOOST_OUTCOME_SYSTEM_ERROR2_REQUIRES(...)
#endif
#ifndef BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE
//! The system_error2 namespace name.
#define BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE system_error2
//! Begins the system_error2 namespace.
#define BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_BEGIN \
namespace system_error2 \
{
//! Ends the system_error2 namespace.
#define BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_END }
#endif
//! Namespace for the library
BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_BEGIN
//! Namespace for user specialised traits
namespace traits
{
/*! Specialise to true if you guarantee that a type is move bitcopying (i.e.
its move constructor equals copying bits from old to new, old is left in a
default constructed state, and calling the destructor on a default constructed
instance is trivial). All trivially copyable types are move bitcopying by
definition, and that is the unspecialised implementation.
*/
template <class T> struct is_move_bitcopying
{
static constexpr bool value = std::is_trivially_copyable<T>::value;
};
} // namespace traits
namespace detail
{
#if __cplusplus >= 201400 || _MSC_VER >= 1910 /* VS2017 */
inline constexpr size_t cstrlen(const char *str)
{
const char *end = nullptr;
for(end = str; *end != 0; ++end) // NOLINT
;
return end - str;
}
#else
inline constexpr size_t cstrlen_(const char *str, size_t acc) { return (str[0] == 0) ? acc : cstrlen_(str + 1, acc + 1); }
inline constexpr size_t cstrlen(const char *str) { return cstrlen_(str, 0); }
#endif
#if(__cplusplus >= 202002L || _MSVC_LANG >= 202002L) && __cpp_lib_remove_cvref >= 201711L
template <class T> using remove_cvref = std::remove_cvref<T>;
#else
template <class T> struct remove_cvref
{
using type = typename std::remove_cv<typename std::remove_reference<T>::type>::type;
};
#endif
/* A partially compliant implementation of C++20's std::bit_cast function contributed
by Jesse Towner.
Our bit_cast is only guaranteed to be constexpr when both the input and output
arguments are either integrals or enums. However, this covers most use cases
since the vast majority of status_codes have an underlying type that is either
an integral or enum. We still attempt a constexpr union-based type pun for non-array
input types, which some compilers accept. For array inputs, we fall back to
non-constexpr memmove.
*/
template <class T> using is_integral_or_enum = std::integral_constant<bool, std::is_integral<T>::value || std::is_enum<T>::value>;
template <class To, class From> using is_static_castable = std::integral_constant<bool, is_integral_or_enum<To>::value && is_integral_or_enum<From>::value>;
template <class To, class From>
using is_union_castable = std::integral_constant<bool, !is_static_castable<To, From>::value && !std::is_array<To>::value && !std::is_array<From>::value>;
template <class To, class From>
using is_bit_castable =
std::integral_constant<bool, sizeof(To) == sizeof(From) && traits::is_move_bitcopying<To>::value && traits::is_move_bitcopying<From>::value>;
template <class To, class From> union bit_cast_union
{
From source;
To target;
};
#if BOOST_OUTCOME_SYSTEM_ERROR2_HAVE_BIT_CAST
using std::bit_cast; // available for all trivially copyable types
// For move bit copying types
template <class To, class From>
requires(is_bit_castable<To, From>::value //
&&is_union_castable<To, From>::value //
&& (!std::is_trivially_copyable_v<From> //
|| !std::is_trivially_copyable_v<To>) ) //
constexpr To bit_cast(const From &from) noexcept
{
return bit_cast_union<To, From>{from}.target;
}
template <class To, class From>
requires(is_bit_castable<To, From>::value //
&& !is_union_castable<To, From>::value //
&& (!std::is_trivially_copyable_v<From> //
|| !std::is_trivially_copyable_v<To>) ) //
To bit_cast(const From &from)
noexcept
{
bit_cast_union<To, From> ret;
memmove(&ret.source, &from, sizeof(ret.source));
return ret.target;
}
#else
BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(class To, class From, int = 5)
BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(is_bit_castable<To, From>::value //
&&is_static_castable<To, From>::value //
&& !is_union_castable<To, From>::value))
constexpr To bit_cast(const From &from) noexcept { return static_cast<To>(from); }
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
#endif
BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(class To, class From, long = 5)
BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(is_bit_castable<To, From>::value //
&& !is_static_castable<To, From>::value //
&& is_union_castable<To, From>::value))
constexpr To bit_cast(const From &from) noexcept { return bit_cast_union<To, From>{from}.target; }
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic pop
#endif
BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(class To, class From, short = 5)
BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(is_bit_castable<To, From>::value //
&& !is_static_castable<To, From>::value //
&& !is_union_castable<To, From>::value))
To bit_cast(const From &from) noexcept
{
bit_cast_union<To, From> ret;
memmove(&ret.source, &from, sizeof(ret.source));
return ret.target;
}
#endif
/* erasure_cast performs a bit_cast with additional rules to handle types
of differing sizes. For integral & enum types, it may perform a narrowing
or widing conversion with static_cast if necessary, before doing the final
conversion with bit_cast. When casting to or from non-integral, non-enum
types it may insert the value into another object with extra padding bytes
to satisfy bit_cast's preconditions that both types have the same size. */
template <class To, class From>
using is_erasure_castable = std::integral_constant<bool, traits::is_move_bitcopying<To>::value && traits::is_move_bitcopying<From>::value>;
template <class T, bool = std::is_enum<T>::value> struct identity_or_underlying_type
{
using type = T;
};
template <class T> struct identity_or_underlying_type<T, true>
{
using type = typename std::underlying_type<T>::type;
};
template <class OfSize, class OfSign>
using erasure_integer_type = typename std::conditional<std::is_signed<typename identity_or_underlying_type<OfSign>::type>::value,
typename std::make_signed<typename identity_or_underlying_type<OfSize>::type>::type,
typename std::make_unsigned<typename identity_or_underlying_type<OfSize>::type>::type>::type;
template <class ErasedType, std::size_t N> struct padded_erasure_object
{
static_assert(traits::is_move_bitcopying<ErasedType>::value, "ErasedType must be TriviallyCopyable or MoveBitcopying");
static_assert(alignof(ErasedType) <= sizeof(ErasedType), "ErasedType must not be over-aligned");
ErasedType value;
char padding[N];
constexpr explicit padded_erasure_object(const ErasedType &v) noexcept
: value(v)
, padding{}
{
}
};
BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(class To, class From)
BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(is_erasure_castable<To, From>::value && (sizeof(To) == sizeof(From))))
constexpr To erasure_cast(const From &from) noexcept { return bit_cast<To>(from); }
#if defined(_WIN32) || defined(__APPLE__) || __LITTLE_ENDIAN__ || (defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && __BYTE_ORDER == __LITTLE_ENDIAN)
// We can avoid the type pun on little endian architectures which can aid optimisation
BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(class To, class From, long = 5)
BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(is_erasure_castable<To, From>::value &&is_static_castable<To, From>::value && (sizeof(To) < sizeof(From))))
constexpr To erasure_cast(const From &from) noexcept { return static_cast<To>(bit_cast<erasure_integer_type<From, To>>(from)); }
BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(class To, class From, int = 5)
BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(is_erasure_castable<To, From>::value &&is_static_castable<To, From>::value && (sizeof(To) > sizeof(From))))
constexpr To erasure_cast(const From &from) noexcept { return bit_cast<To>(static_cast<erasure_integer_type<To, From>>(from)); }
BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(class To, class From, short = 5)
BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(is_erasure_castable<To, From>::value && !is_static_castable<To, From>::value && (sizeof(To) < sizeof(From))))
constexpr To erasure_cast(const From &from) noexcept { return bit_cast<padded_erasure_object<To, sizeof(From) - sizeof(To)>>(from).value; }
BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(class To, class From, char = 5)
BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(is_erasure_castable<To, From>::value && !is_static_castable<To, From>::value && (sizeof(To) > sizeof(From))))
constexpr To erasure_cast(const From &from) noexcept { return bit_cast<To>(padded_erasure_object<From, sizeof(To) - sizeof(From)>{from}); }
#else
BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(class To, class From, short = 5)
BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(is_erasure_castable<To, From>::value && (sizeof(To) < sizeof(From))))
constexpr To erasure_cast(const From &from) noexcept { return bit_cast<padded_erasure_object<To, sizeof(From) - sizeof(To)>>(from).value; }
BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(class To, class From, char = 5)
BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(is_erasure_castable<To, From>::value && (sizeof(To) > sizeof(From))))
constexpr To erasure_cast(const From &from) noexcept { return bit_cast<To>(padded_erasure_object<From, sizeof(To) - sizeof(From)>{from}); }
#endif
} // namespace detail
BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_END
#ifndef BOOST_OUTCOME_SYSTEM_ERROR2_FATAL
#ifdef BOOST_OUTCOME_SYSTEM_ERROR2_NOT_POSIX
#error If BOOST_OUTCOME_SYSTEM_ERROR2_NOT_POSIX is defined, you must define your own BOOST_OUTCOME_SYSTEM_ERROR2_FATAL implementation!
#endif
#include <cstdlib> // for abort
#ifdef __APPLE__
#include <unistd.h> // for write
#endif
BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_BEGIN
namespace detail
{
namespace avoid_stdio_include
{
#if !defined(__APPLE__) && !defined(_MSC_VER)
extern "C" ptrdiff_t write(int, const void *, size_t);
#elif defined(_MSC_VER)
extern ptrdiff_t write(int, const void *, size_t);
#if(defined(__x86_64__) || defined(_M_X64)) || (defined(__aarch64__) || defined(_M_ARM64)) || (defined(__arm__) || defined(_M_ARM))
#pragma comment(linker, "/alternatename:?write@avoid_stdio_include@detail@system_error2@@YA_JHPEBX_K@Z=write")
#elif defined(__x86__) || defined(_M_IX86) || defined(__i386__)
#pragma comment(linker, "/alternatename:?write@avoid_stdio_include@detail@system_error2@@YAHHPBXI@Z=_write")
#else
#error Unknown architecture
#endif
#endif
} // namespace avoid_stdio_include
inline void do_fatal_exit(const char *msg)
{
using namespace avoid_stdio_include;
write(2 /*stderr*/, msg, cstrlen(msg));
write(2 /*stderr*/, "\n", 1);
abort();
}
} // namespace detail
BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_END
//! Prints msg to stderr, and calls `std::terminate()`. Can be overriden via predefinition.
#define BOOST_OUTCOME_SYSTEM_ERROR2_FATAL(msg) ::BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::detail::do_fatal_exit(msg)
#endif
#endif

View File

@@ -1,5 +1,5 @@
/* Proposed SG14 status_code
(C) 2018-2019 Niall Douglas <http://www.nedproductions.biz/> (5 commits)
(C) 2018-2023 Niall Douglas <http://www.nedproductions.biz/> (5 commits)
File Created: Feb 2018
@@ -36,7 +36,7 @@ DEALINGS IN THE SOFTWARE.
BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_BEGIN
/*! An erased `system_code` which is always a failure. The closest equivalent to
/*! An errored `system_code` which is always a failure. The closest equivalent to
`std::error_code`, except it cannot be null and cannot be modified.
This refines `system_code` into an `error` object meeting the requirements of
@@ -51,13 +51,13 @@ the program is terminated as this is a logic error)
- Is immutable.
As with `system_code`, it remains guaranteed to be two CPU registers in size,
and move relocating.
and move bitcopying.
*/
using error = errored_status_code<erased<system_code::value_type>>;
using error = erased_errored_status_code<system_code::value_type>;
#ifndef NDEBUG
static_assert(sizeof(error) == 2 * sizeof(void *), "error is not exactly two pointers in size!");
static_assert(traits::is_move_relocating<error>::value, "error is not move relocating!");
static_assert(traits::is_move_bitcopying<error>::value, "error is not move bitcopying!");
#endif
BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_END

View File

@@ -0,0 +1,438 @@
/* Proposed SG14 status_code
(C) 2018-2023 Niall Douglas <http://www.nedproductions.biz/> (5 commits)
File Created: Jun 2018
Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#ifndef BOOST_OUTCOME_SYSTEM_ERROR2_ERRORED_STATUS_CODE_HPP
#define BOOST_OUTCOME_SYSTEM_ERROR2_ERRORED_STATUS_CODE_HPP
#include "quick_status_code_from_enum.hpp"
BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_BEGIN
/*! A `status_code` which is always a failure. The closest equivalent to
`std::error_code`, except it cannot be modified, and is templated.
Differences from `status_code`:
- Never successful (this contract is checked on construction, if fails then it
terminates the process).
- Is immutable.
*/
template <class DomainType> class errored_status_code : public status_code<DomainType>
{
using _base = status_code<DomainType>;
using _base::clear;
using _base::success;
void _check()
{
if(_base::success())
{
std::terminate();
}
}
public:
//! The type of the domain.
using typename _base::domain_type;
//! The type of the error code.
using typename _base::value_type;
//! The type of a reference to a message string.
using typename _base::string_ref;
//! Default constructor.
errored_status_code() = default;
//! Copy constructor.
errored_status_code(const errored_status_code &) = default;
//! Move constructor.
errored_status_code(errored_status_code &&) = default; // NOLINT
//! Copy assignment.
errored_status_code &operator=(const errored_status_code &) = default;
//! Move assignment.
errored_status_code &operator=(errored_status_code &&) = default; // NOLINT
~errored_status_code() = default;
//! Explicitly construct from any similarly erased status code
explicit errored_status_code(const _base &o) noexcept(std::is_nothrow_copy_constructible<_base>::value)
: _base(o)
{
_check();
}
//! Explicitly construct from any similarly erased status code
explicit errored_status_code(_base &&o) noexcept(std::is_nothrow_move_constructible<_base>::value)
: _base(static_cast<_base &&>(o))
{
_check();
}
/***** KEEP THESE IN SYNC WITH STATUS_CODE *****/
//! Implicit construction from any type where an ADL discovered `make_status_code(T, Args ...)` returns a `status_code`.
BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(
class T, class... Args, //
class MakeStatusCodeResult =
typename detail::safe_get_make_status_code_result<T, Args...>::type) // Safe ADL lookup of make_status_code(), returns void if not found
BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(!std::is_same<typename std::decay<T>::type, errored_status_code>::value // not copy/move of self
&& !std::is_same<typename std::decay<T>::type, in_place_t>::value // not in_place_t
&& is_status_code<MakeStatusCodeResult>::value // ADL makes a status code
&& std::is_constructible<errored_status_code, MakeStatusCodeResult>::value)) // ADLed status code is compatible
errored_status_code(T &&v, Args &&...args) noexcept(noexcept(make_status_code(std::declval<T>(), std::declval<Args>()...))) // NOLINT
: errored_status_code(make_status_code(static_cast<T &&>(v), static_cast<Args &&>(args)...))
{
_check();
}
//! Implicit construction from any `quick_status_code_from_enum<Enum>` enumerated type.
BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(class Enum, //
class QuickStatusCodeType = typename quick_status_code_from_enum<Enum>::code_type) // Enumeration has been activated
BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(std::is_constructible<errored_status_code, QuickStatusCodeType>::value)) // Its status code is compatible
errored_status_code(Enum &&v) noexcept(std::is_nothrow_constructible<errored_status_code, QuickStatusCodeType>::value) // NOLINT
: errored_status_code(QuickStatusCodeType(static_cast<Enum &&>(v)))
{
_check();
}
//! Explicit in-place construction.
template <class... Args>
explicit errored_status_code(in_place_t _, Args &&...args) noexcept(std::is_nothrow_constructible<value_type, Args &&...>::value)
: _base(_, static_cast<Args &&>(args)...)
{
_check();
}
//! Explicit in-place construction from initialiser list.
template <class T, class... Args>
explicit errored_status_code(in_place_t _, std::initializer_list<T> il,
Args &&...args) noexcept(std::is_nothrow_constructible<value_type, std::initializer_list<T>, Args &&...>::value)
: _base(_, il, static_cast<Args &&>(args)...)
{
_check();
}
//! Explicit copy construction from a `value_type`.
explicit errored_status_code(const value_type &v) noexcept(std::is_nothrow_copy_constructible<value_type>::value)
: _base(v)
{
_check();
}
//! Explicit move construction from a `value_type`.
explicit errored_status_code(value_type &&v) noexcept(std::is_nothrow_move_constructible<value_type>::value)
: _base(static_cast<value_type &&>(v))
{
_check();
}
/*! Explicit construction from an erased status code. Available only if
`value_type` is trivially copyable or move bitcopying, and `sizeof(status_code) <= sizeof(status_code<erased<>>)`.
Does not check if domains are equal.
*/
BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(class ErasedType) //
BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(detail::domain_value_type_erasure_is_safe<domain_type, detail::erased<ErasedType>>::value))
explicit errored_status_code(const status_code<detail::erased<ErasedType>> &v) noexcept(std::is_nothrow_copy_constructible<value_type>::value)
: errored_status_code(detail::erasure_cast<value_type>(v.value())) // NOLINT
{
assert(v.domain() == this->domain()); // NOLINT
_check();
}
//! Always false (including at compile time), as errored status codes are never successful.
constexpr bool success() const noexcept { return false; }
//! Return a const reference to the `value_type`.
constexpr const value_type &value() const &noexcept { return this->_value; }
};
namespace traits
{
template <class DomainType> struct is_move_bitcopying<errored_status_code<DomainType>>
{
static constexpr bool value = is_move_bitcopying<typename DomainType::value_type>::value;
};
} // namespace traits
template <class ErasedType> class errored_status_code<detail::erased<ErasedType>> : public status_code<detail::erased<ErasedType>>
{
using _base = status_code<detail::erased<ErasedType>>;
using _base::success;
void _check()
{
if(_base::success())
{
std::terminate();
}
}
public:
using domain_type = typename _base::domain_type;
using value_type = typename _base::value_type;
using string_ref = typename _base::string_ref;
//! Default construction to empty
errored_status_code() = default;
//! Copy constructor
errored_status_code(const errored_status_code &) = default;
//! Move constructor
errored_status_code(errored_status_code &&) = default; // NOLINT
//! Copy assignment
errored_status_code &operator=(const errored_status_code &) = default;
//! Move assignment
errored_status_code &operator=(errored_status_code &&) = default; // NOLINT
~errored_status_code() = default;
//! Explicitly construct from any similarly erased status code
explicit errored_status_code(const _base &o) noexcept(std::is_nothrow_copy_constructible<_base>::value)
: _base(o)
{
_check();
}
//! Explicitly construct from any similarly erased status code
explicit errored_status_code(_base &&o) noexcept(std::is_nothrow_move_constructible<_base>::value)
: _base(static_cast<_base &&>(o))
{
_check();
}
/***** KEEP THESE IN SYNC WITH STATUS_CODE *****/
//! Implicit copy construction from any other status code if its value type is trivially copyable, it would fit into our storage, and it is not an erased
//! status code.
BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(class DomainType) //
BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(detail::domain_value_type_erasure_is_safe<detail::erased<ErasedType>, DomainType>::value),
BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(!detail::is_erased_status_code<status_code<typename std::decay<DomainType>::type>>::value))
errored_status_code(const status_code<DomainType> &v) noexcept
: _base(v) // NOLINT
{
_check();
}
//! Implicit copy construction from any other status code if its value type is trivially copyable and it would fit into our storage, and it is not an erased
//! status code.
BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(class DomainType) //
BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(detail::domain_value_type_erasure_is_safe<detail::erased<ErasedType>, DomainType>::value),
BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(!detail::is_erased_status_code<status_code<typename std::decay<DomainType>::type>>::value))
errored_status_code(const errored_status_code<DomainType> &v) noexcept
: _base(static_cast<const status_code<DomainType> &>(v)) // NOLINT
{
_check();
}
//! Implicit move construction from any other status code if its value type is trivially copyable or move bitcopying and it would fit into our storage
BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(class DomainType) //
BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(detail::domain_value_type_erasure_is_safe<detail::erased<ErasedType>, DomainType>::value))
errored_status_code(status_code<DomainType> &&v) noexcept
: _base(static_cast<status_code<DomainType> &&>(v)) // NOLINT
{
_check();
}
//! Implicit move construction from any other status code if its value type is trivially copyable or move bitcopying and it would fit into our storage
BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(class DomainType) //
BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(detail::domain_value_type_erasure_is_safe<detail::erased<ErasedType>, DomainType>::value))
errored_status_code(errored_status_code<DomainType> &&v) noexcept
: _base(static_cast<status_code<DomainType> &&>(v)) // NOLINT
{
_check();
}
//! Implicit construction from any type where an ADL discovered `make_status_code(T, Args ...)` returns a `status_code`.
BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(
class T, class... Args, //
class MakeStatusCodeResult =
typename detail::safe_get_make_status_code_result<T, Args...>::type) // Safe ADL lookup of make_status_code(), returns void if not found
BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(!std::is_same<typename std::decay<T>::type, errored_status_code>::value // not copy/move of self
&& !std::is_same<typename std::decay<T>::type, value_type>::value // not copy/move of value type
&& is_status_code<MakeStatusCodeResult>::value // ADL makes a status code
&& std::is_constructible<errored_status_code, MakeStatusCodeResult>::value)) // ADLed status code is compatible
errored_status_code(T &&v, Args &&...args) noexcept(noexcept(make_status_code(std::declval<T>(), std::declval<Args>()...))) // NOLINT
: errored_status_code(make_status_code(static_cast<T &&>(v), static_cast<Args &&>(args)...))
{
_check();
}
//! Implicit construction from any `quick_status_code_from_enum<Enum>` enumerated type.
BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(class Enum, //
class QuickStatusCodeType = typename quick_status_code_from_enum<Enum>::code_type) // Enumeration has been activated
BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(std::is_constructible<errored_status_code, QuickStatusCodeType>::value)) // Its status code is compatible
errored_status_code(Enum &&v) noexcept(std::is_nothrow_constructible<errored_status_code, QuickStatusCodeType>::value) // NOLINT
: errored_status_code(QuickStatusCodeType(static_cast<Enum &&>(v)))
{
_check();
}
#if defined(_CPPUNWIND) || defined(__EXCEPTIONS) || defined(BOOST_OUTCOME_STANDARDESE_IS_IN_THE_HOUSE)
//! Explicit copy construction from an unknown status code. Note that this will be empty if its value type is not trivially copyable or would not fit into our
//! storage or the source domain's `_do_erased_copy()` refused the copy.
explicit errored_status_code(const status_code<void> &v) // NOLINT
: _base(v)
{
_check();
}
#endif
//! Always false (including at compile time), as errored status codes are never successful.
constexpr bool success() const noexcept { return false; }
//! Return the erased `value_type` by value.
constexpr value_type value() const noexcept { return this->_value; }
};
/*! An erased type specialisation of `errored_status_code<D>`.
Available only if `ErasedType` satisfies `traits::is_move_bitcopying<ErasedType>::value`.
*/
template <class ErasedType> using erased_errored_status_code = errored_status_code<detail::erased<ErasedType>>;
namespace traits
{
template <class ErasedType> struct is_move_bitcopying<errored_status_code<detail::erased<ErasedType>>>
{
static constexpr bool value = true;
};
} // namespace traits
//! True if the status code's are semantically equal via `equivalent()`.
template <class DomainType1, class DomainType2>
inline bool operator==(const errored_status_code<DomainType1> &a, const errored_status_code<DomainType2> &b) noexcept
{
return a.equivalent(static_cast<const status_code<DomainType2> &>(b));
}
//! True if the status code's are semantically equal via `equivalent()`.
template <class DomainType1, class DomainType2> inline bool operator==(const status_code<DomainType1> &a, const errored_status_code<DomainType2> &b) noexcept
{
return a.equivalent(static_cast<const status_code<DomainType2> &>(b));
}
//! True if the status code's are semantically equal via `equivalent()`.
template <class DomainType1, class DomainType2> inline bool operator==(const errored_status_code<DomainType1> &a, const status_code<DomainType2> &b) noexcept
{
return static_cast<const status_code<DomainType1> &>(a).equivalent(b);
}
//! True if the status code's are not semantically equal via `equivalent()`.
template <class DomainType1, class DomainType2>
inline bool operator!=(const errored_status_code<DomainType1> &a, const errored_status_code<DomainType2> &b) noexcept
{
return !a.equivalent(static_cast<const status_code<DomainType2> &>(b));
}
//! True if the status code's are not semantically equal via `equivalent()`.
template <class DomainType1, class DomainType2> inline bool operator!=(const status_code<DomainType1> &a, const errored_status_code<DomainType2> &b) noexcept
{
return !a.equivalent(static_cast<const status_code<DomainType2> &>(b));
}
//! True if the status code's are not semantically equal via `equivalent()`.
template <class DomainType1, class DomainType2> inline bool operator!=(const errored_status_code<DomainType1> &a, const status_code<DomainType2> &b) noexcept
{
return !static_cast<const status_code<DomainType1> &>(a).equivalent(b);
}
//! True if the status code's are semantically equal via `equivalent()` to `make_status_code(T)`.
BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(class DomainType1, class T, //
class MakeStatusCodeResult =
typename detail::safe_get_make_status_code_result<const T &>::type) // Safe ADL lookup of make_status_code(), returns void if not found
BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(is_status_code<MakeStatusCodeResult>::value)) // ADL makes a status code
inline bool operator==(const errored_status_code<DomainType1> &a, const T &b)
{
return a.equivalent(make_status_code(b));
}
//! True if the status code's are semantically equal via `equivalent()` to `make_status_code(T)`.
BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(class T, class DomainType1, //
class MakeStatusCodeResult =
typename detail::safe_get_make_status_code_result<const T &>::type) // Safe ADL lookup of make_status_code(), returns void if not found
BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(is_status_code<MakeStatusCodeResult>::value)) // ADL makes a status code
inline bool operator==(const T &a, const errored_status_code<DomainType1> &b)
{
return b.equivalent(make_status_code(a));
}
//! True if the status code's are not semantically equal via `equivalent()` to `make_status_code(T)`.
BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(class DomainType1, class T, //
class MakeStatusCodeResult =
typename detail::safe_get_make_status_code_result<const T &>::type) // Safe ADL lookup of make_status_code(), returns void if not found
BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(is_status_code<MakeStatusCodeResult>::value)) // ADL makes a status code
inline bool operator!=(const errored_status_code<DomainType1> &a, const T &b)
{
return !a.equivalent(make_status_code(b));
}
//! True if the status code's are semantically equal via `equivalent()` to `make_status_code(T)`.
BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(class T, class DomainType1, //
class MakeStatusCodeResult =
typename detail::safe_get_make_status_code_result<const T &>::type) // Safe ADL lookup of make_status_code(), returns void if not found
BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(is_status_code<MakeStatusCodeResult>::value)) // ADL makes a status code
inline bool operator!=(const T &a, const errored_status_code<DomainType1> &b)
{
return !b.equivalent(make_status_code(a));
}
//! True if the status code's are semantically equal via `equivalent()` to `quick_status_code_from_enum<T>::code_type(b)`.
template <class DomainType1, class T, //
class QuickStatusCodeType = typename quick_status_code_from_enum<T>::code_type // Enumeration has been activated
>
inline bool operator==(const errored_status_code<DomainType1> &a, const T &b)
{
return a.equivalent(QuickStatusCodeType(b));
}
//! True if the status code's are semantically equal via `equivalent()` to `quick_status_code_from_enum<T>::code_type(a)`.
template <class T, class DomainType1, //
class QuickStatusCodeType = typename quick_status_code_from_enum<T>::code_type // Enumeration has been activated
>
inline bool operator==(const T &a, const errored_status_code<DomainType1> &b)
{
return b.equivalent(QuickStatusCodeType(a));
}
//! True if the status code's are not semantically equal via `equivalent()` to `quick_status_code_from_enum<T>::code_type(b)`.
template <class DomainType1, class T, //
class QuickStatusCodeType = typename quick_status_code_from_enum<T>::code_type // Enumeration has been activated
>
inline bool operator!=(const errored_status_code<DomainType1> &a, const T &b)
{
return !a.equivalent(QuickStatusCodeType(b));
}
//! True if the status code's are not semantically equal via `equivalent()` to `quick_status_code_from_enum<T>::code_type(a)`.
template <class T, class DomainType1, //
class QuickStatusCodeType = typename quick_status_code_from_enum<T>::code_type // Enumeration has been activated
>
inline bool operator!=(const T &a, const errored_status_code<DomainType1> &b)
{
return !b.equivalent(QuickStatusCodeType(a));
}
namespace detail
{
template <class T> struct is_errored_status_code
{
static constexpr bool value = false;
};
template <class T> struct is_errored_status_code<errored_status_code<T>>
{
static constexpr bool value = true;
};
template <class T> struct is_erased_errored_status_code
{
static constexpr bool value = false;
};
template <class T> struct is_erased_errored_status_code<errored_status_code<erased<T>>>
{
static constexpr bool value = true;
};
} // namespace detail
//! Trait returning true if the type is an errored status code.
template <class T> struct is_errored_status_code
{
static constexpr bool value =
detail::is_errored_status_code<typename std::decay<T>::type>::value || detail::is_erased_errored_status_code<typename std::decay<T>::type>::value;
};
BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_END
#endif

View File

@@ -0,0 +1,492 @@
/* Proposed SG14 status_code
(C) 2018 - 2020 Niall Douglas <http://www.nedproductions.biz/> (5 commits)
File Created: Feb 2018
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License in the accompanying file
Licence.txt or at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Distributed under the Boost Software License, Version 1.0.
(See accompanying file Licence.txt or copy at
http://www.boost.org/LICENSE_1_0.txt)
*/
#ifndef BOOST_OUTCOME_SYSTEM_ERROR2_GENERIC_CODE_HPP
#define BOOST_OUTCOME_SYSTEM_ERROR2_GENERIC_CODE_HPP
#include "status_error.hpp"
#include <cerrno> // for error constants
BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_BEGIN
//! The generic error coding (POSIX)
enum class errc : int
{
success = 0,
unknown = -1,
address_family_not_supported = EAFNOSUPPORT,
address_in_use = EADDRINUSE,
address_not_available = EADDRNOTAVAIL,
already_connected = EISCONN,
argument_list_too_long = E2BIG,
argument_out_of_domain = EDOM,
bad_address = EFAULT,
bad_file_descriptor = EBADF,
bad_message = EBADMSG,
broken_pipe = EPIPE,
connection_aborted = ECONNABORTED,
connection_already_in_progress = EALREADY,
connection_refused = ECONNREFUSED,
connection_reset = ECONNRESET,
cross_device_link = EXDEV,
destination_address_required = EDESTADDRREQ,
device_or_resource_busy = EBUSY,
directory_not_empty = ENOTEMPTY,
executable_format_error = ENOEXEC,
file_exists = EEXIST,
file_too_large = EFBIG,
filename_too_long = ENAMETOOLONG,
function_not_supported = ENOSYS,
host_unreachable = EHOSTUNREACH,
identifier_removed = EIDRM,
illegal_byte_sequence = EILSEQ,
inappropriate_io_control_operation = ENOTTY,
interrupted = EINTR,
invalid_argument = EINVAL,
invalid_seek = ESPIPE,
io_error = EIO,
is_a_directory = EISDIR,
message_size = EMSGSIZE,
network_down = ENETDOWN,
network_reset = ENETRESET,
network_unreachable = ENETUNREACH,
no_buffer_space = ENOBUFS,
no_child_process = ECHILD,
no_link = ENOLINK,
no_lock_available = ENOLCK,
no_message = ENOMSG,
no_protocol_option = ENOPROTOOPT,
no_space_on_device = ENOSPC,
no_stream_resources = ENOSR,
no_such_device_or_address = ENXIO,
no_such_device = ENODEV,
no_such_file_or_directory = ENOENT,
no_such_process = ESRCH,
not_a_directory = ENOTDIR,
not_a_socket = ENOTSOCK,
not_a_stream = ENOSTR,
not_connected = ENOTCONN,
not_enough_memory = ENOMEM,
not_supported = ENOTSUP,
operation_canceled = ECANCELED,
operation_in_progress = EINPROGRESS,
operation_not_permitted = EPERM,
operation_not_supported = EOPNOTSUPP,
operation_would_block = EWOULDBLOCK,
owner_dead = EOWNERDEAD,
permission_denied = EACCES,
protocol_error = EPROTO,
protocol_not_supported = EPROTONOSUPPORT,
read_only_file_system = EROFS,
resource_deadlock_would_occur = EDEADLK,
resource_unavailable_try_again = EAGAIN,
result_out_of_range = ERANGE,
state_not_recoverable = ENOTRECOVERABLE,
stream_timeout = ETIME,
text_file_busy = ETXTBSY,
timed_out = ETIMEDOUT,
too_many_files_open_in_system = ENFILE,
too_many_files_open = EMFILE,
too_many_links = EMLINK,
too_many_symbolic_link_levels = ELOOP,
value_too_large = EOVERFLOW,
wrong_protocol_type = EPROTOTYPE
};
namespace detail
{
BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR14 inline const char *generic_code_message(errc code) noexcept
{
switch(code)
{
case errc::success:
return "Success";
case errc::address_family_not_supported:
return "Address family not supported by protocol";
case errc::address_in_use:
return "Address already in use";
case errc::address_not_available:
return "Cannot assign requested address";
case errc::already_connected:
return "Transport endpoint is already connected";
case errc::argument_list_too_long:
return "Argument list too long";
case errc::argument_out_of_domain:
return "Numerical argument out of domain";
case errc::bad_address:
return "Bad address";
case errc::bad_file_descriptor:
return "Bad file descriptor";
case errc::bad_message:
return "Bad message";
case errc::broken_pipe:
return "Broken pipe";
case errc::connection_aborted:
return "Software caused connection abort";
case errc::connection_already_in_progress:
return "Operation already in progress";
case errc::connection_refused:
return "Connection refused";
case errc::connection_reset:
return "Connection reset by peer";
case errc::cross_device_link:
return "Invalid cross-device link";
case errc::destination_address_required:
return "Destination address required";
case errc::device_or_resource_busy:
return "Device or resource busy";
case errc::directory_not_empty:
return "Directory not empty";
case errc::executable_format_error:
return "Exec format error";
case errc::file_exists:
return "File exists";
case errc::file_too_large:
return "File too large";
case errc::filename_too_long:
return "File name too long";
case errc::function_not_supported:
return "Function not implemented";
case errc::host_unreachable:
return "No route to host";
case errc::identifier_removed:
return "Identifier removed";
case errc::illegal_byte_sequence:
return "Invalid or incomplete multibyte or wide character";
case errc::inappropriate_io_control_operation:
return "Inappropriate ioctl for device";
case errc::interrupted:
return "Interrupted system call";
case errc::invalid_argument:
return "Invalid argument";
case errc::invalid_seek:
return "Illegal seek";
case errc::io_error:
return "Input/output error";
case errc::is_a_directory:
return "Is a directory";
case errc::message_size:
return "Message too long";
case errc::network_down:
return "Network is down";
case errc::network_reset:
return "Network dropped connection on reset";
case errc::network_unreachable:
return "Network is unreachable";
case errc::no_buffer_space:
return "No buffer space available";
case errc::no_child_process:
return "No child processes";
case errc::no_link:
return "Link has been severed";
case errc::no_lock_available:
return "No locks available";
case errc::no_message:
return "No message of desired type";
case errc::no_protocol_option:
return "Protocol not available";
case errc::no_space_on_device:
return "No space left on device";
case errc::no_stream_resources:
return "Out of streams resources";
case errc::no_such_device_or_address:
return "No such device or address";
case errc::no_such_device:
return "No such device";
case errc::no_such_file_or_directory:
return "No such file or directory";
case errc::no_such_process:
return "No such process";
case errc::not_a_directory:
return "Not a directory";
case errc::not_a_socket:
return "Socket operation on non-socket";
case errc::not_a_stream:
return "Device not a stream";
case errc::not_connected:
return "Transport endpoint is not connected";
case errc::not_enough_memory:
return "Cannot allocate memory";
#if ENOTSUP != EOPNOTSUPP
case errc::not_supported:
return "Operation not supported";
#endif
case errc::operation_canceled:
return "Operation canceled";
case errc::operation_in_progress:
return "Operation now in progress";
case errc::operation_not_permitted:
return "Operation not permitted";
case errc::operation_not_supported:
return "Operation not supported";
#if EAGAIN != EWOULDBLOCK
case errc::operation_would_block:
return "Resource temporarily unavailable";
#endif
case errc::owner_dead:
return "Owner died";
case errc::permission_denied:
return "Permission denied";
case errc::protocol_error:
return "Protocol error";
case errc::protocol_not_supported:
return "Protocol not supported";
case errc::read_only_file_system:
return "Read-only file system";
case errc::resource_deadlock_would_occur:
return "Resource deadlock avoided";
case errc::resource_unavailable_try_again:
return "Resource temporarily unavailable";
case errc::result_out_of_range:
return "Numerical result out of range";
case errc::state_not_recoverable:
return "State not recoverable";
case errc::stream_timeout:
return "Timer expired";
case errc::text_file_busy:
return "Text file busy";
case errc::timed_out:
return "Connection timed out";
case errc::too_many_files_open_in_system:
return "Too many open files in system";
case errc::too_many_files_open:
return "Too many open files";
case errc::too_many_links:
return "Too many links";
case errc::too_many_symbolic_link_levels:
return "Too many levels of symbolic links";
case errc::value_too_large:
return "Value too large for defined data type";
case errc::wrong_protocol_type:
return "Protocol wrong type for socket";
default:
return "unknown";
}
}
} // namespace detail
/*! The implementation of the domain for generic status codes, those mapped by `errc` (POSIX).
*/
class _generic_code_domain : public status_code_domain
{
template <class> friend class status_code;
template <class StatusCode, class Allocator> friend class detail::indirecting_domain;
using _base = status_code_domain;
public:
//! The value type of the generic code, which is an `errc` as per POSIX.
using value_type = errc;
using string_ref = _base::string_ref;
public:
//! Default constructor
constexpr explicit _generic_code_domain(typename _base::unique_id_type id = 0x746d6354f4f733e9) noexcept
: _base(id)
{
}
_generic_code_domain(const _generic_code_domain &) = default;
_generic_code_domain(_generic_code_domain &&) = default;
_generic_code_domain &operator=(const _generic_code_domain &) = default;
_generic_code_domain &operator=(_generic_code_domain &&) = default;
~_generic_code_domain() = default;
//! Constexpr singleton getter. Returns the constexpr generic_code_domain variable.
static inline constexpr const _generic_code_domain &get();
virtual _base::string_ref name() const noexcept override { return string_ref("generic domain"); } // NOLINT
virtual payload_info_t payload_info() const noexcept override
{
return {sizeof(value_type), sizeof(status_code_domain *) + sizeof(value_type),
(alignof(value_type) > alignof(status_code_domain *)) ? alignof(value_type) : alignof(status_code_domain *)};
}
protected:
virtual bool _do_failure(const status_code<void> &code) const noexcept override // NOLINT
{
assert(code.domain() == *this); // NOLINT
return static_cast<const generic_code &>(code).value() != errc::success; // NOLINT
}
virtual bool _do_equivalent(const status_code<void> &code1, const status_code<void> &code2) const noexcept override // NOLINT
{
assert(code1.domain() == *this); // NOLINT
const auto &c1 = static_cast<const generic_code &>(code1); // NOLINT
if(code2.domain() == *this)
{
const auto &c2 = static_cast<const generic_code &>(code2); // NOLINT
return c1.value() == c2.value();
}
return false;
}
virtual generic_code _generic_code(const status_code<void> &code) const noexcept override // NOLINT
{
assert(code.domain() == *this); // NOLINT
return static_cast<const generic_code &>(code); // NOLINT
}
virtual _base::string_ref _do_message(const status_code<void> &code) const noexcept override // NOLINT
{
assert(code.domain() == *this); // NOLINT
const auto &c = static_cast<const generic_code &>(code); // NOLINT
return string_ref(detail::generic_code_message(c.value()));
}
#if defined(_CPPUNWIND) || defined(__EXCEPTIONS) || defined(BOOST_OUTCOME_STANDARDESE_IS_IN_THE_HOUSE)
BOOST_OUTCOME_SYSTEM_ERROR2_NORETURN virtual void _do_throw_exception(const status_code<void> &code) const override // NOLINT
{
assert(code.domain() == *this); // NOLINT
const auto &c = static_cast<const generic_code &>(code); // NOLINT
throw status_error<_generic_code_domain>(c);
}
#endif
};
//! A specialisation of `status_error` for the generic code domain.
using generic_error = status_error<_generic_code_domain>;
//! A constexpr source variable for the generic code domain, which is that of `errc` (POSIX). Returned by `_generic_code_domain::get()`.
constexpr _generic_code_domain generic_code_domain;
inline constexpr const _generic_code_domain &_generic_code_domain::get()
{
return generic_code_domain;
}
// Enable implicit construction of generic_code from errc
BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR14 inline generic_code make_status_code(errc c) noexcept
{
return generic_code(in_place, c);
}
/*************************************************************************************************************/
template <class T> inline BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR14 bool status_code<void>::equivalent(const status_code<T> &o) const noexcept
{
if(_domain && o._domain)
{
if(_domain->_do_equivalent(*this, o))
{
return true;
}
if(o._domain->_do_equivalent(o, *this))
{
return true;
}
generic_code c1 = o._domain->_generic_code(o);
if(c1.value() != errc::unknown && _domain->_do_equivalent(*this, c1))
{
return true;
}
generic_code c2 = _domain->_generic_code(*this);
if(c2.value() != errc::unknown && o._domain->_do_equivalent(o, c2))
{
return true;
}
}
// If we are both empty, we are equivalent, otherwise not equivalent
return (!_domain && !o._domain);
}
//! True if the status code's are semantically equal via `equivalent()`.
template <class DomainType1, class DomainType2>
BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR14 inline bool operator==(const status_code<DomainType1> &a, const status_code<DomainType2> &b) noexcept
{
return a.equivalent(b);
}
//! True if the status code's are not semantically equal via `equivalent()`.
template <class DomainType1, class DomainType2>
BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR14 inline bool operator!=(const status_code<DomainType1> &a, const status_code<DomainType2> &b) noexcept
{
return !a.equivalent(b);
}
//! True if the status code's are semantically equal via `equivalent()` to `make_status_code(T)`.
BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(class DomainType1, class T, //
class MakeStatusCodeResult =
typename detail::safe_get_make_status_code_result<const T &>::type) // Safe ADL lookup of make_status_code(), returns void if not found
BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(is_status_code<MakeStatusCodeResult>::value)) // ADL makes a status code
BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR14 inline bool operator==(const status_code<DomainType1> &a, const T &b)
{
return a.equivalent(make_status_code(b));
}
//! True if the status code's are semantically equal via `equivalent()` to `make_status_code(T)`.
BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(class T, class DomainType1, //
class MakeStatusCodeResult =
typename detail::safe_get_make_status_code_result<const T &>::type) // Safe ADL lookup of make_status_code(), returns void if not found
BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(is_status_code<MakeStatusCodeResult>::value)) // ADL makes a status code
BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR14 inline bool operator==(const T &a, const status_code<DomainType1> &b)
{
return b.equivalent(make_status_code(a));
}
//! True if the status code's are not semantically equal via `equivalent()` to `make_status_code(T)`.
BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(class DomainType1, class T, //
class MakeStatusCodeResult =
typename detail::safe_get_make_status_code_result<const T &>::type) // Safe ADL lookup of make_status_code(), returns void if not found
BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(is_status_code<MakeStatusCodeResult>::value)) // ADL makes a status code
BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR14 inline bool operator!=(const status_code<DomainType1> &a, const T &b)
{
return !a.equivalent(make_status_code(b));
}
//! True if the status code's are semantically equal via `equivalent()` to `make_status_code(T)`.
BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(class T, class DomainType1, //
class MakeStatusCodeResult =
typename detail::safe_get_make_status_code_result<const T &>::type) // Safe ADL lookup of make_status_code(), returns void if not found
BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(is_status_code<MakeStatusCodeResult>::value)) // ADL makes a status code
BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR14 inline bool operator!=(const T &a, const status_code<DomainType1> &b)
{
return !b.equivalent(make_status_code(a));
}
//! True if the status code's are semantically equal via `equivalent()` to `quick_status_code_from_enum<T>::code_type(b)`.
template <class DomainType1, class T, //
class QuickStatusCodeType = typename quick_status_code_from_enum<T>::code_type // Enumeration has been activated
>
BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR14 inline bool operator==(const status_code<DomainType1> &a, const T &b)
{
return a.equivalent(QuickStatusCodeType(b));
}
//! True if the status code's are semantically equal via `equivalent()` to `quick_status_code_from_enum<T>::code_type(a)`.
template <class T, class DomainType1, //
class QuickStatusCodeType = typename quick_status_code_from_enum<T>::code_type // Enumeration has been activated
>
BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR14 inline bool operator==(const T &a, const status_code<DomainType1> &b)
{
return b.equivalent(QuickStatusCodeType(a));
}
//! True if the status code's are not semantically equal via `equivalent()` to `quick_status_code_from_enum<T>::code_type(b)`.
template <class DomainType1, class T, //
class QuickStatusCodeType = typename quick_status_code_from_enum<T>::code_type // Enumeration has been activated
>
BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR14 inline bool operator!=(const status_code<DomainType1> &a, const T &b)
{
return !a.equivalent(QuickStatusCodeType(b));
}
//! True if the status code's are not semantically equal via `equivalent()` to `quick_status_code_from_enum<T>::code_type(a)`.
template <class T, class DomainType1, //
class QuickStatusCodeType = typename quick_status_code_from_enum<T>::code_type // Enumeration has been activated
>
BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR14 inline bool operator!=(const T &a, const status_code<DomainType1> &b)
{
return !b.equivalent(QuickStatusCodeType(a));
}
BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_END
#endif

View File

@@ -0,0 +1,165 @@
/* Proposed SG14 status_code
(C) 2020-2023 Niall Douglas <http://www.nedproductions.biz/> (5 commits)
File Created: Jan 2020
Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#ifndef BOOST_OUTCOME_SYSTEM_ERROR2_GETADDRINFO_CODE_HPP
#define BOOST_OUTCOME_SYSTEM_ERROR2_GETADDRINFO_CODE_HPP
#include "quick_status_code_from_enum.hpp"
#ifdef _WIN32
#error Not available for Microsoft Windows
#else
#include <netdb.h>
#include <sys/socket.h>
#include <sys/types.h>
#endif
BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_BEGIN
class _getaddrinfo_code_domain;
//! A getaddrinfo error code, those returned by `getaddrinfo()`.
using getaddrinfo_code = status_code<_getaddrinfo_code_domain>;
//! A specialisation of `status_error` for the `getaddrinfo()` error code domain.
using getaddrinfo_error = status_error<_getaddrinfo_code_domain>;
/*! The implementation of the domain for `getaddrinfo()` error codes, those returned by `getaddrinfo()`.
*/
class _getaddrinfo_code_domain : public status_code_domain
{
template <class DomainType> friend class status_code;
template <class StatusCode, class Allocator> friend class detail::indirecting_domain;
using _base = status_code_domain;
public:
//! The value type of the `getaddrinfo()` code, which is an `int`
using value_type = int;
using _base::string_ref;
//! Default constructor
constexpr explicit _getaddrinfo_code_domain(typename _base::unique_id_type id = 0x5b24b2de470ff7b6) noexcept
: _base(id)
{
}
_getaddrinfo_code_domain(const _getaddrinfo_code_domain &) = default;
_getaddrinfo_code_domain(_getaddrinfo_code_domain &&) = default;
_getaddrinfo_code_domain &operator=(const _getaddrinfo_code_domain &) = default;
_getaddrinfo_code_domain &operator=(_getaddrinfo_code_domain &&) = default;
~_getaddrinfo_code_domain() = default;
//! Constexpr singleton getter. Returns constexpr getaddrinfo_code_domain variable.
static inline constexpr const _getaddrinfo_code_domain &get();
virtual string_ref name() const noexcept override { return string_ref("getaddrinfo() domain"); } // NOLINT
virtual payload_info_t payload_info() const noexcept override
{
return {sizeof(value_type), sizeof(status_code_domain *) + sizeof(value_type),
(alignof(value_type) > alignof(status_code_domain *)) ? alignof(value_type) : alignof(status_code_domain *)};
}
protected:
virtual bool _do_failure(const status_code<void> &code) const noexcept override // NOLINT
{
assert(code.domain() == *this); // NOLINT
return static_cast<const getaddrinfo_code &>(code).value() != 0; // NOLINT
}
virtual bool _do_equivalent(const status_code<void> &code1, const status_code<void> &code2) const noexcept override // NOLINT
{
assert(code1.domain() == *this); // NOLINT
const auto &c1 = static_cast<const getaddrinfo_code &>(code1); // NOLINT
if(code2.domain() == *this)
{
const auto &c2 = static_cast<const getaddrinfo_code &>(code2); // NOLINT
return c1.value() == c2.value();
}
return false;
}
virtual generic_code _generic_code(const status_code<void> &code) const noexcept override // NOLINT
{
assert(code.domain() == *this); // NOLINT
const auto &c = static_cast<const getaddrinfo_code &>(code); // NOLINT
switch(c.value())
{
#ifdef EAI_ADDRFAMILY
case EAI_ADDRFAMILY:
return errc::no_such_device_or_address;
#endif
case EAI_FAIL:
return errc::io_error;
case EAI_MEMORY:
return errc::not_enough_memory;
#ifdef EAI_NODATA
case EAI_NODATA:
return errc::no_such_device_or_address;
#endif
case EAI_NONAME:
return errc::no_such_device_or_address;
#ifdef EAI_OVERFLOW
case EAI_OVERFLOW:
return errc::argument_list_too_long;
#endif
case EAI_BADFLAGS: // fallthrough
case EAI_SERVICE:
return errc::invalid_argument;
case EAI_FAMILY: // fallthrough
case EAI_SOCKTYPE:
return errc::operation_not_supported;
case EAI_AGAIN: // fallthrough
case EAI_SYSTEM:
return errc::resource_unavailable_try_again;
default:
return errc::unknown;
}
}
virtual string_ref _do_message(const status_code<void> &code) const noexcept override // NOLINT
{
assert(code.domain() == *this); // NOLINT
const auto &c = static_cast<const getaddrinfo_code &>(code); // NOLINT
return string_ref(gai_strerror(c.value()));
}
#if defined(_CPPUNWIND) || defined(__EXCEPTIONS) || defined(BOOST_OUTCOME_STANDARDESE_IS_IN_THE_HOUSE)
BOOST_OUTCOME_SYSTEM_ERROR2_NORETURN virtual void _do_throw_exception(const status_code<void> &code) const override // NOLINT
{
assert(code.domain() == *this); // NOLINT
const auto &c = static_cast<const getaddrinfo_code &>(code); // NOLINT
throw status_error<_getaddrinfo_code_domain>(c);
}
#endif
};
//! A constexpr source variable for the `getaddrinfo()` code domain, which is that of `getaddrinfo()`. Returned by `_getaddrinfo_code_domain::get()`.
constexpr _getaddrinfo_code_domain getaddrinfo_code_domain;
inline constexpr const _getaddrinfo_code_domain &_getaddrinfo_code_domain::get()
{
return getaddrinfo_code_domain;
}
BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_END
#endif

View File

@@ -0,0 +1,340 @@
/* Proposed SG14 status_code
(C) 2022-2023 Niall Douglas <http://www.nedproductions.biz/> (5 commits)
File Created: Jun 2022
Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#ifndef BOOST_OUTCOME_SYSTEM_ERROR2_HTTP_STATUS_CODE_HPP
#define BOOST_OUTCOME_SYSTEM_ERROR2_HTTP_STATUS_CODE_HPP
#include "status_code.hpp"
BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_BEGIN
class _http_status_code_domain;
//! A HTTP status code.
using http_status_code = status_code<_http_status_code_domain>;
namespace mixins
{
template <class Base> struct mixin<Base, _http_status_code_domain> : public Base
{
using Base::Base;
//! True if the HTTP status code is informational
inline bool is_http_informational() const noexcept;
//! True if the HTTP status code is successful
inline bool is_http_success() const noexcept;
//! True if the HTTP status code is redirection
inline bool is_http_redirection() const noexcept;
//! True if the HTTP status code is client error
inline bool is_http_client_error() const noexcept;
//! True if the HTTP status code is server error
inline bool is_http_server_error() const noexcept;
};
} // namespace mixins
/*! The implementation of the domain for HTTP status codes.
*/
class _http_status_code_domain : public status_code_domain
{
template <class DomainType> friend class status_code;
template <class StatusCode, class Allocator> friend class detail::indirecting_domain;
using _base = status_code_domain;
public:
//! The value type of the HTTP code, which is an `int`
using value_type = int;
using _base::string_ref;
//! Default constructor
constexpr explicit _http_status_code_domain(typename _base::unique_id_type id = 0xbdb4cde88378a333ull) noexcept
: _base(id)
{
}
_http_status_code_domain(const _http_status_code_domain &) = default;
_http_status_code_domain(_http_status_code_domain &&) = default;
_http_status_code_domain &operator=(const _http_status_code_domain &) = default;
_http_status_code_domain &operator=(_http_status_code_domain &&) = default;
~_http_status_code_domain() = default;
//! Constexpr singleton getter. Returns constexpr http_status_code_domain variable.
static inline constexpr const _http_status_code_domain &get();
virtual string_ref name() const noexcept override { return string_ref("HTTP status domain"); } // NOLINT
virtual payload_info_t payload_info() const noexcept override
{
return {sizeof(value_type), sizeof(status_code_domain *) + sizeof(value_type),
(alignof(value_type) > alignof(status_code_domain *)) ? alignof(value_type) : alignof(status_code_domain *)};
}
protected:
virtual bool _do_failure(const status_code<void> &code) const noexcept override // NOLINT
{
assert(code.domain() == *this); // NOLINT
return static_cast<const http_status_code &>(code).value() >= 400; // NOLINT
}
virtual bool _do_equivalent(const status_code<void> &code1, const status_code<void> &code2) const noexcept override // NOLINT
{
assert(code1.domain() == *this); // NOLINT
const auto &c1 = static_cast<const http_status_code &>(code1); // NOLINT
if(code2.domain() == *this)
{
const auto &c2 = static_cast<const http_status_code &>(code2); // NOLINT
return c1.value() == c2.value();
}
return false;
}
virtual generic_code _generic_code(const status_code<void> &code) const noexcept override // NOLINT
{
assert(code.domain() == *this); // NOLINT
const auto &c = static_cast<const http_status_code &>(code); // NOLINT
switch(c.value())
{
case 102:
case 202:
return errc::operation_in_progress;
case 400:
return errc::invalid_argument;
case 401:
return errc::operation_not_permitted;
case 403:
return errc::permission_denied;
case 404:
case 410:
return errc::no_such_file_or_directory;
case 405:
case 418:
return errc::operation_not_supported;
case 406:
return errc::protocol_not_supported;
case 408:
return errc::timed_out;
case 413:
return errc::result_out_of_range;
case 501:
return errc::not_supported;
case 503:
return errc::resource_unavailable_try_again;
case 504:
return errc::timed_out;
case 507:
return errc::no_space_on_device;
default:
return errc::unknown;
}
}
virtual string_ref _do_message(const status_code<void> &code) const noexcept override // NOLINT
{
assert(code.domain() == *this); // NOLINT
const auto &c = static_cast<const http_status_code &>(code); // NOLINT
return string_ref(
[&]() -> const char *
{
switch(c.value())
{
case 100:
return "Continue";
case 101:
return "Switching Protocols";
case 102:
return "Processing";
case 103:
return "Early Hints";
case 200:
return "OK";
case 201:
return "Created";
case 202:
return "Accepted";
case 203:
return "Non-Authoritative Information";
case 204:
return "No Content";
case 205:
return "Reset Content";
case 206:
return "Partial Content";
case 207:
return "Multi-Status";
case 208:
return "Already Reported";
case 209:
return "IM Used";
case 300:
return "Multiple Choices";
case 301:
return "Moved Permanently";
case 302:
return "Found";
case 303:
return "See Other";
case 304:
return "Not Modified";
case 305:
return "Use Proxy";
case 306:
return "Switch Proxy";
case 307:
return "Temporary Redirect";
case 308:
return "Permanent Redirect";
case 400:
return "Bad Request";
case 401:
return "Unauthorized";
case 402:
return "Payment Required";
case 403:
return "Forbidden";
case 404:
return "Not Found";
case 405:
return "Method Not Allowed";
case 406:
return "Not Acceptable";
case 407:
return "Proxy Authentication Required";
case 408:
return "Request Timeout";
case 409:
return "Conflict";
case 410:
return "Gone";
case 411:
return "Length Required";
case 412:
return "Precondition Failed";
case 413:
return "Payload Too Large";
case 414:
return "URI Too Long";
case 415:
return "Unsupported Media Type";
case 416:
return "Range Not Satisfiable";
case 417:
return "Expectation Failed";
case 418:
return "I'm a teapot";
case 421:
return "Misdirected Request";
case 422:
return "Unprocessable Entity";
case 423:
return "Locked";
case 424:
return "Failed Dependency";
case 425:
return "Too Early";
case 426:
return "Upgrade Required";
case 428:
return "Precondition Required";
case 429:
return "Too Many Requests";
case 431:
return "Request Header Fields Too Large";
case 451:
return "Unavailable For Legal Reasons";
case 500:
return "Internal Server Error";
case 501:
return "Not Implemented";
case 502:
return "Bad Gateway";
case 503:
return "Service Unavailable";
case 504:
return "Gateway Timeout";
case 505:
return "HTTP Version Not Supported";
case 506:
return "Variant Also Negotiates";
case 507:
return "Insufficient Storage";
case 508:
return "Loop Detected";
case 510:
return "Not Extended";
case 511:
return "Network Authentication Required";
default:
return "Unknown";
}
}());
}
#if defined(_CPPUNWIND) || defined(__EXCEPTIONS) || defined(BOOST_OUTCOME_STANDARDESE_IS_IN_THE_HOUSE)
BOOST_OUTCOME_SYSTEM_ERROR2_NORETURN virtual void _do_throw_exception(const status_code<void> &code) const override // NOLINT
{
assert(code.domain() == *this); // NOLINT
const auto &c = static_cast<const http_status_code &>(code); // NOLINT
throw status_error<_http_status_code_domain>(c);
}
#endif
};
//! A constexpr source variable for the `getaddrinfo()` code domain, which is that of `getaddrinfo()`. Returned by `_http_status_code_domain::get()`.
constexpr _http_status_code_domain http_status_code_domain;
inline constexpr const _http_status_code_domain &_http_status_code_domain::get()
{
return http_status_code_domain;
}
namespace mixins
{
template <class Base> inline bool mixin<Base, _http_status_code_domain>::is_http_informational() const noexcept
{
const auto &c = static_cast<const http_status_code *>(this)->value();
return c >= 100 && c < 200;
}
template <class Base> inline bool mixin<Base, _http_status_code_domain>::is_http_success() const noexcept
{
const auto &c = static_cast<const http_status_code *>(this)->value();
return c >= 200 && c < 300;
}
template <class Base> inline bool mixin<Base, _http_status_code_domain>::is_http_redirection() const noexcept
{
const auto &c = static_cast<const http_status_code *>(this)->value();
return c >= 300 && c < 400;
}
template <class Base> inline bool mixin<Base, _http_status_code_domain>::is_http_client_error() const noexcept
{
const auto &c = static_cast<const http_status_code *>(this)->value();
return c >= 400 && c < 500;
}
template <class Base> inline bool mixin<Base, _http_status_code_domain>::is_http_server_error() const noexcept
{
const auto &c = static_cast<const http_status_code *>(this)->value();
return c >= 500 && c < 600;
}
} // namespace mixins
BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_END
#endif

View File

@@ -1,5 +1,5 @@
/* Proposed SG14 status_code
(C) 2018-2019 Niall Douglas <http://www.nedproductions.biz/> (5 commits)
(C) 2018-2023 Niall Douglas <http://www.nedproductions.biz/> (5 commits)
File Created: Feb 2018
@@ -33,15 +33,17 @@ DEALINGS IN THE SOFTWARE.
#include "error.hpp"
#include <iostream>
#include <ostream>
BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_BEGIN
/*! Print the status code to a `std::ostream &`.
Requires that `DomainType::value_type` implements an `operator<<` overload for `std::ostream`.
*/
template <class DomainType, //
typename std::enable_if<std::is_same<std::ostream, typename std::decay<decltype(std::declval<std::ostream>() << std::declval<typename status_code<DomainType>::value_type>())>::type>::value, bool>::type = true>
BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(class DomainType) //
BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(
std::is_same<std::ostream,
typename std::decay<decltype(std::declval<std::ostream>() << std::declval<typename status_code<DomainType>::value_type>())>::type>::value))
inline std::ostream &operator<<(std::ostream &s, const status_code<DomainType> &v)
{
if(v.empty())
@@ -51,26 +53,33 @@ inline std::ostream &operator<<(std::ostream &s, const status_code<DomainType> &
return s << v.domain().name().c_str() << ": " << v.value();
}
/*! Print a status code domain's `string_ref` to a `std::ostream &`.
*/
inline std::ostream &operator<<(std::ostream &s, const status_code_domain::string_ref &v)
{
return s << v.c_str();
}
/*! Print the erased status code to a `std::ostream &`.
*/
template <class ErasedType> inline std::ostream &operator<<(std::ostream &s, const status_code<erased<ErasedType>> &v)
*/
template <class ErasedType> inline std::ostream &operator<<(std::ostream &s, const status_code<detail::erased<ErasedType>> &v)
{
if(v.empty())
{
return s << "(empty)";
}
return s << v.domain().name().c_str() << ": " << v.message().c_str();
return s << v.domain().name() << ": " << v.message();
}
/*! Print the generic code to a `std::ostream &`.
*/
*/
inline std::ostream &operator<<(std::ostream &s, const generic_code &v)
{
if(v.empty())
{
return s << "(empty)";
}
return s << v.domain().name().c_str() << ": " << v.message().c_str();
return s << v.domain().name() << ": " << v.message();
}
BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_END

View File

@@ -0,0 +1,256 @@
/* Pointer to a SG14 status_code
(C) 2018 - 2023 Niall Douglas <http://www.nedproductions.biz/> (5 commits)
File Created: Sep 2018
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License in the accompanying file
Licence.txt or at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Distributed under the Boost Software License, Version 1.0.
(See accompanying file Licence.txt or copy at
http://www.boost.org/LICENSE_1_0.txt)
*/
#ifndef BOOST_OUTCOME_SYSTEM_ERROR2_NESTED_STATUS_CODE_HPP
#define BOOST_OUTCOME_SYSTEM_ERROR2_NESTED_STATUS_CODE_HPP
#include "quick_status_code_from_enum.hpp"
#include <memory> // for allocator
BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_BEGIN
namespace detail
{
template <class StatusCode, class Allocator> class indirecting_domain : public status_code_domain
{
template <class DomainType> friend class status_code;
using _base = status_code_domain;
public:
struct payload_type
{
using allocator_traits = std::allocator_traits<Allocator>;
union
{
char _uninit[sizeof(StatusCode)];
StatusCode sc;
};
Allocator alloc;
payload_type(StatusCode _sc, Allocator _alloc)
: alloc(static_cast<Allocator &&>(_alloc))
{
allocator_traits::construct(alloc, &sc, static_cast<StatusCode &&>(_sc));
}
payload_type(const payload_type &) = delete;
payload_type(payload_type &&) = delete;
~payload_type() { allocator_traits::destroy(alloc, &sc); }
};
using value_type = payload_type *;
using payload_allocator_traits = typename payload_type::allocator_traits::template rebind_traits<payload_type>;
using _base::string_ref;
constexpr indirecting_domain() noexcept
: _base(0xc44f7bdeb2cc50e9 ^ typename StatusCode::domain_type().id() /* unique-ish based on domain's unique id */)
{
}
indirecting_domain(const indirecting_domain &) = default;
indirecting_domain(indirecting_domain &&) = default; // NOLINT
indirecting_domain &operator=(const indirecting_domain &) = default;
indirecting_domain &operator=(indirecting_domain &&) = default; // NOLINT
~indirecting_domain() = default;
#if __cplusplus < 201402L && !defined(_MSC_VER)
static inline const indirecting_domain &get()
{
static indirecting_domain v;
return v;
}
#else
static inline constexpr const indirecting_domain &get();
#endif
virtual string_ref name() const noexcept override { return typename StatusCode::domain_type().name(); } // NOLINT
virtual payload_info_t payload_info() const noexcept override
{
return {sizeof(value_type), sizeof(status_code_domain *) + sizeof(value_type),
(alignof(value_type) > alignof(status_code_domain *)) ? alignof(value_type) : alignof(status_code_domain *)};
}
protected:
using _mycode = status_code<indirecting_domain>;
virtual bool _do_failure(const status_code<void> &code) const noexcept override // NOLINT
{
assert(code.domain() == *this);
const auto &c = static_cast<const _mycode &>(code); // NOLINT
return typename StatusCode::domain_type()._do_failure(c.value()->sc);
}
virtual bool _do_equivalent(const status_code<void> &code1, const status_code<void> &code2) const noexcept override // NOLINT
{
assert(code1.domain() == *this);
const auto &c1 = static_cast<const _mycode &>(code1); // NOLINT
return typename StatusCode::domain_type()._do_equivalent(c1.value()->sc, code2);
}
virtual generic_code _generic_code(const status_code<void> &code) const noexcept override // NOLINT
{
assert(code.domain() == *this);
const auto &c = static_cast<const _mycode &>(code); // NOLINT
return typename StatusCode::domain_type()._generic_code(c.value()->sc);
}
virtual string_ref _do_message(const status_code<void> &code) const noexcept override // NOLINT
{
assert(code.domain() == *this);
const auto &c = static_cast<const _mycode &>(code); // NOLINT
return typename StatusCode::domain_type()._do_message(c.value()->sc);
}
#if defined(_CPPUNWIND) || defined(__EXCEPTIONS) || defined(BOOST_OUTCOME_STANDARDESE_IS_IN_THE_HOUSE)
BOOST_OUTCOME_SYSTEM_ERROR2_NORETURN virtual void _do_throw_exception(const status_code<void> &code) const override // NOLINT
{
assert(code.domain() == *this);
const auto &c = static_cast<const _mycode &>(code); // NOLINT
typename StatusCode::domain_type()._do_throw_exception(c.value()->sc);
abort(); // suppress buggy GCC warning
}
#endif
virtual bool _do_erased_copy(status_code<void> &dst, const status_code<void> &src, payload_info_t dstinfo) const override // NOLINT
{
// Note that dst may not have its domain set
const auto srcinfo = payload_info();
assert(src.domain() == *this);
if(dstinfo.total_size < srcinfo.total_size)
{
return false;
}
auto &d = static_cast<_mycode &>(dst); // NOLINT
const auto &_s = static_cast<const _mycode &>(src); // NOLINT
const payload_type &sp = *_s.value();
typename payload_allocator_traits::template rebind_alloc<payload_type> payload_alloc(sp.alloc);
auto *dp = payload_allocator_traits::allocate(payload_alloc, 1);
#if defined(_CPPUNWIND) || defined(__EXCEPTIONS) || defined(BOOST_OUTCOME_STANDARDESE_IS_IN_THE_HOUSE)
try
#endif
{
payload_allocator_traits::construct(payload_alloc, dp, sp.sc, sp.alloc);
new(BOOST_OUTCOME_SYSTEM_ERROR2_ADDRESS_OF(d)) _mycode(in_place, dp);
}
#if defined(_CPPUNWIND) || defined(__EXCEPTIONS) || defined(BOOST_OUTCOME_STANDARDESE_IS_IN_THE_HOUSE)
catch(...)
{
payload_allocator_traits::deallocate(payload_alloc, dp, 1);
throw;
}
#endif
return true;
}
virtual void _do_erased_destroy(status_code<void> &code, payload_info_t /*unused*/) const noexcept override // NOLINT
{
assert(code.domain() == *this);
auto &c = static_cast<_mycode &>(code); // NOLINT
payload_type *p = c.value();
typename payload_allocator_traits::template rebind_alloc<payload_type> payload_alloc(p->alloc);
payload_allocator_traits::destroy(payload_alloc, p);
payload_allocator_traits::deallocate(payload_alloc, p, 1);
}
};
#if __cplusplus >= 201402L || defined(_MSC_VER)
template <class StatusCode, class Allocator> constexpr indirecting_domain<StatusCode, Allocator> _indirecting_domain{};
template <class StatusCode, class Allocator>
inline constexpr const indirecting_domain<StatusCode, Allocator> &indirecting_domain<StatusCode, Allocator>::get()
{
return _indirecting_domain<StatusCode, Allocator>;
}
#endif
} // namespace detail
/*! Make an erased status code which indirects to a dynamically allocated status code,
using the allocator `alloc`.
This is useful for shoehorning a rich status code with large value type into a small
erased status code like `system_code`, with which the status code generated by this
function is compatible. Note that this function can throw if the allocator throws.
*/
BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(class T, class Alloc = std::allocator<typename std::decay<T>::type>)
BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(is_status_code<T>::value)) //
inline status_code<detail::erased<typename std::add_pointer<typename std::decay<T>::type>::type>> make_nested_status_code(T &&v, Alloc alloc = {})
{
using status_code_type = typename std::decay<T>::type;
using domain_type = detail::indirecting_domain<status_code_type, typename std::decay<Alloc>::type>;
using payload_allocator_traits = typename domain_type::payload_allocator_traits;
typename payload_allocator_traits::template rebind_alloc<typename domain_type::payload_type> payload_alloc(alloc);
auto *p = payload_allocator_traits::allocate(payload_alloc, 1);
#if defined(_CPPUNWIND) || defined(__EXCEPTIONS) || defined(BOOST_OUTCOME_STANDARDESE_IS_IN_THE_HOUSE)
try
#endif
{
payload_allocator_traits::construct(payload_alloc, p, static_cast<T &&>(v), static_cast<Alloc &&>(alloc));
return status_code<domain_type>(in_place, p);
}
#if defined(_CPPUNWIND) || defined(__EXCEPTIONS) || defined(BOOST_OUTCOME_STANDARDESE_IS_IN_THE_HOUSE)
catch(...)
{
payload_allocator_traits::deallocate(payload_alloc, p, 1);
throw;
}
#endif
}
/*! If a status code refers to a `nested_status_code` which indirects to a status
code of type `StatusCode`, return a pointer to that `StatusCode`. Otherwise return null.
*/
BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(class StatusCode, class U)
BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(is_status_code<StatusCode>::value)) inline StatusCode *get_if(status_code<detail::erased<U>> *v) noexcept
{
if((0xc44f7bdeb2cc50e9 ^ typename StatusCode::domain_type().id()) != v->domain().id())
{
return nullptr;
}
union
{
U value;
StatusCode *ret;
};
value = v->value();
return ret;
}
//! \overload Const overload
BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(class StatusCode, class U)
BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(is_status_code<StatusCode>::value))
inline const StatusCode *get_if(const status_code<detail::erased<U>> *v) noexcept
{
if((0xc44f7bdeb2cc50e9 ^ typename StatusCode::domain_type().id()) != v->domain().id())
{
return nullptr;
}
union
{
U value;
const StatusCode *ret;
};
value = v->value();
return ret;
}
/*! If a status code refers to a `nested_status_code`, return the id of the erased
status code's domain. Otherwise return a meaningless number.
*/
template <class U> inline typename status_code_domain::unique_id_type get_id(const status_code<detail::erased<U>> &v) noexcept
{
return 0xc44f7bdeb2cc50e9 ^ v.domain().id();
}
BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_END
#endif

View File

@@ -1,5 +1,5 @@
/* Proposed SG14 status_code
(C) 2018-2019 Niall Douglas <http://www.nedproductions.biz/> (5 commits)
(C) 2018-2023 Niall Douglas <http://www.nedproductions.biz/> (5 commits)
File Created: Feb 2018
@@ -47,8 +47,18 @@ namespace win32
// A Win32 HMODULE
using HMODULE = void *;
// Used to retrieve where the NTDLL DLL is mapped into memory
extern "C" HMODULE __stdcall GetModuleHandleW(const wchar_t *lpModuleName);
}
extern HMODULE __stdcall GetModuleHandleW(const wchar_t *lpModuleName);
#pragma comment(lib, "kernel32.lib")
#if(defined(__x86_64__) || defined(_M_X64)) || (defined(__aarch64__) || defined(_M_ARM64))
#pragma comment(linker, "/alternatename:?GetModuleHandleW@win32@system_error2@@YAPEAXPEB_W@Z=GetModuleHandleW")
#elif defined(__x86__) || defined(_M_IX86) || defined(__i386__)
#pragma comment(linker, "/alternatename:?GetModuleHandleW@win32@system_error2@@YGPAXPB_W@Z=_GetModuleHandleW@4")
#elif defined(__arm__) || defined(_M_ARM)
#pragma comment(linker, "/alternatename:?GetModuleHandleW@win32@system_error2@@YAPAXPB_W@Z=GetModuleHandleW")
#else
#error Unknown architecture
#endif
} // namespace win32
class _nt_code_domain;
//! (Windows only) A NT error code, those returned by NT kernel functions.
@@ -57,11 +67,11 @@ using nt_code = status_code<_nt_code_domain>;
using nt_error = status_error<_nt_code_domain>;
/*! (Windows only) The implementation of the domain for NT error codes, those returned by NT kernel functions.
*/
*/
class _nt_code_domain : public status_code_domain
{
template <class DomainType> friend class status_code;
template <class StatusCode> friend class detail::indirecting_domain;
template <class StatusCode, class Allocator> friend class detail::indirecting_domain;
friend class _com_code_domain;
using _base = status_code_domain;
static int _nt_code_to_errno(win32::NTSTATUS c)
@@ -93,7 +103,9 @@ class _nt_code_domain : public status_code_domain
{
wchar_t buffer[32768];
static win32::HMODULE ntdll = win32::GetModuleHandleW(L"NTDLL.DLL");
win32::DWORD wlen = win32::FormatMessageW(0x00000800 /*FORMAT_MESSAGE_FROM_HMODULE*/ | 0x00001000 /*FORMAT_MESSAGE_FROM_SYSTEM*/ | 0x00000200 /*FORMAT_MESSAGE_IGNORE_INSERTS*/, ntdll, c, (1 << 10) /*MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT)*/, buffer, 32768, nullptr);
win32::DWORD wlen =
win32::FormatMessageW(0x00000800 /*FORMAT_MESSAGE_FROM_HMODULE*/ | 0x00001000 /*FORMAT_MESSAGE_FROM_SYSTEM*/ | 0x00000200 /*FORMAT_MESSAGE_IGNORE_INSERTS*/,
ntdll, c, (1 << 10) /*MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT)*/, buffer, 32768, nullptr);
size_t allocation = wlen + (wlen >> 1);
win32::DWORD bytes;
if(wlen == 0)
@@ -135,7 +147,10 @@ public:
public:
//! Default constructor
constexpr explicit _nt_code_domain(typename _base::unique_id_type id = 0x93f3b4487e4af25b) noexcept : _base(id) {}
constexpr explicit _nt_code_domain(typename _base::unique_id_type id = 0x93f3b4487e4af25b) noexcept
: _base(id)
{
}
_nt_code_domain(const _nt_code_domain &) = default;
_nt_code_domain(_nt_code_domain &&) = default;
_nt_code_domain &operator=(const _nt_code_domain &) = default;
@@ -146,6 +161,13 @@ public:
static inline constexpr const _nt_code_domain &get();
virtual string_ref name() const noexcept override { return string_ref("NT domain"); } // NOLINT
virtual payload_info_t payload_info() const noexcept override
{
return {sizeof(value_type), sizeof(status_code_domain *) + sizeof(value_type),
(alignof(value_type) > alignof(status_code_domain *)) ? alignof(value_type) : alignof(status_code_domain *)};
}
protected:
virtual bool _do_failure(const status_code<void> &code) const noexcept override // NOLINT
{

View File

@@ -1,5 +1,5 @@
/* Proposed SG14 status_code
(C) 2018-2019 Niall Douglas <http://www.nedproductions.biz/> (5 commits)
(C) 2018-2023 Niall Douglas <http://www.nedproductions.biz/> (5 commits)
File Created: Feb 2018
@@ -31,24 +31,57 @@ DEALINGS IN THE SOFTWARE.
#ifndef BOOST_OUTCOME_SYSTEM_ERROR2_POSIX_CODE_HPP
#define BOOST_OUTCOME_SYSTEM_ERROR2_POSIX_CODE_HPP
#include "generic_code.hpp"
#ifdef BOOST_OUTCOME_SYSTEM_ERROR2_NOT_POSIX
#error <posix_code.hpp> is not includable when BOOST_OUTCOME_SYSTEM_ERROR2_NOT_POSIX is defined!
#endif
#include "quick_status_code_from_enum.hpp"
#include <cstring> // for strchr and strerror_r
BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_BEGIN
// Fix for issue #48 Issue compiling on arm-none-eabi (newlib) with GNU extensions off
#ifdef __APPLE__
#include <cstring>
#elif !defined(_MSC_VER)
namespace detail
{
namespace avoid_string_include
{
#if defined(__GLIBC__) && !defined(__UCLIBC__)
// This returns int for non-glibc strerror_r, but glibc's is particularly weird so we retain it
extern "C" char *strerror_r(int errnum, char *buf, size_t buflen);
#else
extern "C" int strerror_r(int errnum, char *buf, size_t buflen);
#endif
} // namespace avoid_string_include
} // namespace detail
#endif
class _posix_code_domain;
//! A POSIX error code, those returned by `errno`.
using posix_code = status_code<_posix_code_domain>;
//! A specialisation of `status_error` for the POSIX error code domain.
using posix_error = status_error<_posix_code_domain>;
namespace mixins
{
template <class Base> struct mixin<Base, _posix_code_domain> : public Base
{
using Base::Base;
//! Returns a `posix_code` for the current value of `errno`.
static posix_code current() noexcept;
};
} // namespace mixins
/*! The implementation of the domain for POSIX error codes, those returned by `errno`.
*/
*/
class _posix_code_domain : public status_code_domain
{
template <class DomainType> friend class status_code;
template <class StatusCode> friend class detail::indirecting_domain;
template <class StatusCode, class Allocator> friend class detail::indirecting_domain;
using _base = status_code_domain;
static _base::string_ref _make_string_ref(int c) noexcept
@@ -56,17 +89,19 @@ class _posix_code_domain : public status_code_domain
char buffer[1024] = "";
#ifdef _WIN32
strerror_s(buffer, sizeof(buffer), c);
#elif defined(__linux__)
char *s = strerror_r(c, buffer, sizeof(buffer)); // NOLINT
#elif defined(__GLIBC__) && !defined(__UCLIBC__) // handle glibc's weird strerror_r()
char *s = detail::avoid_string_include::strerror_r(c, buffer, sizeof(buffer)); // NOLINT
if(s != nullptr)
{
strncpy(buffer, s, sizeof(buffer)); // NOLINT
strncpy(buffer, s, sizeof(buffer) - 1); // NOLINT
buffer[1023] = 0;
}
#elif !defined(__APPLE__)
detail::avoid_string_include::strerror_r(c, buffer, sizeof(buffer));
#else
strerror_r(c, buffer, sizeof(buffer));
#endif
size_t length = strlen(buffer); // NOLINT
size_t length = strlen(buffer); // NOLINT
auto *p = static_cast<char *>(malloc(length + 1)); // NOLINT
if(p == nullptr)
{
@@ -82,7 +117,10 @@ public:
using _base::string_ref;
//! Default constructor
constexpr explicit _posix_code_domain(typename _base::unique_id_type id = 0xa59a56fe5f310933) noexcept : _base(id) {}
constexpr explicit _posix_code_domain(typename _base::unique_id_type id = 0xa59a56fe5f310933) noexcept
: _base(id)
{
}
_posix_code_domain(const _posix_code_domain &) = default;
_posix_code_domain(_posix_code_domain &&) = default;
_posix_code_domain &operator=(const _posix_code_domain &) = default;
@@ -93,16 +131,23 @@ public:
static inline constexpr const _posix_code_domain &get();
virtual string_ref name() const noexcept override { return string_ref("posix domain"); } // NOLINT
protected:
virtual bool _do_failure(const status_code<void> &code) const noexcept override // NOLINT
virtual payload_info_t payload_info() const noexcept override
{
assert(code.domain() == *this); // NOLINT
return static_cast<const posix_code &>(code).value() != 0; // NOLINT
return {sizeof(value_type), sizeof(status_code_domain *) + sizeof(value_type),
(alignof(value_type) > alignof(status_code_domain *)) ? alignof(value_type) : alignof(status_code_domain *)};
}
protected:
virtual bool _do_failure(const status_code<void> &code) const noexcept override // NOLINT
{
assert(code.domain() == *this); // NOLINT
return static_cast<const posix_code &>(code).value() != 0; // NOLINT
}
virtual bool _do_equivalent(const status_code<void> &code1, const status_code<void> &code2) const noexcept override // NOLINT
{
assert(code1.domain() == *this); // NOLINT
const auto &c1 = static_cast<const posix_code &>(code1); // NOLINT
assert(code1.domain() == *this); // NOLINT
const auto &c1 = static_cast<const posix_code &>(code1); // NOLINT
if(code2.domain() == *this)
{
const auto &c2 = static_cast<const posix_code &>(code2); // NOLINT
@@ -120,21 +165,21 @@ protected:
}
virtual generic_code _generic_code(const status_code<void> &code) const noexcept override // NOLINT
{
assert(code.domain() == *this); // NOLINT
const auto &c = static_cast<const posix_code &>(code); // NOLINT
assert(code.domain() == *this); // NOLINT
const auto &c = static_cast<const posix_code &>(code); // NOLINT
return generic_code(static_cast<errc>(c.value()));
}
virtual string_ref _do_message(const status_code<void> &code) const noexcept override // NOLINT
{
assert(code.domain() == *this); // NOLINT
const auto &c = static_cast<const posix_code &>(code); // NOLINT
assert(code.domain() == *this); // NOLINT
const auto &c = static_cast<const posix_code &>(code); // NOLINT
return _make_string_ref(c.value());
}
#if defined(_CPPUNWIND) || defined(__EXCEPTIONS) || defined(BOOST_OUTCOME_STANDARDESE_IS_IN_THE_HOUSE)
BOOST_OUTCOME_SYSTEM_ERROR2_NORETURN virtual void _do_throw_exception(const status_code<void> &code) const override // NOLINT
{
assert(code.domain() == *this); // NOLINT
const auto &c = static_cast<const posix_code &>(code); // NOLINT
assert(code.domain() == *this); // NOLINT
const auto &c = static_cast<const posix_code &>(code); // NOLINT
throw status_error<_posix_code_domain>(c);
}
#endif
@@ -146,6 +191,14 @@ inline constexpr const _posix_code_domain &_posix_code_domain::get()
return posix_code_domain;
}
namespace mixins
{
template <class Base> inline posix_code mixin<Base, _posix_code_domain>::current() noexcept
{
return posix_code(errno);
}
} // namespace mixins
BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_END
#endif

View File

@@ -0,0 +1,217 @@
/* Proposed SG14 status_code
(C) 2018 - 2020 Niall Douglas <http://www.nedproductions.biz/> (5 commits)
File Created: May 2020
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License in the accompanying file
Licence.txt or at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Distributed under the Boost Software License, Version 1.0.
(See accompanying file Licence.txt or copy at
http://www.boost.org/LICENSE_1_0.txt)
*/
#ifndef BOOST_OUTCOME_SYSTEM_ERROR2_QUICK_STATUS_CODE_FROM_ENUM_HPP
#define BOOST_OUTCOME_SYSTEM_ERROR2_QUICK_STATUS_CODE_FROM_ENUM_HPP
#include "generic_code.hpp"
BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_BEGIN
template <class Enum> class _quick_status_code_from_enum_domain;
//! A status code wrapping `Enum` generated from `quick_status_code_from_enum`.
template <class Enum> using quick_status_code_from_enum_code = status_code<_quick_status_code_from_enum_domain<Enum>>;
//! Defaults for an implementation of `quick_status_code_from_enum<Enum>`
template <class Enum> struct quick_status_code_from_enum_defaults
{
//! The type of the resulting code
using code_type = quick_status_code_from_enum_code<Enum>;
//! Used within `quick_status_code_from_enum` to define a mapping of enumeration value with its status code
struct mapping
{
//! The enumeration type
using enumeration_type = Enum;
//! The value being mapped
const Enum value;
//! A string representation for this enumeration value
const char *message;
//! A list of `errc` equivalents for this enumeration value
const std::initializer_list<errc> code_mappings;
};
//! Used within `quick_status_code_from_enum` to define mixins for the status code wrapping `Enum`
template <class Base> struct mixin : Base
{
using Base::Base;
};
};
/*! The implementation of the domain for status codes wrapping `Enum` generated from `quick_status_code_from_enum`.
*/
template <class Enum> class _quick_status_code_from_enum_domain : public status_code_domain
{
template <class DomainType> friend class status_code;
template <class StatusCode, class Allocator> friend class detail::indirecting_domain;
using _base = status_code_domain;
using _src = quick_status_code_from_enum<Enum>;
public:
//! The value type of the quick status code from enum
using value_type = Enum;
using _base::string_ref;
constexpr _quick_status_code_from_enum_domain()
: status_code_domain(_src::domain_uuid, _uuid_size<detail::cstrlen(_src::domain_uuid)>())
{
}
_quick_status_code_from_enum_domain(const _quick_status_code_from_enum_domain &) = default;
_quick_status_code_from_enum_domain(_quick_status_code_from_enum_domain &&) = default;
_quick_status_code_from_enum_domain &operator=(const _quick_status_code_from_enum_domain &) = default;
_quick_status_code_from_enum_domain &operator=(_quick_status_code_from_enum_domain &&) = default;
~_quick_status_code_from_enum_domain() = default;
#if __cplusplus < 201402L && !defined(_MSC_VER)
static inline const _quick_status_code_from_enum_domain &get()
{
static _quick_status_code_from_enum_domain v;
return v;
}
#else
static inline constexpr const _quick_status_code_from_enum_domain &get();
#endif
virtual string_ref name() const noexcept override { return string_ref(_src::domain_name); }
virtual payload_info_t payload_info() const noexcept override
{
return {sizeof(value_type), sizeof(status_code_domain *) + sizeof(value_type),
(alignof(value_type) > alignof(status_code_domain *)) ? alignof(value_type) : alignof(status_code_domain *)};
}
protected:
// Not sure if a hash table is worth it here, most enumerations won't be long enough to be worth it
// Also, until C++ 20's consteval, the hash table would get emitted into the binary, bloating it
static BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR14 const typename _src::mapping *_find_mapping(value_type v) noexcept
{
for(const auto &i : _src::value_mappings())
{
if(i.value == v)
{
return &i;
}
}
return nullptr;
}
virtual bool _do_failure(const status_code<void> &code) const noexcept override
{
assert(code.domain() == *this); // NOLINT
// If `errc::success` is in the generic code mapping, it is not a failure
const auto *mapping = _find_mapping(static_cast<const quick_status_code_from_enum_code<value_type> &>(code).value());
assert(mapping != nullptr);
if(mapping != nullptr)
{
for(errc ec : mapping->code_mappings)
{
if(ec == errc::success)
{
return false;
}
}
}
return true;
}
virtual bool _do_equivalent(const status_code<void> &code1, const status_code<void> &code2) const noexcept override
{
assert(code1.domain() == *this); // NOLINT
const auto &c1 = static_cast<const quick_status_code_from_enum_code<value_type> &>(code1); // NOLINT
if(code2.domain() == *this)
{
const auto &c2 = static_cast<const quick_status_code_from_enum_code<value_type> &>(code2); // NOLINT
return c1.value() == c2.value();
}
if(code2.domain() == generic_code_domain)
{
const auto &c2 = static_cast<const generic_code &>(code2); // NOLINT
const auto *mapping = _find_mapping(c1.value());
assert(mapping != nullptr);
if(mapping != nullptr)
{
for(errc ec : mapping->code_mappings)
{
if(ec == c2.value())
{
return true;
}
}
}
}
return false;
}
virtual generic_code _generic_code(const status_code<void> &code) const noexcept override
{
assert(code.domain() == *this); // NOLINT
const auto *mapping = _find_mapping(static_cast<const quick_status_code_from_enum_code<value_type> &>(code).value());
assert(mapping != nullptr);
if(mapping != nullptr)
{
if(mapping->code_mappings.size() > 0)
{
return *mapping->code_mappings.begin();
}
}
return errc::unknown;
}
virtual string_ref _do_message(const status_code<void> &code) const noexcept override
{
assert(code.domain() == *this); // NOLINT
const auto *mapping = _find_mapping(static_cast<const quick_status_code_from_enum_code<value_type> &>(code).value());
assert(mapping != nullptr);
if(mapping != nullptr)
{
return string_ref(mapping->message);
}
return string_ref("unknown");
}
#if defined(_CPPUNWIND) || defined(__EXCEPTIONS) || defined(BOOST_OUTCOME_STANDARDESE_IS_IN_THE_HOUSE)
BOOST_OUTCOME_SYSTEM_ERROR2_NORETURN virtual void _do_throw_exception(const status_code<void> &code) const override
{
assert(code.domain() == *this); // NOLINT
const auto &c = static_cast<const quick_status_code_from_enum_code<value_type> &>(code); // NOLINT
throw status_error<_quick_status_code_from_enum_domain>(c);
}
#endif
};
#if __cplusplus >= 201402L || defined(_MSC_VER)
template <class Enum> constexpr _quick_status_code_from_enum_domain<Enum> quick_status_code_from_enum_domain = {};
template <class Enum> inline constexpr const _quick_status_code_from_enum_domain<Enum> &_quick_status_code_from_enum_domain<Enum>::get()
{
return quick_status_code_from_enum_domain<Enum>;
}
#endif
namespace mixins
{
template <class Base, class Enum>
struct mixin<Base, _quick_status_code_from_enum_domain<Enum>> : public quick_status_code_from_enum<Enum>::template mixin<Base>
{
using quick_status_code_from_enum<Enum>::template mixin<Base>::mixin;
};
} // namespace mixins
BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_END
#endif

View File

@@ -0,0 +1,402 @@
/* A partial result based on std::variant and proposed std::error
(C) 2020-2023 Niall Douglas <http://www.nedproductions.biz/> (11 commits)
File Created: Jan 2020
Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#ifndef BOOST_OUTCOME_SYSTEM_ERROR2_RESULT_HPP
#define BOOST_OUTCOME_SYSTEM_ERROR2_RESULT_HPP
#include "error.hpp"
#if __cplusplus >= 201703L || _HAS_CXX17
#if __has_include(<variant>)
#include <exception>
#include <variant>
BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_BEGIN
template <class T> inline constexpr std::in_place_type_t<T> in_place_type{};
template <class T> class result;
//! \brief A trait for detecting result types
template <class T> struct is_result : public std::false_type
{
};
template <class T> struct is_result<result<T>> : public std::true_type
{
};
/*! \brief Exception type representing the failure to retrieve an error.
*/
class bad_result_access : public std::exception
{
public:
bad_result_access() = default;
//! Return an explanatory string
virtual const char *what() const noexcept override { return "bad result access"; } // NOLINT
};
namespace detail
{
struct void_
{
};
template <class T> using devoid = std::conditional_t<std::is_void_v<T>, void_, T>;
} // namespace detail
/*! \class result
\brief A imperfect `result<T>` type with its error type hardcoded to `error`, only available on C++ 17 or later.
Note that the proper `result<T>` type does not have the possibility of
valueless by exception state. This implementation is therefore imperfect.
*/
template <class T> class result : protected std::variant<BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::error, detail::devoid<T>>
{
using _base = std::variant<BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::error, detail::devoid<T>>;
static_assert(!std::is_reference_v<T>, "Type cannot be a reference");
static_assert(!std::is_array_v<T>, "Type cannot be an array");
static_assert(!std::is_same_v<T, BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::error>, "Type cannot be a std::error");
// not success nor failure types
struct _implicit_converting_constructor_tag
{
};
struct _explicit_converting_constructor_tag
{
};
struct _implicit_constructor_tag
{
};
struct _implicit_in_place_value_constructor_tag
{
};
struct _implicit_in_place_error_constructor_tag
{
};
public:
//! The value type
using value_type = T;
//! The error type
using error_type = BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::error;
//! The value type, if it is available, else a usefully named unusable internal type
using value_type_if_enabled = detail::devoid<T>;
//! Used to rebind result types
template <class U> using rebind = result<U>;
protected:
constexpr void _check() const
{
if(_base::index() == 0)
{
std::get_if<0>(this)->throw_exception();
}
}
constexpr
#ifdef _MSC_VER
__declspec(noreturn)
#elif defined(__GNUC__) || defined(__clang__)
__attribute__((noreturn))
#endif
void _ub()
{
assert(false); // NOLINT
#if defined(__GNUC__) || defined(__clang__)
__builtin_unreachable();
#elif defined(_MSC_VER)
__assume(0);
#endif
}
public:
constexpr _base &_internal() noexcept { return *this; }
constexpr const _base &_internal() const noexcept { return *this; }
//! Default constructor is disabled
result() = delete;
//! Copy constructor
result(const result &) = delete;
//! Move constructor
result(result &&) = default;
//! Copy assignment
result &operator=(const result &) = delete;
//! Move assignment
result &operator=(result &&) = default;
//! Destructor
~result() = default;
//! Implicit result converting move constructor
BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(class U)
BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(std::is_convertible_v<U, T>)) constexpr result(result<U> &&o, _implicit_converting_constructor_tag = {}) noexcept(std::is_nothrow_constructible_v<T, U>)
: _base(std::move(o))
{
}
//! Implicit result converting copy constructor
BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(class U)
BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(std::is_convertible_v<U, T>)) constexpr result(const result<U> &o, _implicit_converting_constructor_tag = {}) noexcept(std::is_nothrow_constructible_v<T, U>)
: _base(o)
{
}
//! Explicit result converting move constructor
BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(class U)
BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(std::is_constructible_v<T, U>)) constexpr explicit result(result<U> &&o, _explicit_converting_constructor_tag = {}) noexcept(std::is_nothrow_constructible_v<T, U>)
: _base(std::move(o))
{
}
//! Explicit result converting copy constructor
BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(class U)
BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(std::is_constructible_v<T, U>)) constexpr explicit result(const result<U> &o, _explicit_converting_constructor_tag = {}) noexcept(std::is_nothrow_constructible_v<T, U>)
: _base(o)
{
}
//! Anything which `std::variant<error, T>` will construct from, we shall implicitly construct from
using _base::_base;
//! Special case `in_place_type_t<void>`
constexpr explicit result(std::in_place_type_t<void> /*unused*/) noexcept
: _base(in_place_type<detail::void_>)
{
}
//! Implicit in-place converting error constructor
BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(class Arg1, class Arg2, class... Args, long = 5) //
BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(!(std::is_constructible_v<value_type, Arg1, Arg2, Args...> && std::is_constructible_v<error_type, Arg1, Arg2, Args...>) //
&&std::is_constructible_v<error_type, Arg1, Arg2, Args...>))
constexpr result(Arg1 &&arg1, Arg2 &&arg2, Args &&...args) noexcept(std::is_nothrow_constructible_v<error_type, Arg1, Arg2, Args...>)
: _base(std::in_place_index<0>, std::forward<Arg1>(arg1), std::forward<Arg2>(arg2), std::forward<Args>(args)...)
{
}
//! Implicit in-place converting value constructor
BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(class Arg1, class Arg2, class... Args, int = 5) //
BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(!(std::is_constructible_v<value_type, Arg1, Arg2, Args...> && std::is_constructible_v<error_type, Arg1, Arg2, Args...>) //
&&std::is_constructible_v<value_type, Arg1, Arg2, Args...>))
constexpr result(Arg1 &&arg1, Arg2 &&arg2, Args &&...args) noexcept(std::is_nothrow_constructible_v<value_type, Arg1, Arg2, Args...>)
: _base(std::in_place_index<1>, std::forward<Arg1>(arg1), std::forward<Arg2>(arg2), std::forward<Args>(args)...)
{
}
//! Implicit construction from any type where an ADL discovered `make_status_code(T, Args ...)` returns a `status_code`.
BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(class U, class... Args, //
class MakeStatusCodeResult = typename detail::safe_get_make_status_code_result<U, Args...>::type) // Safe ADL lookup of make_status_code(), returns void if not found
BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(!std::is_same<typename std::decay<U>::type, result>::value // not copy/move of self
&& !std::is_same<typename std::decay<U>::type, value_type>::value // not copy/move of value type
&& is_status_code<MakeStatusCodeResult>::value // ADL makes a status code
&& std::is_constructible<error_type, MakeStatusCodeResult>::value)) // ADLed status code is compatible
constexpr result(U &&v, Args &&...args) noexcept(noexcept(make_status_code(std::declval<U>(), std::declval<Args>()...))) // NOLINT
: _base(std::in_place_index<0>, make_status_code(static_cast<U &&>(v), static_cast<Args &&>(args)...))
{
}
//! Swap with another result
constexpr void swap(result &o) noexcept(std::is_nothrow_swappable_v<_base>) { _base::swap(o); }
//! Clone the result
constexpr result clone() const { return has_value() ? result(value()) : result(error().clone()); }
//! True if result has a value
constexpr bool has_value() const noexcept { return _base::index() == 1; }
//! True if result has a value
explicit operator bool() const noexcept { return has_value(); }
//! True if result has an error
constexpr bool has_error() const noexcept { return _base::index() == 0; }
//! Accesses the value if one exists, else calls `.error().throw_exception()`.
constexpr value_type_if_enabled &value() &
{
_check();
return std::get<1>(*this);
}
//! Accesses the value if one exists, else calls `.error().throw_exception()`.
constexpr const value_type_if_enabled &value() const &
{
_check();
return std::get<1>(*this);
}
//! Accesses the value if one exists, else calls `.error().throw_exception()`.
constexpr value_type_if_enabled &&value() &&
{
_check();
return std::get<1>(std::move(*this));
}
//! Accesses the value if one exists, else calls `.error().throw_exception()`.
constexpr const value_type_if_enabled &&value() const &&
{
_check();
return std::get<1>(std::move(*this));
}
//! Accesses the error if one exists, else throws `bad_result_access`.
constexpr error_type &error() &
{
if(!has_error())
{
#ifndef BOOST_NO_EXCEPTIONS
throw bad_result_access();
#else
abort();
#endif
}
return *std::get_if<0>(this);
}
//! Accesses the error if one exists, else throws `bad_result_access`.
constexpr const error_type &error() const &
{
if(!has_error())
{
#ifndef BOOST_NO_EXCEPTIONS
throw bad_result_access();
#else
abort();
#endif
}
return *std::get_if<0>(this);
}
//! Accesses the error if one exists, else throws `bad_result_access`.
constexpr error_type &&error() &&
{
if(!has_error())
{
#ifndef BOOST_NO_EXCEPTIONS
throw bad_result_access();
#else
abort();
#endif
}
return std::move(*std::get_if<0>(this));
}
//! Accesses the error if one exists, else throws `bad_result_access`.
constexpr const error_type &&error() const &&
{
if(!has_error())
{
#ifndef BOOST_NO_EXCEPTIONS
throw bad_result_access();
#else
abort();
#endif
}
return std::move(*std::get_if<0>(this));
}
//! Accesses the value, being UB if none exists
constexpr value_type_if_enabled &assume_value() &noexcept
{
if(!has_value())
{
_ub();
}
return *std::get_if<1>(this);
}
//! Accesses the error, being UB if none exists
constexpr const value_type_if_enabled &assume_value() const &noexcept
{
if(!has_value())
{
_ub();
}
return *std::get_if<1>(this);
}
//! Accesses the error, being UB if none exists
constexpr value_type_if_enabled &&assume_value() &&noexcept
{
if(!has_value())
{
_ub();
}
return std::move(*std::get_if<1>(this));
}
//! Accesses the error, being UB if none exists
constexpr const value_type_if_enabled &&assume_value() const &&noexcept
{
if(!has_value())
{
_ub();
}
return std::move(*std::get_if<1>(this));
}
//! Accesses the error, being UB if none exists
constexpr error_type &assume_error() &noexcept
{
if(!has_error())
{
_ub();
}
return *std::get_if<0>(this);
}
//! Accesses the error, being UB if none exists
constexpr const error_type &assume_error() const &noexcept
{
if(!has_error())
{
_ub();
}
return *std::get_if<0>(this);
}
//! Accesses the error, being UB if none exists
constexpr error_type &&assume_error() &&noexcept
{
if(!has_error())
{
_ub();
}
return std::move(*std::get_if<0>(this));
}
//! Accesses the error, being UB if none exists
constexpr const error_type &&assume_error() const &&noexcept
{
if(!has_error())
{
_ub();
}
return std::move(*std::get_if<0>(this));
}
};
//! True if the two results compare equal.
template <class T, class U, typename = decltype(std::declval<T>() == std::declval<U>())> constexpr inline bool operator==(const result<T> &a, const result<U> &b) noexcept
{
const auto &x = a._internal();
return x == b;
}
//! True if the two results compare unequal.
template <class T, class U, typename = decltype(std::declval<T>() != std::declval<U>())> constexpr inline bool operator!=(const result<T> &a, const result<U> &b) noexcept
{
const auto &x = a._internal();
return x != b;
}
BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_END
#endif
#endif
#endif

View File

@@ -0,0 +1,718 @@
/* Proposed SG14 status_code
(C) 2018 - 2023 Niall Douglas <http://www.nedproductions.biz/> (5 commits)
File Created: Feb 2018
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License in the accompanying file
Licence.txt or at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Distributed under the Boost Software License, Version 1.0.
(See accompanying file Licence.txt or copy at
http://www.boost.org/LICENSE_1_0.txt)
*/
#ifndef BOOST_OUTCOME_SYSTEM_ERROR2_STATUS_CODE_HPP
#define BOOST_OUTCOME_SYSTEM_ERROR2_STATUS_CODE_HPP
#include "status_code_domain.hpp"
#if(__cplusplus >= 201700 || _HAS_CXX17) && !defined(BOOST_OUTCOME_SYSTEM_ERROR2_DISABLE_STD_IN_PLACE)
// 0.26
#include <utility> // for in_place
BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_BEGIN
using in_place_t = std::in_place_t;
using std::in_place;
BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_END
#else
BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_BEGIN
//! Aliases `std::in_place_t` if on C++ 17 or later, else defined locally.
struct in_place_t
{
explicit in_place_t() = default;
};
//! Aliases `std::in_place` if on C++ 17 or later, else defined locally.
constexpr in_place_t in_place{};
BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_END
#endif
BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_BEGIN
//! Namespace for user injected mixins
namespace mixins
{
template <class Base, class T> struct mixin : public Base
{
using Base::Base;
};
} // namespace mixins
namespace detail
{
BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(class ErasedType) //
BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(traits::is_move_bitcopying<ErasedType>::value))
struct erased
{
using value_type = ErasedType;
};
} // namespace detail
/*! The tag type used to specialise erased editions of `status_code<D>`.
Available only if `ErasedType` satisfies `traits::is_move_bitcopying<ErasedType>::value`.
*/
template <class ErasedType> //
using status_code_erased_tag_type = detail::erased<ErasedType>;
/*! Specialise this template to quickly wrap a third party enumeration into a
custom status code domain.
Use like this:
```c++
BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_BEGIN
template <> struct quick_status_code_from_enum<AnotherCode> : quick_status_code_from_enum_defaults<AnotherCode>
{
// Text name of the enum
static constexpr const auto domain_name = "Another Code";
// Unique UUID for the enum. PLEASE use https://www.random.org/cgi-bin/randbyte?nbytes=16&format=h
static constexpr const auto domain_uuid = "{be201f65-3962-dd0e-1266-a72e63776a42}";
// Map of each enum value to its text string, and list of semantically equivalent errc's
static const std::initializer_list<mapping> &value_mappings()
{
static const std::initializer_list<mapping<AnotherCode>> v = {
// Format is: { enum value, "string representation", { list of errc mappings ... } }
{AnotherCode::success1, "Success 1", {errc::success}}, //
{AnotherCode::goaway, "Go away", {errc::permission_denied}}, //
{AnotherCode::success2, "Success 2", {errc::success}}, //
{AnotherCode::error2, "Error 2", {}}, //
};
return v;
}
// Completely optional definition of mixin for the status code synthesised from `Enum`. It can be omitted.
template <class Base> struct mixin : Base
{
using Base::Base;
constexpr int custom_method() const { return 42; }
};
};
BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_END
```
Note that if the `errc` mapping contains `errc::success`, then
the enumeration value is considered to be a successful value.
Otherwise it is considered to be a failure value.
The first value in the `errc` mapping is the one chosen as the
`generic_code` conversion. Other values are used during equivalence
comparisons.
*/
template <class Enum> struct quick_status_code_from_enum;
namespace detail
{
template <class T> struct is_status_code
{
static constexpr bool value = false;
};
template <class T> struct is_status_code<status_code<T>>
{
static constexpr bool value = true;
};
template <class T> struct is_erased_status_code
{
static constexpr bool value = false;
};
template <class T> struct is_erased_status_code<status_code<detail::erased<T>>>
{
static constexpr bool value = true;
};
#if !defined(__GNUC__) || defined(__clang__) || __GNUC__ >= 8
// From http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4436.pdf
namespace impl
{
template <typename... Ts> struct make_void
{
using type = void;
};
template <typename... Ts> using void_t = typename make_void<Ts...>::type;
template <class...> struct types
{
using type = types;
};
template <template <class...> class T, class types, class = void> struct test_apply
{
using type = void;
};
template <template <class...> class T, class... Ts> struct test_apply<T, types<Ts...>, void_t<T<Ts...>>>
{
using type = T<Ts...>;
};
} // namespace impl
template <template <class...> class T, class... Ts> using test_apply = impl::test_apply<T, impl::types<Ts...>>;
template <class T, class... Args> using get_make_status_code_result = decltype(make_status_code(std::declval<T>(), std::declval<Args>()...));
template <class... Args> using safe_get_make_status_code_result = test_apply<get_make_status_code_result, Args...>;
#else
// ICE avoidance form for GCCs before 8. Note this form doesn't prevent recursive make_status_code ADL instantation,
// so in certain corner cases this will break. On the other hand, more useful than an ICE.
namespace impl
{
template <typename... Ts> struct make_void
{
using type = void;
};
template <typename... Ts> using void_t = typename make_void<Ts...>::type;
template <class...> struct types
{
using type = types;
};
template <typename Types, typename = void> struct make_status_code_rettype
{
using type = void;
};
template <typename... Args> using get_make_status_code_result = decltype(make_status_code(std::declval<Args>()...));
template <typename... Args> struct make_status_code_rettype<types<Args...>, void_t<get_make_status_code_result<Args...>>>
{
using type = get_make_status_code_result<Args...>;
};
} // namespace impl
template <class... Args> struct safe_get_make_status_code_result
{
using type = typename impl::make_status_code_rettype<impl::types<Args...>>::type;
};
#endif
} // namespace detail
//! Trait returning true if the type is a status code.
template <class T> struct is_status_code
{
static constexpr bool value =
detail::is_status_code<typename std::decay<T>::type>::value || detail::is_erased_status_code<typename std::decay<T>::type>::value;
};
/*! A type erased lightweight status code reflecting empty, success, or failure.
Differs from `status_code<erased<>>` by being always available irrespective of
the domain's value type, but cannot be copied, moved, nor destructed. Thus one
always passes this around by const lvalue reference.
*/
template <> class BOOST_OUTCOME_SYSTEM_ERROR2_TRIVIAL_ABI status_code<void>
{
template <class T> friend class status_code;
public:
//! The type of the domain.
using domain_type = void;
//! The type of the status code.
using value_type = void;
//! The type of a reference to a message string.
using string_ref = typename status_code_domain::string_ref;
protected:
const status_code_domain *_domain{nullptr};
protected:
//! No default construction at type erased level
status_code() = default;
//! No public copying at type erased level
status_code(const status_code &) = default;
//! No public moving at type erased level
status_code(status_code &&) = default;
//! No public assignment at type erased level
status_code &operator=(const status_code &) = default;
//! No public assignment at type erased level
status_code &operator=(status_code &&) = default;
//! No public destruction at type erased level
~status_code() = default;
//! Used to construct a non-empty type erased status code
constexpr explicit status_code(const status_code_domain *v) noexcept
: _domain(v)
{
}
// Used to work around triggering a ubsan failure. Do NOT remove!
constexpr const status_code_domain *_domain_ptr() const noexcept { return _domain; }
public:
//! Return the status code domain.
constexpr const status_code_domain &domain() const noexcept { return *_domain; }
//! True if the status code is empty.
BOOST_OUTCOME_SYSTEM_ERROR2_NODISCARD constexpr bool empty() const noexcept { return _domain == nullptr; }
//! Return a reference to a string textually representing a code.
BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR20 string_ref message() const noexcept
{
// Avoid MSVC's buggy ternary operator for expensive to destruct things
if(_domain != nullptr)
{
return _domain->_do_message(*this);
}
return string_ref("(empty)");
}
//! True if code means success.
BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR20 bool success() const noexcept { return (_domain != nullptr) ? !_domain->_do_failure(*this) : false; }
//! True if code means failure.
BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR20 bool failure() const noexcept { return (_domain != nullptr) ? _domain->_do_failure(*this) : false; }
/*! True if code is strictly (and potentially non-transitively) semantically equivalent to another code in another domain.
Note that usually non-semantic i.e. pure value comparison is used when the other status code has the same domain.
As `equivalent()` will try mapping to generic code, this usually captures when two codes have the same semantic
meaning in `equivalent()`.
*/
template <class T> BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR14 bool strictly_equivalent(const status_code<T> &o) const noexcept
{
if(_domain && o._domain)
{
return _domain->_do_equivalent(*this, o);
}
// If we are both empty, we are equivalent
if(!_domain && !o._domain)
{
return true; // NOLINT
}
// Otherwise not equivalent
return false;
}
/*! True if code is equivalent, by any means, to another code in another domain (guaranteed transitive).
Firstly `strictly_equivalent()` is run in both directions. If neither succeeds, each domain is asked
for the equivalent generic code and those are compared.
*/
template <class T> BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR14 inline bool equivalent(const status_code<T> &o) const noexcept;
#if defined(_CPPUNWIND) || defined(__EXCEPTIONS) || defined(BOOST_OUTCOME_STANDARDESE_IS_IN_THE_HOUSE)
//! Throw a code as a C++ exception.
BOOST_OUTCOME_SYSTEM_ERROR2_NORETURN void throw_exception() const
{
_domain->_do_throw_exception(*this);
abort(); // suppress buggy GCC warning
}
#endif
};
namespace detail
{
template <class DomainType> struct get_domain_value_type
{
using domain_type = DomainType;
using value_type = typename domain_type::value_type;
};
template <class ErasedType> struct get_domain_value_type<erased<ErasedType>>
{
using domain_type = status_code_domain;
using value_type = ErasedType;
};
template <class DomainType> class BOOST_OUTCOME_SYSTEM_ERROR2_TRIVIAL_ABI status_code_storage : public status_code<void>
{
static_assert(!std::is_void<DomainType>::value, "status_code_storage<void> should never occur!");
using _base = status_code<void>;
public:
//! The type of the domain.
using domain_type = typename get_domain_value_type<DomainType>::domain_type;
//! The type of the status code.
using value_type = typename get_domain_value_type<DomainType>::value_type;
//! The type of a reference to a message string.
using string_ref = typename domain_type::string_ref;
#ifndef NDEBUG
static_assert(std::is_move_constructible<value_type>::value || std::is_copy_constructible<value_type>::value,
"DomainType::value_type is neither move nor copy constructible!");
static_assert(!std::is_default_constructible<value_type>::value || std::is_nothrow_default_constructible<value_type>::value,
"DomainType::value_type is not nothrow default constructible!");
static_assert(!std::is_move_constructible<value_type>::value || std::is_nothrow_move_constructible<value_type>::value,
"DomainType::value_type is not nothrow move constructible!");
static_assert(std::is_nothrow_destructible<value_type>::value, "DomainType::value_type is not nothrow destructible!");
#endif
// Replace the type erased implementations with type aware implementations for better codegen
//! Return the status code domain.
constexpr const domain_type &domain() const noexcept { return *static_cast<const domain_type *>(this->_domain); }
//! Reset the code to empty.
BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR14 void clear() noexcept
{
this->_value.~value_type();
this->_domain = nullptr;
new(std::addressof(this->_value)) value_type();
}
#if __cplusplus >= 201400 || _MSC_VER >= 1910 /* VS2017 */
//! Return a reference to the `value_type`.
constexpr value_type &value() & noexcept { return this->_value; }
//! Return a reference to the `value_type`.
constexpr value_type &&value() && noexcept { return static_cast<value_type &&>(this->_value); }
#endif
//! Return a reference to the `value_type`.
constexpr const value_type &value() const & noexcept { return this->_value; }
//! Return a reference to the `value_type`.
constexpr const value_type &&value() const && noexcept { return static_cast<const value_type &&>(this->_value); }
protected:
status_code_storage() = default;
status_code_storage(const status_code_storage &) = default;
BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR14 status_code_storage(status_code_storage &&o) noexcept
: _base(static_cast<status_code_storage &&>(o))
, _value(static_cast<status_code_storage &&>(o)._value)
{
o._domain = nullptr;
}
status_code_storage &operator=(const status_code_storage &) = default;
BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR14 status_code_storage &operator=(status_code_storage &&o) noexcept
{
this->~status_code_storage();
new(this) status_code_storage(static_cast<status_code_storage &&>(o));
return *this;
}
~status_code_storage() = default;
value_type _value{};
struct _value_type_constructor
{
};
template <class... Args>
constexpr status_code_storage(_value_type_constructor /*unused*/, const status_code_domain *v, Args &&...args)
: _base(v)
, _value(static_cast<Args &&>(args)...)
{
}
};
template <class DomainType> struct has_stateful_mixin
{
static constexpr bool value = (sizeof(status_code_storage<DomainType>) != sizeof(mixins::mixin<status_code_storage<DomainType>, DomainType>));
};
template <class ToDomain, class FromDomain> struct domain_value_type_erasure_is_safe
{
using to_value_type = typename get_domain_value_type<ToDomain>::value_type;
using from_value_type = typename get_domain_value_type<FromDomain>::value_type;
static constexpr bool value = traits::is_move_bitcopying<to_value_type>::value //
&& traits::is_move_bitcopying<from_value_type>::value //
&& sizeof(status_code_storage<FromDomain>) <= sizeof(status_code_storage<ToDomain>) //
&& !has_stateful_mixin<FromDomain>::value;
};
template <class ToDomain> struct domain_value_type_erasure_is_safe<ToDomain, void>
{
static constexpr bool value = false;
};
} // namespace detail
namespace traits
{
//! Determines whether the mixin contained in `StatusCode` contains non-static member variables.
template <class StatusCode> using has_stateful_mixin = detail::has_stateful_mixin<typename detail::remove_cvref<StatusCode>::type::value_type>;
//! Determines whether the status code `From` can be type erased into the status code `To`.
template <class To, class From>
using is_type_erasable_to =
detail::domain_value_type_erasure_is_safe<typename detail::remove_cvref<To>::type::domain_type, typename detail::remove_cvref<From>::type::domain_type>;
} // namespace traits
/*! A lightweight, typed, status code reflecting empty, success, or failure.
This is the main workhorse of the system_error2 library. Its characteristics reflect the value type
set by its domain type, so if that value type is move-only or trivial, so is this.
An ADL discovered helper function `make_status_code(T, Args...)` is looked up by one of the constructors.
If it is found, and it generates a status code compatible with this status code, implicit construction
is made available.
You may mix in custom member functions and member function overrides by injecting a specialisation of
`mixins::mixin<Base, YourDomainType>`. Your mixin must inherit from `Base`. Your mixin can carry state,
but if it does, it will no longer be possible to construct erased status codes from such unerased status
codes.
*/
template <class DomainType> class BOOST_OUTCOME_SYSTEM_ERROR2_TRIVIAL_ABI status_code : public mixins::mixin<detail::status_code_storage<DomainType>, DomainType>
{
template <class T> friend class status_code;
using _base = mixins::mixin<detail::status_code_storage<DomainType>, DomainType>;
public:
//! The type of the domain.
using domain_type = DomainType;
//! The type of the status code.
using value_type = typename domain_type::value_type;
//! The type of a reference to a message string.
using string_ref = typename domain_type::string_ref;
protected:
using _base::_base;
public:
//! Default construction to empty
status_code() = default;
//! Copy constructor
status_code(const status_code &) = default;
//! Move constructor
status_code(status_code &&) = default; // NOLINT
//! Copy assignment
status_code &operator=(const status_code &) = default;
//! Move assignment
status_code &operator=(status_code &&) = default; // NOLINT
~status_code() = default;
//! Return a copy of the code.
BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR14 status_code clone() const { return *this; }
/***** KEEP THESE IN SYNC WITH ERRORED_STATUS_CODE *****/
//! Implicit construction from any type where an ADL discovered `make_status_code(T, Args ...)` returns a `status_code`.
BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(
class T, class... Args, //
class MakeStatusCodeResult =
typename detail::safe_get_make_status_code_result<T, Args...>::type) // Safe ADL lookup of make_status_code(), returns void if not found
BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(!std::is_same<typename std::decay<T>::type, status_code>::value // not copy/move of self
&& !std::is_same<typename std::decay<T>::type, in_place_t>::value // not in_place_t
&& is_status_code<MakeStatusCodeResult>::value // ADL makes a status code
&& std::is_constructible<status_code, MakeStatusCodeResult>::value)) // ADLed status code is compatible
constexpr status_code(T &&v, Args &&...args) noexcept(noexcept(make_status_code(std::declval<T>(), std::declval<Args>()...))) // NOLINT
: status_code(make_status_code(static_cast<T &&>(v), static_cast<Args &&>(args)...))
{
}
//! Implicit construction from any `quick_status_code_from_enum<Enum>` enumerated type.
BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(class Enum, //
class QuickStatusCodeType = typename quick_status_code_from_enum<Enum>::code_type) // Enumeration has been activated
BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(std::is_constructible<status_code, QuickStatusCodeType>::value)) // Its status code is compatible
constexpr status_code(Enum &&v) noexcept(std::is_nothrow_constructible<status_code, QuickStatusCodeType>::value) // NOLINT
: status_code(QuickStatusCodeType(static_cast<Enum &&>(v)))
{
}
//! Explicit in-place construction. Disables if `domain_type::get()` is not a valid expression.
template <class... Args>
constexpr explicit status_code(in_place_t /*unused */, Args &&...args) noexcept(std::is_nothrow_constructible<value_type, Args &&...>::value)
: _base(typename _base::_value_type_constructor{}, &domain_type::get(), static_cast<Args &&>(args)...)
{
}
//! Explicit in-place construction from initialiser list. Disables if `domain_type::get()` is not a valid expression.
template <class T, class... Args>
constexpr explicit status_code(in_place_t /*unused */, std::initializer_list<T> il,
Args &&...args) noexcept(std::is_nothrow_constructible<value_type, std::initializer_list<T>, Args &&...>::value)
: _base(typename _base::_value_type_constructor{}, &domain_type::get(), il, static_cast<Args &&>(args)...)
{
}
//! Explicit copy construction from a `value_type`. Disables if `domain_type::get()` is not a valid expression.
constexpr explicit status_code(const value_type &v) noexcept(std::is_nothrow_copy_constructible<value_type>::value)
: _base(typename _base::_value_type_constructor{}, &domain_type::get(), v)
{
}
//! Explicit move construction from a `value_type`. Disables if `domain_type::get()` is not a valid expression.
constexpr explicit status_code(value_type &&v) noexcept(std::is_nothrow_move_constructible<value_type>::value)
: _base(typename _base::_value_type_constructor{}, &domain_type::get(), static_cast<value_type &&>(v))
{
}
/*! Explicit construction from an erased status code. Available only if
`value_type` is trivially copyable or move bitcopying, and `sizeof(status_code) <= sizeof(status_code<erased<>>)`.
Does not check if domains are equal.
*/
BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(class ErasedType) //
BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(detail::domain_value_type_erasure_is_safe<domain_type, detail::erased<ErasedType>>::value))
constexpr explicit status_code(const status_code<detail::erased<ErasedType>> &v) noexcept(std::is_nothrow_copy_constructible<value_type>::value)
: status_code(detail::erasure_cast<value_type>(v.value()))
{
#if __cplusplus >= 201400
assert(v.domain() == this->domain());
#endif
}
//! Return a reference to a string textually representing a code.
BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR20 string_ref message() const noexcept
{
// Avoid MSVC's buggy ternary operator for expensive to destruct things
if(this->_domain != nullptr)
{
return string_ref(this->domain()._do_message(*this));
}
return string_ref("(empty)");
}
};
namespace traits
{
template <class DomainType> struct is_move_bitcopying<status_code<DomainType>>
{
static constexpr bool value = is_move_bitcopying<typename DomainType::value_type>::value;
};
} // namespace traits
/*! Type erased, move-only status_code, unlike `status_code<void>` which cannot be moved nor destroyed. Available
only if `erased<>` is available, which is when the domain's type is trivially
copyable or is move relocatable, and if the size of the domain's typed error code is less than or equal to
this erased error code. Copy construction is disabled, but if you want a copy call `.clone()`.
An ADL discovered helper function `make_status_code(T, Args...)` is looked up by one of the constructors.
If it is found, and it generates a status code compatible with this status code, implicit construction
is made available.
*/
template <class ErasedType>
class BOOST_OUTCOME_SYSTEM_ERROR2_TRIVIAL_ABI status_code<detail::erased<ErasedType>>
: public mixins::mixin<detail::status_code_storage<detail::erased<ErasedType>>, detail::erased<ErasedType>>
{
template <class T> friend class status_code;
using _base = mixins::mixin<detail::status_code_storage<detail::erased<ErasedType>>, detail::erased<ErasedType>>;
public:
//! The type of the domain (void, as it is erased).
using domain_type = void;
//! The type of the erased status code.
using value_type = ErasedType;
//! The type of a reference to a message string.
using string_ref = typename _base::string_ref;
public:
//! Default construction to empty
status_code() = default;
//! Copy constructor
status_code(const status_code &) = delete;
//! Move constructor
status_code(status_code &&) = default; // NOLINT
//! Copy assignment
status_code &operator=(const status_code &) = delete;
//! Move assignment
status_code &operator=(status_code &&) = default; // NOLINT
BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR20 ~status_code()
{
if(nullptr != this->_domain)
{
status_code_domain::payload_info_t info{sizeof(value_type), sizeof(status_code), alignof(status_code)};
this->_domain->_do_erased_destroy(*this, info);
}
}
//! Return a copy of the erased code by asking the domain to perform the erased copy.
BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR20 status_code clone() const
{
if(nullptr == this->_domain)
{
return {};
}
status_code x;
if(!this->_domain->_do_erased_copy(x, *this, this->_domain->payload_info()))
{
abort(); // should not be possible
}
return x;
}
/***** KEEP THESE IN SYNC WITH ERRORED_STATUS_CODE *****/
//! Implicit copy construction from any other status code if its value type is trivially copyable, it would fit into our storage, and it is not an erased
//! status code.
BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(class DomainType) //
BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(detail::domain_value_type_erasure_is_safe<detail::erased<ErasedType>, DomainType>::value),
BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(!detail::is_erased_status_code<status_code<typename std::decay<DomainType>::type>>::value))
constexpr status_code(const status_code<DomainType> &v) noexcept // NOLINT
: _base(typename _base::_value_type_constructor{}, v._domain_ptr(), detail::erasure_cast<value_type>(v.value()))
{
}
//! Implicit move construction from any other status code if its value type is trivially copyable or move bitcopying and it would fit into our storage
BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(class DomainType) //
BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(detail::domain_value_type_erasure_is_safe<detail::erased<ErasedType>, DomainType>::value))
BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR14 status_code(status_code<DomainType> &&v) noexcept // NOLINT
: _base(typename _base::_value_type_constructor{}, v._domain_ptr(), detail::erasure_cast<value_type>(v.value()))
{
alignas(alignof(typename DomainType::value_type)) char buffer[sizeof(typename DomainType::value_type)];
new(buffer) typename DomainType::value_type(static_cast<status_code<DomainType> &&>(v).value());
// deliberately do not destruct value moved into buffer
(void) buffer;
v._domain = nullptr;
}
//! Implicit construction from any type where an ADL discovered `make_status_code(T, Args ...)` returns a `status_code`.
BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(
class T, class... Args, //
class MakeStatusCodeResult =
typename detail::safe_get_make_status_code_result<T, Args...>::type) // Safe ADL lookup of make_status_code(), returns void if not found
BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(!std::is_same<typename std::decay<T>::type, status_code>::value // not copy/move of self
&& !std::is_same<typename std::decay<T>::type, value_type>::value // not copy/move of value type
&& is_status_code<MakeStatusCodeResult>::value // ADL makes a status code
&& std::is_constructible<status_code, MakeStatusCodeResult>::value)) // ADLed status code is compatible
constexpr status_code(T &&v, Args &&...args) noexcept(noexcept(make_status_code(std::declval<T>(), std::declval<Args>()...))) // NOLINT
: status_code(make_status_code(static_cast<T &&>(v), static_cast<Args &&>(args)...))
{
}
//! Implicit construction from any `quick_status_code_from_enum<Enum>` enumerated type.
BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(class Enum, //
class QuickStatusCodeType = typename quick_status_code_from_enum<Enum>::code_type) // Enumeration has been activated
BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(std::is_constructible<status_code, QuickStatusCodeType>::value)) // Its status code is compatible
constexpr status_code(Enum &&v) noexcept(std::is_nothrow_constructible<status_code, QuickStatusCodeType>::value) // NOLINT
: status_code(QuickStatusCodeType(static_cast<Enum &&>(v)))
{
}
#if defined(_CPPUNWIND) || defined(__EXCEPTIONS) || defined(BOOST_OUTCOME_STANDARDESE_IS_IN_THE_HOUSE)
//! Explicit copy construction from an unknown status code. Note that this will throw an exception if its value type is not trivially copyable or would not
//! fit into our storage or the source domain's `_do_erased_copy()` refused the copy.
explicit BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR14 status_code(const status_code<void> &v) // NOLINT
: _base(typename _base::_value_type_constructor{}, v._domain_ptr(), value_type{})
{
status_code_domain::payload_info_t info{sizeof(value_type), sizeof(status_code), alignof(status_code)};
if(this->_domain->_do_erased_copy(*this, v, info))
{
return;
}
struct _ final : public std::exception
{
virtual const char *what() const noexcept override { return "status_code: source domain's erased copy function returned failure or refusal"; }
};
throw _{};
}
#endif
//! Tagged copy construction from an unknown status code. Note that this will be empty if its value type is not trivially copyable or would not fit into our
//! storage or the source domain's `_do_erased_copy()` refused the copy.
BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR20 status_code(std::nothrow_t, const status_code<void> &v) noexcept // NOLINT
: _base(typename _base::_value_type_constructor{}, v._domain_ptr(), value_type{})
{
#if defined(_CPPUNWIND) || defined(__EXCEPTIONS) || defined(BOOST_OUTCOME_STANDARDESE_IS_IN_THE_HOUSE)
try
#endif
{
status_code_domain::payload_info_t info{sizeof(value_type), sizeof(status_code), alignof(status_code)};
if(this->_domain->_do_erased_copy(*this, v, info))
{
return;
}
this->_domain = nullptr;
}
#if defined(_CPPUNWIND) || defined(__EXCEPTIONS) || defined(BOOST_OUTCOME_STANDARDESE_IS_IN_THE_HOUSE)
catch(...)
{
this->_domain = nullptr;
}
#endif
}
/**** By rights ought to be removed in any formal standard ****/
//! Reset the code to empty.
BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR14 void clear() noexcept { *this = status_code(); }
//! Return the erased `value_type` by value.
constexpr value_type value() const noexcept { return this->_value; }
};
/*! An erased type specialisation of `status_code<D>`.
Available only if `ErasedType` satisfies `traits::is_move_bitcopying<ErasedType>::value`.
*/
template <class ErasedType> using erased_status_code = status_code<detail::erased<ErasedType>>;
namespace traits
{
template <class ErasedType> struct is_move_bitcopying<status_code<detail::erased<ErasedType>>>
{
static constexpr bool value = true;
};
} // namespace traits
BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_END
#endif

View File

@@ -1,5 +1,5 @@
/* Proposed SG14 status_code
(C) 2018-2019 Niall Douglas <http://www.nedproductions.biz/> (5 commits)
(C) 2018-2023 Niall Douglas <http://www.nedproductions.biz/> (5 commits)
File Created: Feb 2018
@@ -37,7 +37,8 @@ DEALINGS IN THE SOFTWARE.
BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_BEGIN
/*! The main workhorse of the system_error2 library, can be typed (`status_code<DomainType>`), erased-immutable (`status_code<void>`) or erased-mutable (`status_code<erased<T>>`).
/*! The main workhorse of the system_error2 library, can be typed (`status_code<DomainType>`), erased-immutable (`status_code<void>`) or erased-mutable
(`status_code<erased<T>>`).
Be careful of placing these into containers! Equality and inequality operators are
*semantic* not exact. Therefore two distinct items will test true! To help prevent
@@ -52,17 +53,56 @@ using generic_code = status_code<_generic_code_domain>;
namespace detail
{
template <class StatusCode> class indirecting_domain;
template <class T> struct status_code_sizer
template <class StatusCode, class Allocator> class indirecting_domain;
/* We are severely limited by needing to retain C++ 11 compatibility when doing
constexpr string parsing. MSVC lets you throw exceptions within a constexpr
evaluation context when exceptions are globally disabled, but won't let you
divide by zero, even if never evaluated, ever in constexpr. GCC and clang won't
let you throw exceptions, ever, if exceptions are globally disabled. So let's
use the trick of divide by zero in constexpr on GCC and clang if and only if
exceptions are globally disabled.
*/
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdiv-by-zero"
#endif
#if defined(__cpp_exceptions) || (defined(_MSC_VER) && !defined(__clang__))
#define BOOST_OUTCOME_SYSTEM_ERROR2_FAIL_CONSTEXPR(msg) throw msg
#else
#define BOOST_OUTCOME_SYSTEM_ERROR2_FAIL_CONSTEXPR(msg) ((void) msg, 1 / 0)
#endif
constexpr inline unsigned long long parse_hex_byte(char c)
{
void *a;
T b;
};
template <class To, class From> struct type_erasure_is_safe
return ('0' <= c && c <= '9') ? (c - '0') :
('a' <= c && c <= 'f') ? (10 + c - 'a') :
('A' <= c && c <= 'F') ? (10 + c - 'A') :
BOOST_OUTCOME_SYSTEM_ERROR2_FAIL_CONSTEXPR("Invalid character in UUID");
}
constexpr inline unsigned long long parse_uuid2(const char *s)
{
static constexpr bool value = traits::is_move_relocating<From>::value //
&& (sizeof(status_code_sizer<From>) <= sizeof(status_code_sizer<To>));
};
return ((parse_hex_byte(s[0]) << 0) | (parse_hex_byte(s[1]) << 4) | (parse_hex_byte(s[2]) << 8) | (parse_hex_byte(s[3]) << 12) |
(parse_hex_byte(s[4]) << 16) | (parse_hex_byte(s[5]) << 20) | (parse_hex_byte(s[6]) << 24) | (parse_hex_byte(s[7]) << 28) |
(parse_hex_byte(s[9]) << 32) | (parse_hex_byte(s[10]) << 36) | (parse_hex_byte(s[11]) << 40) | (parse_hex_byte(s[12]) << 44) |
(parse_hex_byte(s[14]) << 48) | (parse_hex_byte(s[15]) << 52) | (parse_hex_byte(s[16]) << 56) | (parse_hex_byte(s[17]) << 60)) //
^ //
((parse_hex_byte(s[19]) << 0) | (parse_hex_byte(s[20]) << 4) | (parse_hex_byte(s[21]) << 8) | (parse_hex_byte(s[22]) << 12) |
(parse_hex_byte(s[24]) << 16) | (parse_hex_byte(s[25]) << 20) | (parse_hex_byte(s[26]) << 24) | (parse_hex_byte(s[27]) << 28) |
(parse_hex_byte(s[28]) << 32) | (parse_hex_byte(s[29]) << 36) | (parse_hex_byte(s[30]) << 40) | (parse_hex_byte(s[31]) << 44) |
(parse_hex_byte(s[32]) << 48) | (parse_hex_byte(s[33]) << 52) | (parse_hex_byte(s[34]) << 56) | (parse_hex_byte(s[35]) << 60));
}
template <size_t N> constexpr inline unsigned long long parse_uuid_from_array(const char (&uuid)[N])
{
return (N == 37) ? parse_uuid2(uuid) : ((N == 39) ? parse_uuid2(uuid + 1) : BOOST_OUTCOME_SYSTEM_ERROR2_FAIL_CONSTEXPR("UUID does not have correct length"));
}
template <size_t N> constexpr inline unsigned long long parse_uuid_from_pointer(const char *uuid)
{
return (N == 36) ? parse_uuid2(uuid) : ((N == 38) ? parse_uuid2(uuid + 1) : BOOST_OUTCOME_SYSTEM_ERROR2_FAIL_CONSTEXPR("UUID does not have correct length"));
}
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
static constexpr unsigned long long test_uuid_parse = parse_uuid_from_array("430f1201-94fc-06c7-430f-120194fc06c7");
// static constexpr unsigned long long test_uuid_parse2 = parse_uuid_from_array("x30f1201-94fc-06c7-430f-120194fc06c7");
} // namespace detail
/*! Abstract base class for a coding domain of a status code.
@@ -70,7 +110,7 @@ namespace detail
class status_code_domain
{
template <class DomainType> friend class status_code;
template <class StatusCode> friend class indirecting_domain;
template <class StatusCode, class Allocator> friend class indirecting_domain;
public:
//! Type of the unique id for this domain.
@@ -116,7 +156,7 @@ public:
{
(void) dest;
(void) src;
assert(dest->_thunk == _checking_string_thunk); // NOLINT
assert(dest->_thunk == _checking_string_thunk); // NOLINT
assert(src == nullptr || src->_thunk == _checking_string_thunk); // NOLINT
// do nothing
}
@@ -130,24 +170,30 @@ public:
//! Handler for when operations occur
const _thunk_spec _thunk{nullptr};
constexpr explicit string_ref(_thunk_spec thunk) noexcept : _thunk(thunk) {}
constexpr explicit string_ref(_thunk_spec thunk) noexcept
: _thunk(thunk)
{
}
public:
//! Construct from a C string literal
BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR14 explicit string_ref(const char *str, size_type len = static_cast<size_type>(-1), void *state0 = nullptr, void *state1 = nullptr, void *state2 = nullptr,
BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR14 explicit string_ref(const char *str, size_type len = static_cast<size_type>(-1), void *state0 = nullptr, void *state1 = nullptr,
void *state2 = nullptr,
#ifndef NDEBUG
_thunk_spec thunk = _checking_string_thunk
#else
_thunk_spec thunk = nullptr
#endif
) noexcept : _begin(str),
_end((len == static_cast<size_type>(-1)) ? (str + detail::cstrlen(str)) : (str + len)), // NOLINT
_state{state0, state1, state2},
_thunk(thunk)
) noexcept
: _begin(str)
, _end((len == static_cast<size_type>(-1)) ? (str + detail::cstrlen(str)) : (str + len))
, // NOLINT
_state{state0, state1, state2}
, _thunk(thunk)
{
}
//! Copy construct the derived implementation.
string_ref(const string_ref &o)
BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR20 string_ref(const string_ref &o)
: _begin(o._begin)
, _end(o._end)
, _state{o._state[0], o._state[1], o._state[2]}
@@ -159,7 +205,11 @@ public:
}
}
//! Move construct the derived implementation.
string_ref(string_ref &&o) noexcept : _begin(o._begin), _end(o._end), _state{o._state[0], o._state[1], o._state[2]}, _thunk(o._thunk)
BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR20 string_ref(string_ref &&o) noexcept
: _begin(o._begin)
, _end(o._end)
, _state{o._state[0], o._state[1], o._state[2]}
, _thunk(o._thunk)
{
if(_thunk != nullptr)
{
@@ -167,7 +217,7 @@ public:
}
}
//! Copy assignment
string_ref &operator=(const string_ref &o)
BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR20 string_ref &operator=(const string_ref &o)
{
if(this != &o)
{
@@ -191,7 +241,7 @@ public:
return *this;
}
//! Move assignment
string_ref &operator=(string_ref &&o) noexcept
BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR20 string_ref &operator=(string_ref &&o) noexcept
{
if(this != &o)
{
@@ -201,7 +251,7 @@ public:
return *this;
}
//! Destruction
~string_ref()
BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR20 ~string_ref()
{
if(_thunk != nullptr)
{
@@ -211,25 +261,25 @@ public:
}
//! Returns whether the reference is empty or not
BOOST_OUTCOME_SYSTEM_ERROR2_NODISCARD bool empty() const noexcept { return _begin == _end; }
BOOST_OUTCOME_SYSTEM_ERROR2_NODISCARD constexpr bool empty() const noexcept { return _begin == _end; }
//! Returns the size of the string
size_type size() const noexcept { return _end - _begin; }
constexpr size_type size() const noexcept { return _end - _begin; }
//! Returns a null terminated C string
const_pointer c_str() const noexcept { return _begin; }
constexpr const_pointer c_str() const noexcept { return _begin; }
//! Returns a null terminated C string
const_pointer data() const noexcept { return _begin; }
constexpr const_pointer data() const noexcept { return _begin; }
//! Returns the beginning of the string
iterator begin() noexcept { return _begin; }
BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR14 iterator begin() noexcept { return _begin; }
//! Returns the beginning of the string
const_iterator begin() const noexcept { return _begin; }
BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR14 const_iterator begin() const noexcept { return _begin; }
//! Returns the beginning of the string
const_iterator cbegin() const noexcept { return _begin; }
constexpr const_iterator cbegin() const noexcept { return _begin; }
//! Returns the end of the string
iterator end() noexcept { return _end; }
BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR14 iterator end() noexcept { return _end; }
//! Returns the end of the string
const_iterator end() const noexcept { return _end; }
BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR14 const_iterator end() const noexcept { return _end; }
//! Returns the end of the string
const_iterator cend() const noexcept { return _end; }
constexpr const_iterator cend() const noexcept { return _end; }
};
/*! A reference counted, threadsafe reference to a message string.
@@ -243,13 +293,13 @@ public:
_allocated_msg *&_msg() noexcept { return reinterpret_cast<_allocated_msg *&>(this->_state[0]); } // NOLINT
const _allocated_msg *_msg() const noexcept { return reinterpret_cast<const _allocated_msg *>(this->_state[0]); } // NOLINT
static void _refcounted_string_thunk(string_ref *_dest, const string_ref *_src, _thunk_op op) noexcept
static BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR20 void _refcounted_string_thunk(string_ref *_dest, const string_ref *_src, _thunk_op op) noexcept
{
auto dest = static_cast<atomic_refcounted_string_ref *>(_dest); // NOLINT
auto dest = static_cast<atomic_refcounted_string_ref *>(_dest); // NOLINT
auto src = static_cast<const atomic_refcounted_string_ref *>(_src); // NOLINT
(void) src;
assert(dest->_thunk == _refcounted_string_thunk); // NOLINT
assert(src == nullptr || src->_thunk == _refcounted_string_thunk); // NOLINT
assert(dest->_thunk == _refcounted_string_thunk); // NOLINT
assert(src == nullptr || src->_thunk == _refcounted_string_thunk); // NOLINT
switch(op)
{
case _thunk_op::copy:
@@ -264,7 +314,7 @@ public:
}
case _thunk_op::move:
{
assert(src); // NOLINT
assert(src); // NOLINT
auto msrc = const_cast<atomic_refcounted_string_ref *>(src); // NOLINT
msrc->_begin = msrc->_end = nullptr;
msrc->_state[0] = msrc->_state[1] = msrc->_state[2] = nullptr;
@@ -279,7 +329,7 @@ public:
{
std::atomic_thread_fence(std::memory_order_acquire);
free((void *) dest->_begin); // NOLINT
delete dest->_msg(); // NOLINT
delete dest->_msg(); // NOLINT
}
}
}
@@ -288,7 +338,8 @@ public:
public:
//! Construct from a C string literal allocated using `malloc()`.
explicit atomic_refcounted_string_ref(const char *str, size_type len = static_cast<size_type>(-1), void *state1 = nullptr, void *state2 = nullptr) noexcept : string_ref(str, len, new(std::nothrow) _allocated_msg, state1, state2, _refcounted_string_thunk)
explicit atomic_refcounted_string_ref(const char *str, size_type len = static_cast<size_type>(-1), void *state1 = nullptr, void *state2 = nullptr) noexcept
: string_ref(str, len, new(std::nothrow) _allocated_msg, state1, state2, _refcounted_string_thunk)
{
if(_msg() == nullptr)
{
@@ -309,7 +360,26 @@ protected:
Do NOT make up your own value. Do NOT use zero.
*/
constexpr explicit status_code_domain(unique_id_type id) noexcept : _id(id) {}
constexpr explicit status_code_domain(unique_id_type id) noexcept
: _id(id)
{
}
/*! UUID constructor, where input is constexpr parsed into a `unique_id_type`.
*/
template <size_t N>
constexpr explicit status_code_domain(const char (&uuid)[N]) noexcept
: _id(detail::parse_uuid_from_array<N>(uuid))
{
}
template <size_t N> struct _uuid_size
{
};
//! Alternative UUID constructor
template <size_t N>
constexpr explicit status_code_domain(const char *uuid, _uuid_size<N> /*unused*/) noexcept
: _id(detail::parse_uuid_from_pointer<N>(uuid))
{
}
//! No public copying at type erased level
status_code_domain(const status_code_domain &) = default;
//! No public moving at type erased level
@@ -332,31 +402,60 @@ public:
//! Returns the unique id used to identify identical category instances.
constexpr unique_id_type id() const noexcept { return _id; }
//! Name of this category.
virtual string_ref name() const noexcept = 0;
BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR20 virtual string_ref name() const noexcept = 0;
//! Information about the payload of the code for this domain
struct payload_info_t
{
size_t payload_size{0}; //!< The payload size in bytes
size_t total_size{0}; //!< The total status code size in bytes (includes domain pointer and mixins state)
size_t total_alignment{1}; //!< The total status code alignment in bytes
payload_info_t() = default;
constexpr payload_info_t(size_t _payload_size, size_t _total_size, size_t _total_alignment)
: payload_size(_payload_size)
, total_size(_total_size)
, total_alignment(_total_alignment)
{
}
};
//! Information about this domain's payload
BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR20 virtual payload_info_t payload_info() const noexcept = 0;
protected:
//! True if code means failure.
virtual bool _do_failure(const status_code<void> &code) const noexcept = 0;
BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR20 virtual bool _do_failure(const status_code<void> &code) const noexcept = 0;
//! True if code is (potentially non-transitively) equivalent to another code in another domain.
virtual bool _do_equivalent(const status_code<void> &code1, const status_code<void> &code2) const noexcept = 0;
BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR20 virtual bool _do_equivalent(const status_code<void> &code1, const status_code<void> &code2) const noexcept = 0;
//! Returns the generic code closest to this code, if any.
virtual generic_code _generic_code(const status_code<void> &code) const noexcept = 0;
BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR20 virtual generic_code _generic_code(const status_code<void> &code) const noexcept = 0;
//! Return a reference to a string textually representing a code.
virtual string_ref _do_message(const status_code<void> &code) const noexcept = 0;
BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR20 virtual string_ref _do_message(const status_code<void> &code) const noexcept = 0;
#if defined(_CPPUNWIND) || defined(__EXCEPTIONS) || defined(BOOST_OUTCOME_STANDARDESE_IS_IN_THE_HOUSE)
//! Throw a code as a C++ exception.
BOOST_OUTCOME_SYSTEM_ERROR2_NORETURN virtual void _do_throw_exception(const status_code<void> &code) const = 0;
BOOST_OUTCOME_SYSTEM_ERROR2_NORETURN BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR20 virtual void _do_throw_exception(const status_code<void> &code) const = 0;
#else
// Keep a vtable slot for binary compatibility
BOOST_OUTCOME_SYSTEM_ERROR2_NORETURN virtual void _do_throw_exception(const status_code<void> & /*code*/) const { abort(); }
#endif
// For a `status_code<erased<T>>` only, copy from `src` to `dst`. Default implementation uses `memcpy()`.
virtual void _do_erased_copy(status_code<void> &dst, const status_code<void> &src, size_t bytes) const { memcpy(&dst, &src, bytes); } // NOLINT
// For a `status_code<erased<T>>` only, copy from `src` to `dst`. Default implementation uses `memcpy()`. You should return false here if your payload is not
// trivially copyable or would not fit.
virtual bool _do_erased_copy(status_code<void> &dst, const status_code<void> &src, payload_info_t dstinfo) const
{
// Note that dst may not have its domain set
const auto srcinfo = payload_info();
if(dstinfo.total_size < srcinfo.total_size)
{
return false;
}
const auto tocopy = (dstinfo.total_size > srcinfo.total_size) ? srcinfo.total_size : dstinfo.total_size;
memcpy(&dst, &src, tocopy);
return true;
} // NOLINT
// For a `status_code<erased<T>>` only, destroy the erased value type. Default implementation does nothing.
virtual void _do_erased_destroy(status_code<void> &code, size_t bytes) const noexcept // NOLINT
BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR20 virtual void _do_erased_destroy(status_code<void> &code, payload_info_t info) const noexcept // NOLINT
{
(void) code;
(void) bytes;
(void) info;
}
};

View File

@@ -0,0 +1,141 @@
/* Proposed SG14 status_code
(C) 2018 - 2022 Niall Douglas <http://www.nedproductions.biz/> (5 commits)
File Created: Feb 2018
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License in the accompanying file
Licence.txt or at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Distributed under the Boost Software License, Version 1.0.
(See accompanying file Licence.txt or copy at
http://www.boost.org/LICENSE_1_0.txt)
*/
#ifndef BOOST_OUTCOME_SYSTEM_ERROR2_STATUS_ERROR_HPP
#define BOOST_OUTCOME_SYSTEM_ERROR2_STATUS_ERROR_HPP
#include "status_code.hpp"
#include <exception> // for std::exception
BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_BEGIN
/*! Exception type representing a thrown status_code
*/
template <class DomainType> class status_error;
/*! The erased type edition of status_error.
*/
template <> class status_error<void> : public std::exception
{
protected:
//! Constructs an instance. Not publicly available.
status_error() = default;
//! Copy constructor. Not publicly available
status_error(const status_error &) = default;
//! Move constructor. Not publicly available
status_error(status_error &&) = default;
//! Copy assignment. Not publicly available
status_error &operator=(const status_error &) = default;
//! Move assignment. Not publicly available
status_error &operator=(status_error &&) = default;
//! Destructor. Not publicly available.
~status_error() override = default;
virtual const status_code<void> &_do_code() const noexcept = 0;
public:
//! The type of the status domain
using domain_type = void;
//! The type of the status code
using status_code_type = status_code<void>;
public:
//! The erased status code which generated this exception instance.
const status_code<void> &code() const noexcept { return _do_code(); }
};
/*! Exception type representing a thrown status_code
*/
template <class DomainType> class status_error : public status_error<void>
{
status_code<DomainType> _code;
typename DomainType::string_ref _msgref;
virtual const status_code<void> &_do_code() const noexcept override final { return _code; }
public:
//! The type of the status domain
using domain_type = DomainType;
//! The type of the status code
using status_code_type = status_code<DomainType>;
//! Constructs an instance
explicit status_error(status_code<DomainType> code)
: _code(static_cast<status_code<DomainType> &&>(code))
, _msgref(_code.message())
{
}
//! Return an explanatory string
virtual const char *what() const noexcept override { return _msgref.c_str(); } // NOLINT
//! Returns a reference to the code
const status_code_type &code() const & { return _code; }
//! Returns a reference to the code
status_code_type &code() & { return _code; }
//! Returns a reference to the code
const status_code_type &&code() const && { return _code; }
//! Returns a reference to the code
status_code_type &&code() && { return _code; }
};
/*! Exception type representing a thrown erased status_code
*/
template <class ErasedType> class status_error<detail::erased<ErasedType>> : public status_error<void>
{
status_code<detail::erased<ErasedType>> _code;
typename status_code_domain::string_ref _msgref;
virtual const status_code<detail::erased<ErasedType>> &_do_code() const noexcept override final { return _code; }
public:
//! The type of the status domain
using domain_type = void;
//! The type of the status code
using status_code_type = status_code<detail::erased<ErasedType>>;
//! Constructs an instance
explicit status_error(status_code<detail::erased<ErasedType>> code)
: _code(static_cast<status_code<detail::erased<ErasedType>> &&>(code))
, _msgref(_code.message())
{
}
//! Return an explanatory string
virtual const char *what() const noexcept override { return _msgref.c_str(); } // NOLINT
//! Returns a reference to the code
const status_code_type &code() const & { return _code; }
//! Returns a reference to the code
status_code_type &code() & { return _code; }
//! Returns a reference to the code
const status_code_type &&code() const && { return _code; }
//! Returns a reference to the code
status_code_type &&code() && { return _code; }
};
BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_END
#endif

View File

@@ -0,0 +1,322 @@
/* Proposed SG14 status_code
(C) 2018 - 2021 Niall Douglas <http://www.nedproductions.biz/> (5 commits)
File Created: Aug 2018
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License in the accompanying file
Licence.txt or at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Distributed under the Boost Software License, Version 1.0.
(See accompanying file Licence.txt or copy at
http://www.boost.org/LICENSE_1_0.txt)
*/
#ifndef BOOST_OUTCOME_SYSTEM_ERROR2_STD_ERROR_CODE_HPP
#define BOOST_OUTCOME_SYSTEM_ERROR2_STD_ERROR_CODE_HPP
#ifndef BOOST_OUTCOME_SYSTEM_ERROR2_NOT_POSIX
#include "posix_code.hpp"
#endif
#if defined(_WIN32) || defined(BOOST_OUTCOME_STANDARDESE_IS_IN_THE_HOUSE)
#include "win32_code.hpp"
#endif
#include <system_error>
BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_BEGIN
class _std_error_code_domain;
//! A `status_code` representing exactly a `std::error_code`
using std_error_code = status_code<_std_error_code_domain>;
namespace mixins
{
template <class Base> struct mixin<Base, _std_error_code_domain> : public Base
{
using Base::Base;
//! Implicit constructor from a `std::error_code`
inline mixin(std::error_code ec);
//! Returns the error code category
inline const std::error_category &category() const noexcept;
};
} // namespace mixins
/*! The implementation of the domain for `std::error_code` error codes.
*/
class _std_error_code_domain final : public status_code_domain
{
template <class DomainType> friend class status_code;
template <class StatusCode, class Allocator> friend class detail::indirecting_domain;
using _base = status_code_domain;
using _error_code_type = std::error_code;
using _error_category_type = std::error_category;
std::string _name;
static _base::string_ref _make_string_ref(_error_code_type c) noexcept
{
#if defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)
try
#endif
{
std::string msg = c.message();
auto *p = static_cast<char *>(malloc(msg.size() + 1)); // NOLINT
if(p == nullptr)
{
return _base::string_ref("failed to allocate message");
}
memcpy(p, msg.c_str(), msg.size() + 1);
return _base::atomic_refcounted_string_ref(p, msg.size());
}
#if defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)
catch(...)
{
return _base::string_ref("failed to allocate message");
}
#endif
}
public:
//! The value type of the `std::error_code` code, which stores the `int` from the `std::error_code`
using value_type = int;
using _base::string_ref;
//! Returns the error category singleton pointer this status code domain represents
const _error_category_type &error_category() const noexcept
{
auto ptr = 0x223a160d20de97b4 ^ this->id();
return *reinterpret_cast<const _error_category_type *>(ptr);
}
//! Default constructor
explicit _std_error_code_domain(const _error_category_type &category) noexcept
: _base(0x223a160d20de97b4 ^ reinterpret_cast<_base::unique_id_type>(&category))
, _name("std_error_code_domain(")
{
_name.append(category.name());
_name.push_back(')');
}
_std_error_code_domain(const _std_error_code_domain &) = default;
_std_error_code_domain(_std_error_code_domain &&) = default;
_std_error_code_domain &operator=(const _std_error_code_domain &) = default;
_std_error_code_domain &operator=(_std_error_code_domain &&) = default;
~_std_error_code_domain() = default;
static inline const _std_error_code_domain *get(_error_code_type ec);
virtual string_ref name() const noexcept override { return string_ref(_name.c_str(), _name.size()); } // NOLINT
virtual payload_info_t payload_info() const noexcept override
{
return {sizeof(value_type), sizeof(status_code_domain *) + sizeof(value_type),
(alignof(value_type) > alignof(status_code_domain *)) ? alignof(value_type) : alignof(status_code_domain *)};
}
protected:
virtual bool _do_failure(const status_code<void> &code) const noexcept override;
virtual bool _do_equivalent(const status_code<void> &code1, const status_code<void> &code2) const noexcept override;
virtual generic_code _generic_code(const status_code<void> &code) const noexcept override;
virtual string_ref _do_message(const status_code<void> &code) const noexcept override;
#if defined(_CPPUNWIND) || defined(__EXCEPTIONS) || defined(BOOST_OUTCOME_STANDARDESE_IS_IN_THE_HOUSE)
BOOST_OUTCOME_SYSTEM_ERROR2_NORETURN virtual void _do_throw_exception(const status_code<void> &code) const override;
#endif
};
namespace detail
{
extern inline _std_error_code_domain *std_error_code_domain_from_category(const std::error_category &category)
{
static constexpr size_t max_items = 64;
static struct storage_t
{
std::atomic<unsigned> _lock;
union item_t
{
int _init;
_std_error_code_domain domain;
constexpr item_t()
: _init(0)
{
}
~item_t() {}
} items[max_items];
size_t count{0};
void lock()
{
while(_lock.exchange(1, std::memory_order_acquire) != 0)
;
}
void unlock() { _lock.store(0, std::memory_order_release); }
storage_t() {}
~storage_t()
{
lock();
for(size_t n = 0; n < count; n++)
{
items[n].domain.~_std_error_code_domain();
}
unlock();
}
_std_error_code_domain *add(const std::error_category &category)
{
_std_error_code_domain *ret = nullptr;
lock();
for(size_t n = 0; n < count; n++)
{
if(items[n].domain.error_category() == category)
{
ret = &items[n].domain;
break;
}
}
if(ret == nullptr && count < max_items)
{
ret = new(std::addressof(items[count++].domain)) _std_error_code_domain(category);
}
unlock();
return ret;
}
} storage;
return storage.add(category);
}
} // namespace detail
namespace mixins
{
template <class Base>
inline mixin<Base, _std_error_code_domain>::mixin(std::error_code ec)
: Base(typename Base::_value_type_constructor{}, _std_error_code_domain::get(ec), ec.value())
{
}
template <class Base> inline const std::error_category &mixin<Base, _std_error_code_domain>::category() const noexcept
{
const auto &domain = static_cast<const _std_error_code_domain &>(this->domain());
return domain.error_category();
};
} // namespace mixins
inline const _std_error_code_domain *_std_error_code_domain::get(std::error_code ec)
{
auto *p = detail::std_error_code_domain_from_category(ec.category());
assert(p != nullptr);
if(p == nullptr)
{
abort();
}
return p;
}
inline bool _std_error_code_domain::_do_failure(const status_code<void> &code) const noexcept
{
assert(code.domain() == *this);
return static_cast<const std_error_code &>(code).value() != 0; // NOLINT
}
inline bool _std_error_code_domain::_do_equivalent(const status_code<void> &code1, const status_code<void> &code2) const noexcept
{
assert(code1.domain() == *this);
const auto &c1 = static_cast<const std_error_code &>(code1); // NOLINT
const auto &cat1 = c1.category();
// Are we comparing to another wrapped error_code?
if(code2.domain() == *this)
{
const auto &c2 = static_cast<const std_error_code &>(code2); // NOLINT
const auto &cat2 = c2.category();
// If the error code categories are identical, do literal comparison
if(cat1 == cat2)
{
return c1.value() == c2.value();
}
// Otherwise fall back onto the _generic_code comparison, which uses default_error_condition()
return false;
}
// Am I an error code with generic category?
if(cat1 == std::generic_category())
{
// Convert to generic code, and compare that
generic_code _c1(static_cast<errc>(c1.value()));
return _c1 == code2;
}
// Am I an error code with system category?
if(cat1 == std::system_category())
{
// Convert to POSIX or Win32 code, and compare that
#ifdef _WIN32
win32_code _c1((win32::DWORD) c1.value());
return _c1 == code2;
#elif !defined(BOOST_OUTCOME_SYSTEM_ERROR2_NOT_POSIX)
posix_code _c1(c1.value());
return _c1 == code2;
#endif
}
return false;
}
inline generic_code _std_error_code_domain::_generic_code(const status_code<void> &code) const noexcept
{
assert(code.domain() == *this);
const auto &c = static_cast<const std_error_code &>(code); // NOLINT
// Ask my embedded error code for its mapping to std::errc, which is a subset of our generic_code errc.
std::error_condition cond(c.category().default_error_condition(c.value()));
if(cond.category() == std::generic_category())
{
return generic_code(static_cast<errc>(cond.value()));
}
#if !defined(BOOST_OUTCOME_SYSTEM_ERROR2_NOT_POSIX) && !defined(_WIN32)
if(cond.category() == std::system_category())
{
return generic_code(static_cast<errc>(cond.value()));
}
#endif
return errc::unknown;
}
inline _std_error_code_domain::string_ref _std_error_code_domain::_do_message(const status_code<void> &code) const noexcept
{
assert(code.domain() == *this);
const auto &c = static_cast<const std_error_code &>(code); // NOLINT
return _make_string_ref(_error_code_type(c.value(), c.category()));
}
#if defined(_CPPUNWIND) || defined(__EXCEPTIONS) || defined(BOOST_OUTCOME_STANDARDESE_IS_IN_THE_HOUSE)
BOOST_OUTCOME_SYSTEM_ERROR2_NORETURN inline void _std_error_code_domain::_do_throw_exception(const status_code<void> &code) const
{
assert(code.domain() == *this);
const auto &c = static_cast<const std_error_code &>(code); // NOLINT
throw std::system_error(std::error_code(c.value(), c.category()));
}
#endif
static_assert(sizeof(std_error_code) <= sizeof(void *) * 2, "std_error_code does not fit into a system_code!");
BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_END
// Enable implicit construction of `std_error_code` from `std::error_code`.
namespace std
{
inline BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::std_error_code make_status_code(error_code c) noexcept
{
return BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::std_error_code(c);
}
} // namespace std
#endif

View File

@@ -1,5 +1,5 @@
/* Proposed SG14 status_code
(C) 2018-2019 Niall Douglas <http://www.nedproductions.biz/> (5 commits)
(C) 2018-2023 Niall Douglas <http://www.nedproductions.biz/> (5 commits)
File Created: Feb 2018
@@ -31,7 +31,11 @@ DEALINGS IN THE SOFTWARE.
#ifndef BOOST_OUTCOME_SYSTEM_ERROR2_SYSTEM_CODE_HPP
#define BOOST_OUTCOME_SYSTEM_ERROR2_SYSTEM_CODE_HPP
#ifndef BOOST_OUTCOME_SYSTEM_ERROR2_NOT_POSIX
#include "posix_code.hpp"
#else
#include "quick_status_code_from_enum.hpp"
#endif
#if defined(_WIN32) || defined(BOOST_OUTCOME_STANDARDESE_IS_IN_THE_HOUSE)
#include "nt_code.hpp"
@@ -54,11 +58,11 @@ For POSIX, `posix_code` is possible.
You are guaranteed that `system_code` can be transported by the compiler
in exactly two CPU registers.
*/
using system_code = status_code<erased<intptr_t>>;
using system_code = erased_status_code<intptr_t>;
#ifndef NDEBUG
static_assert(sizeof(system_code) == 2 * sizeof(void *), "system_code is not exactly two pointers in size!");
static_assert(traits::is_move_relocating<system_code>::value, "system_code is not move relocating!");
static_assert(traits::is_move_bitcopying<system_code>::value, "system_code is not move bitcopying!");
#endif
BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_END

View File

@@ -1,5 +1,5 @@
/* Proposed SG14 status_code
(C) 2018-2019 Niall Douglas <http://www.nedproductions.biz/> (5 commits)
(C) 2018-2023 Niall Douglas <http://www.nedproductions.biz/> (5 commits)
File Created: June 2018
@@ -33,6 +33,8 @@ DEALINGS IN THE SOFTWARE.
#include "system_code.hpp"
#include "status_error.hpp"
#include <exception> // for exception_ptr
#include <stdexcept> // for the exception types
#include <system_error> // for std::system_error
@@ -50,7 +52,31 @@ inline system_code system_code_from_exception(std::exception_ptr &&ep = std::cur
}
try
{
std::rethrow_exception(ep);
try
{
std::rethrow_exception(ep);
}
catch(const status_error<void> &e)
{
try
{
system_code erased(e.code());
if(!erased.empty())
{
return erased;
}
}
catch(...)
{
// Source status code's do_erased_copy() routine refused to copy the original
// Process instead as if the source were not a status_error
}
throw;
}
catch(...)
{
throw;
}
}
catch(const std::invalid_argument & /*unused*/)
{
@@ -89,7 +115,11 @@ inline system_code system_code_from_exception(std::exception_ptr &&ep = std::cur
#ifdef _WIN32
return win32_code(e.code().value());
#else
#ifndef BOOST_OUTCOME_SYSTEM_ERROR2_NOT_POSIX
return posix_code(e.code().value());
#else
return generic_code(static_cast<errc>(e.code().value()));
#endif
#endif
}
// Don't know this error code category, can't wrap it into std_error_code

View File

@@ -1,5 +1,5 @@
/* Proposed SG14 status_code
(C) 2018-2019 Niall Douglas <http://www.nedproductions.biz/> (5 commits)
(C) 2018-2023 Niall Douglas <http://www.nedproductions.biz/> (5 commits)
File Created: Feb 2018

View File

@@ -1,5 +1,5 @@
/* Proposed SG14 status_code
(C) 2018-2019 Niall Douglas <http://www.nedproductions.biz/> (5 commits)
(C) 2018-2023 Niall Douglas <http://www.nedproductions.biz/> (5 commits)
File Created: Feb 2018
@@ -35,7 +35,7 @@ DEALINGS IN THE SOFTWARE.
#error This file should only be included on Windows
#endif
#include "generic_code.hpp"
#include "quick_status_code_from_enum.hpp"
BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_BEGIN
@@ -45,12 +45,29 @@ namespace win32
// A Win32 DWORD
using DWORD = unsigned long;
// Used to retrieve the current Win32 error code
extern "C" DWORD __stdcall GetLastError();
extern DWORD __stdcall GetLastError();
// Used to retrieve a locale-specific message string for some error code
extern "C" DWORD __stdcall FormatMessageW(DWORD dwFlags, const void *lpSource, DWORD dwMessageId, DWORD dwLanguageId, wchar_t *lpBuffer, DWORD nSize, void /*va_list*/ *Arguments);
extern DWORD __stdcall FormatMessageW(DWORD dwFlags, const void *lpSource, DWORD dwMessageId, DWORD dwLanguageId, wchar_t *lpBuffer, DWORD nSize,
void /*va_list*/ *Arguments);
// Converts UTF-16 message string to UTF-8
extern "C" int __stdcall WideCharToMultiByte(unsigned int CodePage, DWORD dwFlags, const wchar_t *lpWideCharStr, int cchWideChar, char *lpMultiByteStr, int cbMultiByte, const char *lpDefaultChar, int *lpUsedDefaultChar);
extern int __stdcall WideCharToMultiByte(unsigned int CodePage, DWORD dwFlags, const wchar_t *lpWideCharStr, int cchWideChar, char *lpMultiByteStr,
int cbMultiByte, const char *lpDefaultChar, int *lpUsedDefaultChar);
#pragma comment(lib, "kernel32.lib")
#if(defined(__x86_64__) || defined(_M_X64)) || (defined(__aarch64__) || defined(_M_ARM64))
#pragma comment(linker, "/alternatename:?GetLastError@win32@system_error2@@YAKXZ=GetLastError")
#pragma comment(linker, "/alternatename:?FormatMessageW@win32@system_error2@@YAKKPEBXKKPEA_WKPEAX@Z=FormatMessageW")
#pragma comment(linker, "/alternatename:?WideCharToMultiByte@win32@system_error2@@YAHIKPEB_WHPEADHPEBDPEAH@Z=WideCharToMultiByte")
#elif defined(__x86__) || defined(_M_IX86) || defined(__i386__)
#pragma comment(linker, "/alternatename:?GetLastError@win32@system_error2@@YGKXZ=_GetLastError@0")
#pragma comment(linker, "/alternatename:?FormatMessageW@win32@system_error2@@YGKKPBXKKPA_WKPAX@Z=_FormatMessageW@28")
#pragma comment(linker, "/alternatename:?WideCharToMultiByte@win32@system_error2@@YGHIKPB_WHPADHPBDPAH@Z=_WideCharToMultiByte@32")
#elif defined(__arm__) || defined(_M_ARM)
#pragma comment(linker, "/alternatename:?GetLastError@win32@system_error2@@YAKXZ=GetLastError")
#pragma comment(linker, "/alternatename:?FormatMessageW@win32@system_error2@@YAKKPBXKKPA_WKPAX@Z=FormatMessageW")
#pragma comment(linker, "/alternatename:?WideCharToMultiByte@win32@system_error2@@YAHIKPB_WHPADHPBDPAH@Z=WideCharToMultiByte")
#else
#error Unknown architecture
#endif
} // namespace win32
class _win32_code_domain;
@@ -60,12 +77,23 @@ using win32_code = status_code<_win32_code_domain>;
//! (Windows only) A specialisation of `status_error` for the Win32 error code domain.
using win32_error = status_error<_win32_code_domain>;
namespace mixins
{
template <class Base> struct mixin<Base, _win32_code_domain> : public Base
{
using Base::Base;
//! Returns a `win32_code` for the current value of `GetLastError()`.
static inline win32_code current() noexcept;
};
} // namespace mixins
/*! (Windows only) The implementation of the domain for Win32 error codes, those returned by `GetLastError()`.
*/
*/
class _win32_code_domain : public status_code_domain
{
template <class DomainType> friend class status_code;
template <class StatusCode> friend class detail::indirecting_domain;
template <class StatusCode, class Allocator> friend class detail::indirecting_domain;
friend class _com_code_domain;
using _base = status_code_domain;
static int _win32_code_to_errno(win32::DWORD c)
@@ -82,7 +110,8 @@ class _win32_code_domain : public status_code_domain
static _base::string_ref _make_string_ref(win32::DWORD c) noexcept
{
wchar_t buffer[32768];
win32::DWORD wlen = win32::FormatMessageW(0x00001000 /*FORMAT_MESSAGE_FROM_SYSTEM*/ | 0x00000200 /*FORMAT_MESSAGE_IGNORE_INSERTS*/, nullptr, c, 0, buffer, 32768, nullptr);
win32::DWORD wlen =
win32::FormatMessageW(0x00001000 /*FORMAT_MESSAGE_FROM_SYSTEM*/ | 0x00000200 /*FORMAT_MESSAGE_IGNORE_INSERTS*/, nullptr, c, 0, buffer, 32768, nullptr);
size_t allocation = wlen + (wlen >> 1);
win32::DWORD bytes;
if(wlen == 0)
@@ -124,7 +153,10 @@ public:
public:
//! Default constructor
constexpr explicit _win32_code_domain(typename _base::unique_id_type id = 0x8cd18ee72d680f1b) noexcept : _base(id) {}
constexpr explicit _win32_code_domain(typename _base::unique_id_type id = 0x8cd18ee72d680f1b) noexcept
: _base(id)
{
}
_win32_code_domain(const _win32_code_domain &) = default;
_win32_code_domain(_win32_code_domain &&) = default;
_win32_code_domain &operator=(const _win32_code_domain &) = default;
@@ -135,6 +167,13 @@ public:
static inline constexpr const _win32_code_domain &get();
virtual string_ref name() const noexcept override { return string_ref("win32 domain"); } // NOLINT
virtual payload_info_t payload_info() const noexcept override
{
return {sizeof(value_type), sizeof(status_code_domain *) + sizeof(value_type),
(alignof(value_type) > alignof(status_code_domain *)) ? alignof(value_type) : alignof(status_code_domain *)};
}
protected:
virtual bool _do_failure(const status_code<void> &code) const noexcept override // NOLINT
{
@@ -188,6 +227,14 @@ inline constexpr const _win32_code_domain &_win32_code_domain::get()
return win32_code_domain;
}
namespace mixins
{
template <class Base> inline win32_code mixin<Base, _win32_code_domain>::current() noexcept
{
return win32_code(win32::GetLastError());
}
} // namespace mixins
BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_END
#endif

View File

@@ -1,502 +0,0 @@
/* Proposed SG14 status_code
(C) 2018-2019 Niall Douglas <http://www.nedproductions.biz/> (5 commits)
File Created: Feb 2018
Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#ifndef BOOST_OUTCOME_SYSTEM_ERROR2_STATUS_CODE_HPP
#define BOOST_OUTCOME_SYSTEM_ERROR2_STATUS_CODE_HPP
#include "status_code_domain.hpp"
#if __cplusplus >= 201700 || _HAS_CXX17
// 0.26
#include <utility> // for in_place
BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_BEGIN
using in_place_t = std::in_place_t;
using std::in_place;
BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_END
#else
BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_BEGIN
//! Aliases `std::in_place_t` if on C++ 17 or later, else defined locally.
struct in_place_t
{
explicit in_place_t() = default;
};
//! Aliases `std::in_place` if on C++ 17 or later, else defined locally.
constexpr in_place_t in_place{};
BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_END
#endif
BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_BEGIN
//! Namespace for user injected mixins
namespace mixins
{
template <class Base, class T> struct mixin : public Base
{
using Base::Base;
};
} // namespace mixins
/*! A tag for an erased value type for `status_code<D>`.
Available only if `ErasedType` satisfies `traits::is_move_relocating<ErasedType>::value`.
*/
template <class ErasedType, //
typename std::enable_if<traits::is_move_relocating<ErasedType>::value, bool>::type = true>
struct erased
{
using value_type = ErasedType;
};
namespace detail
{
template <class T> struct is_status_code
{
static constexpr bool value = false;
};
template <class T> struct is_status_code<status_code<T>>
{
static constexpr bool value = true;
};
template <class T> struct is_erased_status_code
{
static constexpr bool value = false;
};
template <class T> struct is_erased_status_code<status_code<erased<T>>>
{
static constexpr bool value = true;
};
// From http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4436.pdf
namespace impl
{
template <typename... Ts> struct make_void
{
using type = void;
};
template <typename... Ts> using void_t = typename make_void<Ts...>::type;
template <class...> struct types
{
using type = types;
};
template <template <class...> class T, class types, class = void> struct test_apply
{
using type = void;
};
template <template <class...> class T, class... Ts> struct test_apply<T, types<Ts...>, void_t<T<Ts...>>>
{
using type = T<Ts...>;
};
} // namespace impl
template <template <class...> class T, class... Ts> using test_apply = impl::test_apply<T, impl::types<Ts...>>;
template <class T, class... Args> using get_make_status_code_result = decltype(make_status_code(std::declval<T>(), std::declval<Args>()...));
template <class... Args> using safe_get_make_status_code_result = test_apply<get_make_status_code_result, Args...>;
} // namespace detail
//! Trait returning true if the type is a status code.
template <class T> struct is_status_code
{
static constexpr bool value = detail::is_status_code<typename std::decay<T>::type>::value || detail::is_erased_status_code<typename std::decay<T>::type>::value;
};
/*! A type erased lightweight status code reflecting empty, success, or failure.
Differs from `status_code<erased<>>` by being always available irrespective of
the domain's value type, but cannot be copied, moved, nor destructed. Thus one
always passes this around by const lvalue reference.
*/
template <> class status_code<void>
{
template <class T> friend class status_code;
public:
//! The type of the domain.
using domain_type = void;
//! The type of the status code.
using value_type = void;
//! The type of a reference to a message string.
using string_ref = typename status_code_domain::string_ref;
protected:
const status_code_domain *_domain{nullptr};
protected:
//! No default construction at type erased level
status_code() = default;
//! No public copying at type erased level
status_code(const status_code &) = default;
//! No public moving at type erased level
status_code(status_code &&) = default;
//! No public assignment at type erased level
status_code &operator=(const status_code &) = default;
//! No public assignment at type erased level
status_code &operator=(status_code &&) = default;
//! No public destruction at type erased level
~status_code() = default;
//! Used to construct a non-empty type erased status code
constexpr explicit status_code(const status_code_domain *v) noexcept : _domain(v) {}
public:
//! Return the status code domain.
constexpr const status_code_domain &domain() const noexcept { return *_domain; }
//! True if the status code is empty.
BOOST_OUTCOME_SYSTEM_ERROR2_NODISCARD constexpr bool empty() const noexcept { return _domain == nullptr; }
//! Return a reference to a string textually representing a code.
string_ref message() const noexcept { return (_domain != nullptr) ? _domain->_do_message(*this) : string_ref("(empty)"); }
//! True if code means success.
bool success() const noexcept { return (_domain != nullptr) ? !_domain->_do_failure(*this) : false; }
//! True if code means failure.
bool failure() const noexcept { return (_domain != nullptr) ? _domain->_do_failure(*this) : false; }
/*! True if code is strictly (and potentially non-transitively) semantically equivalent to another code in another domain.
Note that usually non-semantic i.e. pure value comparison is used when the other status code has the same domain.
As `equivalent()` will try mapping to generic code, this usually captures when two codes have the same semantic
meaning in `equivalent()`.
*/
template <class T> bool strictly_equivalent(const status_code<T> &o) const noexcept
{
if(_domain && o._domain)
{
return _domain->_do_equivalent(*this, o);
}
// If we are both empty, we are equivalent
if(!_domain && !o._domain)
{
return true; // NOLINT
}
// Otherwise not equivalent
return false;
}
/*! True if code is equivalent, by any means, to another code in another domain (guaranteed transitive).
Firstly `strictly_equivalent()` is run in both directions. If neither succeeds, each domain is asked
for the equivalent generic code and those are compared.
*/
template <class T> inline bool equivalent(const status_code<T> &o) const noexcept;
#if defined(_CPPUNWIND) || defined(__EXCEPTIONS) || defined(BOOST_OUTCOME_STANDARDESE_IS_IN_THE_HOUSE)
//! Throw a code as a C++ exception.
BOOST_OUTCOME_SYSTEM_ERROR2_NORETURN void throw_exception() const { _domain->_do_throw_exception(*this); }
#endif
};
namespace detail
{
template <class DomainType> struct get_domain_value_type
{
using domain_type = DomainType;
using value_type = typename domain_type::value_type;
};
template <class ErasedType> struct get_domain_value_type<erased<ErasedType>>
{
using domain_type = status_code_domain;
using value_type = ErasedType;
};
template <class DomainType> class status_code_storage : public status_code<void>
{
using _base = status_code<void>;
public:
//! The type of the domain.
using domain_type = typename get_domain_value_type<DomainType>::domain_type;
//! The type of the status code.
using value_type = typename get_domain_value_type<DomainType>::value_type;
//! The type of a reference to a message string.
using string_ref = typename domain_type::string_ref;
#ifndef NDEBUG
static_assert(std::is_move_constructible<value_type>::value || std::is_copy_constructible<value_type>::value, "DomainType::value_type is neither move nor copy constructible!");
static_assert(!std::is_default_constructible<value_type>::value || std::is_nothrow_default_constructible<value_type>::value, "DomainType::value_type is not nothrow default constructible!");
static_assert(!std::is_move_constructible<value_type>::value || std::is_nothrow_move_constructible<value_type>::value, "DomainType::value_type is not nothrow move constructible!");
static_assert(std::is_nothrow_destructible<value_type>::value, "DomainType::value_type is not nothrow destructible!");
#endif
// Replace the type erased implementations with type aware implementations for better codegen
//! Return the status code domain.
constexpr const domain_type &domain() const noexcept { return *static_cast<const domain_type *>(this->_domain); }
//! Reset the code to empty.
BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR14 void clear() noexcept
{
this->_value.~value_type();
this->_domain = nullptr;
new(&this->_value) value_type();
}
#if __cplusplus >= 201400 || _MSC_VER >= 1910 /* VS2017 */
//! Return a reference to the `value_type`.
constexpr value_type &value() & noexcept { return this->_value; }
//! Return a reference to the `value_type`.
constexpr value_type &&value() && noexcept { return this->_value; }
#endif
//! Return a reference to the `value_type`.
constexpr const value_type &value() const &noexcept { return this->_value; }
//! Return a reference to the `value_type`.
constexpr const value_type &&value() const &&noexcept { return this->_value; }
protected:
status_code_storage() = default;
status_code_storage(const status_code_storage &) = default;
BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR14 status_code_storage(status_code_storage &&o) noexcept : _base(static_cast<status_code_storage &&>(o)), _value(static_cast<status_code_storage &&>(o)._value) { o._domain = nullptr; }
status_code_storage &operator=(const status_code_storage &) = default;
BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR14 status_code_storage &operator=(status_code_storage &&o) noexcept
{
this->~status_code_storage();
new(this) status_code_storage(static_cast<status_code_storage &&>(o));
return *this;
}
~status_code_storage() = default;
value_type _value{};
struct _value_type_constructor
{
};
template <class... Args>
constexpr status_code_storage(_value_type_constructor /*unused*/, const status_code_domain *v, Args &&... args)
: _base(v)
, _value(static_cast<Args &&>(args)...)
{
}
};
} // namespace detail
/*! A lightweight, typed, status code reflecting empty, success, or failure.
This is the main workhorse of the system_error2 library. Its characteristics reflect the value type
set by its domain type, so if that value type is move-only or trivial, so is this.
An ADL discovered helper function `make_status_code(T, Args...)` is looked up by one of the constructors.
If it is found, and it generates a status code compatible with this status code, implicit construction
is made available.
You may mix in custom member functions and member function overrides by injecting a specialisation of
`mixins::mixin<Base, YourDomainType>`. Your mixin must inherit from `Base`.
*/
template <class DomainType> class status_code : public mixins::mixin<detail::status_code_storage<DomainType>, DomainType>
{
template <class T> friend class status_code;
using _base = mixins::mixin<detail::status_code_storage<DomainType>, DomainType>;
public:
//! The type of the domain.
using domain_type = DomainType;
//! The type of the status code.
using value_type = typename domain_type::value_type;
//! The type of a reference to a message string.
using string_ref = typename domain_type::string_ref;
public:
//! Default construction to empty
status_code() = default;
//! Copy constructor
status_code(const status_code &) = default;
//! Move constructor
status_code(status_code &&) = default; // NOLINT
//! Copy assignment
status_code &operator=(const status_code &) = default;
//! Move assignment
status_code &operator=(status_code &&) = default; // NOLINT
~status_code() = default;
//! Return a copy of the code.
BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR14 status_code clone() const { return *this; }
/***** KEEP THESE IN SYNC WITH ERRORED_STATUS_CODE *****/
//! Implicit construction from any type where an ADL discovered `make_status_code(T, Args ...)` returns a `status_code`.
template <class T, class... Args, //
class MakeStatusCodeResult = typename detail::safe_get_make_status_code_result<T, Args...>::type, // Safe ADL lookup of make_status_code(), returns void if not found
typename std::enable_if<!std::is_same<typename std::decay<T>::type, status_code>::value // not copy/move of self
&& !std::is_same<typename std::decay<T>::type, in_place_t>::value // not in_place_t
&& is_status_code<MakeStatusCodeResult>::value // ADL makes a status code
&& std::is_constructible<status_code, MakeStatusCodeResult>::value, // ADLed status code is compatible
bool>::type = true>
constexpr status_code(T &&v, Args &&... args) noexcept(noexcept(make_status_code(std::declval<T>(), std::declval<Args>()...))) // NOLINT
: status_code(make_status_code(static_cast<T &&>(v), static_cast<Args &&>(args)...))
{
}
//! Explicit in-place construction.
template <class... Args>
constexpr explicit status_code(in_place_t /*unused */, Args &&... args) noexcept(std::is_nothrow_constructible<value_type, Args &&...>::value)
: _base(typename _base::_value_type_constructor{}, &domain_type::get(), static_cast<Args &&>(args)...)
{
}
//! Explicit in-place construction from initialiser list.
template <class T, class... Args>
constexpr explicit status_code(in_place_t /*unused */, std::initializer_list<T> il, Args &&... args) noexcept(std::is_nothrow_constructible<value_type, std::initializer_list<T>, Args &&...>::value)
: _base(typename _base::_value_type_constructor{}, &domain_type::get(), il, static_cast<Args &&>(args)...)
{
}
//! Explicit copy construction from a `value_type`.
constexpr explicit status_code(const value_type &v) noexcept(std::is_nothrow_copy_constructible<value_type>::value)
: _base(typename _base::_value_type_constructor{}, &domain_type::get(), v)
{
}
//! Explicit move construction from a `value_type`.
constexpr explicit status_code(value_type &&v) noexcept(std::is_nothrow_move_constructible<value_type>::value)
: _base(typename _base::_value_type_constructor{}, &domain_type::get(), static_cast<value_type &&>(v))
{
}
/*! Explicit construction from an erased status code. Available only if
`value_type` is trivially copyable or move relocating, and `sizeof(status_code) <= sizeof(status_code<erased<>>)`.
Does not check if domains are equal.
*/
template <class ErasedType, //
typename std::enable_if<detail::type_erasure_is_safe<ErasedType, value_type>::value, bool>::type = true>
constexpr explicit status_code(const status_code<erased<ErasedType>> &v) noexcept(std::is_nothrow_copy_constructible<value_type>::value)
: status_code(detail::erasure_cast<value_type>(v.value()))
{
#if __cplusplus >= 201400
assert(v.domain() == this->domain());
#endif
}
//! Assignment from a `value_type`.
BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR14 status_code &operator=(const value_type &v) noexcept(std::is_nothrow_copy_assignable<value_type>::value)
{
this->_value = v;
return *this;
}
//! Return a reference to a string textually representing a code.
string_ref message() const noexcept { return this->_domain ? string_ref(this->domain()._do_message(*this)) : string_ref("(empty)"); }
};
namespace traits
{
template <class DomainType> struct is_move_relocating<status_code<DomainType>>
{
static constexpr bool value = is_move_relocating<typename DomainType::value_type>::value;
};
} // namespace traits
/*! Type erased, move-only status_code, unlike `status_code<void>` which cannot be moved nor destroyed. Available
only if `erased<>` is available, which is when the domain's type is trivially
copyable or is move relocatable, and if the size of the domain's typed error code is less than or equal to
this erased error code. Copy construction is disabled, but if you want a copy call `.clone()`.
An ADL discovered helper function `make_status_code(T, Args...)` is looked up by one of the constructors.
If it is found, and it generates a status code compatible with this status code, implicit construction
is made available.
*/
template <class ErasedType> class status_code<erased<ErasedType>> : public mixins::mixin<detail::status_code_storage<erased<ErasedType>>, erased<ErasedType>>
{
template <class T> friend class status_code;
using _base = mixins::mixin<detail::status_code_storage<erased<ErasedType>>, erased<ErasedType>>;
public:
//! The type of the domain (void, as it is erased).
using domain_type = void;
//! The type of the erased status code.
using value_type = ErasedType;
//! The type of a reference to a message string.
using string_ref = typename _base::string_ref;
public:
//! Default construction to empty
status_code() = default;
//! Copy constructor
status_code(const status_code &) = delete;
//! Move constructor
status_code(status_code &&) = default; // NOLINT
//! Copy assignment
status_code &operator=(const status_code &) = delete;
//! Move assignment
status_code &operator=(status_code &&) = default; // NOLINT
~status_code()
{
if(nullptr != this->_domain)
{
this->_domain->_do_erased_destroy(*this, sizeof(*this));
}
}
//! Return a copy of the erased code by asking the domain to perform the erased copy.
status_code clone() const
{
if(nullptr == this->_domain)
{
return {};
}
status_code x;
this->_domain->_do_erased_copy(x, *this, sizeof(*this));
return x;
}
/***** KEEP THESE IN SYNC WITH ERRORED_STATUS_CODE *****/
//! Implicit copy construction from any other status code if its value type is trivially copyable and it would fit into our storage
template <class DomainType, //
typename std::enable_if<!detail::is_erased_status_code<status_code<DomainType>>::value //
&& std::is_trivially_copyable<typename DomainType::value_type>::value //
&& detail::type_erasure_is_safe<value_type, typename DomainType::value_type>::value,
bool>::type = true>
constexpr status_code(const status_code<DomainType> &v) noexcept // NOLINT
: _base(typename _base::_value_type_constructor{}, &v.domain(), detail::erasure_cast<value_type>(v.value()))
{
}
//! Implicit move construction from any other status code if its value type is trivially copyable or move relocating and it would fit into our storage
template <class DomainType, //
typename std::enable_if<detail::type_erasure_is_safe<value_type, typename DomainType::value_type>::value, bool>::type = true>
BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR14 status_code(status_code<DomainType> &&v) noexcept // NOLINT
: _base(typename _base::_value_type_constructor{}, &v.domain(), detail::erasure_cast<value_type>(v.value()))
{
v._domain = nullptr;
}
//! Implicit construction from any type where an ADL discovered `make_status_code(T, Args ...)` returns a `status_code`.
template <class T, class... Args, //
class MakeStatusCodeResult = typename detail::safe_get_make_status_code_result<T, Args...>::type, // Safe ADL lookup of make_status_code(), returns void if not found
typename std::enable_if<!std::is_same<typename std::decay<T>::type, status_code>::value // not copy/move of self
&& !std::is_same<typename std::decay<T>::type, value_type>::value // not copy/move of value type
&& is_status_code<MakeStatusCodeResult>::value // ADL makes a status code
&& std::is_constructible<status_code, MakeStatusCodeResult>::value, // ADLed status code is compatible
bool>::type = true>
constexpr status_code(T &&v, Args &&... args) noexcept(noexcept(make_status_code(std::declval<T>(), std::declval<Args>()...))) // NOLINT
: status_code(make_status_code(static_cast<T &&>(v), static_cast<Args &&>(args)...))
{
}
/**** By rights ought to be removed in any formal standard ****/
//! Reset the code to empty.
BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR14 void clear() noexcept { *this = status_code(); }
//! Return the erased `value_type` by value.
constexpr value_type value() const noexcept { return this->_value; }
};
namespace traits
{
template <class ErasedType> struct is_move_relocating<status_code<erased<ErasedType>>>
{
static constexpr bool value = true;
};
} // namespace traits
BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_END
#endif

View File

@@ -1,137 +0,0 @@
/* Pointer to a SG14 status_code
(C) 2018-2019 Niall Douglas <http://www.nedproductions.biz/> (5 commits)
File Created: Sep 2018
Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#ifndef BOOST_OUTCOME_SYSTEM_ERROR2_STATUS_CODE_PTR_HPP
#define BOOST_OUTCOME_SYSTEM_ERROR2_STATUS_CODE_PTR_HPP
#include "status_code.hpp"
BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_BEGIN
namespace detail
{
template <class StatusCode> class indirecting_domain : public status_code_domain
{
template <class DomainType> friend class status_code;
using _base = status_code_domain;
public:
using value_type = StatusCode *;
using _base::string_ref;
constexpr indirecting_domain() noexcept : _base(0xc44f7bdeb2cc50e9 ^ typename StatusCode::domain_type().id() /* unique-ish based on domain's unique id */) {}
indirecting_domain(const indirecting_domain &) = default;
indirecting_domain(indirecting_domain &&) = default; // NOLINT
indirecting_domain &operator=(const indirecting_domain &) = default;
indirecting_domain &operator=(indirecting_domain &&) = default; // NOLINT
~indirecting_domain() = default;
#if __cplusplus < 201402L && !defined(_MSC_VER)
static inline const indirecting_domain &get()
{
static indirecting_domain v;
return v;
}
#else
static inline constexpr const indirecting_domain &get();
#endif
virtual string_ref name() const noexcept override { return typename StatusCode::domain_type().name(); } // NOLINT
protected:
using _mycode = status_code<indirecting_domain>;
virtual bool _do_failure(const status_code<void> &code) const noexcept override // NOLINT
{
assert(code.domain() == *this);
const auto &c = static_cast<const _mycode &>(code); // NOLINT
return typename StatusCode::domain_type()._do_failure(*c.value());
}
virtual bool _do_equivalent(const status_code<void> &code1, const status_code<void> &code2) const noexcept override // NOLINT
{
assert(code1.domain() == *this);
const auto &c1 = static_cast<const _mycode &>(code1); // NOLINT
return typename StatusCode::domain_type()._do_equivalent(*c1.value(), code2);
}
virtual generic_code _generic_code(const status_code<void> &code) const noexcept override // NOLINT
{
assert(code.domain() == *this);
const auto &c = static_cast<const _mycode &>(code); // NOLINT
return typename StatusCode::domain_type()._generic_code(*c.value());
}
virtual string_ref _do_message(const status_code<void> &code) const noexcept override // NOLINT
{
assert(code.domain() == *this);
const auto &c = static_cast<const _mycode &>(code); // NOLINT
return typename StatusCode::domain_type()._do_message(*c.value());
}
#if defined(_CPPUNWIND) || defined(__EXCEPTIONS) || defined(BOOST_OUTCOME_STANDARDESE_IS_IN_THE_HOUSE)
BOOST_OUTCOME_SYSTEM_ERROR2_NORETURN virtual void _do_throw_exception(const status_code<void> &code) const override // NOLINT
{
assert(code.domain() == *this);
const auto &c = static_cast<const _mycode &>(code); // NOLINT
typename StatusCode::domain_type()._do_throw_exception(*c.value());
}
#endif
virtual void _do_erased_copy(status_code<void> &dst, const status_code<void> &src, size_t /*unused*/) const override // NOLINT
{
assert(dst.domain() == *this);
assert(src.domain() == *this);
auto &d = static_cast<_mycode &>(dst); // NOLINT
const auto &_s = static_cast<const _mycode &>(src); // NOLINT
const StatusCode &s = *_s.value();
new(&d) _mycode(in_place, new StatusCode(s));
}
virtual void _do_erased_destroy(status_code<void> &code, size_t /*unused*/) const noexcept override // NOLINT
{
assert(code.domain() == *this);
auto &c = static_cast<_mycode &>(code); // NOLINT
delete c.value(); // NOLINT
}
};
#if __cplusplus >= 201402L || defined(_MSC_VER)
template <class StatusCode> constexpr indirecting_domain<StatusCode> _indirecting_domain{};
template <class StatusCode> inline constexpr const indirecting_domain<StatusCode> &indirecting_domain<StatusCode>::get() { return _indirecting_domain<StatusCode>; }
#endif
} // namespace detail
/*! Make an erased status code which indirects to a dynamically allocated status code.
This is useful for shoehorning a rich status code with large value type into a small
erased status code like `system_code`, with which the status code generated by this
function is compatible. Note that this function can throw due to `bad_alloc`.
*/
template <class T, typename std::enable_if<is_status_code<T>::value, bool>::type = true> //
inline status_code<erased<typename std::add_pointer<typename std::decay<T>::type>::type>> make_status_code_ptr(T &&v)
{
using status_code_type = typename std::decay<T>::type;
return status_code<detail::indirecting_domain<status_code_type>>(in_place, new status_code_type(static_cast<T &&>(v)));
}
BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_END
#endif

View File

@@ -1,104 +0,0 @@
/* Proposed SG14 status_code
(C) 2018-2019 Niall Douglas <http://www.nedproductions.biz/> (5 commits)
File Created: Feb 2018
Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#ifndef BOOST_OUTCOME_SYSTEM_ERROR2_STATUS_ERROR_HPP
#define BOOST_OUTCOME_SYSTEM_ERROR2_STATUS_ERROR_HPP
#include "status_code.hpp"
#include <exception> // for std::exception
BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_BEGIN
/*! Exception type representing a thrown status_code
*/
template <class DomainType> class status_error;
/*! The erased type edition of status_error.
*/
template <> class status_error<void> : public std::exception
{
protected:
//! Constructs an instance. Not publicly available.
status_error() = default;
//! Copy constructor. Not publicly available
status_error(const status_error &) = default;
//! Move constructor. Not publicly available
status_error(status_error &&) = default;
//! Copy assignment. Not publicly available
status_error &operator=(const status_error &) = default;
//! Move assignment. Not publicly available
status_error &operator=(status_error &&) = default;
//! Destructor. Not publicly available.
~status_error() override = default;
public:
//! The type of the status domain
using domain_type = void;
//! The type of the status code
using status_code_type = status_code<void>;
};
/*! Exception type representing a thrown status_code
*/
template <class DomainType> class status_error : public status_error<void>
{
status_code<DomainType> _code;
typename DomainType::string_ref _msgref;
public:
//! The type of the status domain
using domain_type = DomainType;
//! The type of the status code
using status_code_type = status_code<DomainType>;
//! Constructs an instance
explicit status_error(status_code<DomainType> code)
: _code(static_cast<status_code<DomainType> &&>(code))
, _msgref(_code.message())
{
}
//! Return an explanatory string
virtual const char *what() const noexcept override { return _msgref.c_str(); } // NOLINT
//! Returns a reference to the code
const status_code_type &code() const & { return _code; }
//! Returns a reference to the code
status_code_type &code() & { return _code; }
//! Returns a reference to the code
const status_code_type &&code() const && { return _code; }
//! Returns a reference to the code
status_code_type &&code() && { return _code; }
};
BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_END
#endif

View File

@@ -1,184 +0,0 @@
/* Proposed SG14 status_code
(C) 2018-2019 Niall Douglas <http://www.nedproductions.biz/> (5 commits)
File Created: Aug 2018
Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#ifndef BOOST_OUTCOME_SYSTEM_ERROR2_STD_ERROR_CODE_HPP
#define BOOST_OUTCOME_SYSTEM_ERROR2_STD_ERROR_CODE_HPP
#include "posix_code.hpp"
#if defined(_WIN32) || defined(BOOST_OUTCOME_STANDARDESE_IS_IN_THE_HOUSE)
#include "win32_code.hpp"
#endif
#include <system_error>
BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_BEGIN
namespace detail
{
struct make_std_categories
{
static const std::error_category &generic_category() { return std::generic_category(); }
static const std::error_category &system_category() { return std::system_category(); }
};
}
template <class error_code_type, class make_category_types> class _error_code_domain;
//! A wrapper of `std::error_code`.
using std_error_code = status_code<_error_code_domain<std::error_code, detail::make_std_categories>>;
/*! The implementation of the domain for `std::error_code` error codes.
*/
template <class error_code_type, class make_categories_type> class _error_code_domain : public status_code_domain
{
template <class DomainType> friend class status_code;
template <class StatusCode> friend class detail::indirecting_domain;
using _base = status_code_domain;
using _status_code = status_code<_error_code_domain>;
static _base::string_ref _make_string_ref(error_code_type c) noexcept
{
try
{
std::string msg = c.message();
auto *p = static_cast<char *>(malloc(msg.size() + 1)); // NOLINT
if(p == nullptr)
{
return _base::string_ref("failed to allocate message");
}
memcpy(p, msg.c_str(), msg.size() + 1);
return _base::atomic_refcounted_string_ref(p, msg.size());
}
catch(...)
{
return _base::string_ref("failed to allocate message");
}
}
public:
//! The value type of the `std::error_code` code, which is the `std::error_code`
using value_type = error_code_type;
using _base::string_ref;
//! Default constructor
constexpr explicit _error_code_domain(typename _base::unique_id_type id = 0x223a160d20de97b4) noexcept : _base(id) {}
_error_code_domain(const _error_code_domain &) = default;
_error_code_domain(_error_code_domain &&) = default;
_error_code_domain &operator=(const _error_code_domain &) = default;
_error_code_domain &operator=(_error_code_domain &&) = default;
~_error_code_domain() = default;
//! Constexpr singleton getter. Returns constexpr error_code_domain variable.
static inline constexpr const _error_code_domain &get();
virtual string_ref name() const noexcept override { return string_ref("error_code compatibility domain"); } // NOLINT
protected:
virtual bool _do_failure(const status_code<void> &code) const noexcept override final // NOLINT
{
assert(code.domain() == *this);
return static_cast<const _status_code &>(code).value().value() != 0; // NOLINT
}
virtual bool _do_equivalent(const status_code<void> &code1, const status_code<void> &code2) const noexcept override final // NOLINT
{
assert(code1.domain() == *this);
const auto &c1 = static_cast<const _status_code &>(code1); // NOLINT
const auto &cat1 = c1.value().category();
// Are we comparing to another wrapped error_code?
if(code2.domain() == *this)
{
const auto &c2 = static_cast<const _status_code &>(code2); // NOLINT
const auto &cat2 = c2.value().category();
// If the error code categories are identical, do literal comparison
if(cat1 == cat2)
{
return c1.value().value() == c2.value().value();
}
// Otherwise fall back onto the _generic_code comparison, which uses default_error_condition()
return false;
}
// Am I an error code with generic category?
const auto &generic_category = make_categories_type::generic_category();
if(cat1 == generic_category)
{
// Convert to generic code, and compare that
generic_code _c1(static_cast<errc>(c1.value().value()));
return _c1 == code2;
}
// Am I an error code with system category?
const auto &system_category = make_categories_type::system_category();
if(cat1 == system_category)
{
// Convert to POSIX or Win32 code, and compare that
#ifdef _WIN32
win32_code _c1((win32::DWORD) c1.value().value());
#else
posix_code _c1(c1.value().value());
#endif
return _c1 == code2;
}
return false;
}
virtual generic_code _generic_code(const status_code<void> &code) const noexcept override final // NOLINT
{
assert(code.domain() == *this);
const auto &c = static_cast<const _status_code &>(code); // NOLINT
// Ask my embedded error code for its mapping to std::errc, which is a subset of our generic_code errc.
return generic_code(static_cast<errc>(c.value().default_error_condition().value()));
}
virtual string_ref _do_message(const status_code<void> &code) const noexcept override // NOLINT
{
assert(code.domain() == *this);
const auto &c = static_cast<const _status_code &>(code); // NOLINT
return _make_string_ref(c.value());
}
#if defined(_CPPUNWIND) || defined(__EXCEPTIONS) || defined(BOOST_OUTCOME_STANDARDESE_IS_IN_THE_HOUSE)
BOOST_OUTCOME_SYSTEM_ERROR2_NORETURN virtual void _do_throw_exception(const status_code<void> &code) const override // NOLINT
{
assert(code.domain() == *this);
const auto &c = static_cast<const _status_code &>(code); // NOLINT
throw std::system_error(c.value());
}
#endif
};
//! A constexpr source variable for the `std::error_code` code domain. Returned by `_error_code_domain<error_code_type, detail::make_std_categoriesy>::get()`.
constexpr _error_code_domain<std::error_code, detail::make_std_categories> std_error_code_domain;
template <class error_code_type, class make_categories_type> inline constexpr const _error_code_domain<error_code_type, make_categories_type> &_error_code_domain<error_code_type, make_categories_type>::get()
{
return std_error_code_domain;
}
// Enable implicit construction of `std_error_code` from `std::error_code`.
inline std_error_code make_status_code(std::error_code c) noexcept
{
return std_error_code(in_place, c);
}
BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_END
#endif

View File

@@ -1,5 +1,5 @@
/* A less simple result type
(C) 2018-2019 Niall Douglas <http://www.nedproductions.biz/> (59 commits)
(C) 2018-2023 Niall Douglas <http://www.nedproductions.biz/> (17 commits)
File Created: Apr 2018
@@ -58,57 +58,73 @@ BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_END
BOOST_OUTCOME_V2_NAMESPACE_EXPORT_BEGIN
namespace trait
{
namespace detail
{
// Shortcut this for lower build impact
template <class DomainType> struct _is_error_code_available<BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::status_code<DomainType>>
{
static constexpr bool value = true;
};
template <class DomainType> struct _is_error_code_available<BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::errored_status_code<DomainType>>
{
static constexpr bool value = true;
};
} // namespace detail
#if 0
template <class DomainType> struct is_error_type<BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::status_code<DomainType>>
{
static constexpr bool value = true;
};
template <> struct is_error_type<BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::errc>
{
static constexpr bool value = true;
};
template <class DomainType, class Enum> struct is_error_type_enum<BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::status_code<DomainType>, Enum>
{
static constexpr bool value = boost::system::is_error_condition_enum<Enum>::value;
};
#endif
} // namespace trait
namespace experimental
{
namespace policy
{
template <class T, class EC, class E>
using default_status_outcome_policy = std::conditional_t< //
std::is_void<EC>::value && std::is_void<E>::value, //
BOOST_OUTCOME_V2_NAMESPACE::policy::terminate, //
std::conditional_t<(is_status_code<EC>::value || is_errored_status_code<EC>::value) && (std::is_void<E>::value || BOOST_OUTCOME_V2_NAMESPACE::trait::is_exception_ptr_available<E>::value), //
status_code_throw<T, EC, E>, //
BOOST_OUTCOME_V2_NAMESPACE::policy::fail_to_compile_observers //
using default_status_outcome_policy = std::conditional_t< //
std::is_void<EC>::value && std::is_void<E>::value, //
BOOST_OUTCOME_V2_NAMESPACE::policy::terminate, //
std::conditional_t<(is_status_code<EC>::value || is_errored_status_code<EC>::value) &&
(std::is_void<E>::value || BOOST_OUTCOME_V2_NAMESPACE::trait::is_exception_ptr_available<E>::value), //
status_code_throw<T, EC, E>, //
BOOST_OUTCOME_V2_NAMESPACE::policy::fail_to_compile_observers //
>>;
} // namespace policy
/*! AWAITING HUGO JSON CONVERSION TOOL
/*! AWAITING HUGO JSON CONVERSION TOOL
SIGNATURE NOT RECOGNISED
*/
template <class R, class S = system_code, class P = std::exception_ptr, class NoValuePolicy = policy::default_status_outcome_policy<R, S, P>> //
template <class R, class S = erased_errored_status_code<typename system_code::value_type>, class P = std::exception_ptr,
class NoValuePolicy = policy::default_status_outcome_policy<R, S, P>> //
using status_outcome = basic_outcome<R, S, P, NoValuePolicy>;
/*! AWAITING HUGO JSON CONVERSION TOOL
SIGNATURE NOT RECOGNISED
*/
BOOST_OUTCOME_TEMPLATE(class R, class S, class P, class NoValuePolicy)
BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(std::is_copy_constructible<R>::value &&std::is_copy_constructible<P>::value &&
(is_status_code<S>::value || is_errored_status_code<S>::value)))
inline basic_outcome<R, S, P, NoValuePolicy> clone(const basic_outcome<R, S, P, NoValuePolicy> &v)
{
if(v)
{
return success_type<R>(v.assume_value());
}
if(v.has_error() && v.has_exception())
{
return failure_type<S, P>(v.assume_error().clone(), v.assume_exception(), hooks::spare_storage(&v));
}
if(v.has_exception())
{
return failure_type<S, P>(in_place_type<P>, v.assume_exception(), hooks::spare_storage(&v));
}
return failure_type<S, P>(in_place_type<S>, v.assume_error().clone(), hooks::spare_storage(&v));
}
/*! AWAITING HUGO JSON CONVERSION TOOL
SIGNATURE NOT RECOGNISED
*/
BOOST_OUTCOME_TEMPLATE(class S, class P, class NoValuePolicy)
BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(std::is_copy_constructible<P>::value && (is_status_code<S>::value || is_errored_status_code<S>::value)))
inline basic_outcome<void, S, P, NoValuePolicy> clone(const basic_outcome<void, S, P, NoValuePolicy> &v)
{
if(v)
{
return success_type<void>();
}
if(v.has_error() && v.has_exception())
{
return failure_type<S, P>(v.assume_error().clone(), v.assume_exception(), hooks::spare_storage(&v));
}
if(v.has_exception())
{
return failure_type<S, P>(in_place_type<P>, v.assume_exception(), hooks::spare_storage(&v));
}
return failure_type<S, P>(in_place_type<S>, v.assume_error().clone(), hooks::spare_storage(&v));
}
namespace policy
{
template <class T, class DomainType, class E> struct status_code_throw<T, status_code<DomainType>, E> : base
@@ -120,7 +136,8 @@ SIGNATURE NOT RECOGNISED
{
if(base::_has_exception(static_cast<Impl &&>(self)))
{
BOOST_OUTCOME_V2_NAMESPACE::policy::detail::_rethrow_exception<trait::is_exception_ptr_available<E>::value>(base::_exception<T, status_code<DomainType>, E, status_code_throw>(static_cast<Impl &&>(self))); // NOLINT
BOOST_OUTCOME_V2_NAMESPACE::policy::detail::_rethrow_exception<trait::is_exception_ptr_available<E>::value>(
base::_exception<T, status_code<DomainType>, E, status_code_throw>(static_cast<Impl &&>(self))); // NOLINT
}
if(base::_has_error(static_cast<Impl &&>(self)))
{
@@ -135,7 +152,8 @@ SIGNATURE NOT RECOGNISED
template <class Impl> static constexpr void wide_error_check(Impl &&self) { _base::narrow_error_check(static_cast<Impl &&>(self)); }
template <class Impl> static constexpr void wide_exception_check(Impl &&self) { _base::narrow_exception_check(static_cast<Impl &&>(self)); }
};
template <class T, class DomainType, class E> struct status_code_throw<T, errored_status_code<DomainType>, E> : status_code_throw<T, status_code<DomainType>, E>
template <class T, class DomainType, class E>
struct status_code_throw<T, errored_status_code<DomainType>, E> : status_code_throw<T, status_code<DomainType>, E>
{
status_code_throw() = default;
using status_code_throw<T, status_code<DomainType>, E>::status_code_throw;

View File

@@ -1,5 +1,5 @@
/* A very simple result type
(C) 2018-2019 Niall Douglas <http://www.nedproductions.biz/> (59 commits)
(C) 2018-2023 Niall Douglas <http://www.nedproductions.biz/> (11 commits)
File Created: Apr 2018
@@ -34,31 +34,97 @@ DEALINGS IN THE SOFTWARE.
#include "../basic_result.hpp"
#include "../policy/fail_to_compile_observers.hpp"
#include "status-code/system_error2.hpp"
#ifndef BOOST_OUTCOME_SYSTEM_ERROR2_USE_STD_ADDRESSOF
#if BOOST_OUTCOME_USE_STD_ADDRESSOF
#define BOOST_OUTCOME_SYSTEM_ERROR2_USE_STD_ADDRESSOF 1
#endif
#endif
#if __PCPP_ALWAYS_TRUE__
#include "status-code/status-code/system_error2.hpp"
#elif !BOOST_OUTCOME_USE_SYSTEM_STATUS_CODE && __has_include("status-code/status-code/system_error2.hpp")
#include "status-code/status-code/system_error2.hpp"
#else
#include <status-code/system_error2.hpp>
#endif
BOOST_OUTCOME_V2_NAMESPACE_EXPORT_BEGIN
namespace trait
{
namespace detail
{
// Shortcut this for lower build impact. Used to tell outcome's converting constructors
// that they can do E => EC or E => EP as necessary.
template <class DomainType> struct _is_error_code_available<BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::status_code<DomainType>>
{
static constexpr bool value = true;
using type = BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::status_code<DomainType>;
};
template <class DomainType> struct _is_error_code_available<BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::errored_status_code<DomainType>>
{
static constexpr bool value = true;
using type = BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::errored_status_code<DomainType>;
};
} // namespace detail
#if 0 // Do NOT enable weakened implicit construction for these types
template <class DomainType> struct is_error_type<BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::status_code<DomainType>>
{
static constexpr bool value = true;
};
template <> struct is_error_type<BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::errc>
{
static constexpr bool value = true;
};
template <class DomainType, class Enum> struct is_error_type_enum<BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::status_code<DomainType>, Enum>
{
static constexpr bool value = boost::system::is_error_condition_enum<Enum>::value;
};
#endif
template <class DomainType> struct is_move_bitcopying<BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::status_code<DomainType>>
{
static constexpr bool value = BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::traits::is_move_bitcopying<BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::status_code<DomainType>>::value;
};
template <class DomainType> struct is_move_bitcopying<BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::errored_status_code<DomainType>>
{
static constexpr bool value = BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::traits::is_move_bitcopying<BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::errored_status_code<DomainType>>::value;
};
} // namespace trait
namespace detail
{
// Customise _set_error_is_errno
template <class State> constexpr inline void _set_error_is_errno(State &state, const BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::generic_code & /*unused*/) { state._status |= status_error_is_errno; }
template <class State> constexpr inline void _set_error_is_errno(State &state, const BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::posix_code & /*unused*/) { state._status |= status_error_is_errno; }
template <class State> constexpr inline void _set_error_is_errno(State &state, const BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::errc & /*unused*/) { state._status |= status_error_is_errno; }
template <class State> constexpr inline void _set_error_is_errno(State &state, const BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::generic_code & /*unused*/)
{
state._status.set_have_error_is_errno(true);
}
#ifndef BOOST_OUTCOME_SYSTEM_ERROR2_NOT_POSIX
template <class State> constexpr inline void _set_error_is_errno(State &state, const BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::posix_code & /*unused*/)
{
state._status.set_have_error_is_errno(true);
}
#endif
template <class State> constexpr inline void _set_error_is_errno(State &state, const BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::errc & /*unused*/)
{
state._status.set_have_error_is_errno(true);
}
} // namespace detail
namespace experimental
{
using namespace BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE;
using BOOST_OUTCOME_V2_NAMESPACE::success;
using BOOST_OUTCOME_V2_NAMESPACE::failure;
using BOOST_OUTCOME_V2_NAMESPACE::success;
namespace policy
{
using namespace BOOST_OUTCOME_V2_NAMESPACE::policy;
template <class T, class EC, class E> struct status_code_throw
{
static_assert(!std::is_same<T, T>::value, "policy::status_code_throw not specialised for these types, did you use status_result<T, status_code<DomainType>, E>?");
static_assert(!std::is_same<T, T>::value,
"policy::status_code_throw not specialised for these types, did you use status_result<T, status_code<DomainType>, E>?");
};
template <class T, class DomainType> struct status_code_throw<T, status_code<DomainType>, void> : base
{
@@ -79,7 +145,8 @@ namespace experimental
}
template <class Impl> static constexpr void wide_error_check(Impl &&self) { _base::narrow_error_check(static_cast<Impl &&>(self)); }
};
template <class T, class DomainType> struct status_code_throw<T, errored_status_code<DomainType>, void> : status_code_throw<T, status_code<DomainType>, void>
template <class T, class DomainType>
struct status_code_throw<T, errored_status_code<DomainType>, void> : status_code_throw<T, status_code<DomainType>, void>
{
status_code_throw() = default;
using status_code_throw<T, status_code<DomainType>, void>::status_code_throw;
@@ -95,12 +162,41 @@ namespace experimental
>>;
} // namespace policy
/*! AWAITING HUGO JSON CONVERSION TOOL
/*! AWAITING HUGO JSON CONVERSION TOOL
SIGNATURE NOT RECOGNISED
*/
template <class R, class S = system_code, class NoValuePolicy = policy::default_status_result_policy<R, S>> //
template <class R, class S = erased_errored_status_code<typename system_code::value_type>,
class NoValuePolicy = policy::default_status_result_policy<R, S>> //
using status_result = basic_result<R, S, NoValuePolicy>;
/*! AWAITING HUGO JSON CONVERSION TOOL
SIGNATURE NOT RECOGNISED
*/
BOOST_OUTCOME_TEMPLATE(class R, class S, class NoValuePolicy)
BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(std::is_copy_constructible<R>::value && (is_status_code<S>::value || is_errored_status_code<S>::value)))
inline basic_result<R, S, NoValuePolicy> clone(const basic_result<R, S, NoValuePolicy> &v)
{
if(v)
{
return success_type<R>(v.assume_value());
}
return failure_type<S>(v.assume_error().clone(), hooks::spare_storage(&v));
}
/*! AWAITING HUGO JSON CONVERSION TOOL
SIGNATURE NOT RECOGNISED
*/
BOOST_OUTCOME_TEMPLATE(class S, class NoValuePolicy)
BOOST_OUTCOME_TREQUIRES(BOOST_OUTCOME_TPRED(is_status_code<S>::value || is_errored_status_code<S>::value))
inline basic_result<void, S, NoValuePolicy> clone(const basic_result<void, S, NoValuePolicy> &v)
{
if(v)
{
return success_type<void>();
}
return failure_type<S>(v.assume_error().clone(), hooks::spare_storage(&v));
}
} // namespace experimental
BOOST_OUTCOME_V2_NAMESPACE_END