1 /***************************************************************************
2 * Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht          *
3 * Copyright (c) QuantStack                                                 *
4 *                                                                          *
5 * Distributed under the terms of the BSD 3-Clause License.                 *
6 *                                                                          *
7 * The full license is in the file LICENSE, distributed with this software. *
8 ****************************************************************************/
9 
10 #ifndef XTL_OPTIONAL_HPP
11 #define XTL_OPTIONAL_HPP
12 
13 #include <cmath>
14 #include <ostream>
15 #include <type_traits>
16 #include <utility>
17 
18 #ifdef __CLING__
19 #include <nlohmann/json.hpp>
20 #endif
21 
22 #include "xoptional_meta.hpp"
23 #include "xclosure.hpp"
24 #include "xfunctional.hpp"
25 #include "xmeta_utils.hpp"
26 #include "xtl_config.hpp"
27 #include "xtype_traits.hpp"
28 
29 namespace xtl
30 {
31     template <class T, class B>
32     auto optional(T&& t, B&& b) noexcept;
33 
34     /************************
35      * optional declaration *
36      ************************/
37 
38     /**
39      * @class xoptional
40      * @brief Optional value handler.
41      *
42      * The xoptional is an optional proxy. It holds a value (or a reference on a value) and a flag (or reference on a flag)
43      * indicating whether the element should be considered missing.
44      *
45      * xoptional is different from std::optional
46      *
47      *  - no `operator->()` that returns a pointer.
48      *  - no `operator*()` that returns a value.
49      *
50      * The only way to access the underlying value and flag is with the `value` and `value_or` methods.
51      *
52      *  - no explicit convertion to bool. This may lead to confusion when the underlying value type is boolean too.
53      *
54      * @tparam CT Closure type for the value.
55      * @tparam CB Closure type for the missing flag. A falsy flag means that the value is missing.
56      *
57      * \ref xoptional is used both as a value type (with CT and CB being value types) and reference type for containers
58      * with CT and CB being reference types. In other words, it serves as a reference proxy.
59      *
60      */
61     template <class CT, class CB>
62     class xoptional
63     {
64     public:
65 
66         using self_type = xoptional<CT, CB>;
67         using value_closure = CT;
68         using flag_closure = CB;
69 
70         using value_type = std::decay_t<CT>;
71         using flag_type = std::decay_t<CB>;
72 
73         // Constructors
xoptional()74         inline xoptional()
75             : m_value(), m_flag(false)
76         {
77         }
78 
79         template <class T,
80           std::enable_if_t<
81             conjunction<
82               negation<std::is_same<xoptional<CT, CB>, std::decay_t<T>>>,
83               std::is_constructible<CT, T&&>,
84               std::is_convertible<T&&, CT>
85             >::value,
86             bool
87           > = true>
xoptional(T && rhs)88         inline constexpr xoptional(T&& rhs)
89             : m_value(std::forward<T>(rhs)), m_flag(true)
90         {
91         }
92 
93         template <class T,
94           std::enable_if_t<
95             conjunction<
96               negation<std::is_same<xoptional<CT, CB>, std::decay_t<T>>>,
97               std::is_constructible<CT, T&&>,
98               negation<std::is_convertible<T&&, CT>>
99             >::value,
100             bool
101           > = false>
xoptional(T && value)102         inline explicit constexpr xoptional(T&& value)
103             : m_value(std::forward<T>(value)), m_flag(true)
104         {
105         }
106 
107         template <class CTO, class CBO,
108           std::enable_if_t<
109             conjunction<
110               negation<std::is_same<xoptional<CT, CB>, xoptional<CTO, CBO>>>,
111               std::is_constructible<CT, std::add_lvalue_reference_t<std::add_const_t<CTO>>>,
112               std::is_constructible<CB, std::add_lvalue_reference_t<std::add_const_t<CBO>>>,
113               conjunction<
114                 std::is_convertible<std::add_lvalue_reference_t<std::add_const_t<CTO>>, CT>,
115                 std::is_convertible<std::add_lvalue_reference_t<std::add_const_t<CBO>>, CB>
116               >,
117               negation<detail::converts_from_xoptional<CT, CTO, CBO>>
118             >::value,
119             bool
120           > = true>
xoptional(const xoptional<CTO,CBO> & rhs)121         inline constexpr xoptional(const xoptional<CTO, CBO>& rhs)
122             : m_value(rhs.value()), m_flag(rhs.has_value())
123         {
124         }
125 
126         template <class CTO, class CBO,
127           std::enable_if_t<
128             conjunction<
129               negation<std::is_same<xoptional<CT, CB>, xoptional<CTO, CBO>>>,
130               std::is_constructible<CT, std::add_lvalue_reference_t<std::add_const_t<CTO>>>,
131               std::is_constructible<CB, std::add_lvalue_reference_t<std::add_const_t<CBO>>>,
132               disjunction<
133                 negation<std::is_convertible<std::add_lvalue_reference_t<std::add_const_t<CTO>>, CT>>,
134                 negation<std::is_convertible<std::add_lvalue_reference_t<std::add_const_t<CBO>>, CB>>
135               >,
136               negation<detail::converts_from_xoptional<CT, CTO, CBO>>
137             >::value,
138             bool
139           > = false>
xoptional(const xoptional<CTO,CBO> & rhs)140         inline explicit constexpr xoptional(const xoptional<CTO, CBO>& rhs)
141             : m_value(rhs.value()), m_flag(rhs.has_value())
142         {
143         }
144 
145         template <class CTO, class CBO,
146           std::enable_if_t<
147             conjunction<
148               negation<std::is_same<xoptional<CT, CB>, xoptional<CTO, CBO>>>,
149               std::is_constructible<CT, std::conditional_t<std::is_reference<CT>::value, const std::decay_t<CTO>&, std::decay_t<CTO>&&>>,
150               std::is_constructible<CB, std::conditional_t<std::is_reference<CB>::value, const std::decay_t<CBO>&, std::decay_t<CBO>&&>>,
151               conjunction<
152                 std::is_convertible<std::conditional_t<std::is_reference<CT>::value, const std::decay_t<CTO>&, std::decay_t<CTO>&&>, CT>,
153                 std::is_convertible<std::conditional_t<std::is_reference<CB>::value, const std::decay_t<CBO>&, std::decay_t<CBO>&&>, CB>
154               >,
155               negation<detail::converts_from_xoptional<CT, CTO, CBO>>
156             >::value,
157             bool
158           > = true>
xoptional(xoptional<CTO,CBO> && rhs)159         inline constexpr xoptional(xoptional<CTO, CBO>&& rhs)
160             : m_value(std::move(rhs).value()), m_flag(std::move(rhs).has_value())
161         {
162         }
163 
164         template <class CTO, class CBO,
165           std::enable_if_t<
166             conjunction<
167               negation<std::is_same<xoptional<CT, CB>, xoptional<CTO, CBO>>>,
168               std::is_constructible<CT, std::conditional_t<std::is_reference<CT>::value, const std::decay_t<CTO>&, std::decay_t<CTO>&&>>,
169               std::is_constructible<CB, std::conditional_t<std::is_reference<CB>::value, const std::decay_t<CBO>&, std::decay_t<CBO>&&>>,
170               disjunction<
171                 negation<std::is_convertible<std::conditional_t<std::is_reference<CT>::value, const std::decay_t<CTO>&, std::decay_t<CTO>&&>, CT>>,
172                 negation<std::is_convertible<std::conditional_t<std::is_reference<CB>::value, const std::decay_t<CBO>&, std::decay_t<CBO>&&>, CB>>
173               >,
174               negation<detail::converts_from_xoptional<CT, CTO, CBO>>
175             >::value,
176             bool
177           > = false>
xoptional(xoptional<CTO,CBO> && rhs)178         inline explicit constexpr xoptional(xoptional<CTO, CBO>&& rhs)
179             : m_value(std::move(rhs).value()), m_flag(std::move(rhs).has_value())
180         {
181         }
182 
183         xoptional(value_type&&, flag_type&&);
184         xoptional(std::add_lvalue_reference_t<CT>, std::add_lvalue_reference_t<CB>);
185         xoptional(value_type&&, std::add_lvalue_reference_t<CB>);
186         xoptional(std::add_lvalue_reference_t<CT>, flag_type&&);
187 
188         // Assignment
189         template <class T>
190         std::enable_if_t<
191           conjunction<
192             negation<std::is_same<xoptional<CT, CB>, std::decay_t<T>>>,
193             std::is_assignable<std::add_lvalue_reference_t<CT>, T>
194           >::value,
195          xoptional&>
operator =(T && rhs)196         inline operator=(T&& rhs)
197         {
198             m_value = std::forward<T>(rhs);
199             m_flag = true;
200             return *this;
201         }
202 
203         template <class CTO, class CBO>
204         std::enable_if_t<conjunction<
205           negation<std::is_same<xoptional<CT, CB>, xoptional<CTO, CBO>>>,
206           std::is_assignable<std::add_lvalue_reference_t<CT>, CTO>,
207           negation<detail::converts_from_xoptional<CT, CTO, CBO>>,
208           negation<detail::assigns_from_xoptional<CT, CTO, CBO>>
209         >::value,
210         xoptional&>
operator =(const xoptional<CTO,CBO> & rhs)211         inline operator=(const xoptional<CTO, CBO>& rhs)
212         {
213             m_value = rhs.value();
214             m_flag = rhs.has_value();
215             return *this;
216         }
217 
218         template <class CTO, class CBO>
219         std::enable_if_t<conjunction<
220           negation<std::is_same<xoptional<CT, CB>, xoptional<CTO, CBO>>>,
221           std::is_assignable<std::add_lvalue_reference_t<CT>, CTO>,
222           negation<detail::converts_from_xoptional<CT, CTO, CBO>>,
223           negation<detail::assigns_from_xoptional<CT, CTO, CBO>>
224         >::value,
225         xoptional&>
operator =(xoptional<CTO,CBO> && rhs)226         inline operator=(xoptional<CTO, CBO>&& rhs)
227         {
228             m_value = std::move(rhs).value();
229             m_flag = std::move(rhs).has_value();
230             return *this;
231         }
232 
233         // Operators
234         template <class CTO, class CBO>
235         xoptional& operator+=(const xoptional<CTO, CBO>&);
236         template <class CTO, class CBO>
237         xoptional& operator-=(const xoptional<CTO, CBO>&);
238         template <class CTO, class CBO>
239         xoptional& operator*=(const xoptional<CTO, CBO>&);
240         template <class CTO, class CBO>
241         xoptional& operator/=(const xoptional<CTO, CBO>&);
242         template <class CTO, class CBO>
243         xoptional& operator%=(const xoptional<CTO, CBO>&);
244         template <class CTO, class CBO>
245         xoptional& operator&=(const xoptional<CTO, CBO>&);
246         template <class CTO, class CBO>
247         xoptional& operator|=(const xoptional<CTO, CBO>&);
248         template <class CTO, class CBO>
249         xoptional& operator^=(const xoptional<CTO, CBO>&);
250 
251         template <class T, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T>)>
252         xoptional& operator+=(const T&);
253         template <class T, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T>)>
254         xoptional& operator-=(const T&);
255         template <class T, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T>)>
256         xoptional& operator*=(const T&);
257         template <class T, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T>)>
258         xoptional& operator/=(const T&);
259         template <class T, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T>)>
260         xoptional& operator%=(const T&);
261         template <class T, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T>)>
262         xoptional& operator&=(const T&);
263         template <class T, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T>)>
264         xoptional& operator|=(const T&);
265         template <class T, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T>)>
266         xoptional& operator^=(const T&);
267 
268         // Access
269         std::add_lvalue_reference_t<CT> value() & noexcept;
270         std::add_lvalue_reference_t<std::add_const_t<CT>> value() const & noexcept;
271         std::conditional_t<std::is_reference<CT>::value, apply_cv_t<CT, value_type>&, value_type> value() && noexcept;
272         std::conditional_t<std::is_reference<CT>::value, const value_type&, value_type> value() const && noexcept;
273 
274         template <class U>
275         value_type value_or(U&&) const & noexcept;
276         template <class U>
277         value_type value_or(U&&) const && noexcept;
278 
279         // Access
280         std::add_lvalue_reference_t<CB> has_value() & noexcept;
281         std::add_lvalue_reference_t<std::add_const_t<CB>> has_value() const & noexcept;
282         std::conditional_t<std::is_reference<CB>::value, apply_cv_t<CB, flag_type>&, flag_type> has_value() && noexcept;
283         std::conditional_t<std::is_reference<CB>::value, const flag_type&, flag_type> has_value() const && noexcept;
284 
285         // Swap
286         void swap(xoptional& other);
287 
288         // Comparison
289         template <class CTO, class CBO>
290         bool equal(const xoptional<CTO, CBO>& rhs) const noexcept;
291 
292         template <class CTO, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<CTO>)>
293         bool equal(const CTO& rhs) const noexcept;
294 
295         xclosure_pointer<self_type&> operator&() &;
296         xclosure_pointer<const self_type&> operator&() const &;
297         xclosure_pointer<self_type> operator&() &&;
298 
299     private:
300 
301         template <class CTO, class CBO>
302         friend class xoptional;
303 
304         CT m_value;
305         CB m_flag;
306     };
307 
308     // value
309 
310     template <class T, class U = disable_xoptional<std::decay_t<T>>>
value(T && v)311     T&& value(T&& v)
312     {
313         return std::forward<T>(v);
314     }
315 
316     template <class CT, class CB>
value(xtl::xoptional<CT,CB> && v)317     decltype(auto) value(xtl::xoptional<CT, CB>&& v)
318     {
319         return std::move(v).value();
320     }
321 
322     template <class CT, class CB>
value(xtl::xoptional<CT,CB> & v)323     decltype(auto) value(xtl::xoptional<CT, CB>& v)
324     {
325         return v.value();
326     }
327 
328     template <class CT, class CB>
value(const xtl::xoptional<CT,CB> & v)329     decltype(auto) value(const xtl::xoptional<CT, CB>& v)
330     {
331         return v.value();
332     }
333 
334     // has_value
335 
336     template <class T, class U = disable_xoptional<std::decay_t<T>>>
has_value(T &&)337     bool has_value(T&&)
338     {
339         return true;
340     }
341 
342     template <class CT, class CB>
has_value(xtl::xoptional<CT,CB> && v)343     decltype(auto) has_value(xtl::xoptional<CT, CB>&& v)
344     {
345         return std::move(v).has_value();
346     }
347 
348     template <class CT, class CB>
has_value(xtl::xoptional<CT,CB> & v)349     decltype(auto) has_value(xtl::xoptional<CT, CB>& v)
350     {
351         return v.has_value();
352     }
353 
354     template <class CT, class CB>
has_value(const xtl::xoptional<CT,CB> & v)355     decltype(auto) has_value(const xtl::xoptional<CT, CB>& v)
356     {
357         return v.has_value();
358     }
359 
360     /***************************************
361      * optional and missing implementation *
362      ***************************************/
363 
364     /**
365      * @brief Returns an \ref xoptional holding closure types on the specified parameters
366      *
367      * @tparam t the optional value
368      * @tparam b the boolean flag
369      */
370     template <class T, class B>
optional(T && t,B && b)371     inline auto optional(T&& t, B&& b) noexcept
372     {
373         using optional_type = xoptional<closure_type_t<T>, closure_type_t<B>>;
374         return optional_type(std::forward<T>(t), std::forward<B>(b));
375     }
376 
377     /**
378      * @brief Returns an \ref xoptional for a missig value
379      */
380     template <class T>
missing()381     xoptional<T, bool> missing() noexcept
382     {
383         return xoptional<T, bool>(T(), false);
384     }
385 
386     /****************************
387      * xoptional implementation *
388      ****************************/
389 
390     // Constructors
391     template <class CT, class CB>
xoptional(value_type && value,flag_type && flag)392     xoptional<CT, CB>::xoptional(value_type&& value, flag_type&& flag)
393         : m_value(std::move(value)), m_flag(std::move(flag))
394     {
395     }
396 
397     template <class CT, class CB>
xoptional(std::add_lvalue_reference_t<CT> value,std::add_lvalue_reference_t<CB> flag)398     xoptional<CT, CB>::xoptional(std::add_lvalue_reference_t<CT> value, std::add_lvalue_reference_t<CB> flag)
399         : m_value(value), m_flag(flag)
400     {
401     }
402 
403     template <class CT, class CB>
xoptional(value_type && value,std::add_lvalue_reference_t<CB> flag)404     xoptional<CT, CB>::xoptional(value_type&& value, std::add_lvalue_reference_t<CB> flag)
405         : m_value(std::move(value)), m_flag(flag)
406     {
407     }
408 
409     template <class CT, class CB>
xoptional(std::add_lvalue_reference_t<CT> value,flag_type && flag)410     xoptional<CT, CB>::xoptional(std::add_lvalue_reference_t<CT> value, flag_type&& flag)
411         : m_value(value), m_flag(std::move(flag))
412     {
413     }
414 
415     // Operators
416     template <class CT, class CB>
417     template <class CTO, class CBO>
operator +=(const xoptional<CTO,CBO> & rhs)418     auto xoptional<CT, CB>::operator+=(const xoptional<CTO, CBO>& rhs) -> xoptional&
419     {
420         m_flag = m_flag && rhs.m_flag;
421         if (m_flag)
422         {
423             m_value += rhs.m_value;
424         }
425         return *this;
426     }
427 
428     template <class CT, class CB>
429     template <class CTO, class CBO>
operator -=(const xoptional<CTO,CBO> & rhs)430     auto xoptional<CT, CB>::operator-=(const xoptional<CTO, CBO>& rhs) -> xoptional&
431     {
432         m_flag = m_flag && rhs.m_flag;
433         if (m_flag)
434         {
435             m_value -= rhs.m_value;
436         }
437         return *this;
438     }
439 
440     template <class CT, class CB>
441     template <class CTO, class CBO>
operator *=(const xoptional<CTO,CBO> & rhs)442     auto xoptional<CT, CB>::operator*=(const xoptional<CTO, CBO>& rhs) -> xoptional&
443     {
444         m_flag = m_flag && rhs.m_flag;
445         if (m_flag)
446         {
447             m_value *= rhs.m_value;
448         }
449         return *this;
450     }
451 
452     template <class CT, class CB>
453     template <class CTO, class CBO>
operator /=(const xoptional<CTO,CBO> & rhs)454     auto xoptional<CT, CB>::operator/=(const xoptional<CTO, CBO>& rhs) -> xoptional&
455     {
456         m_flag = m_flag && rhs.m_flag;
457         if (m_flag)
458         {
459             m_value /= rhs.m_value;
460         }
461         return *this;
462     }
463 
464     template <class CT, class CB>
465     template <class CTO, class CBO>
operator %=(const xoptional<CTO,CBO> & rhs)466     auto xoptional<CT, CB>::operator%=(const xoptional<CTO, CBO>& rhs) -> xoptional&
467     {
468         m_flag = m_flag && rhs.m_flag;
469         if (m_flag)
470         {
471             m_value %= rhs.m_value;
472         }
473         return *this;
474     }
475 
476     template <class CT, class CB>
477     template <class CTO, class CBO>
operator &=(const xoptional<CTO,CBO> & rhs)478     auto xoptional<CT, CB>::operator&=(const xoptional<CTO, CBO>& rhs) -> xoptional&
479     {
480         m_flag = m_flag && rhs.m_flag;
481         if (m_flag)
482         {
483             m_value &= rhs.m_value;
484         }
485         return *this;
486     }
487 
488     template <class CT, class CB>
489     template <class CTO, class CBO>
operator |=(const xoptional<CTO,CBO> & rhs)490     auto xoptional<CT, CB>::operator|=(const xoptional<CTO, CBO>& rhs) -> xoptional&
491     {
492         m_flag = m_flag && rhs.m_flag;
493         if (m_flag)
494         {
495             m_value |= rhs.m_value;
496         }
497         return *this;
498     }
499 
500     template <class CT, class CB>
501     template <class CTO, class CBO>
operator ^=(const xoptional<CTO,CBO> & rhs)502     auto xoptional<CT, CB>::operator^=(const xoptional<CTO, CBO>& rhs) -> xoptional&
503     {
504         m_flag = m_flag && rhs.m_flag;
505         if (m_flag)
506         {
507             m_value ^= rhs.m_value;
508         }
509         return *this;
510     }
511 
512     template <class CT, class CB>
513     template <class T, check_requires<is_not_xoptional_nor_xmasked_value<T>>>
operator +=(const T & rhs)514     auto xoptional<CT, CB>::operator+=(const T& rhs) -> xoptional&
515     {
516         if (m_flag)
517         {
518             m_value += rhs;
519         }
520         return *this;
521     }
522 
523     template <class CT, class CB>
524     template <class T, check_requires<is_not_xoptional_nor_xmasked_value<T>>>
operator -=(const T & rhs)525     auto xoptional<CT, CB>::operator-=(const T& rhs) -> xoptional&
526     {
527         if (m_flag)
528         {
529             m_value -= rhs;
530         }
531         return *this;
532     }
533 
534     template <class CT, class CB>
535     template <class T, check_requires<is_not_xoptional_nor_xmasked_value<T>>>
operator *=(const T & rhs)536     auto xoptional<CT, CB>::operator*=(const T& rhs) -> xoptional&
537     {
538         if (m_flag)
539         {
540             m_value *= rhs;
541         }
542         return *this;
543     }
544 
545     template <class CT, class CB>
546     template <class T, check_requires<is_not_xoptional_nor_xmasked_value<T>>>
operator /=(const T & rhs)547     auto xoptional<CT, CB>::operator/=(const T& rhs) -> xoptional&
548     {
549         if (m_flag)
550         {
551             m_value /= rhs;
552         }
553         return *this;
554     }
555 
556     template <class CT, class CB>
557     template <class T, check_requires<is_not_xoptional_nor_xmasked_value<T>>>
operator %=(const T & rhs)558     auto xoptional<CT, CB>::operator%=(const T& rhs) -> xoptional&
559     {
560         if (m_flag)
561         {
562             m_value %= rhs;
563         }
564         return *this;
565     }
566 
567     template <class CT, class CB>
568     template <class T, check_requires<is_not_xoptional_nor_xmasked_value<T>>>
operator &=(const T & rhs)569     auto xoptional<CT, CB>::operator&=(const T& rhs) -> xoptional&
570     {
571         if (m_flag)
572         {
573             m_value &= rhs;
574         }
575         return *this;
576     }
577 
578     template <class CT, class CB>
579     template <class T, check_requires<is_not_xoptional_nor_xmasked_value<T>>>
operator |=(const T & rhs)580     auto xoptional<CT, CB>::operator|=(const T& rhs) -> xoptional&
581     {
582         if (m_flag)
583         {
584             m_value |= rhs;
585         }
586         return *this;
587     }
588 
589     template <class CT, class CB>
590     template <class T, check_requires<is_not_xoptional_nor_xmasked_value<T>>>
operator ^=(const T & rhs)591     auto xoptional<CT, CB>::operator^=(const T& rhs) -> xoptional&
592     {
593         if (m_flag)
594         {
595             m_value ^= rhs;
596         }
597         return *this;
598     }
599 
600     // Access
601     template <class CT, class CB>
value()602     auto xoptional<CT, CB>::value() & noexcept -> std::add_lvalue_reference_t<CT>
603     {
604         return m_value;
605     }
606 
607     template <class CT, class CB>
value() const608     auto xoptional<CT, CB>::value() const & noexcept -> std::add_lvalue_reference_t<std::add_const_t<CT>>
609     {
610         return m_value;
611     }
612 
613     template <class CT, class CB>
value()614     auto xoptional<CT, CB>::value() && noexcept -> std::conditional_t<std::is_reference<CT>::value, apply_cv_t<CT, value_type>&, value_type>
615     {
616         return m_value;
617     }
618 
619     template <class CT, class CB>
value() const620     auto xoptional<CT, CB>::value() const && noexcept -> std::conditional_t<std::is_reference<CT>::value, const value_type&, value_type>
621     {
622         return m_value;
623     }
624 
625     template <class CT, class CB>
626     template <class U>
value_or(U && default_value) const627     auto xoptional<CT, CB>::value_or(U&& default_value) const & noexcept -> value_type
628     {
629         return m_flag ? m_value : std::forward<U>(default_value);
630     }
631 
632     template <class CT, class CB>
633     template <class U>
value_or(U && default_value) const634     auto xoptional<CT, CB>::value_or(U&& default_value) const && noexcept -> value_type
635     {
636         return m_flag ? m_value : std::forward<U>(default_value);
637     }
638 
639     // Access
640     template <class CT, class CB>
has_value()641     auto xoptional<CT, CB>::has_value() & noexcept -> std::add_lvalue_reference_t<CB>
642     {
643         return m_flag;
644     }
645 
646     template <class CT, class CB>
has_value() const647     auto xoptional<CT, CB>::has_value() const & noexcept -> std::add_lvalue_reference_t<std::add_const_t<CB>>
648     {
649         return m_flag;
650     }
651 
652     template <class CT, class CB>
has_value()653     auto xoptional<CT, CB>::has_value() && noexcept -> std::conditional_t<std::is_reference<CB>::value, apply_cv_t<CB, flag_type>&, flag_type>
654     {
655         return m_flag;
656     }
657 
658     template <class CT, class CB>
has_value() const659     auto xoptional<CT, CB>::has_value() const && noexcept -> std::conditional_t<std::is_reference<CB>::value, const flag_type&, flag_type>
660     {
661         return m_flag;
662     }
663 
664     // Swap
665     template <class CT, class CB>
swap(xoptional & other)666     void xoptional<CT, CB>::swap(xoptional& other)
667     {
668         std::swap(m_value, other.m_value);
669         std::swap(m_flag, other.m_flag);
670     }
671 
672     // Comparison
673     template <class CT, class CB>
674     template <class CTO, class CBO>
equal(const xoptional<CTO,CBO> & rhs) const675     auto xoptional<CT, CB>::equal(const xoptional<CTO, CBO>& rhs) const noexcept -> bool
676     {
677         return (!m_flag && !rhs.m_flag) || (m_value == rhs.m_value && (m_flag && rhs.m_flag));
678     }
679 
680     template <class CT, class CB>
681     template <class CTO, check_requires<is_not_xoptional_nor_xmasked_value<CTO>>>
equal(const CTO & rhs) const682     bool xoptional<CT, CB>::equal(const CTO& rhs) const noexcept
683     {
684         return m_flag ? (m_value == rhs) : false;
685     }
686 
687     template <class CT, class CB>
operator &()688     inline auto xoptional<CT, CB>::operator&() & -> xclosure_pointer<self_type&>
689     {
690         return xclosure_pointer<self_type&>(*this);
691     }
692 
693     template <class CT, class CB>
operator &() const694     inline auto xoptional<CT, CB>::operator&() const & -> xclosure_pointer<const self_type&>
695     {
696         return xclosure_pointer<const self_type&>(*this);
697     }
698 
699     template <class CT, class CB>
operator &()700     inline auto xoptional<CT, CB>::operator&() && -> xclosure_pointer<self_type>
701     {
702         return xclosure_pointer<self_type>(std::move(*this));
703     }
704 
705     // External operators
706     template <class T, class B, class OC, class OT>
operator <<(std::basic_ostream<OC,OT> & out,const xoptional<T,B> & v)707     inline std::basic_ostream<OC, OT>& operator<<(std::basic_ostream<OC, OT>& out, const xoptional<T, B>& v)
708     {
709         if (v.has_value())
710         {
711             out << v.value();
712         }
713         else
714         {
715             out << "N/A";
716         }
717         return out;
718     }
719 
720 #ifdef __CLING__
721     template <class T, class B>
mime_bundle_repr(const xoptional<T,B> & v)722     nlohmann::json mime_bundle_repr(const xoptional<T, B>& v)
723     {
724         auto bundle = nlohmann::json::object();
725         std::stringstream tmp;
726         tmp << v;
727         bundle["text/plain"] = tmp.str();
728         return bundle;
729     }
730 #endif
731 
732     template <class T1, class B1, class T2, class B2>
operator ==(const xoptional<T1,B1> & e1,const xoptional<T2,B2> & e2)733     inline auto operator==(const xoptional<T1, B1>& e1, const xoptional<T2, B2>& e2) noexcept
734         -> bool
735     {
736         return e1.equal(e2);
737     }
738 
739     template <class T1, class B1, class T2, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T2>)>
operator ==(const xoptional<T1,B1> & e1,const T2 & e2)740     inline bool operator==(const xoptional<T1, B1>& e1, const T2& e2) noexcept
741     {
742         return e1.equal(e2);
743     }
744 
745     template <class T1, class T2, class B2, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T1>)>
operator ==(const T1 & e1,const xoptional<T2,B2> & e2)746     inline bool operator==(const T1& e1, const xoptional<T2, B2>& e2) noexcept
747     {
748         return e2.equal(e1);
749     }
750 
751     template <class T, class B>
operator +(const xoptional<T,B> & e)752     inline auto operator+(const xoptional<T, B>& e) noexcept
753         -> xoptional<std::decay_t<T>>
754     {
755         return e;
756     }
757 
758     template <class T1, class B1, class T2, class B2>
operator !=(const xoptional<T1,B1> & e1,const xoptional<T2,B2> & e2)759     inline auto operator!=(const xoptional<T1, B1>& e1, const xoptional<T2, B2>& e2) noexcept
760         -> bool
761     {
762         return !e1.equal(e2);
763     }
764 
765     template <class T1, class B1, class T2, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T2>)>
operator !=(const xoptional<T1,B1> & e1,const T2 & e2)766     inline bool operator!=(const xoptional<T1, B1>& e1, const T2& e2) noexcept
767     {
768         return !e1.equal(e2);
769     }
770 
771     template <class T1, class T2, class B2, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T1>)>
operator !=(const T1 & e1,const xoptional<T2,B2> & e2)772     inline bool operator!=(const T1& e1, const xoptional<T2, B2>& e2) noexcept
773     {
774         return !e2.equal(e1);
775     }
776 
777     // Operations
778     template <class T, class B>
operator -(const xoptional<T,B> & e)779     inline auto operator-(const xoptional<T, B>& e) noexcept
780         -> xoptional<std::decay_t<T>>
781     {
782         using value_type = std::decay_t<T>;
783         return e.has_value() ? -e.value() : missing<value_type>();
784     }
785 
786     template <class T1, class B1, class T2, class B2>
operator +(const xoptional<T1,B1> & e1,const xoptional<T2,B2> & e2)787     inline auto operator+(const xoptional<T1, B1>& e1, const xoptional<T2, B2>& e2) noexcept
788         -> xoptional<std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>>
789     {
790         using value_type = std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>;
791         return e1.has_value() && e2.has_value() ? e1.value() + e2.value() : missing<value_type>();
792     }
793 
794     template <class T1, class T2, class B2, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T1>)>
operator +(const T1 & e1,const xoptional<T2,B2> & e2)795     inline auto operator+(const T1& e1, const xoptional<T2, B2>& e2) noexcept
796         -> common_optional_t<T1, T2>
797     {
798         using value_type = std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>;
799         return e2.has_value() ? e1 + e2.value() : missing<value_type>();
800     }
801 
802     template <class T1, class B1, class T2, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T2>)>
operator +(const xoptional<T1,B1> & e1,const T2 & e2)803     inline auto operator+(const xoptional<T1, B1>& e1, const T2& e2) noexcept
804         -> common_optional_t<T1, T2>
805     {
806         using value_type = std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>;
807         return e1.has_value() ? e1.value() + e2 : missing<value_type>();
808     }
809 
810     template <class T1, class B1, class T2, class B2>
operator -(const xoptional<T1,B1> & e1,const xoptional<T2,B2> & e2)811     inline auto operator-(const xoptional<T1, B1>& e1, const xoptional<T2, B2>& e2) noexcept
812         -> xoptional<std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>>
813     {
814         using value_type = std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>;
815         return e1.has_value() && e2.has_value() ? e1.value() - e2.value() : missing<value_type>();
816     }
817 
818     template <class T1, class T2, class B2, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T1>)>
operator -(const T1 & e1,const xoptional<T2,B2> & e2)819     inline auto operator-(const T1& e1, const xoptional<T2, B2>& e2) noexcept
820         -> common_optional_t<T1, T2>
821     {
822         using value_type = std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>;
823         return e2.has_value() ? e1 - e2.value() : missing<value_type>();
824     }
825 
826     template <class T1, class B1, class T2, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T2>)>
operator -(const xoptional<T1,B1> & e1,const T2 & e2)827     inline auto operator-(const xoptional<T1, B1>& e1, const T2& e2) noexcept
828         -> common_optional_t<T1, T2>
829     {
830         using value_type = std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>;
831         return e1.has_value() ? e1.value() - e2 : missing<value_type>();
832     }
833 
834     template <class T1, class B1, class T2, class B2>
operator *(const xoptional<T1,B1> & e1,const xoptional<T2,B2> & e2)835     inline auto operator*(const xoptional<T1, B1>& e1, const xoptional<T2, B2>& e2) noexcept
836         -> xoptional<std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>>
837     {
838         using value_type = std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>;
839         return e1.has_value() && e2.has_value() ? e1.value() * e2.value() : missing<value_type>();
840     }
841 
842     template <class T1, class T2, class B2, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T1>)>
operator *(const T1 & e1,const xoptional<T2,B2> & e2)843     inline auto operator*(const T1& e1, const xoptional<T2, B2>& e2) noexcept
844         -> common_optional_t<T1, T2>
845     {
846         using value_type = std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>;
847         return e2.has_value() ? e1 * e2.value() : missing<value_type>();
848     }
849 
850     template <class T1, class B1, class T2, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T2>)>
operator *(const xoptional<T1,B1> & e1,const T2 & e2)851     inline auto operator*(const xoptional<T1, B1>& e1, const T2& e2) noexcept
852         -> common_optional_t<T1, T2>
853     {
854         using value_type = std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>;
855         return e1.has_value() ? e1.value() * e2 : missing<value_type>();
856     }
857 
858     template <class T1, class B1, class T2, class B2>
operator /(const xoptional<T1,B1> & e1,const xoptional<T2,B2> & e2)859     inline auto operator/(const xoptional<T1, B1>& e1, const xoptional<T2, B2>& e2) noexcept
860         -> xoptional<std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>>
861     {
862         using value_type = std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>;
863         return e1.has_value() && e2.has_value() ? e1.value() / e2.value() : missing<value_type>();
864     }
865 
866     template <class T1, class T2, class B2, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T1>)>
operator /(const T1 & e1,const xoptional<T2,B2> & e2)867     inline auto operator/(const T1& e1, const xoptional<T2, B2>& e2) noexcept
868         -> common_optional_t<T1, T2>
869     {
870         using value_type = std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>;
871         return e2.has_value() ? e1 / e2.value() : missing<value_type>();
872     }
873 
874     template <class T1, class B1, class T2, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T2>)>
operator /(const xoptional<T1,B1> & e1,const T2 & e2)875     inline auto operator/(const xoptional<T1, B1>& e1, const T2& e2) noexcept
876         -> common_optional_t<T1, T2>
877     {
878         using value_type = std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>;
879         return e1.has_value() ? e1.value() / e2 : missing<value_type>();
880     }
881 
882     template <class T1, class B1, class T2, class B2>
operator %(const xoptional<T1,B1> & e1,const xoptional<T2,B2> & e2)883     inline auto operator%(const xoptional<T1, B1>& e1, const xoptional<T2, B2>& e2) noexcept
884         -> xoptional<std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>>
885     {
886         using value_type = std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>;
887         return e1.has_value() && e2.has_value() ? e1.value() % e2.value() : missing<value_type>();
888     }
889 
890     template <class T1, class T2, class B2, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T1>)>
operator %(const T1 & e1,const xoptional<T2,B2> & e2)891     inline auto operator%(const T1& e1, const xoptional<T2, B2>& e2) noexcept
892         -> common_optional_t<T1, T2>
893     {
894         using value_type = std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>;
895         return e2.has_value() ? e1 % e2.value() : missing<value_type>();
896     }
897 
898     template <class T1, class B1, class T2, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T2>)>
operator %(const xoptional<T1,B1> & e1,const T2 & e2)899     inline auto operator%(const xoptional<T1, B1>& e1, const T2& e2) noexcept
900         -> common_optional_t<T1, T2>
901     {
902         using value_type = std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>;
903         return e1.has_value() ? e1.value() % e2 : missing<value_type>();
904     }
905 
906     template <class T, class B>
operator ~(const xoptional<T,B> & e)907     inline auto operator~(const xoptional<T, B>& e) noexcept
908         -> xoptional<std::decay_t<T>>
909     {
910         using value_type = std::decay_t<T>;
911         return e.has_value() ? ~e.value() : missing<value_type>();
912     }
913 
914     template <class T1, class B1, class T2, class B2>
operator &(const xoptional<T1,B1> & e1,const xoptional<T2,B2> & e2)915     inline auto operator&(const xoptional<T1, B1>& e1, const xoptional<T2, B2>& e2) noexcept
916         -> xoptional<std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>>
917     {
918         using value_type = std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>;
919         return e1.has_value() && e2.has_value() ? e1.value() & e2.value() : missing<value_type>();
920     }
921 
922     template <class T1, class T2, class B2, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T1>)>
operator &(const T1 & e1,const xoptional<T2,B2> & e2)923     inline auto operator&(const T1& e1, const xoptional<T2, B2>& e2) noexcept
924         -> common_optional_t<T1, T2>
925     {
926         using value_type = std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>;
927         return e2.has_value() ? e1 & e2.value() : missing<value_type>();
928     }
929 
930     template <class T1, class B1, class T2, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T2>)>
operator &(const xoptional<T1,B1> & e1,const T2 & e2)931     inline auto operator&(const xoptional<T1, B1>& e1, const T2& e2) noexcept
932         -> common_optional_t<T1, T2>
933     {
934         using value_type = std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>;
935         return e1.has_value() ? e1.value() & e2 : missing<value_type>();
936     }
937 
938     template <class T1, class B1, class T2, class B2>
operator |(const xoptional<T1,B1> & e1,const xoptional<T2,B2> & e2)939     inline auto operator|(const xoptional<T1, B1>& e1, const xoptional<T2, B2>& e2) noexcept
940         -> xoptional<std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>>
941     {
942         using value_type = std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>;
943         return e1.has_value() && e2.has_value() ? e1.value() | e2.value() : missing<value_type>();
944     }
945 
946     template <class T1, class T2, class B2, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T1>)>
operator |(const T1 & e1,const xoptional<T2,B2> & e2)947     inline auto operator|(const T1& e1, const xoptional<T2, B2>& e2) noexcept
948         -> common_optional_t<T1, T2>
949     {
950         using value_type = std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>;
951         return e2.has_value() ? e1 | e2.value() : missing<value_type>();
952     }
953 
954     template <class T1, class B1, class T2, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T2>)>
operator |(const xoptional<T1,B1> & e1,const T2 & e2)955     inline auto operator|(const xoptional<T1, B1>& e1, const T2& e2) noexcept
956         -> common_optional_t<T1, T2>
957     {
958         using value_type = std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>;
959         return e1.has_value() ? e1.value() | e2 : missing<value_type>();
960     }
961 
962     template <class T1, class B1, class T2, class B2>
operator ^(const xoptional<T1,B1> & e1,const xoptional<T2,B2> & e2)963     inline auto operator^(const xoptional<T1, B1>& e1, const xoptional<T2, B2>& e2) noexcept
964         -> xoptional<std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>>
965     {
966         using value_type = std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>;
967         return e1.has_value() && e2.has_value() ? e1.value() ^ e2.value() : missing<value_type>();
968     }
969 
970     template <class T1, class T2, class B2, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T1>)>
operator ^(const T1 & e1,const xoptional<T2,B2> & e2)971     inline auto operator^(const T1& e1, const xoptional<T2, B2>& e2) noexcept
972         -> common_optional_t<T1, T2>
973     {
974         using value_type = std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>;
975         return e2.has_value() ? e1 ^ e2.value() : missing<value_type>();
976     }
977 
978     template <class T1, class B1, class T2, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T2>)>
operator ^(const xoptional<T1,B1> & e1,const T2 & e2)979     inline auto operator^(const xoptional<T1, B1>& e1, const T2& e2) noexcept
980         -> common_optional_t<T1, T2>
981     {
982         using value_type = std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>;
983         return e1.has_value() ? e1.value() ^ e2 : missing<value_type>();
984     }
985 
986     template <class T1, class B1, class T2, class B2>
operator ||(const xoptional<T1,B1> & e1,const xoptional<T2,B2> & e2)987     inline auto operator||(const xoptional<T1, B1>& e1, const xoptional<T2, B2>& e2) noexcept
988         -> xoptional<std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>>
989     {
990         using value_type = std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>;
991         return e1.has_value() && e2.has_value() ? e1.value() || e2.value() : missing<value_type>();
992     }
993 
994     template <class T1, class T2, class B2, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T1>)>
operator ||(const T1 & e1,const xoptional<T2,B2> & e2)995     inline auto operator||(const T1& e1, const xoptional<T2, B2>& e2) noexcept
996         -> common_optional_t<T1, T2>
997     {
998         using value_type = std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>;
999         return e2.has_value() ? e1 || e2.value() : missing<value_type>();
1000     }
1001 
1002     template <class T1, class B1, class T2, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T2>)>
operator ||(const xoptional<T1,B1> & e1,const T2 & e2)1003     inline auto operator||(const xoptional<T1, B1>& e1, const T2& e2) noexcept
1004         -> common_optional_t<T1, T2>
1005     {
1006         using value_type = std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>;
1007         return e1.has_value() ? e1.value() || e2 : missing<value_type>();
1008     }
1009 
1010 
1011     template <class T1, class B1, class T2, class B2>
operator &&(const xoptional<T1,B1> & e1,const xoptional<T2,B2> & e2)1012     inline auto operator&&(const xoptional<T1, B1>& e1, const xoptional<T2, B2>& e2) noexcept
1013         -> xoptional<std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>>
1014     {
1015         using value_type = std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>;
1016         return e1.has_value() && e2.has_value() ? e1.value() && e2.value() : missing<value_type>();
1017     }
1018 
1019     template <class T1, class T2, class B2, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T1>)>
operator &&(const T1 & e1,const xoptional<T2,B2> & e2)1020     inline auto operator&&(const T1& e1, const xoptional<T2, B2>& e2) noexcept
1021         -> common_optional_t<T1, T2>
1022     {
1023         using value_type = std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>;
1024         return e2.has_value() ? e1 && e2.value() : missing<value_type>();
1025     }
1026 
1027     template <class T1, class B1, class T2, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T2>)>
operator &&(const xoptional<T1,B1> & e1,const T2 & e2)1028     inline auto operator&&(const xoptional<T1, B1>& e1, const T2& e2) noexcept
1029         -> common_optional_t<T1, T2>
1030     {
1031         using value_type = std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>;
1032         return e1.has_value() ? e1.value() && e2 : missing<value_type>();
1033     }
1034 
1035     template <class T, class B>
operator !(const xoptional<T,B> & e)1036     inline auto operator!(const xoptional<T, B>& e) noexcept
1037         -> xoptional<bool>
1038     {
1039         return e.has_value() ? !e.value() : missing<bool>();
1040     }
1041 
1042     template <class T1, class B1, class T2, class B2>
operator <(const xoptional<T1,B1> & e1,const xoptional<T2,B2> & e2)1043     inline auto operator<(const xoptional<T1, B1>& e1, const xoptional<T2, B2>& e2) noexcept
1044         -> xoptional<bool>
1045     {
1046         return e1.has_value() && e2.has_value() ? e1.value() < e2.value() : missing<bool>();
1047     }
1048 
1049     template <class T1, class T2, class B2, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T1>)>
operator <(const T1 & e1,const xoptional<T2,B2> & e2)1050     inline auto operator<(const T1& e1, const xoptional<T2, B2>& e2) noexcept
1051         -> xoptional<bool>
1052     {
1053         return e2.has_value() ? e1 < e2.value() : missing<bool>();
1054     }
1055 
1056     template <class T1, class B1, class T2, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T2>)>
operator <(const xoptional<T1,B1> & e1,const T2 & e2)1057     inline auto operator<(const xoptional<T1, B1>& e1, const T2& e2) noexcept
1058         -> xoptional<bool>
1059     {
1060         return e1.has_value() ? e1.value() < e2 : missing<bool>();
1061     }
1062 
1063     template <class T1, class B1, class T2, class B2>
operator <=(const xoptional<T1,B1> & e1,const xoptional<T2,B2> & e2)1064     inline auto operator<=(const xoptional<T1, B1>& e1, const xoptional<T2, B2>& e2) noexcept
1065         -> xoptional<bool>
1066     {
1067         return e1.has_value() && e2.has_value() ? e1.value() <= e2.value() : missing<bool>();
1068     }
1069 
1070     template <class T1, class T2, class B2, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T1>)>
operator <=(const T1 & e1,const xoptional<T2,B2> & e2)1071     inline auto operator<=(const T1& e1, const xoptional<T2, B2>& e2) noexcept
1072         -> xoptional<bool>
1073     {
1074         return e2.has_value() ? e1 <= e2.value() : missing<bool>();
1075     }
1076 
1077     template <class T1, class B1, class T2, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T2>)>
operator <=(const xoptional<T1,B1> & e1,const T2 & e2)1078     inline auto operator<=(const xoptional<T1, B1>& e1, const T2& e2) noexcept
1079         -> xoptional<bool>
1080     {
1081         return e1.has_value() ? e1.value() <= e2 : missing<bool>();
1082     }
1083 
1084     template <class T1, class B1, class T2, class B2>
operator >(const xoptional<T1,B1> & e1,const xoptional<T2,B2> & e2)1085     inline auto operator>(const xoptional<T1, B1>& e1, const xoptional<T2, B2>& e2) noexcept
1086         -> xoptional<bool>
1087     {
1088         return e1.has_value() && e2.has_value() ? e1.value() > e2.value() : missing<bool>();
1089     }
1090 
1091     template <class T1, class T2, class B2, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T1>)>
operator >(const T1 & e1,const xoptional<T2,B2> & e2)1092     inline auto operator>(const T1& e1, const xoptional<T2, B2>& e2) noexcept
1093         -> xoptional<bool>
1094     {
1095         return e2.has_value() ? e1 > e2.value() : missing<bool>();
1096     }
1097 
1098     template <class T1, class B1, class T2, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T2>)>
operator >(const xoptional<T1,B1> & e1,const T2 & e2)1099     inline auto operator>(const xoptional<T1, B1>& e1, const T2& e2) noexcept
1100         -> xoptional<bool>
1101     {
1102         return e1.has_value() ? e1.value() > e2 : missing<bool>();
1103     }
1104 
1105     template <class T1, class B1, class T2, class B2>
operator >=(const xoptional<T1,B1> & e1,const xoptional<T2,B2> & e2)1106     inline auto operator>=(const xoptional<T1, B1>& e1, const xoptional<T2, B2>& e2) noexcept
1107         -> xoptional<bool>
1108     {
1109         return e1.has_value() && e2.has_value() ? e1.value() >= e2.value() : missing<bool>();
1110     }
1111 
1112     template <class T1, class T2, class B2, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T1>)>
operator >=(const T1 & e1,const xoptional<T2,B2> & e2)1113     inline auto operator>=(const T1& e1, const xoptional<T2, B2>& e2) noexcept
1114         -> xoptional<bool>
1115     {
1116         return e2.has_value() ? e1 >= e2.value() : missing<bool>();
1117     }
1118 
1119     template <class T1, class B1, class T2, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T2>)>
operator >=(const xoptional<T1,B1> & e1,const T2 & e2)1120     inline auto operator>=(const xoptional<T1, B1>& e1, const T2& e2) noexcept
1121         -> xoptional<bool>
1122     {
1123         return e1.has_value() ? e1.value() >= e2 : missing<bool>();
1124     }
1125 
1126 #define UNARY_OPTIONAL(NAME)                                                 \
1127     template <class T, class B>                                              \
1128     inline auto NAME(const xoptional<T, B>& e)                               \
1129     {                                                                        \
1130         using std::NAME;                                                     \
1131         return e.has_value() ? NAME(e.value()) : missing<std::decay_t<T>>(); \
1132     }
1133 
1134 #define UNARY_BOOL_OPTIONAL(NAME)                                       \
1135     template <class T, class B>                                         \
1136     inline xoptional<bool> NAME(const xoptional<T, B>& e)               \
1137     {                                                                   \
1138         using std::NAME;                                                \
1139         return e.has_value() ? bool(NAME(e.value())) : missing<bool>(); \
1140     }
1141 
1142 #define BINARY_OPTIONAL_1(NAME)                                                                   \
1143     template <class T1, class B1, class T2, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T2>)> \
1144     inline auto NAME(const xoptional<T1, B1>& e1, const T2& e2)                                   \
1145         -> common_optional_t<T1, T2>                                                              \
1146     {                                                                                             \
1147         using std::NAME;                                                                          \
1148         using value_type = std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>;                \
1149         return e1.has_value() ? NAME(e1.value(), e2) : missing<value_type>();                     \
1150     }
1151 
1152 
1153 #define BINARY_OPTIONAL_2(NAME)                                                                   \
1154     template <class T1, class T2, class B2, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T1>)> \
1155     inline auto NAME(const T1& e1, const xoptional<T2, B2>& e2)                                   \
1156         -> common_optional_t<T1, T2>                                                              \
1157     {                                                                                             \
1158         using std::NAME;                                                                          \
1159         using value_type = std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>;                \
1160         return e2.has_value() ? NAME(e1, e2.value()) : missing<value_type>();                     \
1161     }
1162 
1163 #define BINARY_OPTIONAL_12(NAME)                                                                        \
1164     template <class T1, class B1, class T2, class B2>                                                   \
1165     inline auto NAME(const xoptional<T1, B1>& e1, const xoptional<T2, B2>& e2)                          \
1166     {                                                                                                   \
1167         using std::NAME;                                                                                \
1168         using value_type = std::common_type_t<std::decay_t<T1>, std::decay_t<T2>>;                      \
1169         return e1.has_value() && e2.has_value() ? NAME(e1.value(), e2.value()) : missing<value_type>(); \
1170     }
1171 
1172 #define BINARY_OPTIONAL(NAME) \
1173     BINARY_OPTIONAL_1(NAME)   \
1174     BINARY_OPTIONAL_2(NAME)   \
1175     BINARY_OPTIONAL_12(NAME)
1176 
1177 #define TERNARY_OPTIONAL_1(NAME)                                                                                                                    \
1178     template <class T1, class B1, class T2, class T3, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T2>, is_not_xoptional_nor_xmasked_value<T3>)> \
1179     inline auto NAME(const xoptional<T1, B1>& e1, const T2& e2, const T3& e3)                                                                       \
1180         -> common_optional_t<T1, T2, T3>                                                                                                            \
1181     {                                                                                                                                               \
1182         using std::NAME;                                                                                                                            \
1183         using value_type = std::common_type_t<std::decay_t<T1>, std::decay_t<T2>, std::decay_t<T3>>;                                                \
1184         return e1.has_value() ? NAME(e1.value(), e2, e3) : missing<value_type>();                                                                   \
1185     }
1186 
1187 #define TERNARY_OPTIONAL_2(NAME)                                                                                                                    \
1188     template <class T1, class T2, class B2, class T3, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T1>, is_not_xoptional_nor_xmasked_value<T3>)> \
1189     inline auto NAME(const T1& e1, const xoptional<T2, B2>& e2, const T3& e3)                                                                       \
1190         -> common_optional_t<T1, T2, T3>                                                                                                            \
1191     {                                                                                                                                               \
1192         using std::NAME;                                                                                                                            \
1193         using value_type = std::common_type_t<std::decay_t<T1>, std::decay_t<T2>, std::decay_t<T3>>;                                                \
1194         return e2.has_value() ? NAME(e1, e2.value(), e3) : missing<value_type>();                                                                   \
1195     }
1196 
1197 #define TERNARY_OPTIONAL_3(NAME)                                                                                                                    \
1198     template <class T1, class T2, class T3, class B3, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T1>, is_not_xoptional_nor_xmasked_value<T2>)> \
1199     inline auto NAME(const T1& e1, const T2& e2, const xoptional<T3, B3>& e3)                                                                       \
1200         -> common_optional_t<T1, T2, T3>                                                                                                            \
1201     {                                                                                                                                               \
1202         using std::NAME;                                                                                                                            \
1203         using value_type = std::common_type_t<std::decay_t<T1>, std::decay_t<T2>, std::decay_t<T3>>;                                                \
1204         return e3.has_value() ? NAME(e1, e2, e3.value()) : missing<value_type>();                                                                   \
1205     }
1206 
1207 #define TERNARY_OPTIONAL_12(NAME)                                                                                     \
1208     template <class T1, class B1, class T2, class B2, class T3, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T3>)> \
1209     inline auto NAME(const xoptional<T1, B1>& e1, const xoptional<T2, B2>& e2, const T3& e3)                          \
1210         -> common_optional_t<T1, T2, T3>                                                                              \
1211     {                                                                                                                 \
1212         using std::NAME;                                                                                              \
1213         using value_type = std::common_type_t<std::decay_t<T1>, std::decay_t<T2>, std::decay_t<T3>>;                  \
1214         return (e1.has_value() && e2.has_value()) ? NAME(e1.value(), e2.value(), e3) : missing<value_type>();         \
1215     }
1216 
1217 #define TERNARY_OPTIONAL_13(NAME)                                                                                     \
1218     template <class T1, class B1, class T2, class T3, class B3, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T2>)> \
1219     inline auto NAME(const xoptional<T1, B1>& e1, const T2& e2, const xoptional<T3, B3>& e3)                          \
1220         -> common_optional_t<T1, T2, T3>                                                                              \
1221     {                                                                                                                 \
1222         using std::NAME;                                                                                              \
1223         using value_type = std::common_type_t<std::decay_t<T1>, std::decay_t<T2>, std::decay_t<T3>>;                  \
1224         return (e1.has_value() && e3.has_value()) ? NAME(e1.value(), e2, e3.value()) : missing<value_type>();         \
1225     }
1226 
1227 #define TERNARY_OPTIONAL_23(NAME)                                                                                     \
1228     template <class T1, class T2, class B2, class T3, class B3, XTL_REQUIRES(is_not_xoptional_nor_xmasked_value<T1>)> \
1229     inline auto NAME(const T1& e1, const xoptional<T2, B2>& e2, const xoptional<T3, B3>& e3)                          \
1230         -> common_optional_t<T1, T2, T3>                                                                              \
1231     {                                                                                                                 \
1232         using std::NAME;                                                                                              \
1233         using value_type = std::common_type_t<std::decay_t<T1>, std::decay_t<T2>, std::decay_t<T3>>;                  \
1234         return (e2.has_value() && e3.has_value()) ? NAME(e1, e2.value(), e3.value()) : missing<value_type>();         \
1235     }
1236 
1237 #define TERNARY_OPTIONAL_123(NAME)                                                                                                      \
1238     template <class T1, class B1, class T2, class B2, class T3, class B3>                                                               \
1239     inline auto NAME(const xoptional<T1, B1>& e1, const xoptional<T2, B2>& e2, const xoptional<T3, B3>& e3)                             \
1240     {                                                                                                                                   \
1241         using std::NAME;                                                                                                                \
1242         using value_type = std::common_type_t<std::decay_t<T1>, std::decay_t<T2>, std::decay_t<T3>>;                                    \
1243         return (e1.has_value() && e2.has_value() && e3.has_value()) ? NAME(e1.value(), e2.value(), e3.value()) : missing<value_type>(); \
1244     }
1245 
1246 #define TERNARY_OPTIONAL(NAME) \
1247     TERNARY_OPTIONAL_1(NAME)   \
1248     TERNARY_OPTIONAL_2(NAME)   \
1249     TERNARY_OPTIONAL_3(NAME)   \
1250     TERNARY_OPTIONAL_12(NAME)  \
1251     TERNARY_OPTIONAL_13(NAME)  \
1252     TERNARY_OPTIONAL_23(NAME)  \
1253     TERNARY_OPTIONAL_123(NAME)
1254 
1255     UNARY_OPTIONAL(abs)
UNARY_OPTIONAL(fabs)1256     UNARY_OPTIONAL(fabs)
1257     BINARY_OPTIONAL(fmod)
1258     BINARY_OPTIONAL(remainder)
1259     TERNARY_OPTIONAL(fma)
1260     BINARY_OPTIONAL(fmax)
1261     BINARY_OPTIONAL(fmin)
1262     BINARY_OPTIONAL(fdim)
1263     UNARY_OPTIONAL(exp)
1264     UNARY_OPTIONAL(exp2)
1265     UNARY_OPTIONAL(expm1)
1266     UNARY_OPTIONAL(log)
1267     UNARY_OPTIONAL(log10)
1268     UNARY_OPTIONAL(log2)
1269     UNARY_OPTIONAL(log1p)
1270     BINARY_OPTIONAL(pow)
1271     UNARY_OPTIONAL(sqrt)
1272     UNARY_OPTIONAL(cbrt)
1273     BINARY_OPTIONAL(hypot)
1274     UNARY_OPTIONAL(sin)
1275     UNARY_OPTIONAL(cos)
1276     UNARY_OPTIONAL(tan)
1277     UNARY_OPTIONAL(acos)
1278     UNARY_OPTIONAL(asin)
1279     UNARY_OPTIONAL(atan)
1280     BINARY_OPTIONAL(atan2)
1281     UNARY_OPTIONAL(sinh)
1282     UNARY_OPTIONAL(cosh)
1283     UNARY_OPTIONAL(tanh)
1284     UNARY_OPTIONAL(acosh)
1285     UNARY_OPTIONAL(asinh)
1286     UNARY_OPTIONAL(atanh)
1287     UNARY_OPTIONAL(erf)
1288     UNARY_OPTIONAL(erfc)
1289     UNARY_OPTIONAL(tgamma)
1290     UNARY_OPTIONAL(lgamma)
1291     UNARY_OPTIONAL(ceil)
1292     UNARY_OPTIONAL(floor)
1293     UNARY_OPTIONAL(trunc)
1294     UNARY_OPTIONAL(round)
1295     UNARY_OPTIONAL(nearbyint)
1296     UNARY_OPTIONAL(rint)
1297     UNARY_BOOL_OPTIONAL(isfinite)
1298     UNARY_BOOL_OPTIONAL(isinf)
1299     UNARY_BOOL_OPTIONAL(isnan)
1300 
1301 #undef TERNARY_OPTIONAL
1302 #undef TERNARY_OPTIONAL_123
1303 #undef TERNARY_OPTIONAL_23
1304 #undef TERNARY_OPTIONAL_13
1305 #undef TERNARY_OPTIONAL_12
1306 #undef TERNARY_OPTIONAL_3
1307 #undef TERNARY_OPTIONAL_2
1308 #undef TERNARY_OPTIONAL_1
1309 #undef BINARY_OPTIONAL
1310 #undef BINARY_OPTIONAL_12
1311 #undef BINARY_OPTIONAL_2
1312 #undef BINARY_OPTIONAL_1
1313 #undef UNARY_OPTIONAL
1314 
1315     /*************************
1316      * select implementation *
1317      *************************/
1318 
1319     template <class B, class T1, class T2, XTL_REQUIRES(at_least_one_xoptional<B, T1, T2>)>
1320     inline common_optional_t<T1, T2> select(const B& cond, const T1& v1, const T2& v2) noexcept
1321     {
1322         using bool_type = common_optional_t<B>;
1323         using return_type = common_optional_t<T1, T2>;
1324         bool_type opt_cond(cond);
1325         return opt_cond.has_value() ?
1326             opt_cond.value() ? return_type(v1) : return_type(v2) :
1327             missing<typename return_type::value_type>();
1328     }
1329 }
1330 
1331 #endif
1332