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