Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-04-04 08:33:21

0001 /* Proposed SG14 status_code
0002 (C) 2018 - 2022 Niall Douglas <http://www.nedproductions.biz/> (5 commits)
0003 File Created: Mar 2022
0004 
0005 
0006 Licensed under the Apache License, Version 2.0 (the "License");
0007 you may not use this file except in compliance with the License.
0008 You may obtain a copy of the License in the accompanying file
0009 Licence.txt or at
0010 
0011 http://www.apache.org/licenses/LICENSE-2.0
0012 
0013 Unless required by applicable law or agreed to in writing, software
0014 distributed under the License is distributed on an "AS IS" BASIS,
0015 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0016 See the License for the specific language governing permissions and
0017 limitations under the License.
0018 
0019 
0020 Distributed under the Boost Software License, Version 1.0.
0021 (See accompanying file Licence.txt or copy at
0022 http://www.boost.org/LICENSE_1_0.txt)
0023 */
0024 
0025 #ifndef BOOST_OUTCOME_SYSTEM_ERROR2_BOOST_ERROR_CODE_HPP
0026 #define BOOST_OUTCOME_SYSTEM_ERROR2_BOOST_ERROR_CODE_HPP
0027 
0028 #ifndef BOOST_OUTCOME_SYSTEM_ERROR2_NOT_POSIX
0029 #include "posix_code.hpp"
0030 #endif
0031 
0032 #if defined(_WIN32) || defined(BOOST_OUTCOME_STANDARDESE_IS_IN_THE_HOUSE)
0033 #include "win32_code.hpp"
0034 #endif
0035 
0036 #include "std_error_code.hpp"
0037 
0038 #include <boost/system/error_code.hpp>
0039 #include <boost/system/system_error.hpp>
0040 
0041 #include <system_error>
0042 
0043 BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_BEGIN
0044 
0045 class _boost_error_code_domain;
0046 //! A `status_code` representing exactly a `boost::system::error_code`
0047 using boost_error_code = status_code<_boost_error_code_domain>;
0048 
0049 namespace mixins
0050 {
0051   template <class Base> struct mixin<Base, _boost_error_code_domain> : public Base
0052   {
0053     using Base::Base;
0054 
0055     //! Implicit constructor from a `boost::system::error_code`
0056     inline mixin(boost::system::error_code ec);
0057 
0058     //! Returns the error code category
0059     inline const boost::system::error_category &category() const noexcept;
0060   };
0061 }  // namespace mixins
0062 
0063 
0064 /*! The implementation of the domain for `boost::system::error_code` error codes.
0065  */
0066 class _boost_error_code_domain final : public status_code_domain
0067 {
0068   template <class DomainType> friend class status_code;
0069   using _base = status_code_domain;
0070   using _error_code_type = boost::system::error_code;
0071   using _error_category_type = boost::system::error_category;
0072 
0073   std::string _name;
0074 
0075   static _base::string_ref _make_string_ref(_error_code_type c) noexcept
0076   {
0077 #if defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)
0078     try
0079 #endif
0080     {
0081       std::string msg = c.message();
0082       auto *p = static_cast<char *>(malloc(msg.size() + 1));  // NOLINT
0083       if(p == nullptr)
0084       {
0085         return _base::string_ref("failed to allocate message");
0086       }
0087       memcpy(p, msg.c_str(), msg.size() + 1);
0088       return _base::atomic_refcounted_string_ref(p, msg.size());
0089     }
0090 #if defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)
0091     catch(...)
0092     {
0093       return _base::string_ref("failed to allocate message");
0094     }
0095 #endif
0096   }
0097 
0098 public:
0099   //! The value type of the `boost::system::error_code` code, which stores the `int` from the `boost::system::error_code`
0100   using value_type = int;
0101   using _base::string_ref;
0102 
0103   //! Returns the error category singleton pointer this status code domain represents
0104   const _error_category_type &error_category() const noexcept
0105   {
0106     auto ptr = 0x0ea88ff382d94915 ^ this->id();
0107     return *reinterpret_cast<const _error_category_type *>(ptr);
0108   }
0109 
0110   //! Default constructor
0111   explicit _boost_error_code_domain(const _error_category_type &category) noexcept
0112       : _base(0x0ea88ff382d94915 ^ reinterpret_cast<_base::unique_id_type>(&category))
0113       , _name("boost_error_code_domain(")
0114   {
0115     _name.append(category.name());
0116     _name.push_back(')');
0117   }
0118   _boost_error_code_domain(const _boost_error_code_domain &) = default;
0119   _boost_error_code_domain(_boost_error_code_domain &&) = default;
0120   _boost_error_code_domain &operator=(const _boost_error_code_domain &) = default;
0121   _boost_error_code_domain &operator=(_boost_error_code_domain &&) = default;
0122   ~_boost_error_code_domain() = default;
0123 
0124   static inline const _boost_error_code_domain *get(_error_code_type ec);
0125 
0126   virtual string_ref name() const noexcept override { return string_ref(_name.c_str(), _name.size()); }  // NOLINT
0127 
0128   virtual payload_info_t payload_info() const noexcept override
0129   {
0130     return {sizeof(value_type), sizeof(status_code_domain *) + sizeof(value_type),
0131             (alignof(value_type) > alignof(status_code_domain *)) ? alignof(value_type) : alignof(status_code_domain *)};
0132   }
0133 
0134 protected:
0135   virtual bool _do_failure(const status_code<void> &code) const noexcept override;
0136   virtual bool _do_equivalent(const status_code<void> &code1, const status_code<void> &code2) const noexcept override;
0137   virtual generic_code _generic_code(const status_code<void> &code) const noexcept override;
0138   virtual string_ref _do_message(const status_code<void> &code) const noexcept override;
0139 #if defined(_CPPUNWIND) || defined(__EXCEPTIONS) || defined(BOOST_OUTCOME_STANDARDESE_IS_IN_THE_HOUSE)
0140   BOOST_OUTCOME_SYSTEM_ERROR2_NORETURN virtual void _do_throw_exception(const status_code<void> &code) const override;
0141 #endif
0142 };
0143 
0144 namespace detail
0145 {
0146   extern inline _boost_error_code_domain *boost_error_code_domain_from_category(const boost::system::error_category &category)
0147   {
0148     static constexpr size_t max_items = 64;
0149     static struct storage_t
0150     {
0151       std::atomic<unsigned> _lock;
0152       union item_t
0153       {
0154         int _init;
0155         _boost_error_code_domain domain;
0156         constexpr item_t()
0157             : _init(0)
0158         {
0159         }
0160         ~item_t() {}
0161       } items[max_items];
0162       size_t count{0};
0163 
0164       void lock()
0165       {
0166         while(_lock.exchange(1, std::memory_order_acquire) != 0)
0167           ;
0168       }
0169       void unlock() { _lock.store(0, std::memory_order_release); }
0170 
0171       storage_t() {}
0172       ~storage_t()
0173       {
0174         lock();
0175         for(size_t n = 0; n < count; n++)
0176         {
0177           items[n].domain.~_boost_error_code_domain();
0178         }
0179         unlock();
0180       }
0181       _boost_error_code_domain *add(const boost::system::error_category &category)
0182       {
0183         _boost_error_code_domain *ret = nullptr;
0184         lock();
0185         for(size_t n = 0; n < count; n++)
0186         {
0187           if(items[n].domain.error_category() == category)
0188           {
0189             ret = &items[n].domain;
0190             break;
0191           }
0192         }
0193         if(ret == nullptr && count < max_items)
0194         {
0195           ret = new(BOOST_OUTCOME_SYSTEM_ERROR2_ADDRESS_OF(items[count++].domain)) _boost_error_code_domain(category);
0196         }
0197         unlock();
0198         return ret;
0199       }
0200     } storage;
0201     return storage.add(category);
0202   }
0203 }  // namespace detail
0204 
0205 namespace mixins
0206 {
0207   template <class Base>
0208   inline mixin<Base, _boost_error_code_domain>::mixin(boost::system::error_code ec)
0209       : Base(typename Base::_value_type_constructor{}, _boost_error_code_domain::get(ec), ec.value())
0210   {
0211   }
0212 
0213   template <class Base> inline const boost::system::error_category &mixin<Base, _boost_error_code_domain>::category() const noexcept
0214   {
0215     const auto &domain = static_cast<const _boost_error_code_domain &>(this->domain());
0216     return domain.error_category();
0217   };
0218 }  // namespace mixins
0219 
0220 inline const _boost_error_code_domain *_boost_error_code_domain::get(boost::system::error_code ec)
0221 {
0222   auto *p = detail::boost_error_code_domain_from_category(ec.category());
0223   assert(p != nullptr);
0224   if(p == nullptr)
0225   {
0226     abort();
0227   }
0228   return p;
0229 }
0230 
0231 
0232 inline bool _boost_error_code_domain::_do_failure(const status_code<void> &code) const noexcept
0233 {
0234   assert(code.domain() == *this);
0235   return static_cast<const boost_error_code &>(code).value() != 0;  // NOLINT
0236 }
0237 
0238 inline bool _boost_error_code_domain::_do_equivalent(const status_code<void> &code1, const status_code<void> &code2) const noexcept
0239 {
0240   assert(code1.domain() == *this);
0241   const auto &c1 = static_cast<const boost_error_code &>(code1);  // NOLINT
0242   const auto &cat1 = c1.category();
0243   // Are we comparing to another wrapped error_code?
0244   if(code2.domain() == *this)
0245   {
0246     const auto &c2 = static_cast<const boost_error_code &>(code2);  // NOLINT
0247     const auto &cat2 = c2.category();
0248     // If the error code categories are identical, do literal comparison
0249     if(cat1 == cat2)
0250     {
0251       return c1.value() == c2.value();
0252     }
0253     // Otherwise fall back onto the _generic_code comparison, which uses default_error_condition()
0254     return false;
0255   }
0256   // Am I an error code with generic category?
0257   if(cat1 == boost::system::generic_category())
0258   {
0259     // Convert to generic code, and compare that
0260     generic_code _c1(static_cast<errc>(c1.value()));
0261     return _c1 == code2;
0262   }
0263   // Am I an error code with system category?
0264   if(cat1 == boost::system::system_category())
0265   {
0266 // Convert to POSIX or Win32 code, and compare that
0267 #ifdef _WIN32
0268     win32_code _c1((win32::DWORD) c1.value());
0269     return _c1 == code2;
0270 #elif !defined(BOOST_OUTCOME_SYSTEM_ERROR2_NOT_POSIX)
0271     posix_code _c1(c1.value());
0272     return _c1 == code2;
0273 #endif
0274   }
0275   return false;
0276 }
0277 
0278 inline generic_code _boost_error_code_domain::_generic_code(const status_code<void> &code) const noexcept
0279 {
0280   assert(code.domain() == *this);
0281   const auto &c = static_cast<const boost_error_code &>(code);  // NOLINT
0282   // Ask my embedded error code for its mapping to boost::system::errc, which is a subset of our generic_code errc.
0283   boost::system::error_condition cond(c.category().default_error_condition(c.value()));
0284   if(cond.category() == boost::system::generic_category())
0285   {
0286     return generic_code(static_cast<errc>(cond.value()));
0287   }
0288 #if !defined(BOOST_OUTCOME_SYSTEM_ERROR2_NOT_POSIX) && !defined(_WIN32)
0289   if(cond.category() == boost::system::system_category())
0290   {
0291     return generic_code(static_cast<errc>(cond.value()));
0292   }
0293 #endif
0294   return errc::unknown;
0295 }
0296 
0297 inline _boost_error_code_domain::string_ref _boost_error_code_domain::_do_message(const status_code<void> &code) const noexcept
0298 {
0299   assert(code.domain() == *this);
0300   const auto &c = static_cast<const boost_error_code &>(code);  // NOLINT
0301   return _make_string_ref(_error_code_type(c.value(), c.category()));
0302 }
0303 
0304 #if defined(_CPPUNWIND) || defined(__EXCEPTIONS) || defined(BOOST_OUTCOME_STANDARDESE_IS_IN_THE_HOUSE)
0305 BOOST_OUTCOME_SYSTEM_ERROR2_NORETURN inline void _boost_error_code_domain::_do_throw_exception(const status_code<void> &code) const
0306 {
0307   assert(code.domain() == *this);
0308   const auto &c = static_cast<const boost_error_code &>(code);  // NOLINT
0309   throw boost::system::system_error(boost::system::error_code(c.value(), c.category()));
0310 }
0311 #endif
0312 
0313 static_assert(sizeof(boost_error_code) <= sizeof(void *) * 2, "boost_error_code does not fit into a system_code!");
0314 
0315 BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_END
0316 
0317 // Enable implicit construction of `boost_error_code` from `boost::system::error_code`.
0318 namespace boost
0319 {
0320   namespace system
0321   {
0322     inline BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::erased_status_code<int> make_status_code(error_code c) noexcept
0323     {
0324       if(c.category() == detail::interop_category())
0325       {
0326         // This is actually a wrap of std::error_code. If this fails to compile, your Boost is too old.
0327         return std::make_status_code(std::error_code(c));
0328       }
0329       return BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::boost_error_code(c);
0330     }
0331   }  // namespace system
0332 }  // namespace boost
0333 
0334 #endif