add boost on mac
This commit is contained in:
82
macx64/include/boost/outcome/experimental/result.h
Normal file
82
macx64/include/boost/outcome/experimental/result.h
Normal file
@@ -0,0 +1,82 @@
|
||||
/* C interface for result
|
||||
(C) 2017-2019 Niall Douglas <http://www.nedproductions.biz/> (59 commits)
|
||||
File Created: Aug 2017
|
||||
|
||||
|
||||
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_RESULT_H
|
||||
#define BOOST_OUTCOME_EXPERIMENTAL_RESULT_H
|
||||
|
||||
#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; \
|
||||
}
|
||||
|
||||
#define BOOST_OUTCOME_C_RESULT(ident) struct cxx_result_##ident
|
||||
|
||||
|
||||
#define BOOST_OUTCOME_C_RESULT_HAS_VALUE(r) (((r).flags & 1U) == 1U)
|
||||
|
||||
#define BOOST_OUTCOME_C_RESULT_HAS_ERROR(r) (((r).flags & 2U) == 2U)
|
||||
|
||||
#define BOOST_OUTCOME_C_RESULT_ERROR_IS_ERRNO(r) (((r).flags & (1U << 4U)) == (1U << 4U))
|
||||
|
||||
|
||||
/***************************** <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_STATUS_CODE(ident) struct cxx_status_code_##ident
|
||||
|
||||
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,240 @@
|
||||
/* 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_COM_CODE_HPP
|
||||
#define BOOST_OUTCOME_SYSTEM_ERROR2_COM_CODE_HPP
|
||||
|
||||
#if !defined(_WIN32) && !defined(BOOST_OUTCOME_STANDARDESE_IS_IN_THE_HOUSE)
|
||||
#error This file should only be included on Windows
|
||||
#endif
|
||||
|
||||
#include "nt_code.hpp"
|
||||
#include "win32_code.hpp"
|
||||
|
||||
#ifndef BOOST_OUTCOME_STANDARDESE_IS_IN_THE_HOUSE
|
||||
#include <comdef.h>
|
||||
#endif
|
||||
|
||||
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
|
||||
to add semantic equivalence testing for whichever extra COM codes that your application specifically needs.
|
||||
*/
|
||||
using com_code = status_code<_com_code_domain>;
|
||||
//! (Windows only) A specialisation of `status_error` for the COM error 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;
|
||||
using _base = status_code_domain;
|
||||
|
||||
//! Construct from a `HRESULT` error code
|
||||
static _base::string_ref _make_string_ref(HRESULT c, IErrorInfo *perrinfo = nullptr) noexcept
|
||||
{
|
||||
_com_error ce(c, perrinfo);
|
||||
#ifdef _UNICODE
|
||||
win32::DWORD wlen = (win32::DWORD) wcslen(ce.ErrorMessage());
|
||||
size_t allocation = wlen + (wlen >> 1);
|
||||
win32::DWORD bytes;
|
||||
if(wlen == 0)
|
||||
{
|
||||
return _base::string_ref("failed to get message from system");
|
||||
}
|
||||
for(;;)
|
||||
{
|
||||
auto *p = static_cast<char *>(malloc(allocation)); // NOLINT
|
||||
if(p == nullptr)
|
||||
{
|
||||
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);
|
||||
if(bytes != 0)
|
||||
{
|
||||
char *end = strchr(p, 0);
|
||||
while(end[-1] == 10 || end[-1] == 13)
|
||||
{
|
||||
--end;
|
||||
}
|
||||
*end = 0; // NOLINT
|
||||
return _base::atomic_refcounted_string_ref(p, end - p);
|
||||
}
|
||||
free(p); // NOLINT
|
||||
if(win32::GetLastError() == 0x7a /*ERROR_INSUFFICIENT_BUFFER*/)
|
||||
{
|
||||
allocation += allocation >> 2;
|
||||
continue;
|
||||
}
|
||||
return _base::string_ref("failed to get message from system");
|
||||
}
|
||||
#else
|
||||
auto wlen = static_cast<win32::DWORD>(strlen(ce.ErrorMessage()));
|
||||
auto *p = static_cast<char *>(malloc(wlen + 1)); // NOLINT
|
||||
if(p == nullptr)
|
||||
{
|
||||
return _base::string_ref("failed to get message from system");
|
||||
}
|
||||
memcpy(p, ce.ErrorMessage(), wlen + 1);
|
||||
char *end = strchr(p, 0);
|
||||
while(end[-1] == 10 || end[-1] == 13)
|
||||
{
|
||||
--end;
|
||||
}
|
||||
*end = 0; // NOLINT
|
||||
return _base::atomic_refcounted_string_ref(p, end - p);
|
||||
#endif
|
||||
}
|
||||
|
||||
public:
|
||||
//! The value type of the COM code, which is a `HRESULT`
|
||||
using value_type = HRESULT;
|
||||
using _base::string_ref;
|
||||
|
||||
public:
|
||||
//! Default constructor
|
||||
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;
|
||||
_com_code_domain &operator=(_com_code_domain &&) = default;
|
||||
~_com_code_domain() = default;
|
||||
|
||||
//! Constexpr singleton getter. Returns the constexpr com_code_domain variable.
|
||||
static inline constexpr const _com_code_domain &get();
|
||||
|
||||
virtual string_ref name() const noexcept override { return string_ref("COM domain"); } // NOLINT
|
||||
protected:
|
||||
virtual bool _do_failure(const status_code<void> &code) const noexcept override // NOLINT
|
||||
{
|
||||
assert(code.domain() == *this);
|
||||
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);
|
||||
const auto &c1 = static_cast<const com_code &>(code1); // NOLINT
|
||||
if(code2.domain() == *this)
|
||||
{
|
||||
const auto &c2 = static_cast<const com_code &>(code2); // NOLINT
|
||||
return c1.value() == c2.value();
|
||||
}
|
||||
if((c1.value() & FACILITY_NT_BIT) != 0)
|
||||
{
|
||||
if(code2.domain() == nt_code_domain)
|
||||
{
|
||||
const auto &c2 = static_cast<const nt_code &>(code2); // NOLINT
|
||||
if(c2.value() == (c1.value() & ~FACILITY_NT_BIT))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if(code2.domain() == generic_code_domain)
|
||||
{
|
||||
const auto &c2 = static_cast<const generic_code &>(code2); // NOLINT
|
||||
if(static_cast<int>(c2.value()) == _nt_code_domain::_nt_code_to_errno(c1.value() & ~FACILITY_NT_BIT))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(HRESULT_FACILITY(c1.value()) == FACILITY_WIN32)
|
||||
{
|
||||
if(code2.domain() == win32_code_domain)
|
||||
{
|
||||
const auto &c2 = static_cast<const win32_code &>(code2); // NOLINT
|
||||
if(c2.value() == HRESULT_CODE(c1.value()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if(code2.domain() == generic_code_domain)
|
||||
{
|
||||
const auto &c2 = static_cast<const generic_code &>(code2); // NOLINT
|
||||
if(static_cast<int>(c2.value()) == _win32_code_domain::_win32_code_to_errno(HRESULT_CODE(c1.value())))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
virtual generic_code _generic_code(const status_code<void> &code) const noexcept override // NOLINT
|
||||
{
|
||||
assert(code.domain() == *this);
|
||||
const auto &c1 = static_cast<const com_code &>(code); // NOLINT
|
||||
if(c1.value() == S_OK)
|
||||
{
|
||||
return generic_code(errc::success);
|
||||
}
|
||||
if((c1.value() & FACILITY_NT_BIT) != 0)
|
||||
{
|
||||
return generic_code(static_cast<errc>(_nt_code_domain::_nt_code_to_errno(c1.value() & ~FACILITY_NT_BIT)));
|
||||
}
|
||||
if(HRESULT_FACILITY(c1.value()) == FACILITY_WIN32)
|
||||
{
|
||||
return generic_code(static_cast<errc>(_win32_code_domain::_win32_code_to_errno(HRESULT_CODE(c1.value()))));
|
||||
}
|
||||
return generic_code(errc::unknown);
|
||||
}
|
||||
virtual string_ref _do_message(const status_code<void> &code) const noexcept override // NOLINT
|
||||
{
|
||||
assert(code.domain() == *this);
|
||||
const auto &c = static_cast<const com_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 com_code &>(code); // NOLINT
|
||||
throw status_error<_com_code_domain>(c);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
//! (Windows only) A constexpr source variable for the COM code domain. Returned by `_com_code_domain::get()`.
|
||||
constexpr _com_code_domain com_code_domain;
|
||||
inline constexpr const _com_code_domain &_com_code_domain::get()
|
||||
{
|
||||
return com_code_domain;
|
||||
}
|
||||
|
||||
BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_END
|
||||
|
||||
#endif
|
||||
261
macx64/include/boost/outcome/experimental/status-code/config.hpp
Normal file
261
macx64/include/boost/outcome/experimental/status-code/config.hpp
Normal file
@@ -0,0 +1,261 @@
|
||||
/* 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
|
||||
@@ -0,0 +1,98 @@
|
||||
case 0x80000002: return EACCES;
|
||||
case 0x8000000f: return EAGAIN;
|
||||
case 0x80000010: return EAGAIN;
|
||||
case 0x80000011: return EBUSY;
|
||||
case 0xc0000002: return ENOSYS;
|
||||
case 0xc0000005: return EACCES;
|
||||
case 0xc0000008: return EINVAL;
|
||||
case 0xc000000e: return ENOENT;
|
||||
case 0xc000000f: return ENOENT;
|
||||
case 0xc0000010: return ENOSYS;
|
||||
case 0xc0000013: return EAGAIN;
|
||||
case 0xc0000017: return ENOMEM;
|
||||
case 0xc000001c: return ENOSYS;
|
||||
case 0xc000001e: return EACCES;
|
||||
case 0xc000001f: return EACCES;
|
||||
case 0xc0000021: return EACCES;
|
||||
case 0xc0000022: return EACCES;
|
||||
case 0xc0000024: return EINVAL;
|
||||
case 0xc0000033: return EINVAL;
|
||||
case 0xc0000034: return ENOENT;
|
||||
case 0xc0000035: return EEXIST;
|
||||
case 0xc0000037: return EINVAL;
|
||||
case 0xc000003a: return ENOENT;
|
||||
case 0xc0000040: return ENOMEM;
|
||||
case 0xc0000041: return EACCES;
|
||||
case 0xc0000042: return EINVAL;
|
||||
case 0xc0000043: return EACCES;
|
||||
case 0xc000004b: return EACCES;
|
||||
case 0xc0000054: return ENOLCK;
|
||||
case 0xc0000055: return ENOLCK;
|
||||
case 0xc0000056: return EACCES;
|
||||
case 0xc000007f: return ENOSPC;
|
||||
case 0xc0000087: return ENOMEM;
|
||||
case 0xc0000097: return ENOMEM;
|
||||
case 0xc000009b: return ENOENT;
|
||||
case 0xc000009e: return EAGAIN;
|
||||
case 0xc00000a2: return EACCES;
|
||||
case 0xc00000a3: return EAGAIN;
|
||||
case 0xc00000af: return ENOSYS;
|
||||
case 0xc00000ba: return EACCES;
|
||||
case 0xc00000c0: return ENODEV;
|
||||
case 0xc00000d4: return EXDEV;
|
||||
case 0xc00000d5: return EACCES;
|
||||
case 0xc00000fb: return ENOENT;
|
||||
case 0xc0000101: return ENOTEMPTY;
|
||||
case 0xc0000103: return EINVAL;
|
||||
case 0xc0000107: return EBUSY;
|
||||
case 0xc0000108: return EBUSY;
|
||||
case 0xc000010a: return EACCES;
|
||||
case 0xc000011f: return EMFILE;
|
||||
case 0xc0000120: return ECANCELED;
|
||||
case 0xc0000121: return EACCES;
|
||||
case 0xc0000123: return EACCES;
|
||||
case 0xc0000128: return EINVAL;
|
||||
case 0xc0000189: return EACCES;
|
||||
case 0xc00001ad: return ENOMEM;
|
||||
case 0xc000022d: return EAGAIN;
|
||||
case 0xc0000235: return EINVAL;
|
||||
case 0xc000026e: return EAGAIN;
|
||||
case 0xc000028a: return EACCES;
|
||||
case 0xc000028b: return EACCES;
|
||||
case 0xc000028d: return EACCES;
|
||||
case 0xc000028e: return EACCES;
|
||||
case 0xc000028f: return EACCES;
|
||||
case 0xc0000290: return EACCES;
|
||||
case 0xc000029c: return ENOSYS;
|
||||
case 0xc00002c5: return EACCES;
|
||||
case 0xc00002d3: return EAGAIN;
|
||||
case 0xc00002ea: return EACCES;
|
||||
case 0xc00002f0: return ENOENT;
|
||||
case 0xc0000373: return ENOMEM;
|
||||
case 0xc0000416: return ENOMEM;
|
||||
case 0xc0000433: return EBUSY;
|
||||
case 0xc0000434: return EBUSY;
|
||||
case 0xc0000455: return EINVAL;
|
||||
case 0xc0000467: return EACCES;
|
||||
case 0xc0000491: return ENOENT;
|
||||
case 0xc0000495: return EAGAIN;
|
||||
case 0xc0000503: return EAGAIN;
|
||||
case 0xc0000507: return EBUSY;
|
||||
case 0xc0000512: return EACCES;
|
||||
case 0xc000070a: return EINVAL;
|
||||
case 0xc000070b: return EINVAL;
|
||||
case 0xc000070c: return EINVAL;
|
||||
case 0xc000070d: return EINVAL;
|
||||
case 0xc000070e: return EINVAL;
|
||||
case 0xc000070f: return EINVAL;
|
||||
case 0xc0000710: return ENOSYS;
|
||||
case 0xc0000711: return ENOSYS;
|
||||
case 0xc0000716: return EINVAL;
|
||||
case 0xc000071b: return ENOSYS;
|
||||
case 0xc000071d: return ENOSYS;
|
||||
case 0xc000071e: return ENOSYS;
|
||||
case 0xc000071f: return ENOSYS;
|
||||
case 0xc0000720: return ENOSYS;
|
||||
case 0xc0000721: return ENOSYS;
|
||||
case 0xc000080f: return EAGAIN;
|
||||
case 0xc000a203: return EACCES;
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,75 @@
|
||||
case 0x1: return ENOSYS;
|
||||
case 0x2: return ENOENT;
|
||||
case 0x3: return ENOENT;
|
||||
case 0x4: return EMFILE;
|
||||
case 0x5: return EACCES;
|
||||
case 0x6: return EINVAL;
|
||||
case 0x8: return ENOMEM;
|
||||
case 0xc: return EACCES;
|
||||
case 0xe: return ENOMEM;
|
||||
case 0xf: return ENODEV;
|
||||
case 0x10: return EACCES;
|
||||
case 0x11: return EXDEV;
|
||||
case 0x13: return EACCES;
|
||||
case 0x14: return ENODEV;
|
||||
case 0x15: return EAGAIN;
|
||||
case 0x19: return EIO;
|
||||
case 0x1d: return EIO;
|
||||
case 0x1e: return EIO;
|
||||
case 0x20: return EACCES;
|
||||
case 0x21: return ENOLCK;
|
||||
case 0x27: return ENOSPC;
|
||||
case 0x37: return ENODEV;
|
||||
case 0x50: return EEXIST;
|
||||
case 0x52: return EACCES;
|
||||
case 0x57: return EINVAL;
|
||||
case 0x6e: return EIO;
|
||||
case 0x6f: return ENAMETOOLONG;
|
||||
case 0x70: return ENOSPC;
|
||||
case 0x7b: return EINVAL;
|
||||
case 0x83: return EINVAL;
|
||||
case 0x8e: return EBUSY;
|
||||
case 0x91: return ENOTEMPTY;
|
||||
case 0xaa: return EBUSY;
|
||||
case 0xb7: return EEXIST;
|
||||
case 0xd4: return ENOLCK;
|
||||
case 0x10b: return EINVAL;
|
||||
case 0x3e3: return ECANCELED;
|
||||
case 0x3e6: return EACCES;
|
||||
case 0x3f3: return EIO;
|
||||
case 0x3f4: return EIO;
|
||||
case 0x3f5: return EIO;
|
||||
case 0x4d5: return EAGAIN;
|
||||
case 0x961: return EBUSY;
|
||||
case 0x964: return EBUSY;
|
||||
case 0x2714: return EINTR;
|
||||
case 0x2719: return EBADF;
|
||||
case 0x271d: return EACCES;
|
||||
case 0x271e: return EFAULT;
|
||||
case 0x2726: return EINVAL;
|
||||
case 0x2728: return EMFILE;
|
||||
case 0x2733: return EWOULDBLOCK;
|
||||
case 0x2734: return EINPROGRESS;
|
||||
case 0x2735: return EALREADY;
|
||||
case 0x2736: return ENOTSOCK;
|
||||
case 0x2737: return EDESTADDRREQ;
|
||||
case 0x2738: return EMSGSIZE;
|
||||
case 0x2739: return EPROTOTYPE;
|
||||
case 0x273a: return ENOPROTOOPT;
|
||||
case 0x273b: return EPROTONOSUPPORT;
|
||||
case 0x273d: return EOPNOTSUPP;
|
||||
case 0x273f: return EAFNOSUPPORT;
|
||||
case 0x2740: return EADDRINUSE;
|
||||
case 0x2741: return EADDRNOTAVAIL;
|
||||
case 0x2742: return ENETDOWN;
|
||||
case 0x2743: return ENETUNREACH;
|
||||
case 0x2744: return ENETRESET;
|
||||
case 0x2745: return ECONNABORTED;
|
||||
case 0x2746: return ECONNRESET;
|
||||
case 0x2747: return ENOBUFS;
|
||||
case 0x2748: return EISCONN;
|
||||
case 0x2749: return ENOTCONN;
|
||||
case 0x274c: return ETIMEDOUT;
|
||||
case 0x274d: return ECONNREFUSED;
|
||||
case 0x274f: return ENAMETOOLONG;
|
||||
case 0x2751: return EHOSTUNREACH;
|
||||
@@ -0,0 +1,65 @@
|
||||
/* 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_ERROR_HPP
|
||||
#define BOOST_OUTCOME_SYSTEM_ERROR2_ERROR_HPP
|
||||
|
||||
#include "errored_status_code.hpp"
|
||||
#include "system_code.hpp"
|
||||
|
||||
BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_BEGIN
|
||||
|
||||
/*! An erased `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
|
||||
[P0709 Zero-overhead deterministic exceptions](https://wg21.link/P0709).
|
||||
|
||||
Differences from `system_code`:
|
||||
|
||||
- Always a failure (this is checked at construction, and if not the case,
|
||||
the program is terminated as this is a logic error)
|
||||
- No default construction.
|
||||
- No empty state possible.
|
||||
- Is immutable.
|
||||
|
||||
As with `system_code`, it remains guaranteed to be two CPU registers in size,
|
||||
and move relocating.
|
||||
*/
|
||||
using error = errored_status_code<erased<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!");
|
||||
#endif
|
||||
|
||||
BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_END
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,342 @@
|
||||
/* 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
|
||||
@@ -0,0 +1,378 @@
|
||||
/* 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
|
||||
@@ -0,0 +1,78 @@
|
||||
/* 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_IOSTREAM_SUPPORT_HPP
|
||||
#define BOOST_OUTCOME_SYSTEM_ERROR2_IOSTREAM_SUPPORT_HPP
|
||||
|
||||
#include "error.hpp"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
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>
|
||||
inline std::ostream &operator<<(std::ostream &s, const status_code<DomainType> &v)
|
||||
{
|
||||
if(v.empty())
|
||||
{
|
||||
return s << "(empty)";
|
||||
}
|
||||
return s << v.domain().name().c_str() << ": " << v.value();
|
||||
}
|
||||
|
||||
/*! 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)
|
||||
{
|
||||
if(v.empty())
|
||||
{
|
||||
return s << "(empty)";
|
||||
}
|
||||
return s << v.domain().name().c_str() << ": " << v.message().c_str();
|
||||
}
|
||||
|
||||
/*! 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();
|
||||
}
|
||||
|
||||
BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_END
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,212 @@
|
||||
/* 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_NT_CODE_HPP
|
||||
#define BOOST_OUTCOME_SYSTEM_ERROR2_NT_CODE_HPP
|
||||
|
||||
#if !defined(_WIN32) && !defined(BOOST_OUTCOME_STANDARDESE_IS_IN_THE_HOUSE)
|
||||
#error This file should only be included on Windows
|
||||
#endif
|
||||
|
||||
#include "win32_code.hpp"
|
||||
|
||||
BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_BEGIN
|
||||
|
||||
//! \exclude
|
||||
namespace win32
|
||||
{
|
||||
// A Win32 NTSTATUS
|
||||
using NTSTATUS = long;
|
||||
// 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);
|
||||
}
|
||||
|
||||
class _nt_code_domain;
|
||||
//! (Windows only) A NT error code, those returned by NT kernel functions.
|
||||
using nt_code = status_code<_nt_code_domain>;
|
||||
//! (Windows only) A specialisation of `status_error` for the NT error 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;
|
||||
friend class _com_code_domain;
|
||||
using _base = status_code_domain;
|
||||
static int _nt_code_to_errno(win32::NTSTATUS c)
|
||||
{
|
||||
if(c >= 0)
|
||||
{
|
||||
return 0; // success
|
||||
}
|
||||
switch(static_cast<unsigned>(c))
|
||||
{
|
||||
#include "detail/nt_code_to_generic_code.ipp"
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
static win32::DWORD _nt_code_to_win32_code(win32::NTSTATUS c) // NOLINT
|
||||
{
|
||||
if(c >= 0)
|
||||
{
|
||||
return 0; // success
|
||||
}
|
||||
switch(static_cast<unsigned>(c))
|
||||
{
|
||||
#include "detail/nt_code_to_win32_code.ipp"
|
||||
}
|
||||
return static_cast<win32::DWORD>(-1);
|
||||
}
|
||||
//! Construct from a NT error code
|
||||
static _base::string_ref _make_string_ref(win32::NTSTATUS c) noexcept
|
||||
{
|
||||
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);
|
||||
size_t allocation = wlen + (wlen >> 1);
|
||||
win32::DWORD bytes;
|
||||
if(wlen == 0)
|
||||
{
|
||||
return _base::string_ref("failed to get message from system");
|
||||
}
|
||||
for(;;)
|
||||
{
|
||||
auto *p = static_cast<char *>(malloc(allocation)); // NOLINT
|
||||
if(p == nullptr)
|
||||
{
|
||||
return _base::string_ref("failed to get message from system");
|
||||
}
|
||||
bytes = win32::WideCharToMultiByte(65001 /*CP_UTF8*/, 0, buffer, (int) (wlen + 1), p, (int) allocation, nullptr, nullptr);
|
||||
if(bytes != 0)
|
||||
{
|
||||
char *end = strchr(p, 0);
|
||||
while(end[-1] == 10 || end[-1] == 13)
|
||||
{
|
||||
--end;
|
||||
}
|
||||
*end = 0; // NOLINT
|
||||
return _base::atomic_refcounted_string_ref(p, end - p);
|
||||
}
|
||||
free(p); // NOLINT
|
||||
if(win32::GetLastError() == 0x7a /*ERROR_INSUFFICIENT_BUFFER*/)
|
||||
{
|
||||
allocation += allocation >> 2;
|
||||
continue;
|
||||
}
|
||||
return _base::string_ref("failed to get message from system");
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
//! The value type of the NT code, which is a `win32::NTSTATUS`
|
||||
using value_type = win32::NTSTATUS;
|
||||
using _base::string_ref;
|
||||
|
||||
public:
|
||||
//! Default constructor
|
||||
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;
|
||||
_nt_code_domain &operator=(_nt_code_domain &&) = default;
|
||||
~_nt_code_domain() = default;
|
||||
|
||||
//! Constexpr singleton getter. Returns the constexpr nt_code_domain variable.
|
||||
static inline constexpr const _nt_code_domain &get();
|
||||
|
||||
virtual string_ref name() const noexcept override { return string_ref("NT domain"); } // NOLINT
|
||||
protected:
|
||||
virtual bool _do_failure(const status_code<void> &code) const noexcept override // NOLINT
|
||||
{
|
||||
assert(code.domain() == *this);
|
||||
return static_cast<const nt_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);
|
||||
const auto &c1 = static_cast<const nt_code &>(code1); // NOLINT
|
||||
if(code2.domain() == *this)
|
||||
{
|
||||
const auto &c2 = static_cast<const nt_code &>(code2); // NOLINT
|
||||
return c1.value() == c2.value();
|
||||
}
|
||||
if(code2.domain() == generic_code_domain)
|
||||
{
|
||||
const auto &c2 = static_cast<const generic_code &>(code2); // NOLINT
|
||||
if(static_cast<int>(c2.value()) == _nt_code_to_errno(c1.value()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if(code2.domain() == win32_code_domain)
|
||||
{
|
||||
const auto &c2 = static_cast<const win32_code &>(code2); // NOLINT
|
||||
if(c2.value() == _nt_code_to_win32_code(c1.value()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
virtual generic_code _generic_code(const status_code<void> &code) const noexcept override // NOLINT
|
||||
{
|
||||
assert(code.domain() == *this);
|
||||
const auto &c = static_cast<const nt_code &>(code); // NOLINT
|
||||
return generic_code(static_cast<errc>(_nt_code_to_errno(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 nt_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 nt_code &>(code); // NOLINT
|
||||
throw status_error<_nt_code_domain>(c);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
//! (Windows only) A constexpr source variable for the NT code domain, which is that of NT kernel functions. Returned by `_nt_code_domain::get()`.
|
||||
constexpr _nt_code_domain nt_code_domain;
|
||||
inline constexpr const _nt_code_domain &_nt_code_domain::get()
|
||||
{
|
||||
return nt_code_domain;
|
||||
}
|
||||
|
||||
BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_END
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,151 @@
|
||||
/* 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_POSIX_CODE_HPP
|
||||
#define BOOST_OUTCOME_SYSTEM_ERROR2_POSIX_CODE_HPP
|
||||
|
||||
#include "generic_code.hpp"
|
||||
|
||||
#include <cstring> // for strchr and strerror_r
|
||||
|
||||
BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_BEGIN
|
||||
|
||||
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>;
|
||||
|
||||
/*! 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;
|
||||
using _base = status_code_domain;
|
||||
|
||||
static _base::string_ref _make_string_ref(int c) noexcept
|
||||
{
|
||||
char buffer[1024] = "";
|
||||
#ifdef _WIN32
|
||||
strerror_s(buffer, sizeof(buffer), c);
|
||||
#elif defined(__linux__)
|
||||
char *s = strerror_r(c, buffer, sizeof(buffer)); // NOLINT
|
||||
if(s != nullptr)
|
||||
{
|
||||
strncpy(buffer, s, sizeof(buffer)); // NOLINT
|
||||
buffer[1023] = 0;
|
||||
}
|
||||
#else
|
||||
strerror_r(c, buffer, sizeof(buffer));
|
||||
#endif
|
||||
size_t length = strlen(buffer); // NOLINT
|
||||
auto *p = static_cast<char *>(malloc(length + 1)); // NOLINT
|
||||
if(p == nullptr)
|
||||
{
|
||||
return _base::string_ref("failed to get message from system");
|
||||
}
|
||||
memcpy(p, buffer, length + 1); // NOLINT
|
||||
return _base::atomic_refcounted_string_ref(p, length);
|
||||
}
|
||||
|
||||
public:
|
||||
//! The value type of the POSIX code, which is an `int`
|
||||
using value_type = int;
|
||||
using _base::string_ref;
|
||||
|
||||
//! Default constructor
|
||||
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;
|
||||
_posix_code_domain &operator=(_posix_code_domain &&) = default;
|
||||
~_posix_code_domain() = default;
|
||||
|
||||
//! Constexpr singleton getter. Returns constexpr posix_code_domain variable.
|
||||
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
|
||||
{
|
||||
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
|
||||
if(code2.domain() == *this)
|
||||
{
|
||||
const auto &c2 = static_cast<const posix_code &>(code2); // NOLINT
|
||||
return c1.value() == c2.value();
|
||||
}
|
||||
if(code2.domain() == generic_code_domain)
|
||||
{
|
||||
const auto &c2 = static_cast<const generic_code &>(code2); // NOLINT
|
||||
if(static_cast<int>(c2.value()) == c1.value())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
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 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
|
||||
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
|
||||
throw status_error<_posix_code_domain>(c);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
//! A constexpr source variable for the POSIX code domain, which is that of `errno`. Returned by `_posix_code_domain::get()`.
|
||||
constexpr _posix_code_domain posix_code_domain;
|
||||
inline constexpr const _posix_code_domain &_posix_code_domain::get()
|
||||
{
|
||||
return posix_code_domain;
|
||||
}
|
||||
|
||||
BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_END
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,502 @@
|
||||
/* 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
|
||||
@@ -0,0 +1,365 @@
|
||||
/* 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_DOMAIN_HPP
|
||||
#define BOOST_OUTCOME_SYSTEM_ERROR2_STATUS_CODE_DOMAIN_HPP
|
||||
|
||||
#include "config.hpp"
|
||||
|
||||
#include <cstring> // for strchr
|
||||
|
||||
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>>`).
|
||||
|
||||
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
|
||||
surprise on this, `operator<` and `std::hash<>` are NOT implemented in order to
|
||||
trap potential incorrectness. Define your own custom comparison functions for your
|
||||
container which perform exact comparisons.
|
||||
*/
|
||||
template <class DomainType> class status_code;
|
||||
class _generic_code_domain;
|
||||
//! The generic code is a status code with the generic code domain, which is that of `errc` (POSIX).
|
||||
using generic_code = status_code<_generic_code_domain>;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template <class StatusCode> class indirecting_domain;
|
||||
template <class T> struct status_code_sizer
|
||||
{
|
||||
void *a;
|
||||
T b;
|
||||
};
|
||||
template <class To, class From> struct type_erasure_is_safe
|
||||
{
|
||||
static constexpr bool value = traits::is_move_relocating<From>::value //
|
||||
&& (sizeof(status_code_sizer<From>) <= sizeof(status_code_sizer<To>));
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
/*! Abstract base class for a coding domain of a status code.
|
||||
*/
|
||||
class status_code_domain
|
||||
{
|
||||
template <class DomainType> friend class status_code;
|
||||
template <class StatusCode> friend class indirecting_domain;
|
||||
|
||||
public:
|
||||
//! Type of the unique id for this domain.
|
||||
using unique_id_type = unsigned long long;
|
||||
/*! (Potentially thread safe) Reference to a message string.
|
||||
|
||||
Be aware that you cannot add payload to implementations of this class.
|
||||
You get exactly the `void *[3]` array to keep state, this is usually
|
||||
sufficient for a `std::shared_ptr<>` or a `std::string`.
|
||||
|
||||
You can install a handler to be called when this object is copied,
|
||||
moved and destructed. This takes the form of a C function pointer.
|
||||
*/
|
||||
class string_ref
|
||||
{
|
||||
public:
|
||||
//! The value type
|
||||
using value_type = const char;
|
||||
//! The size type
|
||||
using size_type = size_t;
|
||||
//! The pointer type
|
||||
using pointer = const char *;
|
||||
//! The const pointer type
|
||||
using const_pointer = const char *;
|
||||
//! The iterator type
|
||||
using iterator = const char *;
|
||||
//! The const iterator type
|
||||
using const_iterator = const char *;
|
||||
|
||||
protected:
|
||||
//! The operation occurring
|
||||
enum class _thunk_op
|
||||
{
|
||||
copy,
|
||||
move,
|
||||
destruct
|
||||
};
|
||||
//! The prototype of the handler function. Copies can throw, moves and destructs cannot.
|
||||
using _thunk_spec = void (*)(string_ref *dest, const string_ref *src, _thunk_op op);
|
||||
#ifndef NDEBUG
|
||||
private:
|
||||
static void _checking_string_thunk(string_ref *dest, const string_ref *src, _thunk_op /*unused*/) noexcept
|
||||
{
|
||||
(void) dest;
|
||||
(void) src;
|
||||
assert(dest->_thunk == _checking_string_thunk); // NOLINT
|
||||
assert(src == nullptr || src->_thunk == _checking_string_thunk); // NOLINT
|
||||
// do nothing
|
||||
}
|
||||
|
||||
protected:
|
||||
#endif
|
||||
//! Pointers to beginning and end of character range
|
||||
pointer _begin{}, _end{};
|
||||
//! Three `void*` of state
|
||||
void *_state[3]{}; // at least the size of a shared_ptr
|
||||
//! Handler for when operations occur
|
||||
const _thunk_spec _thunk{nullptr};
|
||||
|
||||
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,
|
||||
#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)
|
||||
{
|
||||
}
|
||||
//! Copy construct the derived implementation.
|
||||
string_ref(const string_ref &o)
|
||||
: _begin(o._begin)
|
||||
, _end(o._end)
|
||||
, _state{o._state[0], o._state[1], o._state[2]}
|
||||
, _thunk(o._thunk)
|
||||
{
|
||||
if(_thunk != nullptr)
|
||||
{
|
||||
_thunk(this, &o, _thunk_op::copy);
|
||||
}
|
||||
}
|
||||
//! 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)
|
||||
{
|
||||
if(_thunk != nullptr)
|
||||
{
|
||||
_thunk(this, &o, _thunk_op::move);
|
||||
}
|
||||
}
|
||||
//! Copy assignment
|
||||
string_ref &operator=(const string_ref &o)
|
||||
{
|
||||
if(this != &o)
|
||||
{
|
||||
#if defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)
|
||||
string_ref temp(static_cast<string_ref &&>(*this));
|
||||
this->~string_ref();
|
||||
try
|
||||
{
|
||||
new(this) string_ref(o); // may throw
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
new(this) string_ref(static_cast<string_ref &&>(temp));
|
||||
throw;
|
||||
}
|
||||
#else
|
||||
this->~string_ref();
|
||||
new(this) string_ref(o);
|
||||
#endif
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
//! Move assignment
|
||||
string_ref &operator=(string_ref &&o) noexcept
|
||||
{
|
||||
if(this != &o)
|
||||
{
|
||||
this->~string_ref();
|
||||
new(this) string_ref(static_cast<string_ref &&>(o));
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
//! Destruction
|
||||
~string_ref()
|
||||
{
|
||||
if(_thunk != nullptr)
|
||||
{
|
||||
_thunk(this, nullptr, _thunk_op::destruct);
|
||||
}
|
||||
_begin = _end = nullptr;
|
||||
}
|
||||
|
||||
//! Returns whether the reference is empty or not
|
||||
BOOST_OUTCOME_SYSTEM_ERROR2_NODISCARD bool empty() const noexcept { return _begin == _end; }
|
||||
//! Returns the size of the string
|
||||
size_type size() const noexcept { return _end - _begin; }
|
||||
//! Returns a null terminated C string
|
||||
const_pointer c_str() const noexcept { return _begin; }
|
||||
//! Returns a null terminated C string
|
||||
const_pointer data() const noexcept { return _begin; }
|
||||
//! Returns the beginning of the string
|
||||
iterator begin() noexcept { return _begin; }
|
||||
//! Returns the beginning of the string
|
||||
const_iterator begin() const noexcept { return _begin; }
|
||||
//! Returns the beginning of the string
|
||||
const_iterator cbegin() const noexcept { return _begin; }
|
||||
//! Returns the end of the string
|
||||
iterator end() noexcept { return _end; }
|
||||
//! Returns the end of the string
|
||||
const_iterator end() const noexcept { return _end; }
|
||||
//! Returns the end of the string
|
||||
const_iterator cend() const noexcept { return _end; }
|
||||
};
|
||||
|
||||
/*! A reference counted, threadsafe reference to a message string.
|
||||
*/
|
||||
class atomic_refcounted_string_ref : public string_ref
|
||||
{
|
||||
struct _allocated_msg
|
||||
{
|
||||
mutable std::atomic<unsigned> count{1};
|
||||
};
|
||||
_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
|
||||
{
|
||||
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
|
||||
switch(op)
|
||||
{
|
||||
case _thunk_op::copy:
|
||||
{
|
||||
if(dest->_msg() != nullptr)
|
||||
{
|
||||
auto count = dest->_msg()->count.fetch_add(1, std::memory_order_relaxed);
|
||||
(void) count;
|
||||
assert(count != 0); // NOLINT
|
||||
}
|
||||
return;
|
||||
}
|
||||
case _thunk_op::move:
|
||||
{
|
||||
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;
|
||||
return;
|
||||
}
|
||||
case _thunk_op::destruct:
|
||||
{
|
||||
if(dest->_msg() != nullptr)
|
||||
{
|
||||
auto count = dest->_msg()->count.fetch_sub(1, std::memory_order_release);
|
||||
if(count == 1)
|
||||
{
|
||||
std::atomic_thread_fence(std::memory_order_acquire);
|
||||
free((void *) dest->_begin); // NOLINT
|
||||
delete dest->_msg(); // NOLINT
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
if(_msg() == nullptr)
|
||||
{
|
||||
free((void *) this->_begin); // NOLINT
|
||||
_msg() = nullptr; // disabled
|
||||
this->_begin = "failed to get message from system";
|
||||
this->_end = strchr(this->_begin, 0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
unique_id_type _id;
|
||||
|
||||
protected:
|
||||
/*! Use [https://www.random.org/cgi-bin/randbyte?nbytes=8&format=h](https://www.random.org/cgi-bin/randbyte?nbytes=8&format=h) to get a random 64 bit id.
|
||||
|
||||
Do NOT make up your own value. Do NOT use zero.
|
||||
*/
|
||||
constexpr explicit status_code_domain(unique_id_type id) noexcept : _id(id) {}
|
||||
//! No public copying at type erased level
|
||||
status_code_domain(const status_code_domain &) = default;
|
||||
//! No public moving at type erased level
|
||||
status_code_domain(status_code_domain &&) = default;
|
||||
//! No public assignment at type erased level
|
||||
status_code_domain &operator=(const status_code_domain &) = default;
|
||||
//! No public assignment at type erased level
|
||||
status_code_domain &operator=(status_code_domain &&) = default;
|
||||
//! No public destruction at type erased level
|
||||
~status_code_domain() = default;
|
||||
|
||||
public:
|
||||
//! True if the unique ids match.
|
||||
constexpr bool operator==(const status_code_domain &o) const noexcept { return _id == o._id; }
|
||||
//! True if the unique ids do not match.
|
||||
constexpr bool operator!=(const status_code_domain &o) const noexcept { return _id != o._id; }
|
||||
//! True if this unique is lower than the other's unique id.
|
||||
constexpr bool operator<(const status_code_domain &o) const noexcept { return _id < o._id; }
|
||||
|
||||
//! 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;
|
||||
|
||||
protected:
|
||||
//! True if code means failure.
|
||||
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;
|
||||
//! Returns the generic code closest to this code, if any.
|
||||
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;
|
||||
#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;
|
||||
#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, destroy the erased value type. Default implementation does nothing.
|
||||
virtual void _do_erased_destroy(status_code<void> &code, size_t bytes) const noexcept // NOLINT
|
||||
{
|
||||
(void) code;
|
||||
(void) bytes;
|
||||
}
|
||||
};
|
||||
|
||||
BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_END
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,137 @@
|
||||
/* 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
|
||||
@@ -0,0 +1,104 @@
|
||||
/* 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
|
||||
@@ -0,0 +1,184 @@
|
||||
/* 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
|
||||
@@ -0,0 +1,66 @@
|
||||
/* 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_SYSTEM_CODE_HPP
|
||||
#define BOOST_OUTCOME_SYSTEM_ERROR2_SYSTEM_CODE_HPP
|
||||
|
||||
#include "posix_code.hpp"
|
||||
|
||||
#if defined(_WIN32) || defined(BOOST_OUTCOME_STANDARDESE_IS_IN_THE_HOUSE)
|
||||
#include "nt_code.hpp"
|
||||
#include "win32_code.hpp"
|
||||
// NOT "com_code.hpp"
|
||||
#endif
|
||||
|
||||
BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_BEGIN
|
||||
/*! An erased-mutable status code suitably large for all the system codes
|
||||
which can be returned on this system.
|
||||
|
||||
For Windows, these might be:
|
||||
|
||||
- `com_code` (`HRESULT`) [you need to include "com_code.hpp" explicitly for this]
|
||||
- `nt_code` (`LONG`)
|
||||
- `win32_code` (`DWORD`)
|
||||
|
||||
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>>;
|
||||
|
||||
#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!");
|
||||
#endif
|
||||
|
||||
BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_END
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,126 @@
|
||||
/* Proposed SG14 status_code
|
||||
(C) 2018-2019 Niall Douglas <http://www.nedproductions.biz/> (5 commits)
|
||||
File Created: June 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_SYSTEM_CODE_FROM_EXCEPTION_HPP
|
||||
#define BOOST_OUTCOME_SYSTEM_ERROR2_SYSTEM_CODE_FROM_EXCEPTION_HPP
|
||||
|
||||
#include "system_code.hpp"
|
||||
|
||||
#include <exception> // for exception_ptr
|
||||
#include <stdexcept> // for the exception types
|
||||
#include <system_error> // for std::system_error
|
||||
|
||||
BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_BEGIN
|
||||
|
||||
/*! A utility function which returns the closest matching system_code to a supplied
|
||||
exception ptr.
|
||||
*/
|
||||
inline system_code system_code_from_exception(std::exception_ptr &&ep = std::current_exception(), system_code not_matched = generic_code(errc::resource_unavailable_try_again)) noexcept
|
||||
{
|
||||
if(!ep)
|
||||
{
|
||||
return generic_code(errc::success);
|
||||
}
|
||||
try
|
||||
{
|
||||
std::rethrow_exception(ep);
|
||||
}
|
||||
catch(const std::invalid_argument & /*unused*/)
|
||||
{
|
||||
ep = std::exception_ptr();
|
||||
return generic_code(errc::invalid_argument);
|
||||
}
|
||||
catch(const std::domain_error & /*unused*/)
|
||||
{
|
||||
ep = std::exception_ptr();
|
||||
return generic_code(errc::argument_out_of_domain);
|
||||
}
|
||||
catch(const std::length_error & /*unused*/)
|
||||
{
|
||||
ep = std::exception_ptr();
|
||||
return generic_code(errc::argument_list_too_long);
|
||||
}
|
||||
catch(const std::out_of_range & /*unused*/)
|
||||
{
|
||||
ep = std::exception_ptr();
|
||||
return generic_code(errc::result_out_of_range);
|
||||
}
|
||||
catch(const std::logic_error & /*unused*/) /* base class for this group */
|
||||
{
|
||||
ep = std::exception_ptr();
|
||||
return generic_code(errc::invalid_argument);
|
||||
}
|
||||
catch(const std::system_error &e) /* also catches ios::failure */
|
||||
{
|
||||
ep = std::exception_ptr();
|
||||
if(e.code().category() == std::generic_category())
|
||||
{
|
||||
return generic_code(static_cast<errc>(static_cast<int>(e.code().value())));
|
||||
}
|
||||
if(e.code().category() == std::system_category())
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return win32_code(e.code().value());
|
||||
#else
|
||||
return posix_code(e.code().value());
|
||||
#endif
|
||||
}
|
||||
// Don't know this error code category, can't wrap it into std_error_code
|
||||
// as its payload won't fit into system_code, so fall through.
|
||||
}
|
||||
catch(const std::overflow_error & /*unused*/)
|
||||
{
|
||||
ep = std::exception_ptr();
|
||||
return generic_code(errc::value_too_large);
|
||||
}
|
||||
catch(const std::range_error & /*unused*/)
|
||||
{
|
||||
ep = std::exception_ptr();
|
||||
return generic_code(errc::result_out_of_range);
|
||||
}
|
||||
catch(const std::runtime_error & /*unused*/) /* base class for this group */
|
||||
{
|
||||
ep = std::exception_ptr();
|
||||
return generic_code(errc::resource_unavailable_try_again);
|
||||
}
|
||||
catch(const std::bad_alloc & /*unused*/)
|
||||
{
|
||||
ep = std::exception_ptr();
|
||||
return generic_code(errc::not_enough_memory);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
}
|
||||
return not_matched;
|
||||
}
|
||||
|
||||
BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_END
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,36 @@
|
||||
/* 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_HPP
|
||||
#define BOOST_OUTCOME_SYSTEM_ERROR2_HPP
|
||||
|
||||
#include "error.hpp"
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,193 @@
|
||||
/* 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_WIN32_CODE_HPP
|
||||
#define BOOST_OUTCOME_SYSTEM_ERROR2_WIN32_CODE_HPP
|
||||
|
||||
#if !defined(_WIN32) && !defined(BOOST_OUTCOME_STANDARDESE_IS_IN_THE_HOUSE)
|
||||
#error This file should only be included on Windows
|
||||
#endif
|
||||
|
||||
#include "generic_code.hpp"
|
||||
|
||||
BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_BEGIN
|
||||
|
||||
//! \exclude
|
||||
namespace win32
|
||||
{
|
||||
// A Win32 DWORD
|
||||
using DWORD = unsigned long;
|
||||
// Used to retrieve the current Win32 error code
|
||||
extern "C" 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);
|
||||
// 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);
|
||||
#pragma comment(lib, "kernel32.lib")
|
||||
} // namespace win32
|
||||
|
||||
class _win32_code_domain;
|
||||
class _com_code_domain;
|
||||
//! (Windows only) A Win32 error code, those returned by `GetLastError()`.
|
||||
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>;
|
||||
|
||||
/*! (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;
|
||||
friend class _com_code_domain;
|
||||
using _base = status_code_domain;
|
||||
static int _win32_code_to_errno(win32::DWORD c)
|
||||
{
|
||||
switch(c)
|
||||
{
|
||||
case 0:
|
||||
return 0;
|
||||
#include "detail/win32_code_to_generic_code.ipp"
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
//! Construct from a Win32 error code
|
||||
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);
|
||||
size_t allocation = wlen + (wlen >> 1);
|
||||
win32::DWORD bytes;
|
||||
if(wlen == 0)
|
||||
{
|
||||
return _base::string_ref("failed to get message from system");
|
||||
}
|
||||
for(;;)
|
||||
{
|
||||
auto *p = static_cast<char *>(malloc(allocation)); // NOLINT
|
||||
if(p == nullptr)
|
||||
{
|
||||
return _base::string_ref("failed to get message from system");
|
||||
}
|
||||
bytes = win32::WideCharToMultiByte(65001 /*CP_UTF8*/, 0, buffer, (int) (wlen + 1), p, (int) allocation, nullptr, nullptr);
|
||||
if(bytes != 0)
|
||||
{
|
||||
char *end = strchr(p, 0);
|
||||
while(end[-1] == 10 || end[-1] == 13)
|
||||
{
|
||||
--end;
|
||||
}
|
||||
*end = 0; // NOLINT
|
||||
return _base::atomic_refcounted_string_ref(p, end - p);
|
||||
}
|
||||
free(p); // NOLINT
|
||||
if(win32::GetLastError() == 0x7a /*ERROR_INSUFFICIENT_BUFFER*/)
|
||||
{
|
||||
allocation += allocation >> 2;
|
||||
continue;
|
||||
}
|
||||
return _base::string_ref("failed to get message from system");
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
//! The value type of the win32 code, which is a `win32::DWORD`
|
||||
using value_type = win32::DWORD;
|
||||
using _base::string_ref;
|
||||
|
||||
public:
|
||||
//! Default constructor
|
||||
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;
|
||||
_win32_code_domain &operator=(_win32_code_domain &&) = default;
|
||||
~_win32_code_domain() = default;
|
||||
|
||||
//! Constexpr singleton getter. Returns the constexpr win32_code_domain variable.
|
||||
static inline constexpr const _win32_code_domain &get();
|
||||
|
||||
virtual string_ref name() const noexcept override { return string_ref("win32 domain"); } // NOLINT
|
||||
protected:
|
||||
virtual bool _do_failure(const status_code<void> &code) const noexcept override // NOLINT
|
||||
{
|
||||
assert(code.domain() == *this);
|
||||
return static_cast<const win32_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);
|
||||
const auto &c1 = static_cast<const win32_code &>(code1); // NOLINT
|
||||
if(code2.domain() == *this)
|
||||
{
|
||||
const auto &c2 = static_cast<const win32_code &>(code2); // NOLINT
|
||||
return c1.value() == c2.value();
|
||||
}
|
||||
if(code2.domain() == generic_code_domain)
|
||||
{
|
||||
const auto &c2 = static_cast<const generic_code &>(code2); // NOLINT
|
||||
if(static_cast<int>(c2.value()) == _win32_code_to_errno(c1.value()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
virtual generic_code _generic_code(const status_code<void> &code) const noexcept override // NOLINT
|
||||
{
|
||||
assert(code.domain() == *this);
|
||||
const auto &c = static_cast<const win32_code &>(code); // NOLINT
|
||||
return generic_code(static_cast<errc>(_win32_code_to_errno(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 win32_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 win32_code &>(code); // NOLINT
|
||||
throw status_error<_win32_code_domain>(c);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
//! (Windows only) A constexpr source variable for the win32 code domain, which is that of `GetLastError()` (Windows). Returned by `_win32_code_domain::get()`.
|
||||
constexpr _win32_code_domain win32_code_domain;
|
||||
inline constexpr const _win32_code_domain &_win32_code_domain::get()
|
||||
{
|
||||
return win32_code_domain;
|
||||
}
|
||||
|
||||
BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_END
|
||||
|
||||
#endif
|
||||
149
macx64/include/boost/outcome/experimental/status_outcome.hpp
Normal file
149
macx64/include/boost/outcome/experimental/status_outcome.hpp
Normal file
@@ -0,0 +1,149 @@
|
||||
/* A less simple result type
|
||||
(C) 2018-2019 Niall Douglas <http://www.nedproductions.biz/> (59 commits)
|
||||
File Created: Apr 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_EXPERIMENTAL_STATUS_OUTCOME_HPP
|
||||
#define BOOST_OUTCOME_EXPERIMENTAL_STATUS_OUTCOME_HPP
|
||||
|
||||
#include "../basic_outcome.hpp"
|
||||
|
||||
#include "../detail/trait_std_exception.hpp"
|
||||
#include "status_result.hpp"
|
||||
|
||||
#include "boost/exception_ptr.hpp"
|
||||
|
||||
BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_BEGIN
|
||||
template <class DomainType> inline std::exception_ptr basic_outcome_failure_exception_from_error(const status_code<DomainType> &sc)
|
||||
{
|
||||
(void) sc;
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
try
|
||||
{
|
||||
sc.throw_exception();
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
return std::current_exception();
|
||||
}
|
||||
#endif
|
||||
return {};
|
||||
}
|
||||
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 //
|
||||
>>;
|
||||
} // namespace policy
|
||||
|
||||
/*! 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>> //
|
||||
using status_outcome = basic_outcome<R, S, P, NoValuePolicy>;
|
||||
|
||||
namespace policy
|
||||
{
|
||||
template <class T, class DomainType, class E> struct status_code_throw<T, status_code<DomainType>, E> : base
|
||||
{
|
||||
using _base = base;
|
||||
template <class Impl> static constexpr void wide_value_check(Impl &&self)
|
||||
{
|
||||
if(!base::_has_value(static_cast<Impl &&>(self)))
|
||||
{
|
||||
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
|
||||
}
|
||||
if(base::_has_error(static_cast<Impl &&>(self)))
|
||||
{
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
base::_error(static_cast<Impl &&>(self)).throw_exception();
|
||||
#else
|
||||
BOOST_OUTCOME_THROW_EXCEPTION("wide value check failed");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
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>
|
||||
{
|
||||
status_code_throw() = default;
|
||||
using status_code_throw<T, status_code<DomainType>, E>::status_code_throw;
|
||||
};
|
||||
} // namespace policy
|
||||
|
||||
} // namespace experimental
|
||||
|
||||
BOOST_OUTCOME_V2_NAMESPACE_END
|
||||
|
||||
#endif
|
||||
108
macx64/include/boost/outcome/experimental/status_result.hpp
Normal file
108
macx64/include/boost/outcome/experimental/status_result.hpp
Normal file
@@ -0,0 +1,108 @@
|
||||
/* A very simple result type
|
||||
(C) 2018-2019 Niall Douglas <http://www.nedproductions.biz/> (59 commits)
|
||||
File Created: Apr 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_EXPERIMENTAL_STATUS_RESULT_HPP
|
||||
#define BOOST_OUTCOME_EXPERIMENTAL_STATUS_RESULT_HPP
|
||||
|
||||
#include "../basic_result.hpp"
|
||||
#include "../policy/fail_to_compile_observers.hpp"
|
||||
|
||||
#include "status-code/system_error2.hpp"
|
||||
|
||||
BOOST_OUTCOME_V2_NAMESPACE_EXPORT_BEGIN
|
||||
|
||||
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; }
|
||||
|
||||
} // namespace detail
|
||||
|
||||
namespace experimental
|
||||
{
|
||||
using namespace BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE;
|
||||
using BOOST_OUTCOME_V2_NAMESPACE::success;
|
||||
using BOOST_OUTCOME_V2_NAMESPACE::failure;
|
||||
|
||||
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>?");
|
||||
};
|
||||
template <class T, class DomainType> struct status_code_throw<T, status_code<DomainType>, void> : base
|
||||
{
|
||||
using _base = base;
|
||||
template <class Impl> static constexpr void wide_value_check(Impl &&self)
|
||||
{
|
||||
if(!base::_has_value(static_cast<Impl &&>(self)))
|
||||
{
|
||||
if(base::_has_error(static_cast<Impl &&>(self)))
|
||||
{
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
base::_error(static_cast<Impl &&>(self)).throw_exception();
|
||||
#else
|
||||
BOOST_OUTCOME_THROW_EXCEPTION("wide value check failed");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
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>
|
||||
{
|
||||
status_code_throw() = default;
|
||||
using status_code_throw<T, status_code<DomainType>, void>::status_code_throw;
|
||||
};
|
||||
|
||||
template <class T, class EC>
|
||||
using default_status_result_policy = std::conditional_t< //
|
||||
std::is_void<EC>::value, //
|
||||
BOOST_OUTCOME_V2_NAMESPACE::policy::terminate, //
|
||||
std::conditional_t<is_status_code<EC>::value || is_errored_status_code<EC>::value, //
|
||||
status_code_throw<T, EC, void>, //
|
||||
BOOST_OUTCOME_V2_NAMESPACE::policy::fail_to_compile_observers //
|
||||
>>;
|
||||
} // namespace policy
|
||||
|
||||
/*! AWAITING HUGO JSON CONVERSION TOOL
|
||||
SIGNATURE NOT RECOGNISED
|
||||
*/
|
||||
template <class R, class S = system_code, class NoValuePolicy = policy::default_status_result_policy<R, S>> //
|
||||
using status_result = basic_result<R, S, NoValuePolicy>;
|
||||
|
||||
} // namespace experimental
|
||||
|
||||
BOOST_OUTCOME_V2_NAMESPACE_END
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user