1// boost/system/error_code.hpp -------------------------------------------------------//
2
3// Copyright Beman Dawes 2006, 2007
4// Copyright Christoper Kohlhoff 2007
5
6// Distributed under the Boost Software License, Version 1.0. (See accompanying
7// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
8
9// See library home page at http://www.boost.org/libs/system
10
11#ifndef BOOST_SYSTEM_ERROR_CODE_HPP
12#define BOOST_SYSTEM_ERROR_CODE_HPP
13
14#include <boost/system/config.hpp>
15#include <boost/cstdint.hpp>
16#include <boost/assert.hpp>
17#include <boost/noncopyable.hpp>
18#include <boost/utility/enable_if.hpp>
19#include <ostream>
20#include <string>
21#include <stdexcept>
22#include <functional>
23
24// TODO: undef these macros if not already defined
25#include <boost/cerrno.hpp>
26
27#if !defined(BOOST_POSIX_API) && !defined(BOOST_WINDOWS_API)
28# error BOOST_POSIX_API or BOOST_WINDOWS_API must be defined
29#endif
30
31#ifndef BOOST_NO_CXX11_HDR_SYSTEM_ERROR
32#include <system_error>
33#endif
34
35#include <boost/config/abi_prefix.hpp> // must be the last #include
36
37#ifndef BOOST_SYSTEM_NOEXCEPT
38#define BOOST_SYSTEM_NOEXCEPT BOOST_NOEXCEPT
39#endif
40
41namespace boost
42{
43 namespace system
44 {
45
46 class error_code; // values defined by the operating system
47 class error_condition; // portable generic values defined below, but ultimately
48 // based on the POSIX standard
49
50 // "Concept" helpers -------------------------------------------------------------//
51
52 template< class T >
53 struct is_error_code_enum { static const bool value = false; };
54
55 template< class T >
56 struct is_error_condition_enum { static const bool value = false; };
57
58 // generic error_conditions ------------------------------------------------------//
59
60 namespace errc
61 {
62 enum errc_t
63 {
64 success = 0,
65 address_family_not_supported = EAFNOSUPPORT,
66 address_in_use = EADDRINUSE,
67 address_not_available = EADDRNOTAVAIL,
68 already_connected = EISCONN,
69 argument_list_too_long = E2BIG,
70 argument_out_of_domain = EDOM,
71 bad_address = EFAULT,
72 bad_file_descriptor = EBADF,
73 bad_message = EBADMSG,
74 broken_pipe = EPIPE,
75 connection_aborted = ECONNABORTED,
76 connection_already_in_progress = EALREADY,
77 connection_refused = ECONNREFUSED,
78 connection_reset = ECONNRESET,
79 cross_device_link = EXDEV,
80 destination_address_required = EDESTADDRREQ,
81 device_or_resource_busy = EBUSY,
82 directory_not_empty = ENOTEMPTY,
83 executable_format_error = ENOEXEC,
84 file_exists = EEXIST,
85 file_too_large = EFBIG,
86 filename_too_long = ENAMETOOLONG,
87 function_not_supported = ENOSYS,
88 host_unreachable = EHOSTUNREACH,
89 identifier_removed = EIDRM,
90 illegal_byte_sequence = EILSEQ,
91 inappropriate_io_control_operation = ENOTTY,
92 interrupted = EINTR,
93 invalid_argument = EINVAL,
94 invalid_seek = ESPIPE,
95 io_error = EIO,
96 is_a_directory = EISDIR,
97 message_size = EMSGSIZE,
98 network_down = ENETDOWN,
99 network_reset = ENETRESET,
100 network_unreachable = ENETUNREACH,
101 no_buffer_space = ENOBUFS,
102 no_child_process = ECHILD,
103 no_link = ENOLINK,
104 no_lock_available = ENOLCK,
105 no_message_available = ENODATA,
106 no_message = ENOMSG,
107 no_protocol_option = ENOPROTOOPT,
108 no_space_on_device = ENOSPC,
109 no_stream_resources = ENOSR,
110 no_such_device_or_address = ENXIO,
111 no_such_device = ENODEV,
112 no_such_file_or_directory = ENOENT,
113 no_such_process = ESRCH,
114 not_a_directory = ENOTDIR,
115 not_a_socket = ENOTSOCK,
116 not_a_stream = ENOSTR,
117 not_connected = ENOTCONN,
118 not_enough_memory = ENOMEM,
119 not_supported = ENOTSUP,
120 operation_canceled = ECANCELED,
121 operation_in_progress = EINPROGRESS,
122 operation_not_permitted = EPERM,
123 operation_not_supported = EOPNOTSUPP,
124 operation_would_block = EWOULDBLOCK,
125 owner_dead = EOWNERDEAD,
126 permission_denied = EACCES,
127 protocol_error = EPROTO,
128 protocol_not_supported = EPROTONOSUPPORT,
129 read_only_file_system = EROFS,
130 resource_deadlock_would_occur = EDEADLK,
131 resource_unavailable_try_again = EAGAIN,
132 result_out_of_range = ERANGE,
133 state_not_recoverable = ENOTRECOVERABLE,
134 stream_timeout = ETIME,
135 text_file_busy = ETXTBSY,
136 timed_out = ETIMEDOUT,
137 too_many_files_open_in_system = ENFILE,
138 too_many_files_open = EMFILE,
139 too_many_links = EMLINK,
140 too_many_symbolic_link_levels = ELOOP,
141 value_too_large = EOVERFLOW,
142 wrong_protocol_type = EPROTOTYPE
143 };
144
145 } // namespace errc
146
147# ifndef BOOST_SYSTEM_NO_DEPRECATED
148 namespace posix = errc;
149 namespace posix_error = errc;
150# endif
151
152 template<> struct is_error_condition_enum<errc::errc_t>
153 { static const bool value = true; };
154
155
156 // --------------------------------------------------------------------------------//
157
158 // Operating system specific interfaces ------------------------------------------//
159
160
161 // The interface is divided into general and system-specific portions to
162 // meet these requirements:
163 //
164 // * Code calling an operating system API can create an error_code with
165 // a single category (system_category), even for POSIX-like operating
166 // systems that return some POSIX errno values and some native errno
167 // values. This code should not have to pay the cost of distinguishing
168 // between categories, since it is not yet known if that is needed.
169 //
170 // * Users wishing to write system-specific code should be given enums for
171 // at least the common error cases.
172 //
173 // * System specific code should fail at compile time if moved to another
174 // operating system.
175
176 // The system specific portions of the interface are located in headers
177 // with names reflecting the operating system. For example,
178 //
179 // <boost/system/cygwin_error.hpp>
180 // <boost/system/linux_error.hpp>
181 // <boost/system/windows_error.hpp>
182 //
183 // These headers are effectively empty for compiles on operating systems
184 // where they are not applicable.
185
186 // --------------------------------------------------------------------------------//
187
188 class error_category;
189
190 // predefined error categories ---------------------------------------------------//
191
192#ifdef BOOST_ERROR_CODE_HEADER_ONLY
193 inline const error_category & system_category() BOOST_SYSTEM_NOEXCEPT;
194 inline const error_category & generic_category() BOOST_SYSTEM_NOEXCEPT;
195#else
196 BOOST_SYSTEM_DECL const error_category & system_category() BOOST_SYSTEM_NOEXCEPT;
197 BOOST_SYSTEM_DECL const error_category & generic_category() BOOST_SYSTEM_NOEXCEPT;
198#endif
199 // deprecated synonyms ------------------------------------------------------------//
200
201#ifndef BOOST_SYSTEM_NO_DEPRECATED
202 inline const error_category & get_system_category() { return system_category(); }
203 inline const error_category & get_generic_category() { return generic_category(); }
204 inline const error_category & get_posix_category() { return generic_category(); }
205 static const error_category & posix_category BOOST_ATTRIBUTE_UNUSED
206 = generic_category();
207 static const error_category & errno_ecat BOOST_ATTRIBUTE_UNUSED
208 = generic_category();
209 static const error_category & native_ecat BOOST_ATTRIBUTE_UNUSED
210 = system_category();
211#endif
212
213 // class error_category ------------------------------------------------//
214
215 class error_category : public noncopyable
216 {
217#ifndef BOOST_NO_CXX11_HDR_SYSTEM_ERROR
218
219 private:
220
221 class std_category: public std::error_category
222 {
223 private:
224
225 boost::system::error_category const * pc_;
226
227 public:
228
229 explicit std_category( boost::system::error_category const * pc ): pc_( pc )
230 {
231 }
232
233 virtual const char * name() const BOOST_NOEXCEPT
234 {
235 return pc_->name();
236 }
237
238 virtual std::string message( int ev ) const
239 {
240 return pc_->message( ev );
241 }
242
243 virtual std::error_condition default_error_condition( int ev ) const
244 BOOST_NOEXCEPT;
245 virtual bool equivalent( int code, const std::error_condition & condition ) const
246 BOOST_NOEXCEPT;
247 virtual bool equivalent( const std::error_code & code, int condition ) const
248 BOOST_NOEXCEPT;
249 };
250
251 std_category std_cat_;
252
253 public:
254
255 error_category() BOOST_SYSTEM_NOEXCEPT: std_cat_( this ) {}
256
257 operator std::error_category const & () const BOOST_SYSTEM_NOEXCEPT
258 {
259 // do not map generic to std::generic on purpose; occasionally,
260 // there are two std::generic categories in a program, which leads
261 // to error codes/conditions mysteriously not being equal to themselves
262 return std_cat_;
263 }
264
265#else
266
267 // to maintain ABI compatibility between 03 and 11,
268 // define a class with the same layout
269
270 private:
271
272 class std_category
273 {
274 private:
275
276 boost::system::error_category const * pc_;
277
278 public:
279
280 explicit std_category( boost::system::error_category const * pc ): pc_( pc )
281 {
282 }
283
284 virtual ~std_category() {}
285
286 virtual const char * name() const BOOST_NOEXCEPT
287 {
288 return pc_->name();
289 }
290
291 // we can't define message, because (1) it returns an std::string,
292 // which can be different between 03 and 11, and (2) on mingw, there
293 // are actually two `message` functions, not one, so it doesn't work
294 // even if we do
295
296 // neither can we define default_error_condition or equivalent
297
298 // if these functions are called, it will crash, but that's still
299 // better than the alternative of having the class layout change
300 };
301
302 std_category std_cat_;
303
304 public:
305
306 error_category() BOOST_SYSTEM_NOEXCEPT: std_cat_( this ) {}
307
308#endif
309
310 public:
311 virtual ~error_category(){}
312
313 virtual const char * name() const BOOST_SYSTEM_NOEXCEPT = 0;
314 virtual std::string message( int ev ) const = 0;
315 inline virtual error_condition default_error_condition( int ev ) const
316 BOOST_SYSTEM_NOEXCEPT;
317 inline virtual bool equivalent( int code,
318 const error_condition & condition ) const
319 BOOST_SYSTEM_NOEXCEPT;
320 inline virtual bool equivalent( const error_code & code,
321 int condition ) const BOOST_SYSTEM_NOEXCEPT;
322
323 bool operator==(const error_category & rhs) const BOOST_SYSTEM_NOEXCEPT
324 { return this == &rhs; }
325 bool operator!=(const error_category & rhs) const BOOST_SYSTEM_NOEXCEPT
326 { return this != &rhs; }
327 bool operator<( const error_category & rhs ) const BOOST_SYSTEM_NOEXCEPT
328 { return std::less<const error_category*>()( this, &rhs ); }
329 };
330
331 // class error_condition ---------------------------------------------------------//
332
333 // error_conditions are portable, error_codes are system or library specific
334
335 class error_condition
336 {
337 public:
338
339 // constructors:
340 error_condition() BOOST_SYSTEM_NOEXCEPT : m_val(0), m_cat(&generic_category()) {}
341 error_condition( int val, const error_category & cat ) BOOST_SYSTEM_NOEXCEPT
342 : m_val(val), m_cat(&cat) {}
343
344 template <class ErrorConditionEnum>
345 error_condition(ErrorConditionEnum e,
346 typename boost::enable_if<is_error_condition_enum<ErrorConditionEnum> >::type*
347 = 0) BOOST_SYSTEM_NOEXCEPT
348 {
349 *this = make_error_condition(e);
350 }
351
352 // modifiers:
353
354 void assign( int val, const error_category & cat ) BOOST_SYSTEM_NOEXCEPT
355 {
356 m_val = val;
357 m_cat = &cat;
358 }
359
360 template<typename ErrorConditionEnum>
361 typename boost::enable_if<is_error_condition_enum<ErrorConditionEnum>,
362 error_condition>::type &
363 operator=( ErrorConditionEnum val ) BOOST_SYSTEM_NOEXCEPT
364 {
365 *this = make_error_condition(val);
366 return *this;
367 }
368
369 void clear() BOOST_SYSTEM_NOEXCEPT
370 {
371 m_val = 0;
372 m_cat = &generic_category();
373 }
374
375 // observers:
376 int value() const BOOST_SYSTEM_NOEXCEPT { return m_val; }
377 const error_category & category() const BOOST_SYSTEM_NOEXCEPT { return *m_cat; }
378 std::string message() const { return m_cat->message(value()); }
379
380 typedef void (*unspecified_bool_type)();
381 static void unspecified_bool_true() {}
382
383 operator unspecified_bool_type() const BOOST_SYSTEM_NOEXCEPT // true if error
384 {
385 return m_val == 0 ? 0 : unspecified_bool_true;
386 }
387
388 bool operator!() const BOOST_SYSTEM_NOEXCEPT // true if no error
389 {
390 return m_val == 0;
391 }
392
393 // relationals:
394 // the more symmetrical non-member syntax allows enum
395 // conversions work for both rhs and lhs.
396 inline friend bool operator==( const error_condition & lhs,
397 const error_condition & rhs ) BOOST_SYSTEM_NOEXCEPT
398 {
399 return lhs.m_cat == rhs.m_cat && lhs.m_val == rhs.m_val;
400 }
401
402 inline friend bool operator<( const error_condition & lhs,
403 const error_condition & rhs ) BOOST_SYSTEM_NOEXCEPT
404 // the more symmetrical non-member syntax allows enum
405 // conversions work for both rhs and lhs.
406 {
407 return lhs.m_cat < rhs.m_cat
408 || (lhs.m_cat == rhs.m_cat && lhs.m_val < rhs.m_val);
409 }
410
411#ifndef BOOST_NO_CXX11_HDR_SYSTEM_ERROR
412
413 operator std::error_condition () const BOOST_SYSTEM_NOEXCEPT
414 {
415 return std::error_condition( value(), category() );
416 }
417
418#endif
419
420 private:
421 int m_val;
422 const error_category * m_cat;
423
424 };
425
426 // class error_code --------------------------------------------------------------//
427
428 // We want error_code to be a value type that can be copied without slicing
429 // and without requiring heap allocation, but we also want it to have
430 // polymorphic behavior based on the error category. This is achieved by
431 // abstract base class error_category supplying the polymorphic behavior,
432 // and error_code containing a pointer to an object of a type derived
433 // from error_category.
434 class error_code
435 {
436 public:
437
438 // constructors:
439 error_code() BOOST_SYSTEM_NOEXCEPT : m_val(0), m_cat(&system_category()) {}
440 error_code( int val, const error_category & cat ) BOOST_SYSTEM_NOEXCEPT
441 : m_val(val), m_cat(&cat) {}
442
443 template <class ErrorCodeEnum>
444 error_code(ErrorCodeEnum e,
445 typename boost::enable_if<is_error_code_enum<ErrorCodeEnum> >::type* = 0)
446 BOOST_SYSTEM_NOEXCEPT
447 {
448 *this = make_error_code(e);
449 }
450
451 // modifiers:
452 void assign( int val, const error_category & cat ) BOOST_SYSTEM_NOEXCEPT
453 {
454 m_val = val;
455 m_cat = &cat;
456 }
457
458 template<typename ErrorCodeEnum>
459 typename boost::enable_if<is_error_code_enum<ErrorCodeEnum>, error_code>::type &
460 operator=( ErrorCodeEnum val ) BOOST_SYSTEM_NOEXCEPT
461 {
462 *this = make_error_code(val);
463 return *this;
464 }
465
466 void clear() BOOST_SYSTEM_NOEXCEPT
467 {
468 m_val = 0;
469 m_cat = &system_category();
470 }
471
472 // observers:
473 int value() const BOOST_SYSTEM_NOEXCEPT { return m_val; }
474 const error_category & category() const BOOST_SYSTEM_NOEXCEPT { return *m_cat; }
475 error_condition default_error_condition() const BOOST_SYSTEM_NOEXCEPT
476 { return m_cat->default_error_condition(value()); }
477 std::string message() const { return m_cat->message(value()); }
478
479 typedef void (*unspecified_bool_type)();
480 static void unspecified_bool_true() {}
481
482 operator unspecified_bool_type() const BOOST_SYSTEM_NOEXCEPT // true if error
483 {
484 return m_val == 0 ? 0 : unspecified_bool_true;
485 }
486
487 bool operator!() const BOOST_SYSTEM_NOEXCEPT // true if no error
488 {
489 return m_val == 0;
490 }
491
492 // relationals:
493 inline friend bool operator==( const error_code & lhs,
494 const error_code & rhs ) BOOST_SYSTEM_NOEXCEPT
495 // the more symmetrical non-member syntax allows enum
496 // conversions work for both rhs and lhs.
497 {
498 return lhs.m_cat == rhs.m_cat && lhs.m_val == rhs.m_val;
499 }
500
501 inline friend bool operator<( const error_code & lhs,
502 const error_code & rhs ) BOOST_SYSTEM_NOEXCEPT
503 // the more symmetrical non-member syntax allows enum
504 // conversions work for both rhs and lhs.
505 {
506 return lhs.m_cat < rhs.m_cat
507 || (lhs.m_cat == rhs.m_cat && lhs.m_val < rhs.m_val);
508 }
509
510#ifndef BOOST_NO_CXX11_HDR_SYSTEM_ERROR
511
512 operator std::error_code () const BOOST_SYSTEM_NOEXCEPT
513 {
514 return std::error_code( value(), category() );
515 }
516
517#endif
518
519 private:
520 int m_val;
521 const error_category * m_cat;
522
523 };
524
525 // predefined error_code object used as "throw on error" tag
526# ifndef BOOST_SYSTEM_NO_DEPRECATED
527 BOOST_SYSTEM_DECL extern error_code throws;
528# endif
529
530 // Moving from a "throws" object to a "throws" function without breaking
531 // existing code is a bit of a problem. The workaround is to place the
532 // "throws" function in namespace boost rather than namespace boost::system.
533
534 } // namespace system
535
536 namespace detail { inline system::error_code * throws() { return 0; } }
537 // Misuse of the error_code object is turned into a noisy failure by
538 // poisoning the reference. This particular implementation doesn't
539 // produce warnings or errors from popular compilers, is very efficient
540 // (as determined by inspecting generated code), and does not suffer
541 // from order of initialization problems. In practice, it also seems
542 // cause user function error handling implementation errors to be detected
543 // very early in the development cycle.
544
545 inline system::error_code & throws()
546 { return *detail::throws(); }
547
548 namespace system
549 {
550 // non-member functions ------------------------------------------------//
551
552 inline bool operator!=( const error_code & lhs,
553 const error_code & rhs ) BOOST_SYSTEM_NOEXCEPT
554 {
555 return !(lhs == rhs);
556 }
557
558 inline bool operator!=( const error_condition & lhs,
559 const error_condition & rhs ) BOOST_SYSTEM_NOEXCEPT
560 {
561 return !(lhs == rhs);
562 }
563
564 inline bool operator==( const error_code & code,
565 const error_condition & condition ) BOOST_SYSTEM_NOEXCEPT
566 {
567 return code.category().equivalent( code.value(), condition )
568 || condition.category().equivalent( code, condition.value() );
569 }
570
571 inline bool operator!=( const error_code & lhs,
572 const error_condition & rhs ) BOOST_SYSTEM_NOEXCEPT
573 {
574 return !(lhs == rhs);
575 }
576
577 inline bool operator==( const error_condition & condition,
578 const error_code & code ) BOOST_SYSTEM_NOEXCEPT
579 {
580 return condition.category().equivalent( code, condition.value() )
581 || code.category().equivalent( code.value(), condition );
582 }
583
584 inline bool operator!=( const error_condition & lhs,
585 const error_code & rhs ) BOOST_SYSTEM_NOEXCEPT
586 {
587 return !(lhs == rhs);
588 }
589
590 // TODO: both of these may move elsewhere, but the LWG hasn't spoken yet.
591
592 template <class charT, class traits>
593 inline std::basic_ostream<charT,traits>&
594 operator<< (std::basic_ostream<charT,traits>& os, error_code ec)
595 {
596 os << ec.category().name() << ':' << ec.value();
597 return os;
598 }
599
600 inline std::size_t hash_value( const error_code & ec )
601 {
602 return static_cast<std::size_t>(ec.value())
603 + reinterpret_cast<std::size_t>(&ec.category());
604 }
605
606 // make_* functions for errc::errc_t ---------------------------------------------//
607
608 namespace errc
609 {
610 // explicit conversion:
611 inline error_code make_error_code( errc_t e ) BOOST_SYSTEM_NOEXCEPT
612 { return error_code( e, generic_category() ); }
613
614 // implicit conversion:
615 inline error_condition make_error_condition( errc_t e ) BOOST_SYSTEM_NOEXCEPT
616 { return error_condition( e, generic_category() ); }
617 }
618
619 // error_category default implementation -----------------------------------------//
620
621 error_condition error_category::default_error_condition( int ev ) const
622 BOOST_SYSTEM_NOEXCEPT
623 {
624 return error_condition( ev, *this );
625 }
626
627 bool error_category::equivalent( int code,
628 const error_condition & condition ) const BOOST_SYSTEM_NOEXCEPT
629 {
630 return default_error_condition( code ) == condition;
631 }
632
633 bool error_category::equivalent( const error_code & code,
634 int condition ) const BOOST_SYSTEM_NOEXCEPT
635 {
636 return *this == code.category() && code.value() == condition;
637 }
638
639#ifndef BOOST_NO_CXX11_HDR_SYSTEM_ERROR
640
641 inline std::error_condition error_category::std_category::default_error_condition(
642 int ev ) const BOOST_NOEXCEPT
643 {
644 return pc_->default_error_condition( ev );
645 }
646
647 inline bool error_category::std_category::equivalent( int code,
648 const std::error_condition & condition ) const BOOST_NOEXCEPT
649 {
650 if( condition.category() == *this )
651 {
652 boost::system::error_condition bn( condition.value(), *pc_ );
653 return pc_->equivalent( code, bn );
654 }
655 else if( condition.category() == std::generic_category()
656 || condition.category() == boost::system::generic_category() )
657 {
658 boost::system::error_condition bn( condition.value(),
659 boost::system::generic_category() );
660
661 return pc_->equivalent( code, bn );
662 }
663#ifndef BOOST_NO_RTTI
664 else if( std_category const* pc2 = dynamic_cast< std_category const* >(
665 &condition.category() ) )
666 {
667 boost::system::error_condition bn( condition.value(), *pc2->pc_ );
668 return pc_->equivalent( code, bn );
669 }
670#endif
671 else
672 {
673 return default_error_condition( code ) == condition;
674 }
675 }
676
677 inline bool error_category::std_category::equivalent( const std::error_code & code,
678 int condition ) const BOOST_NOEXCEPT
679 {
680 if( code.category() == *this )
681 {
682 boost::system::error_code bc( code.value(), *pc_ );
683 return pc_->equivalent( bc, condition );
684 }
685 else if( code.category() == std::generic_category()
686 || code.category() == boost::system::generic_category() )
687 {
688 boost::system::error_code bc( code.value(),
689 boost::system::generic_category() );
690
691 return pc_->equivalent( bc, condition );
692 }
693#ifndef BOOST_NO_RTTI
694 else if( std_category const* pc2 = dynamic_cast< std_category const* >(
695 &code.category() ) )
696 {
697 boost::system::error_code bc( code.value(), *pc2->pc_ );
698 return pc_->equivalent( bc, condition );
699 }
700#endif
701 else if( *pc_ == boost::system::generic_category() )
702 {
703 return std::generic_category().equivalent( code, condition );
704 }
705 else
706 {
707 return false;
708 }
709 }
710
711#endif
712
713 } // namespace system
714} // namespace boost
715
716#include <boost/config/abi_suffix.hpp> // pops abi_prefix.hpp pragmas
717
718# ifdef BOOST_ERROR_CODE_HEADER_ONLY
719# include <boost/system/detail/error_code.ipp>
720# endif
721
722#endif // BOOST_SYSTEM_ERROR_CODE_HPP
723