sparrow 0.3.0
Loading...
Searching...
No Matches
nullable.hpp
Go to the documentation of this file.
1// Copyright 2024 Man Group Operations Limited
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#pragma once
16
17#include <compare>
18#include <concepts>
19#include <exception>
20#if defined(__cpp_lib_format)
21# include <format>
22# include <ostream>
23#endif
24#include <type_traits>
25#include <variant>
26
28
29
30#if defined(SPARROW_CONSTEXPR)
31# error "SPARROW_CONSTEXPR already defined"
32#endif
33
34// clang workaround: clang instantiates the constructor in SFINAE context,
35// which is incompatible with the implementation of standard libraries which
36// are not libc++. This leads to wrong compilation errors. Making the constructor
37// not constexpr prevents the compiler from instantiating it.
38#if defined(__clang__) && not defined(_LIBCPP_VERSION)
39# define SPARROW_CONSTEXPR
40#else
41# define SPARROW_CONSTEXPR constexpr
42#endif
43
44namespace sparrow
45{
46 template <class T, mpl::boolean_like B>
47 class nullable;
48
49 template <class T>
50 struct is_nullable : std::false_type
51 {
52 };
53
54 template <class T, mpl::boolean_like B>
55 struct is_nullable<nullable<T, B>> : std::true_type
56 {
57 };
58
59 template <class T>
60 inline constexpr bool is_nullable_v = is_nullable<T>::value;
61
62 template <class N, class T>
63 concept is_nullable_of = is_nullable_v<N> && std::same_as<typename N::value_type, T>;
64
65 template <class N, class T>
66 concept is_nullable_of_convertible_to = is_nullable_v<N> && std::convertible_to<typename N::value_type, T>;
67
68 /*
69 * Matches a range of nullables objects.
70 *
71 * A range is considered a range of nullables if it is a range and its value type is a nullable.
72 *
73 * @tparam RangeOfNullables The range to check.
74 */
75 template <class RangeOfNullables>
76 concept range_of_nullables = std::ranges::range<RangeOfNullables>
78
79 /*
80 * Default traits for the nullable class. These traits should be specialized
81 * for proxy classes whose reference and const_reference types are not
82 * defined as usual. For instance:
83 *
84 * @code{.cpp}
85 * struct nullable_traits<string_proxy>
86 * {
87 * using value_type = std::string;
88 * using reference = string_proxy;
89 * using const_reference = std::string_view;
90 * using rvalue_reverence = std::string&&;
91 * using const_rvalue_reference = const std::string&&;
92 * };
93 * @endcode
94 */
95 template <class T>
97 {
98 using value_type = T;
99 using reference = std::add_lvalue_reference_t<value_type>;
100 using const_reference = std::add_lvalue_reference_t<std::add_const_t<value_type>>;
103 };
104
105 template <class T>
107 {
108 using value_type = T;
109 using reference = std::add_lvalue_reference_t<value_type>;
110 using const_reference = std::add_lvalue_reference_t<std::add_const_t<value_type>>;
113 };
114
115 /*
116 * Defines a type of object to be thrown by nullable::value when accessing
117 * a nullable object whose value is null.
118 */
119 class bad_nullable_access : public std::exception
120 {
121 public:
122
123 bad_nullable_access() noexcept = default;
124 bad_nullable_access(const bad_nullable_access&) noexcept = default;
125 bad_nullable_access& operator=(const bad_nullable_access&) noexcept = default;
126
127 [[nodiscard]] const char* what() const noexcept override
128 {
129 return message;
130 }
131
132 private:
133
134 static constexpr const char* message = "Invalid access to nullable underlying value";
135 };
136
141 {
142 // This is required to disable the generation of
143 // the default constructor. Otherwise, a = {} where
144 // a is a nullable would lead to an ambiguous call
145 // where both operator=(nullable&&) and operator=(nullval_t)
146 // are valid.
147 constexpr explicit nullval_t(int)
148 {
149 }
150 };
151
152 inline constexpr nullval_t nullval(0);
153
154 namespace impl
155 {
159 template <class T, class TArgs, class U, class UArgs>
160 concept both_constructible_from_cref = std::constructible_from<T, mpl::add_const_lvalue_reference_t<TArgs>>
161 and std::constructible_from<U, mpl::add_const_lvalue_reference_t<UArgs>>;
162
163 template <class To1, class From1, class To2, class From2>
164 concept both_convertible_from_cref = std::convertible_to<mpl::add_const_lvalue_reference_t<From1>, To1>
165 and std::convertible_to<mpl::add_const_lvalue_reference_t<From2>, To2>;
166
167 template <class T, class... Args>
168 concept constructible_from_one = (std::constructible_from<T, Args> || ...);
169
170 template <class T, class... Args>
171 concept convertible_from_one = (std::convertible_to<Args, T> || ...);
172
173 template <class T, class... Args>
175
176 template <class T, class Arg>
178
179 // We prefer std::is_assignable_v to std::assignable_from<To, From> because
180 // std::assignable_from requires the existence of an implicit conversion
181 // from From to To
182 template <class To, class... Args>
183 concept assignable_from_one = (std::is_assignable_v<std::add_lvalue_reference<To>, Args> && ...);
184
185 template <class T, class Arg>
187
188 template <class T, class U>
189 using conditional_ref_t = std::conditional_t<std::is_reference_v<T>, const std::decay_t<U>&, std::decay_t<U>&&>;
190
191 template <class T, class Targs, class U, class UArgs>
192 concept both_constructible_from_cond_ref = std::constructible_from<T, conditional_ref_t<T, Targs>>
193 and std::constructible_from<U, conditional_ref_t<U, UArgs>>;
194
195 template <class To1, class From1, class To2, class From2>
196 concept both_convertible_from_cond_ref = std::convertible_to<conditional_ref_t<To1, From1>, To1>
197 and std::convertible_to<conditional_ref_t<To2, From2>, To2>;
198
199 template <class To1, class From1, class To2, class From2>
200 concept both_assignable_from_cref = std::is_assignable_v<
201 std::add_lvalue_reference_t<To1>,
203 and std::is_assignable_v<
204 std::add_lvalue_reference_t<To2>,
206
207 template <class To1, class From1, class To2, class From2>
208 concept both_assignable_from_cond_ref = std::is_assignable_v<
209 std::add_lvalue_reference_t<To1>,
211 and std::is_assignable_v<
212 std::add_lvalue_reference_t<To2>,
214
215 template <class T>
217 }
218
278 template <class T, mpl::boolean_like B = bool>
280 {
281 public:
282
296
297 template <std::default_initializable U = T, std::default_initializable BB = B>
298 constexpr nullable() noexcept
299 : m_value()
300 , m_null_flag(false)
301 {
302 }
303
304 template <std::default_initializable U = T, std::default_initializable BB = B>
305 constexpr nullable(nullval_t) noexcept
306 : m_value()
307 , m_null_flag(false)
308 {
309 }
310
311 template <class U>
312 requires(not std::same_as<self_type, std::decay_t<U>> and std::constructible_from<T, U &&>)
313 explicit(not std::convertible_to<U&&, T>) constexpr nullable(U&& value
314 ) noexcept(noexcept(T(std::declval<U>())))
315 : m_value(std::forward<U>(value))
316 , m_null_flag(true)
317 {
318 }
319
320 constexpr nullable(const self_type&) = default;
321
322 template <class TO, mpl::boolean_like BO>
327 : m_value(rhs.get())
328 , m_null_flag(rhs.null_flag())
329 {
330 }
331
332#ifdef __clang__
333 template <class TO, mpl::boolean_like BO>
334 requires(impl::both_constructible_from_cref<T, TO, B, BO> and std::same_as<std::decay_t<T>, bool>)
337 : m_value(rhs.get())
338 , m_null_flag(rhs.null_flag())
339 {
340 }
341#endif
342
343 constexpr nullable(self_type&&) noexcept = default;
344
345 template <class TO, mpl::boolean_like BO>
346 requires(impl::both_constructible_from_cond_ref<T, TO, B, BO>
347 and not impl::initializable_from_refs<T, nullable<TO, BO>>)
348 explicit(not impl::both_convertible_from_cond_ref<T, TO, B, BO>) SPARROW_CONSTEXPR
350 : m_value(std::move(rhs).get())
351 , m_null_flag(std::move(rhs).null_flag())
352 {
353 }
354
355#ifdef __clang__
356 template <class TO, mpl::boolean_like BO>
358 and std::same_as<std::decay_t<T>, bool>)
361 : m_value(std::move(rhs).get())
362 , m_null_flag(std::move(rhs).null_flag())
363 {
364 }
365#endif
366
368 : m_value(std::move(value))
369 , m_null_flag(std::move(null_flag))
370 {
371 }
372
373 constexpr nullable(std::add_lvalue_reference_t<T> value, std::add_lvalue_reference_t<B> null_flag)
374 : m_value(value)
375 , m_null_flag(null_flag)
376 {
377 }
378
379 constexpr nullable(value_type&& value, std::add_lvalue_reference_t<B> null_flag)
380 : m_value(std::move(value))
381 , m_null_flag(null_flag)
382 {
383 }
384
385 constexpr nullable(std::add_lvalue_reference_t<T> value, flag_type&& null_flag)
386 : m_value(value)
387 , m_null_flag(std::move(null_flag))
388 {
389 }
390
392 {
393 m_null_flag = false;
394 return *this;
395 }
396
397 template <class TO>
398 requires(not std::same_as<self_type, TO> and std::assignable_from<std::add_lvalue_reference_t<T>, TO>)
399 constexpr self_type& operator=(TO&& rhs)
400 {
401 m_value = std::forward<TO>(rhs);
402 m_null_flag = true;
403 return *this;
404 }
405
406 constexpr self_type& operator=(const self_type& rhs)
407 {
408 m_value = rhs.get();
409 m_null_flag = rhs.null_flag();
410 return *this;
411 }
412
413 template <class TO, mpl::boolean_like BO>
415 constexpr self_type& operator=(const nullable<TO, BO>& rhs)
416 {
417 m_value = rhs.get();
418 m_null_flag = rhs.null_flag();
419 return *this;
420 }
421
423 {
424 m_value = std::move(rhs).get();
425 m_null_flag = std::move(rhs).null_flag();
426 return *this;
427 }
428
429 template <class TO, mpl::boolean_like BO>
431 constexpr self_type& operator=(nullable<TO, BO>&& rhs)
432 {
433 m_value = std::move(rhs).get();
434 m_null_flag = std::move(rhs).null_flag();
435 return *this;
436 }
437
438 constexpr explicit operator bool() const noexcept;
439 [[nodiscard]] constexpr bool has_value() const noexcept;
440
441 [[nodiscard]] constexpr flag_reference null_flag() & noexcept;
442 [[nodiscard]] constexpr flag_const_reference null_flag() const& noexcept;
443 [[nodiscard]] constexpr flag_rvalue_reference null_flag() && noexcept;
444 [[nodiscard]] constexpr flag_const_rvalue_reference null_flag() const&& noexcept;
445
446 [[nodiscard]] constexpr reference get() & noexcept;
447 [[nodiscard]] constexpr const_reference get() const& noexcept;
448 [[nodiscard]] constexpr rvalue_reference get() && noexcept;
449 [[nodiscard]] constexpr const_rvalue_reference get() const&& noexcept;
450
451 [[nodiscard]] constexpr reference value() &;
452 [[nodiscard]] constexpr const_reference value() const&;
453 [[nodiscard]] constexpr rvalue_reference value() &&;
454 [[nodiscard]] constexpr const_rvalue_reference value() const&&;
455
456 template <class U>
457 [[nodiscard]] constexpr value_type value_or(U&& default_value) const&;
458
459 template <class U>
460 [[nodiscard]] constexpr value_type value_or(U&& default_value) &&;
461
462 void swap(self_type& other) noexcept;
463 void reset() noexcept;
464
465 private:
466
467 void throw_if_null() const;
468
469 T m_value;
470 B m_null_flag;
471
472 template <class TO, mpl::boolean_like BO>
473 friend class nullable;
474 };
475
476 template <class T, class B>
477 constexpr void swap(nullable<T, B>& lhs, nullable<T, B>& rhs) noexcept;
478
479 template <class T, class B>
480 constexpr bool operator==(const nullable<T, B>& lhs, nullval_t) noexcept;
481
482 template <class T, mpl::boolean_like B>
483 constexpr std::strong_ordering operator<=>(const nullable<T, B>& lhs, nullval_t) noexcept;
484
485 template <class T, class B, class U>
486 constexpr bool operator==(const nullable<T, B>& lhs, const U& rhs) noexcept;
487
488 template <class T, class B, class U>
489 requires(!impl::is_nullable_v<U> && std::three_way_comparable_with<U, T>)
490 constexpr std::compare_three_way_result_t<T, U>
491 operator<=>(const nullable<T, B>& lhs, const U& rhs) noexcept;
492
493 template <class T, class B, class U, class UB>
494 constexpr bool operator==(const nullable<T, B>& lhs, const nullable<U, UB>& rhs) noexcept;
495
496 template <class T, class B, std::three_way_comparable_with<T> U, class UB>
497 constexpr std::compare_three_way_result_t<T, U>
498 operator<=>(const nullable<T, B>& lhs, const nullable<U, UB>& rhs) noexcept;
499
500 // Even if we have CTAD in C++20, some constructors add lvalue reference
501 // to their argument, making the deduction impossible.
502 template <class T, mpl::boolean_like B = bool>
503 constexpr nullable<T, B> make_nullable(T&& value, B&& flag = true);
504
510 template <class... T>
511 requires(is_nullable_v<T> && ...)
512 class nullable_variant : public std::variant<T...>
513 {
514 public:
515
516 using base_type = std::variant<T...>;
517 using base_type::base_type;
518
519 constexpr nullable_variant(const nullable_variant&) = default;
520 constexpr nullable_variant(nullable_variant&&) noexcept = default;
521
522 constexpr nullable_variant& operator=(const nullable_variant&);
523 constexpr nullable_variant& operator=(nullable_variant&&);
524
525 constexpr explicit operator bool() const;
526 constexpr bool has_value() const;
527 };
528}
529
530namespace std
531{
532 namespace mpl = sparrow::mpl;
533
534 // Specialization of basic_common_reference for nullable proxies so
535 // we can use ranges algorithm on iterators returning nullable
536 template <class T, mpl::boolean_like TB, class U, mpl::boolean_like UB, template <class> class TQual, template <class> class UQual>
537 struct basic_common_reference<sparrow::nullable<T, TB>, sparrow::nullable<U, UB>, TQual, UQual>
538 {
539 using type = sparrow::
540 nullable<std::common_reference_t<TQual<T>, UQual<U>>, std::common_reference_t<TQual<TB>, UQual<UB>>>;
541 };
542}
543
544namespace sparrow
545{
546 /***************************
547 * nullable implementation *
548 ***************************/
549
550 template <class T, mpl::boolean_like B>
551 constexpr nullable<T, B>::operator bool() const noexcept
552 {
553 return m_null_flag;
554 }
555
556 template <class T, mpl::boolean_like B>
557 constexpr bool nullable<T, B>::has_value() const noexcept
558 {
559 return m_null_flag;
560 }
561
562 template <class T, mpl::boolean_like B>
563 constexpr auto nullable<T, B>::null_flag() & noexcept -> flag_reference
564 {
565 return m_null_flag;
566 }
567
568 template <class T, mpl::boolean_like B>
569 constexpr auto nullable<T, B>::null_flag() const& noexcept -> flag_const_reference
570 {
571 return m_null_flag;
572 }
573
574 template <class T, mpl::boolean_like B>
575 constexpr auto nullable<T, B>::null_flag() && noexcept -> flag_rvalue_reference
576 {
577 if constexpr (std::is_reference_v<B>)
578 {
579 return m_null_flag;
580 }
581 else
582 {
583 return flag_rvalue_reference(m_null_flag);
584 }
585 }
586
587 template <class T, mpl::boolean_like B>
588 constexpr auto nullable<T, B>::null_flag() const&& noexcept -> flag_const_rvalue_reference
589 {
590 if constexpr (std::is_reference_v<B>)
591 {
592 return m_null_flag;
593 }
594 else
595 {
596 return flag_const_rvalue_reference(m_null_flag);
597 }
598 }
599
600 template <class T, mpl::boolean_like B>
601 constexpr auto nullable<T, B>::get() & noexcept -> reference
602 {
603 return m_value;
604 }
605
606 template <class T, mpl::boolean_like B>
607 constexpr auto nullable<T, B>::get() const& noexcept -> const_reference
608 {
609 return m_value;
610 }
611
612 template <class T, mpl::boolean_like B>
613 constexpr auto nullable<T, B>::get() && noexcept -> rvalue_reference
614 {
615 if constexpr (std::is_reference_v<T>)
616 {
617 return m_value;
618 }
619 else
620 {
621 return rvalue_reference(m_value);
622 }
623 }
624
625 template <class T, mpl::boolean_like B>
626 constexpr auto nullable<T, B>::get() const&& noexcept -> const_rvalue_reference
627 {
628 if constexpr (std::is_reference_v<T>)
629 {
630 return m_value;
631 }
632 else
633 {
634 return const_rvalue_reference(m_value);
635 }
636 }
637
638 template <class T, mpl::boolean_like B>
639 constexpr auto nullable<T, B>::value() & -> reference
640 {
641 throw_if_null();
642 return get();
643 }
644
645 template <class T, mpl::boolean_like B>
646 constexpr auto nullable<T, B>::value() const& -> const_reference
647 {
648 throw_if_null();
649 return get();
650 }
651
652 template <class T, mpl::boolean_like B>
654 {
655 throw_if_null();
656 return std::move(*this).get();
657 }
658
659 template <class T, mpl::boolean_like B>
661 {
662 throw_if_null();
663 return std::move(*this).get();
664 }
665
666 template <class T, mpl::boolean_like B>
667 template <class U>
668 constexpr auto nullable<T, B>::value_or(U&& default_value) const& -> value_type
669 {
670 return *this ? get() : value_type(std::forward<U>(default_value));
671 }
672
673 template <class T, mpl::boolean_like B>
674 template <class U>
675 constexpr auto nullable<T, B>::value_or(U&& default_value) && -> value_type
676 {
677 return *this ? get() : value_type(std::forward<U>(default_value));
678 }
679
680 template <class T, mpl::boolean_like B>
681 void nullable<T, B>::swap(self_type& other) noexcept
682 {
683 using std::swap;
684 swap(m_value, other.m_value);
685 swap(m_null_flag, other.m_null_flag);
686 }
687
688 template <class T, mpl::boolean_like B>
689 void nullable<T, B>::reset() noexcept
690 {
691 m_null_flag = false;
692 }
693
694 template <class T, mpl::boolean_like B>
695 void nullable<T, B>::throw_if_null() const
696 {
697 if (!m_null_flag)
698 {
699 throw bad_nullable_access{};
700 }
701 }
702
703 template <class T, class B>
704 constexpr void swap(nullable<T, B>& lhs, nullable<T, B>& rhs) noexcept
705 {
706 lhs.swap(rhs);
707 }
708
709 template <class T, class B>
710 constexpr bool operator==(const nullable<T, B>& lhs, nullval_t) noexcept
711 {
712 return !lhs;
713 }
714
715 template <class T, class B>
716 constexpr std::strong_ordering operator<=>(const nullable<T, B>& lhs, nullval_t) noexcept
717 {
718 return lhs <=> false;
719 }
720
721 template <class T, class B, class U>
722 constexpr bool operator==(const nullable<T, B>& lhs, const U& rhs) noexcept
723 {
724 return lhs && (lhs.get() == rhs);
725 }
726
727 template <class T, class B, class U>
728 requires(!impl::is_nullable_v<U> && std::three_way_comparable_with<U, T>)
729 constexpr std::compare_three_way_result_t<T, U> operator<=>(const nullable<T, B>& lhs, const U& rhs) noexcept
730 {
731 return lhs ? lhs.get() <=> rhs : std::strong_ordering::less;
732 }
733
734 template <class T, class B, class U, class UB>
735 constexpr bool operator==(const nullable<T, B>& lhs, const nullable<U, UB>& rhs) noexcept
736 {
737 return rhs ? lhs == rhs.get() : !lhs;
738 }
739
740 template <class T, class B, std::three_way_comparable_with<T> U, class UB>
741 constexpr std::compare_three_way_result_t<T, U>
742 operator<=>(const nullable<T, B>& lhs, const nullable<U, UB>& rhs) noexcept
743 {
744 return (lhs && rhs) ? lhs.get() <=> rhs.get() : bool(lhs) <=> bool(rhs);
745 }
746
747 template <class T, mpl::boolean_like B>
748 constexpr nullable<T, B> make_nullable(T&& value, B&& flag)
749 {
750 return nullable<T, B>(std::forward<T>(value), std::forward<B>(flag));
751 }
752
753 /***********************************
754 * nullable_variant implementation *
755 ***********************************/
756
757 template <class... T>
758 requires(is_nullable_v<T> && ...)
759 constexpr nullable_variant<T...>& nullable_variant<T...>::operator=(const nullable_variant& rhs)
760 {
761 base_type::operator=(rhs);
762 return *this;
763 }
764
765 template <class... T>
766 requires(is_nullable_v<T> && ...)
767 constexpr nullable_variant<T...>& nullable_variant<T...>::operator=(nullable_variant&& rhs)
768 {
769 base_type::operator=(std::move(rhs));
770 return *this;
771 }
772
773 template <class... T>
774 requires(is_nullable_v<T> && ...)
775 constexpr nullable_variant<T...>::operator bool() const
776 {
777 return has_value();
778 }
779
780 template <class... T>
781 requires(is_nullable_v<T> && ...)
782 constexpr bool nullable_variant<T...>::has_value() const
783 {
784 return std::visit(
785 [](const auto& v)
786 {
787 return v.has_value();
788 },
789 *this
790 );
791 }
792}
793
794#if defined(__cpp_lib_format)
795
796template <typename T, sparrow::mpl::boolean_like B>
797struct std::formatter<sparrow::nullable<T, B>>
798{
799 constexpr auto parse(format_parse_context& ctx)
800 {
801 auto pos = ctx.begin();
802 while (pos != ctx.end() && *pos != '}')
803 {
804 m_format_string.push_back(*pos);
805 ++pos;
806 }
807 m_format_string.push_back('}');
808 return pos;
809 }
810
811 auto format(const sparrow::nullable<T, B>& n, std::format_context& ctx) const
812 {
813 if (n.has_value())
814 {
815 return std::vformat_to(ctx.out(), m_format_string, std::make_format_args(n.get()));
816 }
817 else
818 {
819 return std::format_to(ctx.out(), "{}", "null");
820 }
821 }
822
823 std::string m_format_string = "{:";
824};
825
826template <typename T, sparrow::mpl::boolean_like B>
827std::ostream& operator<<(std::ostream& os, const sparrow::nullable<T, B>& value)
828{
829 os << std::format("{}", value);
830 return os;
831}
832
833template <class... T>
834struct std::formatter<sparrow::nullable_variant<T...>>
835{
836 constexpr auto parse(format_parse_context& ctx)
837 {
838 auto pos = ctx.begin();
839 while (pos != ctx.end() && *pos != '}')
840 {
841 m_format_string.push_back(*pos);
842 ++pos;
843 }
844 m_format_string.push_back('}');
845 return pos;
846 }
847
848 auto format(const sparrow::nullable_variant<T...>& variant, std::format_context& ctx) const
849 {
850 if (variant.has_value())
851 {
852 return std::visit(
853 [&](const auto& value)
854 {
855 return std::vformat_to(ctx.out(), m_format_string, std::make_format_args(value));
856 },
857 variant
858 );
859 }
860 else
861 {
862 return std::format_to(ctx.out(), "{}", "null");
863 }
864 }
865
866 std::string m_format_string = "{:";
867};
868
869template <class... T>
870std::ostream& operator<<(std::ostream& os, const sparrow::nullable_variant<T...>& value)
871{
872 os << std::format("{}", value);
873 return os;
874}
875
876
877#endif
878
879#undef SPARROW_CONSTEXPR
const char * what() const noexcept override
Definition nullable.hpp:127
bad_nullable_access() noexcept=default
constexpr nullable_variant(nullable_variant &&) noexcept=default
constexpr nullable_variant(const nullable_variant &)=default
constexpr bool has_value() const
Definition nullable.hpp:782
std::variant< T... > base_type
Definition nullable.hpp:516
The nullable class models a value or a reference that can be "null", or missing, like values traditio...
Definition nullable.hpp:280
nullable_traits< bool > flag_traits
Definition nullable.hpp:290
explicit(not std::convertible_to< U &&, inner_value_type >) const expr nullable(U &&value) noexcept(noexcept(inner_value_type(std::declval< U >())))
Definition nullable.hpp:313
constexpr nullable(std::add_lvalue_reference_t< T > value, flag_type &&null_flag)
Definition nullable.hpp:385
typename value_traits::const_reference const_reference
Definition nullable.hpp:287
constexpr nullable(value_type &&value, flag_type &&null_flag)
Definition nullable.hpp:367
constexpr nullable() noexcept
Definition nullable.hpp:298
friend class nullable
Definition nullable.hpp:473
typename flag_traits::reference flag_reference
Definition nullable.hpp:292
constexpr nullable(nullval_t) noexcept
Definition nullable.hpp:305
typename flag_traits::const_reference flag_const_reference
Definition nullable.hpp:293
constexpr self_type & operator=(nullval_t)
Definition nullable.hpp:391
typename flag_traits::value_type flag_type
Definition nullable.hpp:291
nullable< inner_value_type, bool > self_type
Definition nullable.hpp:283
constexpr bool has_value() const noexcept
void swap(self_type &other) noexcept
constexpr reference get() &noexcept
typename value_traits::rvalue_reference rvalue_reference
Definition nullable.hpp:288
typename value_traits::value_type value_type
Definition nullable.hpp:285
constexpr nullable(value_type &&value, std::add_lvalue_reference_t< B > null_flag)
Definition nullable.hpp:379
constexpr value_type value_or(U &&default_value) const &
constexpr nullable(const self_type &)=default
typename flag_traits::const_rvalue_reference flag_const_rvalue_reference
Definition nullable.hpp:295
constexpr self_type & operator=(self_type &&rhs)
Definition nullable.hpp:422
constexpr flag_reference null_flag() &noexcept
typename flag_traits::rvalue_reference flag_rvalue_reference
Definition nullable.hpp:294
typename value_traits::reference reference
Definition nullable.hpp:286
constexpr nullable(std::add_lvalue_reference_t< T > value, std::add_lvalue_reference_t< B > null_flag)
Definition nullable.hpp:373
nullable_traits< inner_value_type > value_traits
Definition nullable.hpp:284
constexpr nullable(self_type &&) noexcept=default
typename value_traits::const_rvalue_reference const_rvalue_reference
Definition nullable.hpp:289
constexpr self_type & operator=(const self_type &rhs)
Definition nullable.hpp:406
Concepts used to disambiguate the nullable class constructors.
Definition nullable.hpp:160
static constexpr bool is_nullable_v
Definition nullable.hpp:216
std::conditional_t< std::is_reference_v< T >, const std::decay_t< U > &, std::decay_t< U > && > conditional_ref_t
Definition nullable.hpp:189
constexpr bool is_type_instance_of_v
true if T is a concrete type template instanciation of U which is a type template.
Definition mp_utils.hpp:50
typename add_const_lvalue_reference< T >::type add_const_lvalue_reference_t
Definition mp_utils.hpp:373
constexpr std::compare_three_way_result_t< typename cloning_ptr< T1 >::pointer, typename cloning_ptr< T2 >::pointer > operator<=>(const cloning_ptr< T1 > &lhs, const cloning_ptr< T2 > &rhs) noexcept
Definition memory.hpp:475
SPARROW_API bool operator==(const array &lhs, const array &rhs)
Compares the content of two arrays.
SPARROW_API void swap(ArrowArray &lhs, ArrowArray &rhs)
Swaps the contents of the two ArrowArray objects.
constexpr nullval_t nullval(0)
constexpr bool is_nullable_v
Definition nullable.hpp:60
std::ostream & operator<<(std::ostream &stream, T n)
Definition large_int.hpp:93
constexpr nullable< T, B > make_nullable(T &&value, B &&flag=true)
Definition nullable.hpp:748
#define SPARROW_CONSTEXPR
Definition nullable.hpp:41
const_reference const_rvalue_reference
Definition nullable.hpp:112
std::add_lvalue_reference_t< value_type > reference
Definition nullable.hpp:109
std::add_lvalue_reference_t< std::add_const_t< value_type > > const_reference
Definition nullable.hpp:110
const value_type && const_rvalue_reference
Definition nullable.hpp:102
std::add_lvalue_reference_t< value_type > reference
Definition nullable.hpp:99
value_type && rvalue_reference
Definition nullable.hpp:101
std::add_lvalue_reference_t< std::add_const_t< value_type > > const_reference
Definition nullable.hpp:100
nullval_t is an empty class used to indicate that a nullable is null.
Definition nullable.hpp:141
constexpr nullval_t(int)
Definition nullable.hpp:147
sparrow:: nullable< std::common_reference_t< TQual< T >, UQual< U > >, std::common_reference_t< TQual< TB >, UQual< UB > > > type
Definition nullable.hpp:539