]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/outcome/experimental/status-code/status_code.hpp
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / boost / boost / outcome / experimental / status-code / status_code.hpp
1 /* Proposed SG14 status_code
2 (C) 2018 - 2020 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_STATUS_CODE_HPP
26 #define BOOST_OUTCOME_SYSTEM_ERROR2_STATUS_CODE_HPP
27
28 #include "status_code_domain.hpp"
29
30 #if(__cplusplus >= 201700 || _HAS_CXX17) && !defined(BOOST_OUTCOME_SYSTEM_ERROR2_DISABLE_STD_IN_PLACE)
31 // 0.26
32 #include <utility> // for in_place
33
34 BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_BEGIN
35 using in_place_t = std::in_place_t;
36 using std::in_place;
37 BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_END
38
39 #else
40
41 BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_BEGIN
42 //! Aliases `std::in_place_t` if on C++ 17 or later, else defined locally.
43 struct in_place_t
44 {
45 explicit in_place_t() = default;
46 };
47 //! Aliases `std::in_place` if on C++ 17 or later, else defined locally.
48 constexpr in_place_t in_place{};
49 BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_END
50 #endif
51
52 BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_BEGIN
53
54 //! Namespace for user injected mixins
55 namespace mixins
56 {
57 template <class Base, class T> struct mixin : public Base
58 {
59 using Base::Base;
60 };
61 } // namespace mixins
62
63 /*! A tag for an erased value type for `status_code<D>`.
64 Available only if `ErasedType` satisfies `traits::is_move_bitcopying<ErasedType>::value`.
65 */
66 BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(class ErasedType) //
67 BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(traits::is_move_bitcopying<ErasedType>::value))
68 struct erased
69 {
70 using value_type = ErasedType;
71 };
72
73 /*! Specialise this template to quickly wrap a third party enumeration into a
74 custom status code domain.
75
76 Use like this:
77
78 ```c++
79 BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_BEGIN
80 template <> struct quick_status_code_from_enum<AnotherCode> : quick_status_code_from_enum_defaults<AnotherCode>
81 {
82 // Text name of the enum
83 static constexpr const auto domain_name = "Another Code";
84 // Unique UUID for the enum. PLEASE use https://www.random.org/cgi-bin/randbyte?nbytes=16&format=h
85 static constexpr const auto domain_uuid = "{be201f65-3962-dd0e-1266-a72e63776a42}";
86 // Map of each enum value to its text string, and list of semantically equivalent errc's
87 static const std::initializer_list<mapping> &value_mappings()
88 {
89 static const std::initializer_list<mapping<AnotherCode>> v = {
90 // Format is: { enum value, "string representation", { list of errc mappings ... } }
91 {AnotherCode::success1, "Success 1", {errc::success}}, //
92 {AnotherCode::goaway, "Go away", {errc::permission_denied}}, //
93 {AnotherCode::success2, "Success 2", {errc::success}}, //
94 {AnotherCode::error2, "Error 2", {}}, //
95 };
96 return v;
97 }
98 // Completely optional definition of mixin for the status code synthesised from `Enum`. It can be omitted.
99 template <class Base> struct mixin : Base
100 {
101 using Base::Base;
102 constexpr int custom_method() const { return 42; }
103 };
104 };
105 BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_END
106 ```
107
108 Note that if the `errc` mapping contains `errc::success`, then
109 the enumeration value is considered to be a successful value.
110 Otherwise it is considered to be a failure value.
111
112 The first value in the `errc` mapping is the one chosen as the
113 `generic_code` conversion. Other values are used during equivalence
114 comparisons.
115 */
116 template <class Enum> struct quick_status_code_from_enum;
117
118 namespace detail
119 {
120 template <class T> struct is_status_code
121 {
122 static constexpr bool value = false;
123 };
124 template <class T> struct is_status_code<status_code<T>>
125 {
126 static constexpr bool value = true;
127 };
128 template <class T> struct is_erased_status_code
129 {
130 static constexpr bool value = false;
131 };
132 template <class T> struct is_erased_status_code<status_code<erased<T>>>
133 {
134 static constexpr bool value = true;
135 };
136
137 #if !defined(__GNUC__) || defined(__clang__) || __GNUC__ >= 8
138 // From http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4436.pdf
139 namespace impl
140 {
141 template <typename... Ts> struct make_void
142 {
143 using type = void;
144 };
145 template <typename... Ts> using void_t = typename make_void<Ts...>::type;
146 template <class...> struct types
147 {
148 using type = types;
149 };
150 template <template <class...> class T, class types, class = void> struct test_apply
151 {
152 using type = void;
153 };
154 template <template <class...> class T, class... Ts> struct test_apply<T, types<Ts...>, void_t<T<Ts...>>>
155 {
156 using type = T<Ts...>;
157 };
158 } // namespace impl
159 template <template <class...> class T, class... Ts> using test_apply = impl::test_apply<T, impl::types<Ts...>>;
160
161 template <class T, class... Args> using get_make_status_code_result = decltype(make_status_code(std::declval<T>(), std::declval<Args>()...));
162 template <class... Args> using safe_get_make_status_code_result = test_apply<get_make_status_code_result, Args...>;
163
164 #else
165
166 // ICE avoidance form for GCCs before 8. Note this form doesn't prevent recursive make_status_code ADL instantation,
167 // so in certain corner cases this will break. On the other hand, more useful than an ICE.
168 namespace impl
169 {
170 template <typename... Ts> struct make_void
171 {
172 using type = void;
173 };
174 template <typename... Ts> using void_t = typename make_void<Ts...>::type;
175 template <class...> struct types
176 {
177 using type = types;
178 };
179 template <typename Types, typename = void> struct make_status_code_rettype
180 {
181 using type = void;
182 };
183 template <typename... Args> using get_make_status_code_result = decltype(make_status_code(std::declval<Args>()...));
184 template <typename... Args> struct make_status_code_rettype<types<Args...>, void_t<get_make_status_code_result<Args...>>>
185 {
186 using type = get_make_status_code_result<Args...>;
187 };
188 } // namespace impl
189 template <class... Args> struct safe_get_make_status_code_result
190 {
191 using type = typename impl::make_status_code_rettype<impl::types<Args...>>::type;
192 };
193 #endif
194 } // namespace detail
195
196 //! Trait returning true if the type is a status code.
197 template <class T> struct is_status_code
198 {
199 static constexpr bool value = detail::is_status_code<typename std::decay<T>::type>::value || detail::is_erased_status_code<typename std::decay<T>::type>::value;
200 };
201
202 /*! A type erased lightweight status code reflecting empty, success, or failure.
203 Differs from `status_code<erased<>>` by being always available irrespective of
204 the domain's value type, but cannot be copied, moved, nor destructed. Thus one
205 always passes this around by const lvalue reference.
206 */
207 template <> class BOOST_OUTCOME_SYSTEM_ERROR2_TRIVIAL_ABI status_code<void>
208 {
209 template <class T> friend class status_code;
210
211 public:
212 //! The type of the domain.
213 using domain_type = void;
214 //! The type of the status code.
215 using value_type = void;
216 //! The type of a reference to a message string.
217 using string_ref = typename status_code_domain::string_ref;
218
219 protected:
220 const status_code_domain *_domain{nullptr};
221
222 protected:
223 //! No default construction at type erased level
224 status_code() = default;
225 //! No public copying at type erased level
226 status_code(const status_code &) = default;
227 //! No public moving at type erased level
228 status_code(status_code &&) = default;
229 //! No public assignment at type erased level
230 status_code &operator=(const status_code &) = default;
231 //! No public assignment at type erased level
232 status_code &operator=(status_code &&) = default;
233 //! No public destruction at type erased level
234 ~status_code() = default;
235
236 //! Used to construct a non-empty type erased status code
237 constexpr explicit status_code(const status_code_domain *v) noexcept
238 : _domain(v)
239 {
240 }
241
242 // Used to work around triggering a ubsan failure. Do NOT remove!
243 constexpr const status_code_domain *_domain_ptr() const noexcept { return _domain; }
244
245 public:
246 //! Return the status code domain.
247 constexpr const status_code_domain &domain() const noexcept { return *_domain; }
248 //! True if the status code is empty.
249 BOOST_OUTCOME_SYSTEM_ERROR2_NODISCARD constexpr bool empty() const noexcept { return _domain == nullptr; }
250
251 //! Return a reference to a string textually representing a code.
252 BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR20 string_ref message() const noexcept
253 {
254 // Avoid MSVC's buggy ternary operator for expensive to destruct things
255 if(_domain != nullptr)
256 {
257 return _domain->_do_message(*this);
258 }
259 return string_ref("(empty)");
260 }
261 //! True if code means success.
262 BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR20 bool success() const noexcept { return (_domain != nullptr) ? !_domain->_do_failure(*this) : false; }
263 //! True if code means failure.
264 BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR20 bool failure() const noexcept { return (_domain != nullptr) ? _domain->_do_failure(*this) : false; }
265 /*! True if code is strictly (and potentially non-transitively) semantically equivalent to another code in another domain.
266 Note that usually non-semantic i.e. pure value comparison is used when the other status code has the same domain.
267 As `equivalent()` will try mapping to generic code, this usually captures when two codes have the same semantic
268 meaning in `equivalent()`.
269 */
270 template <class T> BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR14 bool strictly_equivalent(const status_code<T> &o) const noexcept
271 {
272 if(_domain && o._domain)
273 {
274 return _domain->_do_equivalent(*this, o);
275 }
276 // If we are both empty, we are equivalent
277 if(!_domain && !o._domain)
278 {
279 return true; // NOLINT
280 }
281 // Otherwise not equivalent
282 return false;
283 }
284 /*! True if code is equivalent, by any means, to another code in another domain (guaranteed transitive).
285 Firstly `strictly_equivalent()` is run in both directions. If neither succeeds, each domain is asked
286 for the equivalent generic code and those are compared.
287 */
288 template <class T> BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR14 inline bool equivalent(const status_code<T> &o) const noexcept;
289 #if defined(_CPPUNWIND) || defined(__EXCEPTIONS) || defined(BOOST_OUTCOME_STANDARDESE_IS_IN_THE_HOUSE)
290 //! Throw a code as a C++ exception.
291 BOOST_OUTCOME_SYSTEM_ERROR2_NORETURN void throw_exception() const
292 {
293 _domain->_do_throw_exception(*this);
294 abort(); // suppress buggy GCC warning
295 }
296 #endif
297 };
298
299 namespace detail
300 {
301 template <class DomainType> struct get_domain_value_type
302 {
303 using domain_type = DomainType;
304 using value_type = typename domain_type::value_type;
305 };
306 template <class ErasedType> struct get_domain_value_type<erased<ErasedType>>
307 {
308 using domain_type = status_code_domain;
309 using value_type = ErasedType;
310 };
311 template <class DomainType> class BOOST_OUTCOME_SYSTEM_ERROR2_TRIVIAL_ABI status_code_storage : public status_code<void>
312 {
313 using _base = status_code<void>;
314
315 public:
316 //! The type of the domain.
317 using domain_type = typename get_domain_value_type<DomainType>::domain_type;
318 //! The type of the status code.
319 using value_type = typename get_domain_value_type<DomainType>::value_type;
320 //! The type of a reference to a message string.
321 using string_ref = typename domain_type::string_ref;
322
323 #ifndef NDEBUG
324 static_assert(std::is_move_constructible<value_type>::value || std::is_copy_constructible<value_type>::value, "DomainType::value_type is neither move nor copy constructible!");
325 static_assert(!std::is_default_constructible<value_type>::value || std::is_nothrow_default_constructible<value_type>::value, "DomainType::value_type is not nothrow default constructible!");
326 static_assert(!std::is_move_constructible<value_type>::value || std::is_nothrow_move_constructible<value_type>::value, "DomainType::value_type is not nothrow move constructible!");
327 static_assert(std::is_nothrow_destructible<value_type>::value, "DomainType::value_type is not nothrow destructible!");
328 #endif
329
330 // Replace the type erased implementations with type aware implementations for better codegen
331 //! Return the status code domain.
332 constexpr const domain_type &domain() const noexcept { return *static_cast<const domain_type *>(this->_domain); }
333
334 //! Reset the code to empty.
335 BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR14 void clear() noexcept
336 {
337 this->_value.~value_type();
338 this->_domain = nullptr;
339 new(&this->_value) value_type();
340 }
341
342 #if __cplusplus >= 201400 || _MSC_VER >= 1910 /* VS2017 */
343 //! Return a reference to the `value_type`.
344 constexpr value_type &value() &noexcept { return this->_value; }
345 //! Return a reference to the `value_type`.
346 constexpr value_type &&value() &&noexcept { return static_cast<value_type &&>(this->_value); }
347 #endif
348 //! Return a reference to the `value_type`.
349 constexpr const value_type &value() const &noexcept { return this->_value; }
350 //! Return a reference to the `value_type`.
351 constexpr const value_type &&value() const &&noexcept { return static_cast<const value_type &&>(this->_value); }
352
353 protected:
354 status_code_storage() = default;
355 status_code_storage(const status_code_storage &) = default;
356 BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR14 status_code_storage(status_code_storage &&o) noexcept
357 : _base(static_cast<status_code_storage &&>(o))
358 , _value(static_cast<status_code_storage &&>(o)._value)
359 {
360 o._domain = nullptr;
361 }
362 status_code_storage &operator=(const status_code_storage &) = default;
363 BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR14 status_code_storage &operator=(status_code_storage &&o) noexcept
364 {
365 this->~status_code_storage();
366 new(this) status_code_storage(static_cast<status_code_storage &&>(o));
367 return *this;
368 }
369 ~status_code_storage() = default;
370
371 value_type _value{};
372 struct _value_type_constructor
373 {
374 };
375 template <class... Args>
376 constexpr status_code_storage(_value_type_constructor /*unused*/, const status_code_domain *v, Args &&...args)
377 : _base(v)
378 , _value(static_cast<Args &&>(args)...)
379 {
380 }
381 };
382 } // namespace detail
383
384 /*! A lightweight, typed, status code reflecting empty, success, or failure.
385 This is the main workhorse of the system_error2 library. Its characteristics reflect the value type
386 set by its domain type, so if that value type is move-only or trivial, so is this.
387
388 An ADL discovered helper function `make_status_code(T, Args...)` is looked up by one of the constructors.
389 If it is found, and it generates a status code compatible with this status code, implicit construction
390 is made available.
391
392 You may mix in custom member functions and member function overrides by injecting a specialisation of
393 `mixins::mixin<Base, YourDomainType>`. Your mixin must inherit from `Base`.
394 */
395 template <class DomainType> class BOOST_OUTCOME_SYSTEM_ERROR2_TRIVIAL_ABI status_code : public mixins::mixin<detail::status_code_storage<DomainType>, DomainType>
396 {
397 template <class T> friend class status_code;
398 using _base = mixins::mixin<detail::status_code_storage<DomainType>, DomainType>;
399
400 public:
401 //! The type of the domain.
402 using domain_type = DomainType;
403 //! The type of the status code.
404 using value_type = typename domain_type::value_type;
405 //! The type of a reference to a message string.
406 using string_ref = typename domain_type::string_ref;
407
408 protected:
409 using _base::_base;
410
411 public:
412 //! Default construction to empty
413 status_code() = default;
414 //! Copy constructor
415 status_code(const status_code &) = default;
416 //! Move constructor
417 status_code(status_code &&) = default; // NOLINT
418 //! Copy assignment
419 status_code &operator=(const status_code &) = default;
420 //! Move assignment
421 status_code &operator=(status_code &&) = default; // NOLINT
422 ~status_code() = default;
423
424 //! Return a copy of the code.
425 BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR14 status_code clone() const { return *this; }
426
427 /***** KEEP THESE IN SYNC WITH ERRORED_STATUS_CODE *****/
428 //! Implicit construction from any type where an ADL discovered `make_status_code(T, Args ...)` returns a `status_code`.
429 BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(class T, class... Args, //
430 class MakeStatusCodeResult = typename detail::safe_get_make_status_code_result<T, Args...>::type) // Safe ADL lookup of make_status_code(), returns void if not found
431 BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(!std::is_same<typename std::decay<T>::type, status_code>::value // not copy/move of self
432 && !std::is_same<typename std::decay<T>::type, in_place_t>::value // not in_place_t
433 && is_status_code<MakeStatusCodeResult>::value // ADL makes a status code
434 && std::is_constructible<status_code, MakeStatusCodeResult>::value)) // ADLed status code is compatible
435 constexpr status_code(T &&v, Args &&...args) noexcept(noexcept(make_status_code(std::declval<T>(), std::declval<Args>()...))) // NOLINT
436 : status_code(make_status_code(static_cast<T &&>(v), static_cast<Args &&>(args)...))
437 {
438 }
439 //! Implicit construction from any `quick_status_code_from_enum<Enum>` enumerated type.
440 BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(class Enum, //
441 class QuickStatusCodeType = typename quick_status_code_from_enum<Enum>::code_type) // Enumeration has been activated
442 BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(std::is_constructible<status_code, QuickStatusCodeType>::value)) // Its status code is compatible
443 constexpr status_code(Enum &&v) noexcept(std::is_nothrow_constructible<status_code, QuickStatusCodeType>::value) // NOLINT
444 : status_code(QuickStatusCodeType(static_cast<Enum &&>(v)))
445 {
446 }
447 //! Explicit in-place construction. Disables if `domain_type::get()` is not a valid expression.
448 template <class... Args>
449 constexpr explicit status_code(in_place_t /*unused */, Args &&...args) noexcept(std::is_nothrow_constructible<value_type, Args &&...>::value)
450 : _base(typename _base::_value_type_constructor{}, &domain_type::get(), static_cast<Args &&>(args)...)
451 {
452 }
453 //! Explicit in-place construction from initialiser list. Disables if `domain_type::get()` is not a valid expression.
454 template <class T, class... Args>
455 constexpr explicit status_code(in_place_t /*unused */, std::initializer_list<T> il, Args &&...args) noexcept(std::is_nothrow_constructible<value_type, std::initializer_list<T>, Args &&...>::value)
456 : _base(typename _base::_value_type_constructor{}, &domain_type::get(), il, static_cast<Args &&>(args)...)
457 {
458 }
459 //! Explicit copy construction from a `value_type`. Disables if `domain_type::get()` is not a valid expression.
460 constexpr explicit status_code(const value_type &v) noexcept(std::is_nothrow_copy_constructible<value_type>::value)
461 : _base(typename _base::_value_type_constructor{}, &domain_type::get(), v)
462 {
463 }
464 //! Explicit move construction from a `value_type`. Disables if `domain_type::get()` is not a valid expression.
465 constexpr explicit status_code(value_type &&v) noexcept(std::is_nothrow_move_constructible<value_type>::value)
466 : _base(typename _base::_value_type_constructor{}, &domain_type::get(), static_cast<value_type &&>(v))
467 {
468 }
469 /*! Explicit construction from an erased status code. Available only if
470 `value_type` is trivially copyable or move bitcopying, and `sizeof(status_code) <= sizeof(status_code<erased<>>)`.
471 Does not check if domains are equal.
472 */
473 BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(class ErasedType) //
474 BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(detail::type_erasure_is_safe<ErasedType, value_type>::value))
475 constexpr explicit status_code(const status_code<erased<ErasedType>> &v) noexcept(std::is_nothrow_copy_constructible<value_type>::value)
476 : status_code(detail::erasure_cast<value_type>(v.value()))
477 {
478 #if __cplusplus >= 201400
479 assert(v.domain() == this->domain());
480 #endif
481 }
482
483 //! Return a reference to a string textually representing a code.
484 BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR20 string_ref message() const noexcept
485 {
486 // Avoid MSVC's buggy ternary operator for expensive to destruct things
487 if(this->_domain != nullptr)
488 {
489 return string_ref(this->domain()._do_message(*this));
490 }
491 return string_ref("(empty)");
492 }
493 };
494
495 namespace traits
496 {
497 template <class DomainType> struct is_move_bitcopying<status_code<DomainType>>
498 {
499 static constexpr bool value = is_move_bitcopying<typename DomainType::value_type>::value;
500 };
501 } // namespace traits
502
503
504 /*! Type erased, move-only status_code, unlike `status_code<void>` which cannot be moved nor destroyed. Available
505 only if `erased<>` is available, which is when the domain's type is trivially
506 copyable or is move relocatable, and if the size of the domain's typed error code is less than or equal to
507 this erased error code. Copy construction is disabled, but if you want a copy call `.clone()`.
508
509 An ADL discovered helper function `make_status_code(T, Args...)` is looked up by one of the constructors.
510 If it is found, and it generates a status code compatible with this status code, implicit construction
511 is made available.
512 */
513 template <class ErasedType> class BOOST_OUTCOME_SYSTEM_ERROR2_TRIVIAL_ABI status_code<erased<ErasedType>> : public mixins::mixin<detail::status_code_storage<erased<ErasedType>>, erased<ErasedType>>
514 {
515 template <class T> friend class status_code;
516 using _base = mixins::mixin<detail::status_code_storage<erased<ErasedType>>, erased<ErasedType>>;
517
518 public:
519 //! The type of the domain (void, as it is erased).
520 using domain_type = void;
521 //! The type of the erased status code.
522 using value_type = ErasedType;
523 //! The type of a reference to a message string.
524 using string_ref = typename _base::string_ref;
525
526 public:
527 //! Default construction to empty
528 status_code() = default;
529 //! Copy constructor
530 status_code(const status_code &) = delete;
531 //! Move constructor
532 status_code(status_code &&) = default; // NOLINT
533 //! Copy assignment
534 status_code &operator=(const status_code &) = delete;
535 //! Move assignment
536 status_code &operator=(status_code &&) = default; // NOLINT
537 BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR20 ~status_code()
538 {
539 if(nullptr != this->_domain)
540 {
541 this->_domain->_do_erased_destroy(*this, sizeof(*this));
542 }
543 }
544
545 //! Return a copy of the erased code by asking the domain to perform the erased copy.
546 BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR20 status_code clone() const
547 {
548 if(nullptr == this->_domain)
549 {
550 return {};
551 }
552 status_code x;
553 this->_domain->_do_erased_copy(x, *this, sizeof(*this));
554 return x;
555 }
556
557 /***** KEEP THESE IN SYNC WITH ERRORED_STATUS_CODE *****/
558 //! Implicit copy construction from any other status code if its value type is trivially copyable and it would fit into our storage
559 BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(class DomainType) //
560 BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(std::is_trivially_copyable<typename DomainType::value_type>::value //
561 &&detail::type_erasure_is_safe<value_type, typename DomainType::value_type>::value))
562 constexpr status_code(const status_code<DomainType> &v) noexcept // NOLINT
563 : _base(typename _base::_value_type_constructor{}, v._domain_ptr(), detail::erasure_cast<value_type>(v.value()))
564 {
565 }
566 //! Implicit move construction from any other status code if its value type is trivially copyable or move bitcopying and it would fit into our storage
567 BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(class DomainType) //
568 BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(detail::type_erasure_is_safe<value_type, typename DomainType::value_type>::value))
569 BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR14 status_code(status_code<DomainType> &&v) noexcept // NOLINT
570 : _base(typename _base::_value_type_constructor{}, v._domain_ptr(), detail::erasure_cast<value_type>(v.value()))
571 {
572 v._domain = nullptr;
573 }
574 //! Implicit construction from any type where an ADL discovered `make_status_code(T, Args ...)` returns a `status_code`.
575 BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(class T, class... Args, //
576 class MakeStatusCodeResult = typename detail::safe_get_make_status_code_result<T, Args...>::type) // Safe ADL lookup of make_status_code(), returns void if not found
577 BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(!std::is_same<typename std::decay<T>::type, status_code>::value // not copy/move of self
578 && !std::is_same<typename std::decay<T>::type, value_type>::value // not copy/move of value type
579 && is_status_code<MakeStatusCodeResult>::value // ADL makes a status code
580 && std::is_constructible<status_code, MakeStatusCodeResult>::value)) // ADLed status code is compatible
581 constexpr status_code(T &&v, Args &&...args) noexcept(noexcept(make_status_code(std::declval<T>(), std::declval<Args>()...))) // NOLINT
582 : status_code(make_status_code(static_cast<T &&>(v), static_cast<Args &&>(args)...))
583 {
584 }
585
586 //! Implicit construction from any `quick_status_code_from_enum<Enum>` enumerated type.
587 BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(class Enum, //
588 class QuickStatusCodeType = typename quick_status_code_from_enum<Enum>::code_type) // Enumeration has been activated
589 BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(std::is_constructible<status_code, QuickStatusCodeType>::value)) // Its status code is compatible
590 constexpr status_code(Enum &&v) noexcept(std::is_nothrow_constructible<status_code, QuickStatusCodeType>::value) // NOLINT
591 : status_code(QuickStatusCodeType(static_cast<Enum &&>(v)))
592 {
593 }
594
595 /**** By rights ought to be removed in any formal standard ****/
596 //! Reset the code to empty.
597 BOOST_OUTCOME_SYSTEM_ERROR2_CONSTEXPR14 void clear() noexcept { *this = status_code(); }
598 //! Return the erased `value_type` by value.
599 constexpr value_type value() const noexcept { return this->_value; }
600 };
601
602 namespace traits
603 {
604 template <class ErasedType> struct is_move_bitcopying<status_code<erased<ErasedType>>>
605 {
606 static constexpr bool value = true;
607 };
608 } // namespace traits
609
610 BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_END
611
612 #endif