| // ndnboost/system/error_code.hpp ---------------------------------------------// |
| |
| // Copyright Beman Dawes 2006, 2007 |
| // Copyright Christoper Kohlhoff 2007 |
| |
| // 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 |
| |
| #ifndef NDNBOOST_ERROR_CODE_HPP |
| #define NDNBOOST_ERROR_CODE_HPP |
| |
| #include <ndnboost/system/config.hpp> |
| #include <ndnboost/cstdint.hpp> |
| #include <ndnboost/assert.hpp> |
| #include <ndnboost/operators.hpp> |
| #include <ndnboost/noncopyable.hpp> |
| #include <ndnboost/utility/enable_if.hpp> |
| #include <ostream> |
| #include <string> |
| #include <stdexcept> |
| #include <functional> |
| |
| // TODO: undef these macros if not already defined |
| #include <ndnboost/cerrno.hpp> |
| |
| #if !defined(NDNBOOST_POSIX_API) && !defined(NDNBOOST_WINDOWS_API) |
| # error NDNBOOST_POSIX_API or NDNBOOST_WINDOWS_API must be defined |
| #endif |
| |
| #include <ndnboost/config/abi_prefix.hpp> // must be the last #include |
| |
| #ifndef NDNBOOST_SYSTEM_NOEXCEPT |
| #define NDNBOOST_SYSTEM_NOEXCEPT NDNBOOST_NOEXCEPT |
| #endif |
| |
| namespace ndnboost |
| { |
| namespace system |
| { |
| |
| class error_code; |
| class error_condition; |
| |
| // "Concept" helpers ---------------------------------------------------// |
| |
| template< class T > |
| struct is_error_code_enum { static const bool value = false; }; |
| |
| template< class T > |
| struct is_error_condition_enum { static const bool value = false; }; |
| |
| // generic error_conditions --------------------------------------------// |
| |
| namespace errc |
| { |
| enum errc_t |
| { |
| success = 0, |
| 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_available = ENODATA, |
| 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, |
| protocol_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 errc |
| |
| # ifndef NDNBOOST_SYSTEM_NO_DEPRECATED |
| namespace posix = errc; |
| namespace posix_error = errc; |
| # endif |
| |
| template<> struct is_error_condition_enum<errc::errc_t> |
| { static const bool value = true; }; |
| |
| |
| // ----------------------------------------------------------------------// |
| |
| // Operating system specific interfaces --------------------------------// |
| |
| |
| // The interface is divided into general and system-specific portions to |
| // meet these requirements: |
| // |
| // * Code calling an operating system API can create an error_code with |
| // a single category (system_category), even for POSIX-like operating |
| // systems that return some POSIX errno values and some native errno |
| // values. This code should not have to pay the cost of distinguishing |
| // between categories, since it is not yet known if that is needed. |
| // |
| // * Users wishing to write system-specific code should be given enums for |
| // at least the common error cases. |
| // |
| // * System specific code should fail at compile time if moved to another |
| // operating system. |
| |
| // The system specific portions of the interface are located in headers |
| // with names reflecting the operating system. For example, |
| // |
| // <ndnboost/system/cygwin_error.hpp> |
| // <ndnboost/system/linux_error.hpp> |
| // <ndnboost/system/windows_error.hpp> |
| // |
| // These headers are effectively empty for compiles on operating systems |
| // where they are not applicable. |
| |
| // ----------------------------------------------------------------------// |
| |
| // class error_category ------------------------------------------------// |
| |
| class error_category : public noncopyable |
| { |
| public: |
| virtual ~error_category(){} |
| |
| virtual const char * name() const NDNBOOST_SYSTEM_NOEXCEPT = 0; |
| virtual std::string message( int ev ) const = 0; |
| inline virtual error_condition default_error_condition( int ev ) const NDNBOOST_SYSTEM_NOEXCEPT; |
| inline virtual bool equivalent( int code, |
| const error_condition & condition ) const NDNBOOST_SYSTEM_NOEXCEPT; |
| inline virtual bool equivalent( const error_code & code, |
| int condition ) const NDNBOOST_SYSTEM_NOEXCEPT; |
| |
| bool operator==(const error_category & rhs) const NDNBOOST_SYSTEM_NOEXCEPT { return this == &rhs; } |
| bool operator!=(const error_category & rhs) const NDNBOOST_SYSTEM_NOEXCEPT { return this != &rhs; } |
| bool operator<( const error_category & rhs ) const NDNBOOST_SYSTEM_NOEXCEPT |
| { |
| return std::less<const error_category*>()( this, &rhs ); |
| } |
| }; |
| |
| // predefined error categories -----------------------------------------// |
| |
| # ifdef NDNBOOST_ERROR_CODE_HEADER_ONLY |
| inline const error_category & system_category() NDNBOOST_SYSTEM_NOEXCEPT; |
| inline const error_category & generic_category() NDNBOOST_SYSTEM_NOEXCEPT; |
| #else |
| NDNBOOST_SYSTEM_DECL const error_category & system_category() NDNBOOST_SYSTEM_NOEXCEPT; |
| NDNBOOST_SYSTEM_DECL const error_category & generic_category() NDNBOOST_SYSTEM_NOEXCEPT; |
| #endif |
| // deprecated synonyms --------------------------------------------------// |
| |
| # ifndef NDNBOOST_SYSTEM_NO_DEPRECATED |
| inline const error_category & get_system_category() { return system_category(); } |
| inline const error_category & get_generic_category() { return generic_category(); } |
| inline const error_category & get_posix_category() { return generic_category(); } |
| static const error_category & posix_category = generic_category(); |
| static const error_category & errno_ecat = generic_category(); |
| static const error_category & native_ecat = system_category(); |
| # endif |
| |
| // class error_condition -----------------------------------------------// |
| |
| // error_conditions are portable, error_codes are system or library specific |
| |
| class error_condition |
| { |
| public: |
| |
| // constructors: |
| error_condition() NDNBOOST_SYSTEM_NOEXCEPT : m_val(0), m_cat(&generic_category()) {} |
| error_condition( int val, const error_category & cat ) NDNBOOST_SYSTEM_NOEXCEPT : m_val(val), m_cat(&cat) {} |
| |
| template <class ErrorConditionEnum> |
| error_condition(ErrorConditionEnum e, |
| typename ndnboost::enable_if<is_error_condition_enum<ErrorConditionEnum> >::type* = 0) NDNBOOST_SYSTEM_NOEXCEPT |
| { |
| *this = make_error_condition(e); |
| } |
| |
| // modifiers: |
| |
| void assign( int val, const error_category & cat ) NDNBOOST_SYSTEM_NOEXCEPT |
| { |
| m_val = val; |
| m_cat = &cat; |
| } |
| |
| template<typename ErrorConditionEnum> |
| typename ndnboost::enable_if<is_error_condition_enum<ErrorConditionEnum>, error_condition>::type & |
| operator=( ErrorConditionEnum val ) NDNBOOST_SYSTEM_NOEXCEPT |
| { |
| *this = make_error_condition(val); |
| return *this; |
| } |
| |
| void clear() NDNBOOST_SYSTEM_NOEXCEPT |
| { |
| m_val = 0; |
| m_cat = &generic_category(); |
| } |
| |
| // observers: |
| int value() const NDNBOOST_SYSTEM_NOEXCEPT { return m_val; } |
| const error_category & category() const NDNBOOST_SYSTEM_NOEXCEPT { return *m_cat; } |
| std::string message() const { return m_cat->message(value()); } |
| |
| typedef void (*unspecified_bool_type)(); |
| static void unspecified_bool_true() {} |
| |
| operator unspecified_bool_type() const NDNBOOST_SYSTEM_NOEXCEPT // true if error |
| { |
| return m_val == 0 ? 0 : unspecified_bool_true; |
| } |
| |
| bool operator!() const NDNBOOST_SYSTEM_NOEXCEPT // true if no error |
| { |
| return m_val == 0; |
| } |
| |
| // relationals: |
| // the more symmetrical non-member syntax allows enum |
| // conversions work for both rhs and lhs. |
| inline friend bool operator==( const error_condition & lhs, |
| const error_condition & rhs ) NDNBOOST_SYSTEM_NOEXCEPT |
| { |
| return lhs.m_cat == rhs.m_cat && lhs.m_val == rhs.m_val; |
| } |
| |
| inline friend bool operator<( const error_condition & lhs, |
| const error_condition & rhs ) NDNBOOST_SYSTEM_NOEXCEPT |
| // the more symmetrical non-member syntax allows enum |
| // conversions work for both rhs and lhs. |
| { |
| return lhs.m_cat < rhs.m_cat |
| || (lhs.m_cat == rhs.m_cat && lhs.m_val < rhs.m_val); |
| } |
| |
| private: |
| int m_val; |
| const error_category * m_cat; |
| |
| }; |
| |
| // 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. |
| class error_code |
| { |
| public: |
| |
| // constructors: |
| error_code() NDNBOOST_SYSTEM_NOEXCEPT : m_val(0), m_cat(&system_category()) {} |
| error_code( int val, const error_category & cat ) NDNBOOST_SYSTEM_NOEXCEPT : m_val(val), m_cat(&cat) {} |
| |
| template <class ErrorCodeEnum> |
| error_code(ErrorCodeEnum e, |
| typename ndnboost::enable_if<is_error_code_enum<ErrorCodeEnum> >::type* = 0) NDNBOOST_SYSTEM_NOEXCEPT |
| { |
| *this = make_error_code(e); |
| } |
| |
| // modifiers: |
| void assign( int val, const error_category & cat ) NDNBOOST_SYSTEM_NOEXCEPT |
| { |
| m_val = val; |
| m_cat = &cat; |
| } |
| |
| template<typename ErrorCodeEnum> |
| typename ndnboost::enable_if<is_error_code_enum<ErrorCodeEnum>, error_code>::type & |
| operator=( ErrorCodeEnum val ) NDNBOOST_SYSTEM_NOEXCEPT |
| { |
| *this = make_error_code(val); |
| return *this; |
| } |
| |
| void clear() NDNBOOST_SYSTEM_NOEXCEPT |
| { |
| m_val = 0; |
| m_cat = &system_category(); |
| } |
| |
| // observers: |
| int value() const NDNBOOST_SYSTEM_NOEXCEPT { return m_val; } |
| const error_category & category() const NDNBOOST_SYSTEM_NOEXCEPT { return *m_cat; } |
| error_condition default_error_condition() const NDNBOOST_SYSTEM_NOEXCEPT { return m_cat->default_error_condition(value()); } |
| std::string message() const { return m_cat->message(value()); } |
| |
| typedef void (*unspecified_bool_type)(); |
| static void unspecified_bool_true() {} |
| |
| operator unspecified_bool_type() const NDNBOOST_SYSTEM_NOEXCEPT // true if error |
| { |
| return m_val == 0 ? 0 : unspecified_bool_true; |
| } |
| |
| bool operator!() const NDNBOOST_SYSTEM_NOEXCEPT // true if no error |
| { |
| return m_val == 0; |
| } |
| |
| // relationals: |
| inline friend bool operator==( const error_code & lhs, |
| const error_code & rhs ) NDNBOOST_SYSTEM_NOEXCEPT |
| // the more symmetrical non-member syntax allows enum |
| // conversions work for both rhs and lhs. |
| { |
| return lhs.m_cat == rhs.m_cat && lhs.m_val == rhs.m_val; |
| } |
| |
| inline friend bool operator<( const error_code & lhs, |
| const error_code & rhs ) NDNBOOST_SYSTEM_NOEXCEPT |
| // the more symmetrical non-member syntax allows enum |
| // conversions work for both rhs and lhs. |
| { |
| return lhs.m_cat < rhs.m_cat |
| || (lhs.m_cat == rhs.m_cat && lhs.m_val < rhs.m_val); |
| } |
| |
| private: |
| int m_val; |
| const error_category * m_cat; |
| |
| }; |
| |
| // predefined error_code object used as "throw on error" tag |
| # ifndef NDNBOOST_SYSTEM_NO_DEPRECATED |
| NDNBOOST_SYSTEM_DECL extern error_code throws; |
| # endif |
| |
| // Moving from a "throws" object to a "throws" function without breaking |
| // existing code is a bit of a problem. The workaround is to place the |
| // "throws" function in namespace ndnboost rather than namespace ndnboost::system. |
| |
| } // namespace system |
| |
| namespace detail { inline system::error_code * throws() { return 0; } } |
| // Misuse of the error_code object is turned into a noisy failure by |
| // poisoning the reference. This particular implementation doesn't |
| // produce warnings or errors from popular compilers, is very efficient |
| // (as determined by inspecting generated code), and does not suffer |
| // from order of initialization problems. In practice, it also seems |
| // cause user function error handling implementation errors to be detected |
| // very early in the development cycle. |
| |
| inline system::error_code & throws() |
| { return *detail::throws(); } |
| |
| namespace system |
| { |
| // non-member functions ------------------------------------------------// |
| |
| inline bool operator!=( const error_code & lhs, |
| const error_code & rhs ) NDNBOOST_SYSTEM_NOEXCEPT |
| { |
| return !(lhs == rhs); |
| } |
| |
| inline bool operator!=( const error_condition & lhs, |
| const error_condition & rhs ) NDNBOOST_SYSTEM_NOEXCEPT |
| { |
| return !(lhs == rhs); |
| } |
| |
| inline bool operator==( const error_code & code, |
| const error_condition & condition ) NDNBOOST_SYSTEM_NOEXCEPT |
| { |
| return code.category().equivalent( code.value(), condition ) |
| || condition.category().equivalent( code, condition.value() ); |
| } |
| |
| inline bool operator!=( const error_code & lhs, |
| const error_condition & rhs ) NDNBOOST_SYSTEM_NOEXCEPT |
| { |
| return !(lhs == rhs); |
| } |
| |
| inline bool operator==( const error_condition & condition, |
| const error_code & code ) NDNBOOST_SYSTEM_NOEXCEPT |
| { |
| return condition.category().equivalent( code, condition.value() ) |
| || code.category().equivalent( code.value(), condition ); |
| } |
| |
| inline bool operator!=( const error_condition & lhs, |
| const error_code & rhs ) NDNBOOST_SYSTEM_NOEXCEPT |
| { |
| return !(lhs == rhs); |
| } |
| |
| // TODO: both of these may move elsewhere, but the LWG hasn't spoken yet. |
| |
| template <class charT, class traits> |
| inline std::basic_ostream<charT,traits>& |
| operator<< (std::basic_ostream<charT,traits>& os, error_code ec) |
| { |
| os << ec.category().name() << ':' << ec.value(); |
| return os; |
| } |
| |
| inline std::size_t hash_value( const error_code & ec ) |
| { |
| return static_cast<std::size_t>(ec.value()) |
| + reinterpret_cast<std::size_t>(&ec.category()); |
| } |
| |
| // make_* functions for errc::errc_t -----------------------------// |
| |
| namespace errc |
| { |
| // explicit conversion: |
| inline error_code make_error_code( errc_t e ) NDNBOOST_SYSTEM_NOEXCEPT |
| { return error_code( e, generic_category() ); } |
| |
| // implicit conversion: |
| inline error_condition make_error_condition( errc_t e ) NDNBOOST_SYSTEM_NOEXCEPT |
| { return error_condition( e, generic_category() ); } |
| } |
| |
| // error_category default implementation -------------------------------// |
| |
| error_condition error_category::default_error_condition( int ev ) const NDNBOOST_SYSTEM_NOEXCEPT |
| { |
| return error_condition( ev, *this ); |
| } |
| |
| bool error_category::equivalent( int code, |
| const error_condition & condition ) const NDNBOOST_SYSTEM_NOEXCEPT |
| { |
| return default_error_condition( code ) == condition; |
| } |
| |
| bool error_category::equivalent( const error_code & code, |
| int condition ) const NDNBOOST_SYSTEM_NOEXCEPT |
| { |
| return *this == code.category() && code.value() == condition; |
| } |
| |
| } // namespace system |
| } // namespace ndnboost |
| |
| #include <ndnboost/config/abi_suffix.hpp> // pops abi_prefix.hpp pragmas |
| |
| # ifdef NDNBOOST_ERROR_CODE_HEADER_ONLY |
| # include <ndnboost/../libs/system/src/error_code.cpp> |
| # endif |
| |
| #endif // NDNBOOST_ERROR_CODE_HPP |
| |
| |