Chris@16: // boost/system/error_code.hpp ---------------------------------------------// Chris@16: Chris@16: // Copyright Beman Dawes 2006, 2007 Chris@16: // Copyright Christoper Kohlhoff 2007 Chris@16: Chris@16: // Distributed under the Boost Software License, Version 1.0. (See accompanying Chris@16: // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Chris@16: Chris@16: // See library home page at http://www.boost.org/libs/system Chris@16: Chris@16: #ifndef BOOST_ERROR_CODE_HPP Chris@16: #define BOOST_ERROR_CODE_HPP Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: // TODO: undef these macros if not already defined Chris@16: #include Chris@16: Chris@16: #if !defined(BOOST_POSIX_API) && !defined(BOOST_WINDOWS_API) Chris@16: # error BOOST_POSIX_API or BOOST_WINDOWS_API must be defined Chris@16: #endif Chris@16: Chris@16: #include // must be the last #include Chris@16: Chris@16: #ifndef BOOST_SYSTEM_NOEXCEPT Chris@16: #define BOOST_SYSTEM_NOEXCEPT BOOST_NOEXCEPT Chris@16: #endif Chris@16: Chris@16: namespace boost Chris@16: { Chris@16: namespace system Chris@16: { Chris@16: Chris@16: class error_code; Chris@16: class error_condition; Chris@16: Chris@16: // "Concept" helpers ---------------------------------------------------// Chris@16: Chris@16: template< class T > Chris@16: struct is_error_code_enum { static const bool value = false; }; Chris@16: Chris@16: template< class T > Chris@16: struct is_error_condition_enum { static const bool value = false; }; Chris@16: Chris@16: // generic error_conditions --------------------------------------------// Chris@16: Chris@16: namespace errc Chris@16: { Chris@16: enum errc_t Chris@16: { Chris@16: success = 0, Chris@16: address_family_not_supported = EAFNOSUPPORT, Chris@16: address_in_use = EADDRINUSE, Chris@16: address_not_available = EADDRNOTAVAIL, Chris@16: already_connected = EISCONN, Chris@16: argument_list_too_long = E2BIG, Chris@16: argument_out_of_domain = EDOM, Chris@16: bad_address = EFAULT, Chris@16: bad_file_descriptor = EBADF, Chris@16: bad_message = EBADMSG, Chris@16: broken_pipe = EPIPE, Chris@16: connection_aborted = ECONNABORTED, Chris@16: connection_already_in_progress = EALREADY, Chris@16: connection_refused = ECONNREFUSED, Chris@16: connection_reset = ECONNRESET, Chris@16: cross_device_link = EXDEV, Chris@16: destination_address_required = EDESTADDRREQ, Chris@16: device_or_resource_busy = EBUSY, Chris@16: directory_not_empty = ENOTEMPTY, Chris@16: executable_format_error = ENOEXEC, Chris@16: file_exists = EEXIST, Chris@16: file_too_large = EFBIG, Chris@16: filename_too_long = ENAMETOOLONG, Chris@16: function_not_supported = ENOSYS, Chris@16: host_unreachable = EHOSTUNREACH, Chris@16: identifier_removed = EIDRM, Chris@16: illegal_byte_sequence = EILSEQ, Chris@16: inappropriate_io_control_operation = ENOTTY, Chris@16: interrupted = EINTR, Chris@16: invalid_argument = EINVAL, Chris@16: invalid_seek = ESPIPE, Chris@16: io_error = EIO, Chris@16: is_a_directory = EISDIR, Chris@16: message_size = EMSGSIZE, Chris@16: network_down = ENETDOWN, Chris@16: network_reset = ENETRESET, Chris@16: network_unreachable = ENETUNREACH, Chris@16: no_buffer_space = ENOBUFS, Chris@16: no_child_process = ECHILD, Chris@16: no_link = ENOLINK, Chris@16: no_lock_available = ENOLCK, Chris@16: no_message_available = ENODATA, Chris@16: no_message = ENOMSG, Chris@16: no_protocol_option = ENOPROTOOPT, Chris@16: no_space_on_device = ENOSPC, Chris@16: no_stream_resources = ENOSR, Chris@16: no_such_device_or_address = ENXIO, Chris@16: no_such_device = ENODEV, Chris@16: no_such_file_or_directory = ENOENT, Chris@16: no_such_process = ESRCH, Chris@16: not_a_directory = ENOTDIR, Chris@16: not_a_socket = ENOTSOCK, Chris@16: not_a_stream = ENOSTR, Chris@16: not_connected = ENOTCONN, Chris@16: not_enough_memory = ENOMEM, Chris@16: not_supported = ENOTSUP, Chris@16: operation_canceled = ECANCELED, Chris@16: operation_in_progress = EINPROGRESS, Chris@16: operation_not_permitted = EPERM, Chris@16: operation_not_supported = EOPNOTSUPP, Chris@16: operation_would_block = EWOULDBLOCK, Chris@16: owner_dead = EOWNERDEAD, Chris@16: permission_denied = EACCES, Chris@16: protocol_error = EPROTO, Chris@16: protocol_not_supported = EPROTONOSUPPORT, Chris@16: read_only_file_system = EROFS, Chris@16: resource_deadlock_would_occur = EDEADLK, Chris@16: resource_unavailable_try_again = EAGAIN, Chris@16: result_out_of_range = ERANGE, Chris@16: state_not_recoverable = ENOTRECOVERABLE, Chris@16: stream_timeout = ETIME, Chris@16: text_file_busy = ETXTBSY, Chris@16: timed_out = ETIMEDOUT, Chris@16: too_many_files_open_in_system = ENFILE, Chris@16: too_many_files_open = EMFILE, Chris@16: too_many_links = EMLINK, Chris@16: too_many_symbolic_link_levels = ELOOP, Chris@16: value_too_large = EOVERFLOW, Chris@16: wrong_protocol_type = EPROTOTYPE Chris@16: }; Chris@16: Chris@16: } // namespace errc Chris@16: Chris@16: # ifndef BOOST_SYSTEM_NO_DEPRECATED Chris@16: namespace posix = errc; Chris@16: namespace posix_error = errc; Chris@16: # endif Chris@16: Chris@16: template<> struct is_error_condition_enum Chris@16: { static const bool value = true; }; Chris@16: Chris@16: Chris@16: // ----------------------------------------------------------------------// Chris@16: Chris@16: // Operating system specific interfaces --------------------------------// Chris@16: Chris@16: Chris@16: // The interface is divided into general and system-specific portions to Chris@16: // meet these requirements: Chris@16: // Chris@16: // * Code calling an operating system API can create an error_code with Chris@16: // a single category (system_category), even for POSIX-like operating Chris@16: // systems that return some POSIX errno values and some native errno Chris@16: // values. This code should not have to pay the cost of distinguishing Chris@16: // between categories, since it is not yet known if that is needed. Chris@16: // Chris@16: // * Users wishing to write system-specific code should be given enums for Chris@16: // at least the common error cases. Chris@16: // Chris@16: // * System specific code should fail at compile time if moved to another Chris@16: // operating system. Chris@16: Chris@16: // The system specific portions of the interface are located in headers Chris@16: // with names reflecting the operating system. For example, Chris@16: // Chris@16: // Chris@16: // Chris@16: // Chris@16: // Chris@16: // These headers are effectively empty for compiles on operating systems Chris@16: // where they are not applicable. Chris@16: Chris@16: // ----------------------------------------------------------------------// Chris@16: Chris@16: // class error_category ------------------------------------------------// Chris@16: Chris@16: class error_category : public noncopyable Chris@16: { Chris@16: public: Chris@16: virtual ~error_category(){} Chris@16: Chris@16: virtual const char * name() const BOOST_SYSTEM_NOEXCEPT = 0; Chris@16: virtual std::string message( int ev ) const = 0; Chris@16: inline virtual error_condition default_error_condition( int ev ) const BOOST_SYSTEM_NOEXCEPT; Chris@16: inline virtual bool equivalent( int code, Chris@16: const error_condition & condition ) const BOOST_SYSTEM_NOEXCEPT; Chris@16: inline virtual bool equivalent( const error_code & code, Chris@16: int condition ) const BOOST_SYSTEM_NOEXCEPT; Chris@16: Chris@16: bool operator==(const error_category & rhs) const BOOST_SYSTEM_NOEXCEPT { return this == &rhs; } Chris@16: bool operator!=(const error_category & rhs) const BOOST_SYSTEM_NOEXCEPT { return this != &rhs; } Chris@16: bool operator<( const error_category & rhs ) const BOOST_SYSTEM_NOEXCEPT Chris@16: { Chris@16: return std::less()( this, &rhs ); Chris@16: } Chris@16: }; Chris@16: Chris@16: // predefined error categories -----------------------------------------// Chris@16: Chris@16: # ifdef BOOST_ERROR_CODE_HEADER_ONLY Chris@16: inline const error_category & system_category() BOOST_SYSTEM_NOEXCEPT; Chris@16: inline const error_category & generic_category() BOOST_SYSTEM_NOEXCEPT; Chris@16: #else Chris@16: BOOST_SYSTEM_DECL const error_category & system_category() BOOST_SYSTEM_NOEXCEPT; Chris@16: BOOST_SYSTEM_DECL const error_category & generic_category() BOOST_SYSTEM_NOEXCEPT; Chris@16: #endif Chris@16: // deprecated synonyms --------------------------------------------------// Chris@16: Chris@16: # ifndef BOOST_SYSTEM_NO_DEPRECATED Chris@16: inline const error_category & get_system_category() { return system_category(); } Chris@16: inline const error_category & get_generic_category() { return generic_category(); } Chris@16: inline const error_category & get_posix_category() { return generic_category(); } Chris@16: static const error_category & posix_category = generic_category(); Chris@16: static const error_category & errno_ecat = generic_category(); Chris@16: static const error_category & native_ecat = system_category(); Chris@16: # endif Chris@16: Chris@16: // class error_condition -----------------------------------------------// Chris@16: Chris@16: // error_conditions are portable, error_codes are system or library specific Chris@16: Chris@16: class error_condition Chris@16: { Chris@16: public: Chris@16: Chris@16: // constructors: Chris@16: error_condition() BOOST_SYSTEM_NOEXCEPT : m_val(0), m_cat(&generic_category()) {} Chris@16: error_condition( int val, const error_category & cat ) BOOST_SYSTEM_NOEXCEPT : m_val(val), m_cat(&cat) {} Chris@16: Chris@16: template Chris@16: error_condition(ErrorConditionEnum e, Chris@16: typename boost::enable_if >::type* = 0) BOOST_SYSTEM_NOEXCEPT Chris@16: { Chris@16: *this = make_error_condition(e); Chris@16: } Chris@16: Chris@16: // modifiers: Chris@16: Chris@16: void assign( int val, const error_category & cat ) BOOST_SYSTEM_NOEXCEPT Chris@16: { Chris@16: m_val = val; Chris@16: m_cat = &cat; Chris@16: } Chris@16: Chris@16: template Chris@16: typename boost::enable_if, error_condition>::type & Chris@16: operator=( ErrorConditionEnum val ) BOOST_SYSTEM_NOEXCEPT Chris@16: { Chris@16: *this = make_error_condition(val); Chris@16: return *this; Chris@16: } Chris@16: Chris@16: void clear() BOOST_SYSTEM_NOEXCEPT Chris@16: { Chris@16: m_val = 0; Chris@16: m_cat = &generic_category(); Chris@16: } Chris@16: Chris@16: // observers: Chris@16: int value() const BOOST_SYSTEM_NOEXCEPT { return m_val; } Chris@16: const error_category & category() const BOOST_SYSTEM_NOEXCEPT { return *m_cat; } Chris@16: std::string message() const { return m_cat->message(value()); } Chris@16: Chris@16: typedef void (*unspecified_bool_type)(); Chris@16: static void unspecified_bool_true() {} Chris@16: Chris@16: operator unspecified_bool_type() const BOOST_SYSTEM_NOEXCEPT // true if error Chris@16: { Chris@16: return m_val == 0 ? 0 : unspecified_bool_true; Chris@16: } Chris@16: Chris@16: bool operator!() const BOOST_SYSTEM_NOEXCEPT // true if no error Chris@16: { Chris@16: return m_val == 0; Chris@16: } Chris@16: Chris@16: // relationals: Chris@16: // the more symmetrical non-member syntax allows enum Chris@16: // conversions work for both rhs and lhs. Chris@16: inline friend bool operator==( const error_condition & lhs, Chris@16: const error_condition & rhs ) BOOST_SYSTEM_NOEXCEPT Chris@16: { Chris@16: return lhs.m_cat == rhs.m_cat && lhs.m_val == rhs.m_val; Chris@16: } Chris@16: Chris@16: inline friend bool operator<( const error_condition & lhs, Chris@16: const error_condition & rhs ) BOOST_SYSTEM_NOEXCEPT Chris@16: // the more symmetrical non-member syntax allows enum Chris@16: // conversions work for both rhs and lhs. Chris@16: { Chris@16: return lhs.m_cat < rhs.m_cat Chris@16: || (lhs.m_cat == rhs.m_cat && lhs.m_val < rhs.m_val); Chris@16: } Chris@16: Chris@16: private: Chris@16: int m_val; Chris@16: const error_category * m_cat; Chris@16: Chris@16: }; Chris@16: Chris@16: // class error_code ----------------------------------------------------// Chris@16: Chris@16: // We want error_code to be a value type that can be copied without slicing Chris@16: // and without requiring heap allocation, but we also want it to have Chris@16: // polymorphic behavior based on the error category. This is achieved by Chris@16: // abstract base class error_category supplying the polymorphic behavior, Chris@16: // and error_code containing a pointer to an object of a type derived Chris@16: // from error_category. Chris@16: class error_code Chris@16: { Chris@16: public: Chris@16: Chris@16: // constructors: Chris@16: error_code() BOOST_SYSTEM_NOEXCEPT : m_val(0), m_cat(&system_category()) {} Chris@16: error_code( int val, const error_category & cat ) BOOST_SYSTEM_NOEXCEPT : m_val(val), m_cat(&cat) {} Chris@16: Chris@16: template Chris@16: error_code(ErrorCodeEnum e, Chris@16: typename boost::enable_if >::type* = 0) BOOST_SYSTEM_NOEXCEPT Chris@16: { Chris@16: *this = make_error_code(e); Chris@16: } Chris@16: Chris@16: // modifiers: Chris@16: void assign( int val, const error_category & cat ) BOOST_SYSTEM_NOEXCEPT Chris@16: { Chris@16: m_val = val; Chris@16: m_cat = &cat; Chris@16: } Chris@16: Chris@16: template Chris@16: typename boost::enable_if, error_code>::type & Chris@16: operator=( ErrorCodeEnum val ) BOOST_SYSTEM_NOEXCEPT Chris@16: { Chris@16: *this = make_error_code(val); Chris@16: return *this; Chris@16: } Chris@16: Chris@16: void clear() BOOST_SYSTEM_NOEXCEPT Chris@16: { Chris@16: m_val = 0; Chris@16: m_cat = &system_category(); Chris@16: } Chris@16: Chris@16: // observers: Chris@16: int value() const BOOST_SYSTEM_NOEXCEPT { return m_val; } Chris@16: const error_category & category() const BOOST_SYSTEM_NOEXCEPT { return *m_cat; } Chris@16: error_condition default_error_condition() const BOOST_SYSTEM_NOEXCEPT { return m_cat->default_error_condition(value()); } Chris@16: std::string message() const { return m_cat->message(value()); } Chris@16: Chris@16: typedef void (*unspecified_bool_type)(); Chris@16: static void unspecified_bool_true() {} Chris@16: Chris@16: operator unspecified_bool_type() const BOOST_SYSTEM_NOEXCEPT // true if error Chris@16: { Chris@16: return m_val == 0 ? 0 : unspecified_bool_true; Chris@16: } Chris@16: Chris@16: bool operator!() const BOOST_SYSTEM_NOEXCEPT // true if no error Chris@16: { Chris@16: return m_val == 0; Chris@16: } Chris@16: Chris@16: // relationals: Chris@16: inline friend bool operator==( const error_code & lhs, Chris@16: const error_code & rhs ) BOOST_SYSTEM_NOEXCEPT Chris@16: // the more symmetrical non-member syntax allows enum Chris@16: // conversions work for both rhs and lhs. Chris@16: { Chris@16: return lhs.m_cat == rhs.m_cat && lhs.m_val == rhs.m_val; Chris@16: } Chris@16: Chris@16: inline friend bool operator<( const error_code & lhs, Chris@16: const error_code & rhs ) BOOST_SYSTEM_NOEXCEPT Chris@16: // the more symmetrical non-member syntax allows enum Chris@16: // conversions work for both rhs and lhs. Chris@16: { Chris@16: return lhs.m_cat < rhs.m_cat Chris@16: || (lhs.m_cat == rhs.m_cat && lhs.m_val < rhs.m_val); Chris@16: } Chris@16: Chris@16: private: Chris@16: int m_val; Chris@16: const error_category * m_cat; Chris@16: Chris@16: }; Chris@16: Chris@16: // predefined error_code object used as "throw on error" tag Chris@16: # ifndef BOOST_SYSTEM_NO_DEPRECATED Chris@16: BOOST_SYSTEM_DECL extern error_code throws; Chris@16: # endif Chris@16: Chris@16: // Moving from a "throws" object to a "throws" function without breaking Chris@16: // existing code is a bit of a problem. The workaround is to place the Chris@16: // "throws" function in namespace boost rather than namespace boost::system. Chris@16: Chris@16: } // namespace system Chris@16: Chris@16: namespace detail { inline system::error_code * throws() { return 0; } } Chris@16: // Misuse of the error_code object is turned into a noisy failure by Chris@16: // poisoning the reference. This particular implementation doesn't Chris@16: // produce warnings or errors from popular compilers, is very efficient Chris@16: // (as determined by inspecting generated code), and does not suffer Chris@16: // from order of initialization problems. In practice, it also seems Chris@16: // cause user function error handling implementation errors to be detected Chris@16: // very early in the development cycle. Chris@16: Chris@16: inline system::error_code & throws() Chris@16: { return *detail::throws(); } Chris@16: Chris@16: namespace system Chris@16: { Chris@16: // non-member functions ------------------------------------------------// Chris@16: Chris@16: inline bool operator!=( const error_code & lhs, Chris@16: const error_code & rhs ) BOOST_SYSTEM_NOEXCEPT Chris@16: { Chris@16: return !(lhs == rhs); Chris@16: } Chris@16: Chris@16: inline bool operator!=( const error_condition & lhs, Chris@16: const error_condition & rhs ) BOOST_SYSTEM_NOEXCEPT Chris@16: { Chris@16: return !(lhs == rhs); Chris@16: } Chris@16: Chris@16: inline bool operator==( const error_code & code, Chris@16: const error_condition & condition ) BOOST_SYSTEM_NOEXCEPT Chris@16: { Chris@16: return code.category().equivalent( code.value(), condition ) Chris@16: || condition.category().equivalent( code, condition.value() ); Chris@16: } Chris@16: Chris@16: inline bool operator!=( const error_code & lhs, Chris@16: const error_condition & rhs ) BOOST_SYSTEM_NOEXCEPT Chris@16: { Chris@16: return !(lhs == rhs); Chris@16: } Chris@16: Chris@16: inline bool operator==( const error_condition & condition, Chris@16: const error_code & code ) BOOST_SYSTEM_NOEXCEPT Chris@16: { Chris@16: return condition.category().equivalent( code, condition.value() ) Chris@16: || code.category().equivalent( code.value(), condition ); Chris@16: } Chris@16: Chris@16: inline bool operator!=( const error_condition & lhs, Chris@16: const error_code & rhs ) BOOST_SYSTEM_NOEXCEPT Chris@16: { Chris@16: return !(lhs == rhs); Chris@16: } Chris@16: Chris@16: // TODO: both of these may move elsewhere, but the LWG hasn't spoken yet. Chris@16: Chris@16: template Chris@16: inline std::basic_ostream& Chris@16: operator<< (std::basic_ostream& os, error_code ec) Chris@16: { Chris@16: os << ec.category().name() << ':' << ec.value(); Chris@16: return os; Chris@16: } Chris@16: Chris@16: inline std::size_t hash_value( const error_code & ec ) Chris@16: { Chris@16: return static_cast(ec.value()) Chris@16: + reinterpret_cast(&ec.category()); Chris@16: } Chris@16: Chris@16: // make_* functions for errc::errc_t -----------------------------// Chris@16: Chris@16: namespace errc Chris@16: { Chris@16: // explicit conversion: Chris@16: inline error_code make_error_code( errc_t e ) BOOST_SYSTEM_NOEXCEPT Chris@16: { return error_code( e, generic_category() ); } Chris@16: Chris@16: // implicit conversion: Chris@16: inline error_condition make_error_condition( errc_t e ) BOOST_SYSTEM_NOEXCEPT Chris@16: { return error_condition( e, generic_category() ); } Chris@16: } Chris@16: Chris@16: // error_category default implementation -------------------------------// Chris@16: Chris@16: error_condition error_category::default_error_condition( int ev ) const BOOST_SYSTEM_NOEXCEPT Chris@16: { Chris@16: return error_condition( ev, *this ); Chris@16: } Chris@16: Chris@16: bool error_category::equivalent( int code, Chris@16: const error_condition & condition ) const BOOST_SYSTEM_NOEXCEPT Chris@16: { Chris@16: return default_error_condition( code ) == condition; Chris@16: } Chris@16: Chris@16: bool error_category::equivalent( const error_code & code, Chris@16: int condition ) const BOOST_SYSTEM_NOEXCEPT Chris@16: { Chris@16: return *this == code.category() && code.value() == condition; Chris@16: } Chris@16: Chris@16: } // namespace system Chris@16: } // namespace boost Chris@16: Chris@16: #include // pops abi_prefix.hpp pragmas Chris@16: Chris@16: # ifdef BOOST_ERROR_CODE_HEADER_ONLY Chris@101: # include Chris@16: # endif Chris@16: Chris@16: #endif // BOOST_ERROR_CODE_HPP Chris@16: Chris@16: