1/* Proposed SG14 status_code
2(C) 2018 - 2020 Niall Douglas <http://www.nedproductions.biz/> (5 commits)
3File Created: Feb 2018
4
5
6Licensed under the Apache License, Version 2.0 (the "License");
7you may not use this file except in compliance with the License.
8You may obtain a copy of the License in the accompanying file
9Licence.txt or at
10
11http://www.apache.org/licenses/LICENSE-2.0
12
13Unless required by applicable law or agreed to in writing, software
14distributed under the License is distributed on an "AS IS" BASIS,
15WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16See the License for the specific language governing permissions and
17limitations under the License.
18
19
20Distributed under the Boost Software License, Version 1.0.
21(See accompanying file Licence.txt or copy at
22http://www.boost.org/LICENSE_1_0.txt)
23*/
24
25#ifndef BOOST_OUTCOME_SYSTEM_ERROR2_GENERIC_CODE_HPP
26#define BOOST_OUTCOME_SYSTEM_ERROR2_GENERIC_CODE_HPP
27
28#include "status_error.hpp"
29
30#include <cerrno> // for error constants
31
32BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_BEGIN
33
34//! The generic error coding (POSIX)
35enum class errc : int
36{
37 success = 0,
38 unknown = -1,
39
40 address_family_not_supported = EAFNOSUPPORT,
41 address_in_use = EADDRINUSE,
42 address_not_available = EADDRNOTAVAIL,
43 already_connected = EISCONN,
44 argument_list_too_long = E2BIG,
45 argument_out_of_domain = EDOM,
46 bad_address = EFAULT,
47 bad_file_descriptor = EBADF,
48 bad_message = EBADMSG,
49 broken_pipe = EPIPE,
50 connection_aborted = ECONNABORTED,
51 connection_already_in_progress = EALREADY,
52 connection_refused = ECONNREFUSED,
53 connection_reset = ECONNRESET,
54 cross_device_link = EXDEV,
55 destination_address_required = EDESTADDRREQ,
56 device_or_resource_busy = EBUSY,
57 directory_not_empty = ENOTEMPTY,
58 executable_format_error = ENOEXEC,
59 file_exists = EEXIST,
60 file_too_large = EFBIG,
61 filename_too_long = ENAMETOOLONG,
62 function_not_supported = ENOSYS,
63 host_unreachable = EHOSTUNREACH,
64 identifier_removed = EIDRM,
65 illegal_byte_sequence = EILSEQ,
66 inappropriate_io_control_operation = ENOTTY,
67 interrupted = EINTR,
68 invalid_argument = EINVAL,
69 invalid_seek = ESPIPE,
70 io_error = EIO,
71 is_a_directory = EISDIR,
72 message_size = EMSGSIZE,
73 network_down = ENETDOWN,
74 network_reset = ENETRESET,
75 network_unreachable = ENETUNREACH,
76 no_buffer_space = ENOBUFS,
77 no_child_process = ECHILD,
78 no_link = ENOLINK,
79 no_lock_available = ENOLCK,
80 no_message = ENOMSG,
81 no_protocol_option = ENOPROTOOPT,
82 no_space_on_device = ENOSPC,
83 no_stream_resources = ENOSR,
84 no_such_device_or_address = ENXIO,
85 no_such_device = ENODEV,
86 no_such_file_or_directory = ENOENT,
87 no_such_process = ESRCH,
88 not_a_directory = ENOTDIR,
89 not_a_socket = ENOTSOCK,
90 not_a_stream = ENOSTR,
91 not_connected = ENOTCONN,
92 not_enough_memory = ENOMEM,
93 not_supported = ENOTSUP,
94 operation_canceled = ECANCELED,
95 operation_in_progress = EINPROGRESS,
96 operation_not_permitted = EPERM,
97 operation_not_supported = EOPNOTSUPP,
98 operation_would_block = EWOULDBLOCK,
99 owner_dead = EOWNERDEAD,
100 permission_denied = EACCES,
101 protocol_error = EPROTO,
102 protocol_not_supported = EPROTONOSUPPORT,
103 read_only_file_system = EROFS,
104 resource_deadlock_would_occur = EDEADLK,
105 resource_unavailable_try_again = EAGAIN,
106 result_out_of_range = ERANGE,
107 state_not_recoverable = ENOTRECOVERABLE,
108 stream_timeout = ETIME,
109 text_file_busy = ETXTBSY,
110 timed_out = ETIMEDOUT,
111 too_many_files_open_in_system = ENFILE,
112 too_many_files_open = EMFILE,
113 too_many_links = EMLINK,
114 too_many_symbolic_link_levels = ELOOP,
115 value_too_large = EOVERFLOW,
116 wrong_protocol_type = EPROTOTYPE
117};
118
119namespace detail
120{
121 BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR14 inline const char *generic_code_message(errc code) noexcept
122 {
123 switch(code)
124 {
125 case errc::success:
126 return "Success";
127 case errc::address_family_not_supported:
128 return "Address family not supported by protocol";
129 case errc::address_in_use:
130 return "Address already in use";
131 case errc::address_not_available:
132 return "Cannot assign requested address";
133 case errc::already_connected:
134 return "Transport endpoint is already connected";
135 case errc::argument_list_too_long:
136 return "Argument list too long";
137 case errc::argument_out_of_domain:
138 return "Numerical argument out of domain";
139 case errc::bad_address:
140 return "Bad address";
141 case errc::bad_file_descriptor:
142 return "Bad file descriptor";
143 case errc::bad_message:
144 return "Bad message";
145 case errc::broken_pipe:
146 return "Broken pipe";
147 case errc::connection_aborted:
148 return "Software caused connection abort";
149 case errc::connection_already_in_progress:
150 return "Operation already in progress";
151 case errc::connection_refused:
152 return "Connection refused";
153 case errc::connection_reset:
154 return "Connection reset by peer";
155 case errc::cross_device_link:
156 return "Invalid cross-device link";
157 case errc::destination_address_required:
158 return "Destination address required";
159 case errc::device_or_resource_busy:
160 return "Device or resource busy";
161 case errc::directory_not_empty:
162 return "Directory not empty";
163 case errc::executable_format_error:
164 return "Exec format error";
165 case errc::file_exists:
166 return "File exists";
167 case errc::file_too_large:
168 return "File too large";
169 case errc::filename_too_long:
170 return "File name too long";
171 case errc::function_not_supported:
172 return "Function not implemented";
173 case errc::host_unreachable:
174 return "No route to host";
175 case errc::identifier_removed:
176 return "Identifier removed";
177 case errc::illegal_byte_sequence:
178 return "Invalid or incomplete multibyte or wide character";
179 case errc::inappropriate_io_control_operation:
180 return "Inappropriate ioctl for device";
181 case errc::interrupted:
182 return "Interrupted system call";
183 case errc::invalid_argument:
184 return "Invalid argument";
185 case errc::invalid_seek:
186 return "Illegal seek";
187 case errc::io_error:
188 return "Input/output error";
189 case errc::is_a_directory:
190 return "Is a directory";
191 case errc::message_size:
192 return "Message too long";
193 case errc::network_down:
194 return "Network is down";
195 case errc::network_reset:
196 return "Network dropped connection on reset";
197 case errc::network_unreachable:
198 return "Network is unreachable";
199 case errc::no_buffer_space:
200 return "No buffer space available";
201 case errc::no_child_process:
202 return "No child processes";
203 case errc::no_link:
204 return "Link has been severed";
205 case errc::no_lock_available:
206 return "No locks available";
207 case errc::no_message:
208 return "No message of desired type";
209 case errc::no_protocol_option:
210 return "Protocol not available";
211 case errc::no_space_on_device:
212 return "No space left on device";
213 case errc::no_stream_resources:
214 return "Out of streams resources";
215 case errc::no_such_device_or_address:
216 return "No such device or address";
217 case errc::no_such_device:
218 return "No such device";
219 case errc::no_such_file_or_directory:
220 return "No such file or directory";
221 case errc::no_such_process:
222 return "No such process";
223 case errc::not_a_directory:
224 return "Not a directory";
225 case errc::not_a_socket:
226 return "Socket operation on non-socket";
227 case errc::not_a_stream:
228 return "Device not a stream";
229 case errc::not_connected:
230 return "Transport endpoint is not connected";
231 case errc::not_enough_memory:
232 return "Cannot allocate memory";
233#if ENOTSUP != EOPNOTSUPP
234 case errc::not_supported:
235 return "Operation not supported";
236#endif
237 case errc::operation_canceled:
238 return "Operation canceled";
239 case errc::operation_in_progress:
240 return "Operation now in progress";
241 case errc::operation_not_permitted:
242 return "Operation not permitted";
243 case errc::operation_not_supported:
244 return "Operation not supported";
245#if EAGAIN != EWOULDBLOCK
246 case errc::operation_would_block:
247 return "Resource temporarily unavailable";
248#endif
249 case errc::owner_dead:
250 return "Owner died";
251 case errc::permission_denied:
252 return "Permission denied";
253 case errc::protocol_error:
254 return "Protocol error";
255 case errc::protocol_not_supported:
256 return "Protocol not supported";
257 case errc::read_only_file_system:
258 return "Read-only file system";
259 case errc::resource_deadlock_would_occur:
260 return "Resource deadlock avoided";
261 case errc::resource_unavailable_try_again:
262 return "Resource temporarily unavailable";
263 case errc::result_out_of_range:
264 return "Numerical result out of range";
265 case errc::state_not_recoverable:
266 return "State not recoverable";
267 case errc::stream_timeout:
268 return "Timer expired";
269 case errc::text_file_busy:
270 return "Text file busy";
271 case errc::timed_out:
272 return "Connection timed out";
273 case errc::too_many_files_open_in_system:
274 return "Too many open files in system";
275 case errc::too_many_files_open:
276 return "Too many open files";
277 case errc::too_many_links:
278 return "Too many links";
279 case errc::too_many_symbolic_link_levels:
280 return "Too many levels of symbolic links";
281 case errc::value_too_large:
282 return "Value too large for defined data type";
283 case errc::wrong_protocol_type:
284 return "Protocol wrong type for socket";
285 default:
286 return "unknown";
287 }
288 }
289} // namespace detail
290
291/*! The implementation of the domain for generic status codes, those mapped by `errc` (POSIX).
292 */
293class _generic_code_domain : public status_code_domain
294{
295 template <class> friend class status_code;
296 using _base = status_code_domain;
297
298public:
299 //! The value type of the generic code, which is an `errc` as per POSIX.
300 using value_type = errc;
301 using string_ref = _base::string_ref;
302
303public:
304 //! Default constructor
305 constexpr explicit _generic_code_domain(typename _base::unique_id_type id = 0x746d6354f4f733e9) noexcept
306 : _base(id)
307 {
308 }
309 _generic_code_domain(const _generic_code_domain &) = default;
310 _generic_code_domain(_generic_code_domain &&) = default;
311 _generic_code_domain &operator=(const _generic_code_domain &) = default;
312 _generic_code_domain &operator=(_generic_code_domain &&) = default;
313 ~_generic_code_domain() = default;
314
315 //! Constexpr singleton getter. Returns the constexpr generic_code_domain variable.
316 static inline constexpr const _generic_code_domain &get();
317
318 virtual _base::string_ref name() const noexcept override { return string_ref("generic domain"); } // NOLINT
319
320 virtual payload_info_t payload_info() const noexcept override
321 {
322 return {sizeof(value_type), sizeof(status_code_domain *) + sizeof(value_type),
323 (alignof(value_type) > alignof(status_code_domain *)) ? alignof(value_type) : alignof(status_code_domain *)};
324 }
325
326protected:
327 virtual bool _do_failure(const status_code<void> &code) const noexcept override // NOLINT
328 {
329 assert(code.domain() == *this); // NOLINT
330 return static_cast<const generic_code &>(code).value() != errc::success; // NOLINT
331 }
332 virtual bool _do_equivalent(const status_code<void> &code1, const status_code<void> &code2) const noexcept override // NOLINT
333 {
334 assert(code1.domain() == *this); // NOLINT
335 const auto &c1 = static_cast<const generic_code &>(code1); // NOLINT
336 if(code2.domain() == *this)
337 {
338 const auto &c2 = static_cast<const generic_code &>(code2); // NOLINT
339 return c1.value() == c2.value();
340 }
341 return false;
342 }
343 virtual generic_code _generic_code(const status_code<void> &code) const noexcept override // NOLINT
344 {
345 assert(code.domain() == *this); // NOLINT
346 return static_cast<const generic_code &>(code); // NOLINT
347 }
348 virtual _base::string_ref _do_message(const status_code<void> &code) const noexcept override // NOLINT
349 {
350 assert(code.domain() == *this); // NOLINT
351 const auto &c = static_cast<const generic_code &>(code); // NOLINT
352 return string_ref(detail::generic_code_message(code: c.value()));
353 }
354#if defined(_CPPUNWIND) || defined(__EXCEPTIONS) || defined(BOOST_OUTCOME_STANDARDESE_IS_IN_THE_HOUSE)
355 BOOST_OUTCOME_SYSTEM_ERROR2_NORETURN virtual void _do_throw_exception(const status_code<void> &code) const override // NOLINT
356 {
357 assert(code.domain() == *this); // NOLINT
358 const auto &c = static_cast<const generic_code &>(code); // NOLINT
359 throw status_error<_generic_code_domain>(c);
360 }
361#endif
362};
363//! A specialisation of `status_error` for the generic code domain.
364using generic_error = status_error<_generic_code_domain>;
365//! A constexpr source variable for the generic code domain, which is that of `errc` (POSIX). Returned by `_generic_code_domain::get()`.
366constexpr _generic_code_domain generic_code_domain;
367inline constexpr const _generic_code_domain &_generic_code_domain::get()
368{
369 return generic_code_domain;
370}
371// Enable implicit construction of generic_code from errc
372BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR14 inline generic_code make_status_code(errc c) noexcept
373{
374 return generic_code(in_place, c);
375}
376
377
378/*************************************************************************************************************/
379
380
381template <class T> inline BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR14 bool status_code<void>::equivalent(const status_code<T> &o) const noexcept
382{
383 if(_domain && o._domain)
384 {
385 if(_domain->_do_equivalent(code1: *this, code2: o))
386 {
387 return true;
388 }
389 if(o._domain->_do_equivalent(o, *this))
390 {
391 return true;
392 }
393 generic_code c1 = o._domain->_generic_code(o);
394 if(c1.value() != errc::unknown && _domain->_do_equivalent(code1: *this, code2: c1))
395 {
396 return true;
397 }
398 generic_code c2 = _domain->_generic_code(code: *this);
399 if(c2.value() != errc::unknown && o._domain->_do_equivalent(o, c2))
400 {
401 return true;
402 }
403 }
404 // If we are both empty, we are equivalent, otherwise not equivalent
405 return (!_domain && !o._domain);
406}
407//! True if the status code's are semantically equal via `equivalent()`.
408template <class DomainType1, class DomainType2>
409BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR14 inline bool operator==(const status_code<DomainType1> &a, const status_code<DomainType2> &b) noexcept
410{
411 return a.equivalent(b);
412}
413//! True if the status code's are not semantically equal via `equivalent()`.
414template <class DomainType1, class DomainType2>
415BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR14 inline bool operator!=(const status_code<DomainType1> &a, const status_code<DomainType2> &b) noexcept
416{
417 return !a.equivalent(b);
418}
419//! True if the status code's are semantically equal via `equivalent()` to `make_status_code(T)`.
420BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(class DomainType1, class T, //
421 class MakeStatusCodeResult =
422 typename detail::safe_get_make_status_code_result<const T &>::type) // Safe ADL lookup of make_status_code(), returns void if not found
423BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(is_status_code<MakeStatusCodeResult>::value)) // ADL makes a status code
424BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR14 inline bool operator==(const status_code<DomainType1> &a, const T &b)
425{
426 return a.equivalent(make_status_code(b));
427}
428//! True if the status code's are semantically equal via `equivalent()` to `make_status_code(T)`.
429BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(class T, class DomainType1, //
430 class MakeStatusCodeResult =
431 typename detail::safe_get_make_status_code_result<const T &>::type) // Safe ADL lookup of make_status_code(), returns void if not found
432BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(is_status_code<MakeStatusCodeResult>::value)) // ADL makes a status code
433BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR14 inline bool operator==(const T &a, const status_code<DomainType1> &b)
434{
435 return b.equivalent(make_status_code(a));
436}
437//! True if the status code's are not semantically equal via `equivalent()` to `make_status_code(T)`.
438BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(class DomainType1, class T, //
439 class MakeStatusCodeResult =
440 typename detail::safe_get_make_status_code_result<const T &>::type) // Safe ADL lookup of make_status_code(), returns void if not found
441BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(is_status_code<MakeStatusCodeResult>::value)) // ADL makes a status code
442BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR14 inline bool operator!=(const status_code<DomainType1> &a, const T &b)
443{
444 return !a.equivalent(make_status_code(b));
445}
446//! True if the status code's are semantically equal via `equivalent()` to `make_status_code(T)`.
447BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(class T, class DomainType1, //
448 class MakeStatusCodeResult =
449 typename detail::safe_get_make_status_code_result<const T &>::type) // Safe ADL lookup of make_status_code(), returns void if not found
450BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(is_status_code<MakeStatusCodeResult>::value)) // ADL makes a status code
451BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR14 inline bool operator!=(const T &a, const status_code<DomainType1> &b)
452{
453 return !b.equivalent(make_status_code(a));
454}
455//! True if the status code's are semantically equal via `equivalent()` to `quick_status_code_from_enum<T>::code_type(b)`.
456template <class DomainType1, class T, //
457 class QuickStatusCodeType = typename quick_status_code_from_enum<T>::code_type // Enumeration has been activated
458 >
459BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR14 inline bool operator==(const status_code<DomainType1> &a, const T &b)
460{
461 return a.equivalent(QuickStatusCodeType(b));
462}
463//! True if the status code's are semantically equal via `equivalent()` to `quick_status_code_from_enum<T>::code_type(a)`.
464template <class T, class DomainType1, //
465 class QuickStatusCodeType = typename quick_status_code_from_enum<T>::code_type // Enumeration has been activated
466 >
467BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR14 inline bool operator==(const T &a, const status_code<DomainType1> &b)
468{
469 return b.equivalent(QuickStatusCodeType(a));
470}
471//! True if the status code's are not semantically equal via `equivalent()` to `quick_status_code_from_enum<T>::code_type(b)`.
472template <class DomainType1, class T, //
473 class QuickStatusCodeType = typename quick_status_code_from_enum<T>::code_type // Enumeration has been activated
474 >
475BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR14 inline bool operator!=(const status_code<DomainType1> &a, const T &b)
476{
477 return !a.equivalent(QuickStatusCodeType(b));
478}
479//! True if the status code's are not semantically equal via `equivalent()` to `quick_status_code_from_enum<T>::code_type(a)`.
480template <class T, class DomainType1, //
481 class QuickStatusCodeType = typename quick_status_code_from_enum<T>::code_type // Enumeration has been activated
482 >
483BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR14 inline bool operator!=(const T &a, const status_code<DomainType1> &b)
484{
485 return !b.equivalent(QuickStatusCodeType(a));
486}
487
488
489BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_END
490
491#endif
492

source code of boost/libs/outcome/include/boost/outcome/experimental/status-code/generic_code.hpp