File indexing completed on 2025-04-04 08:33:21
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025 #ifndef BOOST_OUTCOME_SYSTEM_ERROR2_NESTED_STATUS_CODE_HPP
0026 #define BOOST_OUTCOME_SYSTEM_ERROR2_NESTED_STATUS_CODE_HPP
0027
0028 #include "quick_status_code_from_enum.hpp"
0029
0030 #include <memory> // for allocator
0031
0032 BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_BEGIN
0033
0034 namespace detail
0035 {
0036 template <class StatusCode, class Allocator> class indirecting_domain : public status_code_domain
0037 {
0038 template <class DomainType> friend class status_code;
0039 using _base = status_code_domain;
0040
0041 public:
0042 struct payload_type
0043 {
0044 using allocator_traits = std::allocator_traits<Allocator>;
0045 union
0046 {
0047 char _uninit[sizeof(StatusCode)];
0048 StatusCode sc;
0049 };
0050 Allocator alloc;
0051
0052 payload_type(StatusCode _sc, Allocator _alloc)
0053 : alloc(static_cast<Allocator &&>(_alloc))
0054 {
0055 allocator_traits::construct(alloc, &sc, static_cast<StatusCode &&>(_sc));
0056 }
0057 payload_type(const payload_type &) = delete;
0058 payload_type(payload_type &&) = delete;
0059 ~payload_type() { allocator_traits::destroy(alloc, &sc); }
0060 };
0061 using value_type = payload_type *;
0062 using payload_allocator_traits = typename payload_type::allocator_traits::template rebind_traits<payload_type>;
0063 using _base::string_ref;
0064
0065 constexpr indirecting_domain() noexcept
0066 : _base(0xc44f7bdeb2cc50e9 ^ typename StatusCode::domain_type().id() )
0067 {
0068 }
0069 indirecting_domain(const indirecting_domain &) = default;
0070 indirecting_domain(indirecting_domain &&) = default;
0071 indirecting_domain &operator=(const indirecting_domain &) = default;
0072 indirecting_domain &operator=(indirecting_domain &&) = default;
0073 ~indirecting_domain() = default;
0074
0075 #if __cplusplus < 201402L && !defined(_MSC_VER)
0076 static inline const indirecting_domain &get()
0077 {
0078 static indirecting_domain v;
0079 return v;
0080 }
0081 #else
0082 static inline constexpr const indirecting_domain &get();
0083 #endif
0084
0085 virtual string_ref name() const noexcept override { return typename StatusCode::domain_type().name(); }
0086
0087 virtual payload_info_t payload_info() const noexcept override
0088 {
0089 return {sizeof(value_type), sizeof(status_code_domain *) + sizeof(value_type),
0090 (alignof(value_type) > alignof(status_code_domain *)) ? alignof(value_type) : alignof(status_code_domain *)};
0091 }
0092
0093 protected:
0094 using _mycode = status_code<indirecting_domain>;
0095 virtual bool _do_failure(const status_code<void> &code) const noexcept override
0096 {
0097 assert(code.domain() == *this);
0098 const auto &c = static_cast<const _mycode &>(code);
0099 return static_cast<status_code_domain &&>(typename StatusCode::domain_type())._do_failure(c.value()->sc);
0100 }
0101 virtual bool _do_equivalent(const status_code<void> &code1, const status_code<void> &code2) const noexcept override
0102 {
0103 assert(code1.domain() == *this);
0104 const auto &c1 = static_cast<const _mycode &>(code1);
0105 return static_cast<status_code_domain &&>(typename StatusCode::domain_type())._do_equivalent(c1.value()->sc, code2);
0106 }
0107 virtual generic_code _generic_code(const status_code<void> &code) const noexcept override
0108 {
0109 assert(code.domain() == *this);
0110 const auto &c = static_cast<const _mycode &>(code);
0111 return static_cast<status_code_domain &&>(typename StatusCode::domain_type())._generic_code(c.value()->sc);
0112 }
0113 virtual string_ref _do_message(const status_code<void> &code) const noexcept override
0114 {
0115 assert(code.domain() == *this);
0116 const auto &c = static_cast<const _mycode &>(code);
0117 return static_cast<status_code_domain &&>(typename StatusCode::domain_type())._do_message(c.value()->sc);
0118 }
0119 #if defined(_CPPUNWIND) || defined(__EXCEPTIONS) || defined(BOOST_OUTCOME_STANDARDESE_IS_IN_THE_HOUSE)
0120 BOOST_OUTCOME_SYSTEM_ERROR2_NORETURN virtual void _do_throw_exception(const status_code<void> &code) const override
0121 {
0122 assert(code.domain() == *this);
0123 const auto &c = static_cast<const _mycode &>(code);
0124 static_cast<status_code_domain &&>(typename StatusCode::domain_type())._do_throw_exception(c.value()->sc);
0125 abort();
0126 }
0127 #endif
0128 virtual bool _do_erased_copy(status_code<void> &dst, const status_code<void> &src, payload_info_t dstinfo) const override
0129 {
0130
0131 const auto srcinfo = payload_info();
0132 assert(src.domain() == *this);
0133 if(dstinfo.total_size < srcinfo.total_size)
0134 {
0135 return false;
0136 }
0137 auto &d = static_cast<_mycode &>(dst);
0138 const auto &_s = static_cast<const _mycode &>(src);
0139 const payload_type &sp = *_s.value();
0140 typename payload_allocator_traits::template rebind_alloc<payload_type> payload_alloc(sp.alloc);
0141 auto *dp = payload_allocator_traits::allocate(payload_alloc, 1);
0142 #if defined(_CPPUNWIND) || defined(__EXCEPTIONS) || defined(BOOST_OUTCOME_STANDARDESE_IS_IN_THE_HOUSE)
0143 try
0144 #endif
0145 {
0146 payload_allocator_traits::construct(payload_alloc, dp, sp.sc, sp.alloc);
0147 new(BOOST_OUTCOME_SYSTEM_ERROR2_ADDRESS_OF(d)) _mycode(in_place, dp);
0148 }
0149 #if defined(_CPPUNWIND) || defined(__EXCEPTIONS) || defined(BOOST_OUTCOME_STANDARDESE_IS_IN_THE_HOUSE)
0150 catch(...)
0151 {
0152 payload_allocator_traits::deallocate(payload_alloc, dp, 1);
0153 throw;
0154 }
0155 #endif
0156 return true;
0157 }
0158 virtual void _do_erased_destroy(status_code<void> &code, payload_info_t ) const noexcept override
0159 {
0160 assert(code.domain() == *this);
0161 auto &c = static_cast<_mycode &>(code);
0162 payload_type *p = c.value();
0163 typename payload_allocator_traits::template rebind_alloc<payload_type> payload_alloc(p->alloc);
0164 payload_allocator_traits::destroy(payload_alloc, p);
0165 payload_allocator_traits::deallocate(payload_alloc, p, 1);
0166 }
0167 };
0168 #if __cplusplus >= 201402L || defined(_MSC_VER)
0169 template <class StatusCode, class Allocator> constexpr indirecting_domain<StatusCode, Allocator> _indirecting_domain{};
0170 template <class StatusCode, class Allocator>
0171 inline constexpr const indirecting_domain<StatusCode, Allocator> &indirecting_domain<StatusCode, Allocator>::get()
0172 {
0173 return _indirecting_domain<StatusCode, Allocator>;
0174 }
0175 #endif
0176 }
0177
0178
0179
0180
0181
0182
0183
0184
0185 BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(class T, class Alloc = std::allocator<typename std::decay<T>::type>)
0186 BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(is_status_code<T>::value))
0187 inline status_code<detail::erased<typename std::add_pointer<typename std::decay<T>::type>::type>> make_nested_status_code(T &&v, Alloc alloc = {})
0188 {
0189 using status_code_type = typename std::decay<T>::type;
0190 using domain_type = detail::indirecting_domain<status_code_type, typename std::decay<Alloc>::type>;
0191 using payload_allocator_traits = typename domain_type::payload_allocator_traits;
0192 typename payload_allocator_traits::template rebind_alloc<typename domain_type::payload_type> payload_alloc(alloc);
0193 auto *p = payload_allocator_traits::allocate(payload_alloc, 1);
0194 #if defined(_CPPUNWIND) || defined(__EXCEPTIONS) || defined(BOOST_OUTCOME_STANDARDESE_IS_IN_THE_HOUSE)
0195 try
0196 #endif
0197 {
0198 payload_allocator_traits::construct(payload_alloc, p, static_cast<T &&>(v), static_cast<Alloc &&>(alloc));
0199 return status_code<domain_type>(in_place, p);
0200 }
0201 #if defined(_CPPUNWIND) || defined(__EXCEPTIONS) || defined(BOOST_OUTCOME_STANDARDESE_IS_IN_THE_HOUSE)
0202 catch(...)
0203 {
0204 payload_allocator_traits::deallocate(payload_alloc, p, 1);
0205 throw;
0206 }
0207 #endif
0208 }
0209
0210
0211
0212
0213 BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(class StatusCode, class U)
0214 BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(is_status_code<StatusCode>::value)) inline StatusCode *get_if(status_code<detail::erased<U>> *v) noexcept
0215 {
0216 if((0xc44f7bdeb2cc50e9 ^ typename StatusCode::domain_type().id()) != v->domain().id())
0217 {
0218 return nullptr;
0219 }
0220 union
0221 {
0222 U value;
0223 StatusCode *ret;
0224 };
0225 value = v->value();
0226 return ret;
0227 }
0228
0229 BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(class StatusCode, class U)
0230 BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(is_status_code<StatusCode>::value))
0231 inline const StatusCode *get_if(const status_code<detail::erased<U>> *v) noexcept
0232 {
0233 if((0xc44f7bdeb2cc50e9 ^ typename StatusCode::domain_type().id()) != v->domain().id())
0234 {
0235 return nullptr;
0236 }
0237 union
0238 {
0239 U value;
0240 const StatusCode *ret;
0241 };
0242 value = v->value();
0243 return ret;
0244 }
0245
0246
0247
0248
0249 template <class U> inline typename status_code_domain::unique_id_type get_id(const status_code<detail::erased<U>> &v) noexcept
0250 {
0251 return 0xc44f7bdeb2cc50e9 ^ v.domain().id();
0252 }
0253
0254 BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_END
0255
0256 #endif