blob: 9d92c85bbee699886339e63af4b34744246e4a43 [file] [log] [blame]
Jeff Thompson86b6d642013-10-17 15:01:56 -07001// ndnboost/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 NDNBOOST_ERROR_CODE_HPP
12#define NDNBOOST_ERROR_CODE_HPP
13
14#include <ndnboost/system/config.hpp>
15#include <ndnboost/cstdint.hpp>
16#include <ndnboost/assert.hpp>
17#include <ndnboost/operators.hpp>
18#include <ndnboost/noncopyable.hpp>
19#include <ndnboost/utility/enable_if.hpp>
20#include <ostream>
21#include <string>
22#include <stdexcept>
23#include <functional>
24
25// TODO: undef these macros if not already defined
26#include <ndnboost/cerrno.hpp>
27
28#if !defined(NDNBOOST_POSIX_API) && !defined(NDNBOOST_WINDOWS_API)
29# error NDNBOOST_POSIX_API or NDNBOOST_WINDOWS_API must be defined
30#endif
31
32#include <ndnboost/config/abi_prefix.hpp> // must be the last #include
33
34#ifndef NDNBOOST_SYSTEM_NOEXCEPT
35#define NDNBOOST_SYSTEM_NOEXCEPT NDNBOOST_NOEXCEPT
36#endif
37
38namespace ndnboost
39{
40 namespace system
41 {
42
43 class error_code;
44 class error_condition;
45
46 // "Concept" helpers ---------------------------------------------------//
47
48 template< class T >
49 struct is_error_code_enum { static const bool value = false; };
50
51 template< class T >
52 struct is_error_condition_enum { static const bool value = false; };
53
54 // generic error_conditions --------------------------------------------//
55
56 namespace errc
57 {
58 enum errc_t
59 {
60 success = 0,
61 address_family_not_supported = EAFNOSUPPORT,
62 address_in_use = EADDRINUSE,
63 address_not_available = EADDRNOTAVAIL,
64 already_connected = EISCONN,
65 argument_list_too_long = E2BIG,
66 argument_out_of_domain = EDOM,
67 bad_address = EFAULT,
68 bad_file_descriptor = EBADF,
69 bad_message = EBADMSG,
70 broken_pipe = EPIPE,
71 connection_aborted = ECONNABORTED,
72 connection_already_in_progress = EALREADY,
73 connection_refused = ECONNREFUSED,
74 connection_reset = ECONNRESET,
75 cross_device_link = EXDEV,
76 destination_address_required = EDESTADDRREQ,
77 device_or_resource_busy = EBUSY,
78 directory_not_empty = ENOTEMPTY,
79 executable_format_error = ENOEXEC,
80 file_exists = EEXIST,
81 file_too_large = EFBIG,
82 filename_too_long = ENAMETOOLONG,
83 function_not_supported = ENOSYS,
84 host_unreachable = EHOSTUNREACH,
85 identifier_removed = EIDRM,
86 illegal_byte_sequence = EILSEQ,
87 inappropriate_io_control_operation = ENOTTY,
88 interrupted = EINTR,
89 invalid_argument = EINVAL,
90 invalid_seek = ESPIPE,
91 io_error = EIO,
92 is_a_directory = EISDIR,
93 message_size = EMSGSIZE,
94 network_down = ENETDOWN,
95 network_reset = ENETRESET,
96 network_unreachable = ENETUNREACH,
97 no_buffer_space = ENOBUFS,
98 no_child_process = ECHILD,
99 no_link = ENOLINK,
100 no_lock_available = ENOLCK,
101 no_message_available = ENODATA,
102 no_message = ENOMSG,
103 no_protocol_option = ENOPROTOOPT,
104 no_space_on_device = ENOSPC,
105 no_stream_resources = ENOSR,
106 no_such_device_or_address = ENXIO,
107 no_such_device = ENODEV,
108 no_such_file_or_directory = ENOENT,
109 no_such_process = ESRCH,
110 not_a_directory = ENOTDIR,
111 not_a_socket = ENOTSOCK,
112 not_a_stream = ENOSTR,
113 not_connected = ENOTCONN,
114 not_enough_memory = ENOMEM,
115 not_supported = ENOTSUP,
116 operation_canceled = ECANCELED,
117 operation_in_progress = EINPROGRESS,
118 operation_not_permitted = EPERM,
119 operation_not_supported = EOPNOTSUPP,
120 operation_would_block = EWOULDBLOCK,
121 owner_dead = EOWNERDEAD,
122 permission_denied = EACCES,
123 protocol_error = EPROTO,
124 protocol_not_supported = EPROTONOSUPPORT,
125 read_only_file_system = EROFS,
126 resource_deadlock_would_occur = EDEADLK,
127 resource_unavailable_try_again = EAGAIN,
128 result_out_of_range = ERANGE,
129 state_not_recoverable = ENOTRECOVERABLE,
130 stream_timeout = ETIME,
131 text_file_busy = ETXTBSY,
132 timed_out = ETIMEDOUT,
133 too_many_files_open_in_system = ENFILE,
134 too_many_files_open = EMFILE,
135 too_many_links = EMLINK,
136 too_many_symbolic_link_levels = ELOOP,
137 value_too_large = EOVERFLOW,
138 wrong_protocol_type = EPROTOTYPE
139 };
140
141 } // namespace errc
142
143# ifndef NDNBOOST_SYSTEM_NO_DEPRECATED
144 namespace posix = errc;
145 namespace posix_error = errc;
146# endif
147
148 template<> struct is_error_condition_enum<errc::errc_t>
149 { static const bool value = true; };
150
151
152 // ----------------------------------------------------------------------//
153
154 // Operating system specific interfaces --------------------------------//
155
156
157 // The interface is divided into general and system-specific portions to
158 // meet these requirements:
159 //
160 // * Code calling an operating system API can create an error_code with
161 // a single category (system_category), even for POSIX-like operating
162 // systems that return some POSIX errno values and some native errno
163 // values. This code should not have to pay the cost of distinguishing
164 // between categories, since it is not yet known if that is needed.
165 //
166 // * Users wishing to write system-specific code should be given enums for
167 // at least the common error cases.
168 //
169 // * System specific code should fail at compile time if moved to another
170 // operating system.
171
172 // The system specific portions of the interface are located in headers
173 // with names reflecting the operating system. For example,
174 //
175 // <ndnboost/system/cygwin_error.hpp>
176 // <ndnboost/system/linux_error.hpp>
177 // <ndnboost/system/windows_error.hpp>
178 //
179 // These headers are effectively empty for compiles on operating systems
180 // where they are not applicable.
181
182 // ----------------------------------------------------------------------//
183
184 // class error_category ------------------------------------------------//
185
186 class error_category : public noncopyable
187 {
188 public:
189 virtual ~error_category(){}
190
191 virtual const char * name() const NDNBOOST_SYSTEM_NOEXCEPT = 0;
192 virtual std::string message( int ev ) const = 0;
193 inline virtual error_condition default_error_condition( int ev ) const NDNBOOST_SYSTEM_NOEXCEPT;
194 inline virtual bool equivalent( int code,
195 const error_condition & condition ) const NDNBOOST_SYSTEM_NOEXCEPT;
196 inline virtual bool equivalent( const error_code & code,
197 int condition ) const NDNBOOST_SYSTEM_NOEXCEPT;
198
199 bool operator==(const error_category & rhs) const NDNBOOST_SYSTEM_NOEXCEPT { return this == &rhs; }
200 bool operator!=(const error_category & rhs) const NDNBOOST_SYSTEM_NOEXCEPT { return this != &rhs; }
201 bool operator<( const error_category & rhs ) const NDNBOOST_SYSTEM_NOEXCEPT
202 {
203 return std::less<const error_category*>()( this, &rhs );
204 }
205 };
206
207 // predefined error categories -----------------------------------------//
208
209# ifdef NDNBOOST_ERROR_CODE_HEADER_ONLY
210 inline const error_category & system_category() NDNBOOST_SYSTEM_NOEXCEPT;
211 inline const error_category & generic_category() NDNBOOST_SYSTEM_NOEXCEPT;
212#else
213 NDNBOOST_SYSTEM_DECL const error_category & system_category() NDNBOOST_SYSTEM_NOEXCEPT;
214 NDNBOOST_SYSTEM_DECL const error_category & generic_category() NDNBOOST_SYSTEM_NOEXCEPT;
215#endif
216 // deprecated synonyms --------------------------------------------------//
217
218# ifndef NDNBOOST_SYSTEM_NO_DEPRECATED
219 inline const error_category & get_system_category() { return system_category(); }
220 inline const error_category & get_generic_category() { return generic_category(); }
221 inline const error_category & get_posix_category() { return generic_category(); }
222 static const error_category & posix_category = generic_category();
223 static const error_category & errno_ecat = generic_category();
224 static const error_category & native_ecat = system_category();
225# endif
226
227 // class error_condition -----------------------------------------------//
228
229 // error_conditions are portable, error_codes are system or library specific
230
231 class error_condition
232 {
233 public:
234
235 // constructors:
236 error_condition() NDNBOOST_SYSTEM_NOEXCEPT : m_val(0), m_cat(&generic_category()) {}
237 error_condition( int val, const error_category & cat ) NDNBOOST_SYSTEM_NOEXCEPT : m_val(val), m_cat(&cat) {}
238
239 template <class ErrorConditionEnum>
240 error_condition(ErrorConditionEnum e,
241 typename ndnboost::enable_if<is_error_condition_enum<ErrorConditionEnum> >::type* = 0) NDNBOOST_SYSTEM_NOEXCEPT
242 {
243 *this = make_error_condition(e);
244 }
245
246 // modifiers:
247
248 void assign( int val, const error_category & cat ) NDNBOOST_SYSTEM_NOEXCEPT
249 {
250 m_val = val;
251 m_cat = &cat;
252 }
253
254 template<typename ErrorConditionEnum>
255 typename ndnboost::enable_if<is_error_condition_enum<ErrorConditionEnum>, error_condition>::type &
256 operator=( ErrorConditionEnum val ) NDNBOOST_SYSTEM_NOEXCEPT
257 {
258 *this = make_error_condition(val);
259 return *this;
260 }
261
262 void clear() NDNBOOST_SYSTEM_NOEXCEPT
263 {
264 m_val = 0;
265 m_cat = &generic_category();
266 }
267
268 // observers:
269 int value() const NDNBOOST_SYSTEM_NOEXCEPT { return m_val; }
270 const error_category & category() const NDNBOOST_SYSTEM_NOEXCEPT { return *m_cat; }
271 std::string message() const { return m_cat->message(value()); }
272
273 typedef void (*unspecified_bool_type)();
274 static void unspecified_bool_true() {}
275
276 operator unspecified_bool_type() const NDNBOOST_SYSTEM_NOEXCEPT // true if error
277 {
278 return m_val == 0 ? 0 : unspecified_bool_true;
279 }
280
281 bool operator!() const NDNBOOST_SYSTEM_NOEXCEPT // true if no error
282 {
283 return m_val == 0;
284 }
285
286 // relationals:
287 // the more symmetrical non-member syntax allows enum
288 // conversions work for both rhs and lhs.
289 inline friend bool operator==( const error_condition & lhs,
290 const error_condition & rhs ) NDNBOOST_SYSTEM_NOEXCEPT
291 {
292 return lhs.m_cat == rhs.m_cat && lhs.m_val == rhs.m_val;
293 }
294
295 inline friend bool operator<( const error_condition & lhs,
296 const error_condition & rhs ) NDNBOOST_SYSTEM_NOEXCEPT
297 // the more symmetrical non-member syntax allows enum
298 // conversions work for both rhs and lhs.
299 {
300 return lhs.m_cat < rhs.m_cat
301 || (lhs.m_cat == rhs.m_cat && lhs.m_val < rhs.m_val);
302 }
303
304 private:
305 int m_val;
306 const error_category * m_cat;
307
308 };
309
310 // class error_code ----------------------------------------------------//
311
312 // We want error_code to be a value type that can be copied without slicing
313 // and without requiring heap allocation, but we also want it to have
314 // polymorphic behavior based on the error category. This is achieved by
315 // abstract base class error_category supplying the polymorphic behavior,
316 // and error_code containing a pointer to an object of a type derived
317 // from error_category.
318 class error_code
319 {
320 public:
321
322 // constructors:
323 error_code() NDNBOOST_SYSTEM_NOEXCEPT : m_val(0), m_cat(&system_category()) {}
324 error_code( int val, const error_category & cat ) NDNBOOST_SYSTEM_NOEXCEPT : m_val(val), m_cat(&cat) {}
325
326 template <class ErrorCodeEnum>
327 error_code(ErrorCodeEnum e,
328 typename ndnboost::enable_if<is_error_code_enum<ErrorCodeEnum> >::type* = 0) NDNBOOST_SYSTEM_NOEXCEPT
329 {
330 *this = make_error_code(e);
331 }
332
333 // modifiers:
334 void assign( int val, const error_category & cat ) NDNBOOST_SYSTEM_NOEXCEPT
335 {
336 m_val = val;
337 m_cat = &cat;
338 }
339
340 template<typename ErrorCodeEnum>
341 typename ndnboost::enable_if<is_error_code_enum<ErrorCodeEnum>, error_code>::type &
342 operator=( ErrorCodeEnum val ) NDNBOOST_SYSTEM_NOEXCEPT
343 {
344 *this = make_error_code(val);
345 return *this;
346 }
347
348 void clear() NDNBOOST_SYSTEM_NOEXCEPT
349 {
350 m_val = 0;
351 m_cat = &system_category();
352 }
353
354 // observers:
355 int value() const NDNBOOST_SYSTEM_NOEXCEPT { return m_val; }
356 const error_category & category() const NDNBOOST_SYSTEM_NOEXCEPT { return *m_cat; }
357 error_condition default_error_condition() const NDNBOOST_SYSTEM_NOEXCEPT { return m_cat->default_error_condition(value()); }
358 std::string message() const { return m_cat->message(value()); }
359
360 typedef void (*unspecified_bool_type)();
361 static void unspecified_bool_true() {}
362
363 operator unspecified_bool_type() const NDNBOOST_SYSTEM_NOEXCEPT // true if error
364 {
365 return m_val == 0 ? 0 : unspecified_bool_true;
366 }
367
368 bool operator!() const NDNBOOST_SYSTEM_NOEXCEPT // true if no error
369 {
370 return m_val == 0;
371 }
372
373 // relationals:
374 inline friend bool operator==( const error_code & lhs,
375 const error_code & rhs ) NDNBOOST_SYSTEM_NOEXCEPT
376 // the more symmetrical non-member syntax allows enum
377 // conversions work for both rhs and lhs.
378 {
379 return lhs.m_cat == rhs.m_cat && lhs.m_val == rhs.m_val;
380 }
381
382 inline friend bool operator<( const error_code & lhs,
383 const error_code & rhs ) NDNBOOST_SYSTEM_NOEXCEPT
384 // the more symmetrical non-member syntax allows enum
385 // conversions work for both rhs and lhs.
386 {
387 return lhs.m_cat < rhs.m_cat
388 || (lhs.m_cat == rhs.m_cat && lhs.m_val < rhs.m_val);
389 }
390
391 private:
392 int m_val;
393 const error_category * m_cat;
394
395 };
396
397 // predefined error_code object used as "throw on error" tag
398# ifndef NDNBOOST_SYSTEM_NO_DEPRECATED
399 NDNBOOST_SYSTEM_DECL extern error_code throws;
400# endif
401
402 // Moving from a "throws" object to a "throws" function without breaking
403 // existing code is a bit of a problem. The workaround is to place the
404 // "throws" function in namespace ndnboost rather than namespace ndnboost::system.
405
406 } // namespace system
407
408 namespace detail { inline system::error_code * throws() { return 0; } }
409 // Misuse of the error_code object is turned into a noisy failure by
410 // poisoning the reference. This particular implementation doesn't
411 // produce warnings or errors from popular compilers, is very efficient
412 // (as determined by inspecting generated code), and does not suffer
413 // from order of initialization problems. In practice, it also seems
414 // cause user function error handling implementation errors to be detected
415 // very early in the development cycle.
416
417 inline system::error_code & throws()
418 { return *detail::throws(); }
419
420 namespace system
421 {
422 // non-member functions ------------------------------------------------//
423
424 inline bool operator!=( const error_code & lhs,
425 const error_code & rhs ) NDNBOOST_SYSTEM_NOEXCEPT
426 {
427 return !(lhs == rhs);
428 }
429
430 inline bool operator!=( const error_condition & lhs,
431 const error_condition & rhs ) NDNBOOST_SYSTEM_NOEXCEPT
432 {
433 return !(lhs == rhs);
434 }
435
436 inline bool operator==( const error_code & code,
437 const error_condition & condition ) NDNBOOST_SYSTEM_NOEXCEPT
438 {
439 return code.category().equivalent( code.value(), condition )
440 || condition.category().equivalent( code, condition.value() );
441 }
442
443 inline bool operator!=( const error_code & lhs,
444 const error_condition & rhs ) NDNBOOST_SYSTEM_NOEXCEPT
445 {
446 return !(lhs == rhs);
447 }
448
449 inline bool operator==( const error_condition & condition,
450 const error_code & code ) NDNBOOST_SYSTEM_NOEXCEPT
451 {
452 return condition.category().equivalent( code, condition.value() )
453 || code.category().equivalent( code.value(), condition );
454 }
455
456 inline bool operator!=( const error_condition & lhs,
457 const error_code & rhs ) NDNBOOST_SYSTEM_NOEXCEPT
458 {
459 return !(lhs == rhs);
460 }
461
462 // TODO: both of these may move elsewhere, but the LWG hasn't spoken yet.
463
464 template <class charT, class traits>
465 inline std::basic_ostream<charT,traits>&
466 operator<< (std::basic_ostream<charT,traits>& os, error_code ec)
467 {
468 os << ec.category().name() << ':' << ec.value();
469 return os;
470 }
471
472 inline std::size_t hash_value( const error_code & ec )
473 {
474 return static_cast<std::size_t>(ec.value())
475 + reinterpret_cast<std::size_t>(&ec.category());
476 }
477
478 // make_* functions for errc::errc_t -----------------------------//
479
480 namespace errc
481 {
482 // explicit conversion:
483 inline error_code make_error_code( errc_t e ) NDNBOOST_SYSTEM_NOEXCEPT
484 { return error_code( e, generic_category() ); }
485
486 // implicit conversion:
487 inline error_condition make_error_condition( errc_t e ) NDNBOOST_SYSTEM_NOEXCEPT
488 { return error_condition( e, generic_category() ); }
489 }
490
491 // error_category default implementation -------------------------------//
492
493 error_condition error_category::default_error_condition( int ev ) const NDNBOOST_SYSTEM_NOEXCEPT
494 {
495 return error_condition( ev, *this );
496 }
497
498 bool error_category::equivalent( int code,
499 const error_condition & condition ) const NDNBOOST_SYSTEM_NOEXCEPT
500 {
501 return default_error_condition( code ) == condition;
502 }
503
504 bool error_category::equivalent( const error_code & code,
505 int condition ) const NDNBOOST_SYSTEM_NOEXCEPT
506 {
507 return *this == code.category() && code.value() == condition;
508 }
509
510 } // namespace system
511} // namespace ndnboost
512
513#include <ndnboost/config/abi_suffix.hpp> // pops abi_prefix.hpp pragmas
514
515# ifdef NDNBOOST_ERROR_CODE_HEADER_ONLY
516# include <ndnboost/../libs/system/src/error_code.cpp>
517# endif
518
519#endif // NDNBOOST_ERROR_CODE_HPP
520
521