1/* Proposed SG14 status_code
2(C) 2018-2024 Niall Douglas <http://www.nedproductions.biz/> (5 commits)
3File Created: Jun 2018
4
5
6Boost Software License - Version 1.0 - August 17th, 2003
7
8Permission is hereby granted, free of charge, to any person or organization
9obtaining a copy of the software and accompanying documentation covered by
10this license (the "Software") to use, reproduce, display, distribute,
11execute, and transmit the Software, and to prepare derivative works of the
12Software, and to permit third-parties to whom the Software is furnished to
13do so, all subject to the following:
14
15The copyright notices in the Software and this entire statement, including
16the above license grant, this restriction and the following disclaimer,
17must be included in all copies of the Software, in whole or in part, and
18all derivative works of the Software, unless such copies or derivative
19works are solely in the form of machine-executable object code generated by
20a source language processor.
21
22THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
25SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
26FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
27ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28DEALINGS IN THE SOFTWARE.
29*/
30
31#ifndef BOOST_OUTCOME_SYSTEM_ERROR2_ERRORED_STATUS_CODE_HPP
32#define BOOST_OUTCOME_SYSTEM_ERROR2_ERRORED_STATUS_CODE_HPP
33
34#include "quick_status_code_from_enum.hpp"
35
36BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_BEGIN
37
38/*! A `status_code` which is always a failure. The closest equivalent to
39`std::error_code`, except it cannot be modified, and is templated.
40
41Differences from `status_code`:
42
43- Never successful (this contract is checked on construction, if fails then it
44terminates the process).
45- Is immutable.
46*/
47template <class DomainType> class errored_status_code : public status_code<DomainType>
48{
49 using _base = status_code<DomainType>;
50 using _base::clear;
51 using _base::success;
52
53 void _check()
54 {
55 if(_base::success())
56 {
57 std::terminate();
58 }
59 }
60
61public:
62 //! The type of the domain.
63 using typename _base::domain_type;
64 //! The type of the error code.
65 using typename _base::value_type;
66 //! The type of a reference to a message string.
67 using typename _base::string_ref;
68
69 //! Default constructor.
70 errored_status_code() = default;
71 //! Copy constructor.
72 errored_status_code(const errored_status_code &) = default;
73 //! Move constructor.
74 errored_status_code(errored_status_code &&) = default; // NOLINT
75 //! Copy assignment.
76 errored_status_code &operator=(const errored_status_code &) = default;
77 //! Move assignment.
78 errored_status_code &operator=(errored_status_code &&) = default; // NOLINT
79 ~errored_status_code() = default;
80
81 //! Explicitly construct from any similarly erased status code
82 explicit errored_status_code(const _base &o) noexcept(std::is_nothrow_copy_constructible<_base>::value)
83 : _base(o)
84 {
85 _check();
86 }
87 //! Explicitly construct from any similarly erased status code
88 explicit errored_status_code(_base &&o) noexcept(std::is_nothrow_move_constructible<_base>::value)
89 : _base(static_cast<_base &&>(o))
90 {
91 _check();
92 }
93
94 /***** KEEP THESE IN SYNC WITH STATUS_CODE *****/
95 //! Implicit construction from any type where an ADL discovered `make_status_code(T, Args ...)` returns a `status_code`.
96 BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(
97 class T, class... Args, //
98 class MakeStatusCodeResult =
99 typename detail::safe_get_make_status_code_result<T, Args...>::type) // Safe ADL lookup of make_status_code(), returns void if not found
100 BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(!std::is_same<typename std::decay<T>::type, errored_status_code>::value // not copy/move of self
101 && !std::is_same<typename std::decay<T>::type, in_place_t>::value // not in_place_t
102 && is_status_code<MakeStatusCodeResult>::value // ADL makes a status code
103 && std::is_constructible<errored_status_code, MakeStatusCodeResult>::value)) // ADLed status code is compatible
104 errored_status_code(T &&v, Args &&...args) noexcept(noexcept(make_status_code(std::declval<T>(), std::declval<Args>()...))) // NOLINT
105 : errored_status_code(make_status_code(static_cast<T &&>(v), static_cast<Args &&>(args)...))
106 {
107 _check();
108 }
109
110 //! Implicit construction from any `quick_status_code_from_enum<Enum>` enumerated type.
111 BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(class Enum, //
112 class QuickStatusCodeType = typename quick_status_code_from_enum<Enum>::code_type) // Enumeration has been activated
113 BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(std::is_constructible<errored_status_code, QuickStatusCodeType>::value)) // Its status code is compatible
114 errored_status_code(Enum &&v) noexcept(std::is_nothrow_constructible<errored_status_code, QuickStatusCodeType>::value) // NOLINT
115 : errored_status_code(QuickStatusCodeType(static_cast<Enum &&>(v)))
116 {
117 _check();
118 }
119 //! Explicit in-place construction.
120 template <class... Args>
121 explicit errored_status_code(in_place_t _, Args &&...args) noexcept(std::is_nothrow_constructible<value_type, Args &&...>::value)
122 : _base(_, static_cast<Args &&>(args)...)
123 {
124 _check();
125 }
126 //! Explicit in-place construction from initialiser list.
127 template <class T, class... Args>
128 explicit errored_status_code(in_place_t _, std::initializer_list<T> il,
129 Args &&...args) noexcept(std::is_nothrow_constructible<value_type, std::initializer_list<T>, Args &&...>::value)
130 : _base(_, il, static_cast<Args &&>(args)...)
131 {
132 _check();
133 }
134 //! Explicit copy construction from a `value_type`.
135 explicit errored_status_code(const value_type &v) noexcept(std::is_nothrow_copy_constructible<value_type>::value)
136 : _base(v)
137 {
138 _check();
139 }
140 //! Explicit move construction from a `value_type`.
141 explicit errored_status_code(value_type &&v) noexcept(std::is_nothrow_move_constructible<value_type>::value)
142 : _base(static_cast<value_type &&>(v))
143 {
144 _check();
145 }
146 /*! Explicit construction from an erased status code. Available only if
147 `value_type` is trivially copyable or move bitcopying, and `sizeof(status_code) <= sizeof(status_code<erased<>>)`.
148 Does not check if domains are equal.
149 */
150 BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(class ErasedType) //
151 BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(detail::domain_value_type_erasure_is_safe<domain_type, detail::erased<ErasedType>>::value))
152 explicit errored_status_code(const status_code<detail::erased<ErasedType>> &v) noexcept(std::is_nothrow_copy_constructible<value_type>::value)
153 : errored_status_code(detail::erasure_cast<value_type>(v.value())) // NOLINT
154 {
155 assert(v.domain() == this->domain()); // NOLINT
156 _check();
157 }
158
159 //! Always false (including at compile time), as errored status codes are never successful.
160 constexpr bool success() const noexcept { return false; }
161 //! Return a const reference to the `value_type`.
162 constexpr const value_type &value() const & noexcept { return this->_value; }
163};
164
165namespace traits
166{
167 template <class DomainType> struct is_move_bitcopying<errored_status_code<DomainType>>
168 {
169 static constexpr bool value = is_move_bitcopying<typename DomainType::value_type>::value;
170 };
171} // namespace traits
172
173template <class ErasedType> class errored_status_code<detail::erased<ErasedType>> : public status_code<detail::erased<ErasedType>>
174{
175 using _base = status_code<detail::erased<ErasedType>>;
176 using _base::success;
177
178 void _check()
179 {
180 if(_base::success())
181 {
182 std::terminate();
183 }
184 }
185
186public:
187 using domain_type = typename _base::domain_type;
188 using value_type = typename _base::value_type;
189 using string_ref = typename _base::string_ref;
190
191 //! Default construction to empty
192 errored_status_code() = default;
193 //! Copy constructor
194 errored_status_code(const errored_status_code &) = default;
195 //! Move constructor
196 errored_status_code(errored_status_code &&) = default; // NOLINT
197 //! Copy assignment
198 errored_status_code &operator=(const errored_status_code &) = default;
199 //! Move assignment
200 errored_status_code &operator=(errored_status_code &&) = default; // NOLINT
201 ~errored_status_code() = default;
202
203 //! Explicitly construct from any similarly erased status code
204 explicit errored_status_code(const _base &o) noexcept(std::is_nothrow_copy_constructible<_base>::value)
205 : _base(o)
206 {
207 _check();
208 }
209 //! Explicitly construct from any similarly erased status code
210 explicit errored_status_code(_base &&o) noexcept(std::is_nothrow_move_constructible<_base>::value)
211 : _base(static_cast<_base &&>(o))
212 {
213 _check();
214 }
215
216 /***** KEEP THESE IN SYNC WITH STATUS_CODE *****/
217 //! Implicit copy construction from any other status code if its value type is trivially copyable, it would fit into our storage, and it is not an erased
218 //! status code.
219 BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(class DomainType) //
220 BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(detail::domain_value_type_erasure_is_safe<detail::erased<ErasedType>, DomainType>::value),
221 BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(!detail::is_erased_status_code<status_code<typename std::decay<DomainType>::type>>::value))
222 errored_status_code(const status_code<DomainType> &v) noexcept
223 : _base(v) // NOLINT
224 {
225 _check();
226 }
227 //! Implicit copy construction from any other status code if its value type is trivially copyable and it would fit into our storage, and it is not an erased
228 //! status code.
229 BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(class DomainType) //
230 BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(detail::domain_value_type_erasure_is_safe<detail::erased<ErasedType>, DomainType>::value),
231 BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(!detail::is_erased_status_code<status_code<typename std::decay<DomainType>::type>>::value))
232 errored_status_code(const errored_status_code<DomainType> &v) noexcept
233 : _base(static_cast<const status_code<DomainType> &>(v)) // NOLINT
234 {
235 _check();
236 }
237 //! 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
238 BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(class DomainType) //
239 BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(detail::domain_value_type_erasure_is_safe<detail::erased<ErasedType>, DomainType>::value))
240 errored_status_code(status_code<DomainType> &&v) noexcept
241 : _base(static_cast<status_code<DomainType> &&>(v)) // NOLINT
242 {
243 _check();
244 }
245 //! 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
246 BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(class DomainType) //
247 BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(detail::domain_value_type_erasure_is_safe<detail::erased<ErasedType>, DomainType>::value))
248 errored_status_code(errored_status_code<DomainType> &&v) noexcept
249 : _base(static_cast<status_code<DomainType> &&>(v)) // NOLINT
250 {
251 _check();
252 }
253 //! Implicit construction from any type where an ADL discovered `make_status_code(T, Args ...)` returns a `status_code`.
254 BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(
255 class T, class... Args, //
256 class MakeStatusCodeResult =
257 typename detail::safe_get_make_status_code_result<T, Args...>::type) // Safe ADL lookup of make_status_code(), returns void if not found
258 BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(!std::is_same<typename std::decay<T>::type, errored_status_code>::value // not copy/move of self
259 && !std::is_same<typename std::decay<T>::type, value_type>::value // not copy/move of value type
260 && is_status_code<MakeStatusCodeResult>::value // ADL makes a status code
261 && std::is_constructible<errored_status_code, MakeStatusCodeResult>::value)) // ADLed status code is compatible
262 errored_status_code(T &&v, Args &&...args) noexcept(noexcept(make_status_code(std::declval<T>(), std::declval<Args>()...))) // NOLINT
263 : errored_status_code(make_status_code(static_cast<T &&>(v), static_cast<Args &&>(args)...))
264 {
265 _check();
266 }
267 //! Implicit construction from any `quick_status_code_from_enum<Enum>` enumerated type.
268 BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(class Enum, //
269 class QuickStatusCodeType = typename quick_status_code_from_enum<Enum>::code_type) // Enumeration has been activated
270 BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(std::is_constructible<errored_status_code, QuickStatusCodeType>::value)) // Its status code is compatible
271 errored_status_code(Enum &&v) noexcept(std::is_nothrow_constructible<errored_status_code, QuickStatusCodeType>::value) // NOLINT
272 : errored_status_code(QuickStatusCodeType(static_cast<Enum &&>(v)))
273 {
274 _check();
275 }
276#if defined(_CPPUNWIND) || defined(__EXCEPTIONS) || defined(BOOST_OUTCOME_STANDARDESE_IS_IN_THE_HOUSE)
277 //! Explicit copy construction from an unknown status code. Note that this will be empty if its value type is not trivially copyable or would not fit into our
278 //! storage or the source domain's `_do_erased_copy()` refused the copy.
279 explicit errored_status_code(in_place_t _, const status_code<void> &v) // NOLINT
280 : _base(_, v)
281 {
282 _check();
283 }
284#endif
285
286 //! Always false (including at compile time), as errored status codes are never successful.
287 constexpr bool success() const noexcept { return false; }
288 //! Return the erased `value_type` by value.
289 constexpr value_type value() const noexcept { return this->_value; }
290};
291/*! An erased type specialisation of `errored_status_code<D>`.
292Available only if `ErasedType` satisfies `traits::is_move_bitcopying<ErasedType>::value`.
293*/
294template <class ErasedType> using erased_errored_status_code = errored_status_code<detail::erased<ErasedType>>;
295
296
297namespace traits
298{
299 template <class ErasedType> struct is_move_bitcopying<errored_status_code<detail::erased<ErasedType>>>
300 {
301 static constexpr bool value = true;
302 };
303} // namespace traits
304
305
306//! True if the status code's are semantically equal via `equivalent()`.
307template <class DomainType1, class DomainType2>
308inline bool operator==(const errored_status_code<DomainType1> &a, const errored_status_code<DomainType2> &b) noexcept
309{
310 return a.equivalent(static_cast<const status_code<DomainType2> &>(b));
311}
312//! True if the status code's are semantically equal via `equivalent()`.
313template <class DomainType1, class DomainType2> inline bool operator==(const status_code<DomainType1> &a, const errored_status_code<DomainType2> &b) noexcept
314{
315 return a.equivalent(static_cast<const status_code<DomainType2> &>(b));
316}
317//! True if the status code's are semantically equal via `equivalent()`.
318template <class DomainType1, class DomainType2> inline bool operator==(const errored_status_code<DomainType1> &a, const status_code<DomainType2> &b) noexcept
319{
320 return static_cast<const status_code<DomainType1> &>(a).equivalent(b);
321}
322//! True if the status code's are not semantically equal via `equivalent()`.
323template <class DomainType1, class DomainType2>
324inline bool operator!=(const errored_status_code<DomainType1> &a, const errored_status_code<DomainType2> &b) noexcept
325{
326 return !a.equivalent(static_cast<const status_code<DomainType2> &>(b));
327}
328//! True if the status code's are not semantically equal via `equivalent()`.
329template <class DomainType1, class DomainType2> inline bool operator!=(const status_code<DomainType1> &a, const errored_status_code<DomainType2> &b) noexcept
330{
331 return !a.equivalent(static_cast<const status_code<DomainType2> &>(b));
332}
333//! True if the status code's are not semantically equal via `equivalent()`.
334template <class DomainType1, class DomainType2> inline bool operator!=(const errored_status_code<DomainType1> &a, const status_code<DomainType2> &b) noexcept
335{
336 return !static_cast<const status_code<DomainType1> &>(a).equivalent(b);
337}
338//! True if the status code's are semantically equal via `equivalent()` to `make_status_code(T)`.
339BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(class DomainType1, class T, //
340 class MakeStatusCodeResult =
341 typename detail::safe_get_make_status_code_result<const T &>::type) // Safe ADL lookup of make_status_code(), returns void if not found
342BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(is_status_code<MakeStatusCodeResult>::value)) // ADL makes a status code
343inline bool operator==(const errored_status_code<DomainType1> &a, const T &b)
344{
345 return a.equivalent(make_status_code(b));
346}
347//! True if the status code's are semantically equal via `equivalent()` to `make_status_code(T)`.
348BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(class T, class DomainType1, //
349 class MakeStatusCodeResult =
350 typename detail::safe_get_make_status_code_result<const T &>::type) // Safe ADL lookup of make_status_code(), returns void if not found
351BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(is_status_code<MakeStatusCodeResult>::value)) // ADL makes a status code
352inline bool operator==(const T &a, const errored_status_code<DomainType1> &b)
353{
354 return b.equivalent(make_status_code(a));
355}
356//! True if the status code's are not semantically equal via `equivalent()` to `make_status_code(T)`.
357BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(class DomainType1, class T, //
358 class MakeStatusCodeResult =
359 typename detail::safe_get_make_status_code_result<const T &>::type) // Safe ADL lookup of make_status_code(), returns void if not found
360BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(is_status_code<MakeStatusCodeResult>::value)) // ADL makes a status code
361inline bool operator!=(const errored_status_code<DomainType1> &a, const T &b)
362{
363 return !a.equivalent(make_status_code(b));
364}
365//! True if the status code's are semantically equal via `equivalent()` to `make_status_code(T)`.
366BOOST_OUTCOME_SYSTEM_ERROR2_TEMPLATE(class T, class DomainType1, //
367 class MakeStatusCodeResult =
368 typename detail::safe_get_make_status_code_result<const T &>::type) // Safe ADL lookup of make_status_code(), returns void if not found
369BOOST_OUTCOME_SYSTEM_ERROR2_TREQUIRES(BOOST_OUTCOME_SYSTEM_ERROR2_TPRED(is_status_code<MakeStatusCodeResult>::value)) // ADL makes a status code
370inline bool operator!=(const T &a, const errored_status_code<DomainType1> &b)
371{
372 return !b.equivalent(make_status_code(a));
373}
374//! True if the status code's are semantically equal via `equivalent()` to `quick_status_code_from_enum<T>::code_type(b)`.
375template <class DomainType1, class T, //
376 class QuickStatusCodeType = typename quick_status_code_from_enum<T>::code_type // Enumeration has been activated
377 >
378inline bool operator==(const errored_status_code<DomainType1> &a, const T &b)
379{
380 return a.equivalent(QuickStatusCodeType(b));
381}
382//! True if the status code's are semantically equal via `equivalent()` to `quick_status_code_from_enum<T>::code_type(a)`.
383template <class T, class DomainType1, //
384 class QuickStatusCodeType = typename quick_status_code_from_enum<T>::code_type // Enumeration has been activated
385 >
386inline bool operator==(const T &a, const errored_status_code<DomainType1> &b)
387{
388 return b.equivalent(QuickStatusCodeType(a));
389}
390//! True if the status code's are not semantically equal via `equivalent()` to `quick_status_code_from_enum<T>::code_type(b)`.
391template <class DomainType1, class T, //
392 class QuickStatusCodeType = typename quick_status_code_from_enum<T>::code_type // Enumeration has been activated
393 >
394inline bool operator!=(const errored_status_code<DomainType1> &a, const T &b)
395{
396 return !a.equivalent(QuickStatusCodeType(b));
397}
398//! True if the status code's are not semantically equal via `equivalent()` to `quick_status_code_from_enum<T>::code_type(a)`.
399template <class T, class DomainType1, //
400 class QuickStatusCodeType = typename quick_status_code_from_enum<T>::code_type // Enumeration has been activated
401 >
402inline bool operator!=(const T &a, const errored_status_code<DomainType1> &b)
403{
404 return !b.equivalent(QuickStatusCodeType(a));
405}
406
407
408namespace detail
409{
410 template <class T> struct is_errored_status_code
411 {
412 static constexpr bool value = false;
413 };
414 template <class T> struct is_errored_status_code<errored_status_code<T>>
415 {
416 static constexpr bool value = true;
417 };
418 template <class T> struct is_erased_errored_status_code
419 {
420 static constexpr bool value = false;
421 };
422 template <class T> struct is_erased_errored_status_code<errored_status_code<erased<T>>>
423 {
424 static constexpr bool value = true;
425 };
426} // namespace detail
427
428//! Trait returning true if the type is an errored status code.
429template <class T> struct is_errored_status_code
430{
431 static constexpr bool value =
432 detail::is_errored_status_code<typename std::decay<T>::type>::value || detail::is_erased_errored_status_code<typename std::decay<T>::type>::value;
433};
434
435
436BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_END
437
438#endif
439

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