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