Imported Upstream version 1.72.0
[platform/upstream/boost.git] / boost / outcome / experimental / status-code / generic_code.hpp
1 /* Proposed SG14 status_code
2 (C) 2018 - 2019 Niall Douglas <http://www.nedproductions.biz/> (5 commits)
3 File Created: Feb 2018
4
5
6 Licensed under the Apache License, Version 2.0 (the "License");
7 you may not use this file except in compliance with the License.
8 You may obtain a copy of the License in the accompanying file
9 Licence.txt or at
10
11 http://www.apache.org/licenses/LICENSE-2.0
12
13 Unless required by applicable law or agreed to in writing, software
14 distributed under the License is distributed on an "AS IS" BASIS,
15 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 See the License for the specific language governing permissions and
17 limitations under the License.
18
19
20 Distributed under the Boost Software License, Version 1.0.
21 (See accompanying file Licence.txt or copy at
22 http://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
32 BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_BEGIN
33
34 //! The generic error coding (POSIX)
35 enum 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   protcol_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
119 namespace 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::protcol_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  */
293 class _generic_code_domain : public status_code_domain
294 {
295   template <class> friend class status_code;
296   template <class StatusCode> friend class detail::indirecting_domain;
297   using _base = status_code_domain;
298
299 public:
300   //! The value type of the generic code, which is an `errc` as per POSIX.
301   using value_type = errc;
302   using string_ref = _base::string_ref;
303
304 public:
305   //! Default constructor
306   constexpr explicit _generic_code_domain(typename _base::unique_id_type id = 0x746d6354f4f733e9) noexcept : _base(id) {}
307   _generic_code_domain(const _generic_code_domain &) = default;
308   _generic_code_domain(_generic_code_domain &&) = default;
309   _generic_code_domain &operator=(const _generic_code_domain &) = default;
310   _generic_code_domain &operator=(_generic_code_domain &&) = default;
311   ~_generic_code_domain() = default;
312
313   //! Constexpr singleton getter. Returns the constexpr generic_code_domain variable.
314   static inline constexpr const _generic_code_domain &get();
315
316   virtual _base::string_ref name() const noexcept override { return string_ref("generic domain"); }  // NOLINT
317 protected:
318   virtual bool _do_failure(const status_code<void> &code) const noexcept override  // NOLINT
319   {
320     assert(code.domain() == *this);                                           // NOLINT
321     return static_cast<const generic_code &>(code).value() != errc::success;  // NOLINT
322   }
323   virtual bool _do_equivalent(const status_code<void> &code1, const status_code<void> &code2) const noexcept override  // NOLINT
324   {
325     assert(code1.domain() == *this);                            // NOLINT
326     const auto &c1 = static_cast<const generic_code &>(code1);  // NOLINT
327     if(code2.domain() == *this)
328     {
329       const auto &c2 = static_cast<const generic_code &>(code2);  // NOLINT
330       return c1.value() == c2.value();
331     }
332     return false;
333   }
334   virtual generic_code _generic_code(const status_code<void> &code) const noexcept override  // NOLINT
335   {
336     assert(code.domain() == *this);                  // NOLINT
337     return static_cast<const generic_code &>(code);  // NOLINT
338   }
339   virtual _base::string_ref _do_message(const status_code<void> &code) const noexcept override  // NOLINT
340   {
341     assert(code.domain() == *this);                           // NOLINT
342     const auto &c = static_cast<const generic_code &>(code);  // NOLINT
343     return string_ref(detail::generic_code_message(c.value()));
344   }
345 #if defined(_CPPUNWIND) || defined(__EXCEPTIONS) || defined(BOOST_OUTCOME_STANDARDESE_IS_IN_THE_HOUSE)
346   BOOST_OUTCOME_SYSTEM_ERROR2_NORETURN virtual void _do_throw_exception(const status_code<void> &code) const override  // NOLINT
347   {
348     assert(code.domain() == *this);                           // NOLINT
349     const auto &c = static_cast<const generic_code &>(code);  // NOLINT
350     throw status_error<_generic_code_domain>(c);
351   }
352 #endif
353 };
354 //! A specialisation of `status_error` for the generic code domain.
355 using generic_error = status_error<_generic_code_domain>;
356 //! A constexpr source variable for the generic code domain, which is that of `errc` (POSIX). Returned by `_generic_code_domain::get()`.
357 constexpr _generic_code_domain generic_code_domain;
358 inline constexpr const _generic_code_domain &_generic_code_domain::get()
359 {
360   return generic_code_domain;
361 }
362 // Enable implicit construction of generic_code from errc
363 BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR14 inline generic_code make_status_code(errc c) noexcept
364 {
365   return generic_code(in_place, c);
366 }
367
368
369 /*************************************************************************************************************/
370
371
372 template <class T> inline bool status_code<void>::equivalent(const status_code<T> &o) const noexcept
373 {
374   if(_domain && o._domain)
375   {
376     if(_domain->_do_equivalent(*this, o))
377     {
378       return true;
379     }
380     if(o._domain->_do_equivalent(o, *this))
381     {
382       return true;
383     }
384     generic_code c1 = o._domain->_generic_code(o);
385     if(c1.value() != errc::unknown && _domain->_do_equivalent(*this, c1))
386     {
387       return true;
388     }
389     generic_code c2 = _domain->_generic_code(*this);
390     if(c2.value() != errc::unknown && o._domain->_do_equivalent(o, c2))
391     {
392       return true;
393     }
394   }
395   // If we are both empty, we are equivalent, otherwise not equivalent
396   return (!_domain && !o._domain);
397 }
398 //! True if the status code's are semantically equal via `equivalent()`.
399 template <class DomainType1, class DomainType2> inline bool operator==(const status_code<DomainType1> &a, const status_code<DomainType2> &b) noexcept
400 {
401   return a.equivalent(b);
402 }
403 //! True if the status code's are not semantically equal via `equivalent()`.
404 template <class DomainType1, class DomainType2> inline bool operator!=(const status_code<DomainType1> &a, const status_code<DomainType2> &b) noexcept
405 {
406   return !a.equivalent(b);
407 }
408 //! True if the status code's are semantically equal via `equivalent()` to `make_status_code(T)`.
409 template <class DomainType1, class T,                                                                       //
410           class MakeStatusCodeResult = typename detail::safe_get_make_status_code_result<const T &>::type,  // Safe ADL lookup of make_status_code(), returns void if not found
411           typename std::enable_if<is_status_code<MakeStatusCodeResult>::value, bool>::type = true>          // ADL makes a status code
412 inline bool operator==(const status_code<DomainType1> &a, const T &b)
413 {
414   return a.equivalent(make_status_code(b));
415 }
416 //! True if the status code's are semantically equal via `equivalent()` to `make_status_code(T)`.
417 template <class T, class DomainType1,                                                                       //
418           class MakeStatusCodeResult = typename detail::safe_get_make_status_code_result<const T &>::type,  // Safe ADL lookup of make_status_code(), returns void if not found
419           typename std::enable_if<is_status_code<MakeStatusCodeResult>::value, bool>::type = true>          // ADL makes a status code
420 inline bool operator==(const T &a, const status_code<DomainType1> &b)
421 {
422   return b.equivalent(make_status_code(a));
423 }
424 //! True if the status code's are not semantically equal via `equivalent()` to `make_status_code(T)`.
425 template <class DomainType1, class T,                                                                       //
426           class MakeStatusCodeResult = typename detail::safe_get_make_status_code_result<const T &>::type,  // Safe ADL lookup of make_status_code(), returns void if not found
427           typename std::enable_if<is_status_code<MakeStatusCodeResult>::value, bool>::type = true>          // ADL makes a status code
428 inline bool operator!=(const status_code<DomainType1> &a, const T &b)
429 {
430   return !a.equivalent(make_status_code(b));
431 }
432 //! True if the status code's are semantically equal via `equivalent()` to `make_status_code(T)`.
433 template <class T, class DomainType1,                                                                       //
434           class MakeStatusCodeResult = typename detail::safe_get_make_status_code_result<const T &>::type,  // Safe ADL lookup of make_status_code(), returns void if not found
435           typename std::enable_if<is_status_code<MakeStatusCodeResult>::value, bool>::type = true>          // ADL makes a status code
436 inline bool operator!=(const T &a, const status_code<DomainType1> &b)
437 {
438   return !b.equivalent(make_status_code(a));
439 }
440
441 BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_END
442
443 #endif