#ifndef BOOST_SYSTEM_DETAIL_ERROR_CODE_HPP_INCLUDED #define BOOST_SYSTEM_DETAIL_ERROR_CODE_HPP_INCLUDED // Copyright Beman Dawes 2006, 2007 // Copyright Christoper Kohlhoff 2007 // Copyright Peter Dimov 2017-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // // See library home page at http://www.boost.org/libs/system #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined(BOOST_GCC) && BOOST_GCC >= 40600 && BOOST_GCC < 70000 # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wstrict-aliasing" #endif namespace boost { namespace system { // class error_code // We want error_code to be a value type that can be copied without slicing // and without requiring heap allocation, but we also want it to have // polymorphic behavior based on the error category. This is achieved by // abstract base class error_category supplying the polymorphic behavior, // and error_code containing a pointer to an object of a type derived // from error_category. bool operator==( const error_code & code, const error_condition & condition ) noexcept; std::size_t hash_value( error_code const & ec ); class error_code { private: friend bool operator==( const error_code & code, const error_condition & condition ) noexcept; friend std::size_t hash_value( error_code const & ec ); private: struct data { int val_; const error_category * cat_; }; union { data d1_; unsigned char d2_[ sizeof(std::error_code) ]; }; // 0: default constructed, d1_ value initialized // 1: holds std::error_code in d2_ // 2: holds error code in d1_, failed == false // 3: holds error code in d1_, failed == true // >3: pointer to source_location, failed_ in lsb boost::uintptr_t lc_flags_; private: char const* category_name() const noexcept { // return category().name(); if( lc_flags_ == 0 ) { // must match detail::system_error_category::name() return "system"; } else if( lc_flags_ == 1 ) { // must match detail::interop_error_category::name() return "std:unknown"; } else { return d1_.cat_->name(); } } public: // constructors: constexpr error_code() noexcept: d1_(), lc_flags_( 0 ) { } BOOST_SYSTEM_CONSTEXPR error_code( int val, const error_category & cat ) noexcept: d1_(), lc_flags_( 2 + detail::failed_impl( val, cat ) ) { d1_.val_ = val; d1_.cat_ = &cat; } error_code( int val, const error_category & cat, source_location const * loc ) noexcept: d1_(), lc_flags_( ( loc? reinterpret_cast( loc ): 2 ) | +detail::failed_impl( val, cat ) ) { d1_.val_ = val; d1_.cat_ = &cat; } template BOOST_SYSTEM_CONSTEXPR error_code( ErrorCodeEnum e, typename detail::enable_if< is_error_code_enum::value || std::is_error_code_enum::value >::type* = 0 ) noexcept: d1_(), lc_flags_( 0 ) { *this = make_error_code( e ); } error_code( error_code const& ec, source_location const * loc ) noexcept: d1_(), lc_flags_( 0 ) { *this = ec; if( ec.lc_flags_ != 0 && ec.lc_flags_ != 1 ) { lc_flags_ = ( loc? reinterpret_cast( loc ): 2 ) | ( ec.lc_flags_ & 1 ); } } error_code( std::error_code const& ec ) noexcept: d1_(), lc_flags_( 0 ) { #ifndef BOOST_NO_RTTI if( detail::std_category const* pc2 = dynamic_cast< detail::std_category const* >( &ec.category() ) ) { *this = boost::system::error_code( ec.value(), pc2->original_category() ); } else #endif { ::new( d2_ ) std::error_code( ec ); lc_flags_ = 1; } } // modifiers: BOOST_SYSTEM_CONSTEXPR void assign( int val, const error_category & cat ) noexcept { *this = error_code( val, cat ); } void assign( int val, const error_category & cat, source_location const * loc ) noexcept { *this = error_code( val, cat, loc ); } void assign( error_code const& ec, source_location const * loc ) noexcept { *this = error_code( ec, loc ); } template BOOST_SYSTEM_CONSTEXPR typename detail::enable_if::value, error_code>::type & operator=( ErrorCodeEnum val ) noexcept { *this = make_error_code( val ); return *this; } BOOST_SYSTEM_CONSTEXPR void clear() noexcept { *this = error_code(); } // observers: BOOST_SYSTEM_CONSTEXPR int value() const noexcept { if( lc_flags_ != 1 ) { return d1_.val_; } else { std::error_code const& ec = *reinterpret_cast( d2_ ); unsigned cv = static_cast( ec.value() ); unsigned ch = static_cast( reinterpret_cast( &ec.category() ) % 2097143 ); // 2^21-9, prime return static_cast( cv + 1000 * ch ); } } BOOST_SYSTEM_CONSTEXPR const error_category & category() const noexcept { if( lc_flags_ == 0 ) { return system_category(); } else if( lc_flags_ == 1 ) { return detail::interop_category(); } else { return *d1_.cat_; } } // deprecated? error_condition default_error_condition() const noexcept { return category().default_error_condition( value() ); } std::string message() const { if( lc_flags_ == 1 ) { std::error_code const& ec = *reinterpret_cast( d2_ ); return ec.message(); } else if( lc_flags_ == 0 ) { return detail::system_error_category_message( value() ); } else { return category().message( value() ); } } char const * message( char * buffer, std::size_t len ) const noexcept { if( lc_flags_ == 1 ) { std::error_code const& ec = *reinterpret_cast( d2_ ); #if !defined(BOOST_NO_EXCEPTIONS) try #endif { detail::snprintf( buffer, len, "%s", ec.message().c_str() ); return buffer; } #if !defined(BOOST_NO_EXCEPTIONS) catch( ... ) { detail::snprintf( buffer, len, "No message text available for error std:%s:%d", ec.category().name(), ec.value() ); return buffer; } #endif } else if( lc_flags_ == 0 ) { return detail::system_error_category_message( value(), buffer, len ); } else { return category().message( value(), buffer, len ); } } BOOST_SYSTEM_CONSTEXPR bool failed() const noexcept { if( lc_flags_ & 1 ) { if( lc_flags_ == 1 ) { std::error_code const& ec = *reinterpret_cast( d2_ ); return ec.value() != 0; } return true; } else { return false; } } BOOST_SYSTEM_CONSTEXPR explicit operator bool() const noexcept // true if error { return failed(); } bool has_location() const noexcept { return lc_flags_ >= 4; } source_location const & location() const noexcept { BOOST_STATIC_CONSTEXPR source_location loc; return lc_flags_ >= 4? *reinterpret_cast( lc_flags_ &~ static_cast( 1 ) ): loc; } // relationals: private: // private equality for use in error_category::equivalent friend class error_category; BOOST_SYSTEM_CONSTEXPR bool equals( int val, error_category const& cat ) const noexcept { if( lc_flags_ == 0 ) { return val == 0 && cat.id_ == detail::system_category_id; } else if( lc_flags_ == 1 ) { return cat.id_ == detail::interop_category_id && val == value(); } else { return val == d1_.val_ && cat == *d1_.cat_; } } public: // the more symmetrical non-member syntax allows enum // conversions work for both rhs and lhs. BOOST_SYSTEM_CONSTEXPR inline friend bool operator==( const error_code & lhs, const error_code & rhs ) noexcept { bool s1 = lhs.lc_flags_ == 1; bool s2 = rhs.lc_flags_ == 1; if( s1 != s2 ) return false; if( s1 && s2 ) { std::error_code const& e1 = *reinterpret_cast( lhs.d2_ ); std::error_code const& e2 = *reinterpret_cast( rhs.d2_ ); return e1 == e2; } else { return lhs.value() == rhs.value() && lhs.category() == rhs.category(); } } BOOST_SYSTEM_CONSTEXPR inline friend bool operator<( const error_code & lhs, const error_code & rhs ) noexcept { bool s1 = lhs.lc_flags_ == 1; bool s2 = rhs.lc_flags_ == 1; if( s1 < s2 ) return true; if( s2 < s1 ) return false; if( s1 && s2 ) { std::error_code const& e1 = *reinterpret_cast( lhs.d2_ ); std::error_code const& e2 = *reinterpret_cast( rhs.d2_ ); return e1 < e2; } else { return lhs.category() < rhs.category() || (lhs.category() == rhs.category() && lhs.value() < rhs.value()); } } BOOST_SYSTEM_CONSTEXPR inline friend bool operator!=( const error_code & lhs, const error_code & rhs ) noexcept { return !( lhs == rhs ); } inline friend bool operator==( std::error_code const & lhs, error_code const & rhs ) noexcept { return lhs == static_cast< std::error_code >( rhs ); } inline friend bool operator==( error_code const & lhs, std::error_code const & rhs ) noexcept { return static_cast< std::error_code >( lhs ) == rhs; } inline friend bool operator!=( std::error_code const & lhs, error_code const & rhs ) noexcept { return !( lhs == rhs ); } inline friend bool operator!=( error_code const & lhs, std::error_code const & rhs ) noexcept { return !( lhs == rhs ); } // template::value>::type> inline friend bool operator==( error_code const & lhs, E rhs ) noexcept { return lhs == make_error_condition( rhs ); } template::value>::type> inline friend bool operator==( E lhs, error_code const & rhs ) noexcept { return make_error_condition( lhs ) == rhs; } template::value>::type> inline friend bool operator!=( error_code const & lhs, E rhs ) noexcept { return !( lhs == rhs ); } template::value>::type> inline friend bool operator!=( E lhs, error_code const & rhs ) noexcept { return !( lhs == rhs ); } // template::value>::type> BOOST_SYSTEM_CONSTEXPR inline friend bool operator==( error_code const & lhs, E rhs ) noexcept { return lhs == make_error_code( rhs ); } template::value>::type> BOOST_SYSTEM_CONSTEXPR inline friend bool operator==( E lhs, error_code const & rhs ) noexcept { return make_error_code( lhs ) == rhs; } template::value>::type> BOOST_SYSTEM_CONSTEXPR inline friend bool operator!=( error_code const & lhs, E rhs ) noexcept { return !( lhs == rhs ); } template::value>::type> BOOST_SYSTEM_CONSTEXPR inline friend bool operator!=( E lhs, error_code const & rhs ) noexcept { return !( lhs == rhs ); } #if defined(BOOST_SYSTEM_CLANG_6) inline friend bool operator==( error_code const & lhs, std::error_condition const & rhs ) noexcept { return static_cast< std::error_code >( lhs ) == rhs; } inline friend bool operator==( std::error_condition const & lhs, error_code const & rhs ) noexcept { return lhs == static_cast< std::error_code >( rhs ); } inline friend bool operator!=( error_code const & lhs, std::error_condition const & rhs ) noexcept { return !( lhs == rhs ); } inline friend bool operator!=( std::error_condition const & lhs, error_code const & rhs ) noexcept { return !( lhs == rhs ); } #endif // conversions operator std::error_code () const { if( lc_flags_ == 1 ) { return *reinterpret_cast( d2_ ); } else if( lc_flags_ == 0 ) { // This condition must be the same as the one in error_category_impl.hpp #if defined(BOOST_SYSTEM_AVOID_STD_SYSTEM_CATEGORY) return std::error_code( 0, boost::system::system_category() ); #else return std::error_code(); #endif } else { return std::error_code( d1_.val_, *d1_.cat_ ); } } operator std::error_code () { return const_cast( *this ); } template::value>::type> operator T& () { if( lc_flags_ != 1 ) { std::error_code e2( *this ); ::new( d2_ ) std::error_code( e2 ); lc_flags_ = 1; } return *reinterpret_cast( d2_ ); } #if defined(BOOST_SYSTEM_CLANG_6) template::value>::type> operator T const& () = delete; #endif std::string to_string() const { if( lc_flags_ == 1 ) { std::error_code const& e2 = *reinterpret_cast( d2_ ); std::string r( "std:" ); r += e2.category().name(); detail::append_int( r, e2.value() ); return r; } else { std::string r = category_name(); detail::append_int( r, value() ); return r; } } template inline friend std::basic_ostream& operator<< (std::basic_ostream& os, error_code const & ec) { return os << ec.to_string().c_str(); } std::string what() const { std::string r = message(); r += " ["; r += to_string(); if( has_location() ) { r += " at "; r += location().to_string(); } r += "]"; return r; } }; inline bool operator==( const error_code & code, const error_condition & condition ) noexcept { if( code.lc_flags_ == 1 ) { return static_cast( code ) == static_cast( condition ); } else { return code.category().equivalent( code.value(), condition ) || condition.category().equivalent( code, condition.value() ); } } inline bool operator==( const error_condition & condition, const error_code & code ) noexcept { return code == condition; } inline bool operator!=( const error_code & lhs, const error_condition & rhs ) noexcept { return !( lhs == rhs ); } inline bool operator!=( const error_condition & lhs, const error_code & rhs ) noexcept { return !( lhs == rhs ); } inline std::size_t hash_value( error_code const & ec ) { if( ec.lc_flags_ == 1 ) { std::error_code const& e2 = *reinterpret_cast( ec.d2_ ); return std::hash()( e2 ); } error_category const & cat = ec.category(); boost::ulong_long_type id_ = cat.id_; if( id_ == 0 ) { id_ = reinterpret_cast( &cat ); } boost::ulong_long_type hv = ( boost::ulong_long_type( 0xCBF29CE4 ) << 32 ) + 0x84222325; boost::ulong_long_type const prime = ( boost::ulong_long_type( 0x00000100 ) << 32 ) + 0x000001B3; // id hv ^= id_; hv *= prime; // value hv ^= static_cast( ec.value() ); hv *= prime; return static_cast( hv ); } } // namespace system } // namespace boost #if defined(BOOST_GCC) && BOOST_GCC >= 40600 && BOOST_GCC < 70000 # pragma GCC diagnostic pop #endif #endif // #ifndef BOOST_SYSTEM_DETAIL_ERROR_CODE_HPP_INCLUDED