20#if defined(__cpp_lib_format)
31#if defined(SPARROW_CONSTEXPR)
32# error "SPARROW_CONSTEXPR already defined"
39#if defined(__clang__) && not defined(_LIBCPP_VERSION)
40# define SPARROW_CONSTEXPR
42# define SPARROW_CONSTEXPR constexpr
47 template <
class T, mpl::
boolean_like B>
55 template <
class T, mpl::
boolean_like B>
63 template <
class N,
class T>
66 template <
class N,
class T>
76 template <
class RangeOfNullables>
100 using reference = std::add_lvalue_reference_t<value_type>;
110 using reference = std::add_lvalue_reference_t<value_type>;
128 [[nodiscard]] const
char*
what() const noexcept
override
135 static constexpr const char* message =
"Invalid access to nullable underlying value";
160 template <
class T,
class TArgs,
class U,
class UArgs>
162 and std::constructible_from<U, mpl::add_const_lvalue_reference_t<UArgs>>;
164 template <
class To1,
class From1,
class To2,
class From2>
166 and std::convertible_to<mpl::add_const_lvalue_reference_t<From2>, To2>;
168 template <
class T,
class... Args>
171 template <
class T,
class... Args>
174 template <
class T,
class... Args>
177 template <
class T,
class Arg>
183 template <
class To,
class... Args>
186 template <
class T,
class Arg>
189 template <
class T,
class U>
190 using conditional_ref_t = std::conditional_t<std::is_reference_v<T>,
const std::decay_t<U>&, std::decay_t<U>&&>;
192 template <
class T,
class Targs,
class U,
class UArgs>
194 and std::constructible_from<U, conditional_ref_t<U, UArgs>>;
196 template <
class To1,
class From1,
class To2,
class From2>
198 and std::convertible_to<conditional_ref_t<To2, From2>, To2>;
200 template <
class To1,
class From1,
class To2,
class From2>
202 std::add_lvalue_reference_t<To1>,
204 and std::is_assignable_v<
205 std::add_lvalue_reference_t<To2>,
208 template <
class To1,
class From1,
class To2,
class From2>
210 std::add_lvalue_reference_t<To1>,
212 and std::is_assignable_v<
213 std::add_lvalue_reference_t<To2>,
279 template <
class T, mpl::
boolean_like B =
bool>
298 template <std::default_initializable U = T, std::default_initializable BB = B>
305 template <std::default_initializable U = T, std::default_initializable BB = B>
313 requires(not std::same_as<self_type, std::decay_t<U>> and std::constructible_from<T, U &&>)
314 explicit(not std::convertible_to<U&&, T>)
constexpr nullable(U&&
value)
noexcept(
315 noexcept(T(std::declval<U>()))
324 template <
class TO, mpl::
boolean_like BO>
336 template <
class TO, mpl::
boolean_like BO>
349 template <class TO,
mpl::boolean_like BO>
350 requires(
impl::both_constructible_from_cond_ref<T, TO, B, BO>
351 and not
impl::initializable_from_refs<T,
nullable<TO, BO>>)
361 template <
class TO, mpl::
boolean_like BO>
363 and std::same_as<std::decay_t<T>,
bool>)
404 requires(not std::same_as<self_type, TO> and std::assignable_from<std::add_lvalue_reference_t<T>, TO>)
407 m_value = std::forward<TO>(
rhs);
415 m_null_flag =
rhs.null_flag();
419 template <
class TO, mpl::
boolean_like BO>
428 m_null_flag =
rhs.null_flag();
434 m_value = std::move(
rhs).get();
435 m_null_flag = std::move(
rhs).null_flag();
439 template <
class TO, mpl::
boolean_like BO>
447 m_value = std::move(
rhs).get();
448 m_null_flag = std::move(
rhs).null_flag();
452 constexpr explicit operator bool() const noexcept;
453 [[nodiscard]] constexpr
bool has_value() const noexcept;
481 void throw_if_null() const;
486 template <class TO,
mpl::boolean_like BO>
490 template <class T, class B>
493 template <class T, class B>
496 template <class T,
mpl::boolean_like B>
499 template <class T, class B, class U>
500 constexpr
bool operator==(const
nullable<T, B>& lhs, const U&
rhs) noexcept;
502 template <class T, class B, class U>
504 constexpr
std::compare_three_way_result_t<T, U>
505 operator<=>(const
nullable<T, B>& lhs, const U&
rhs) noexcept;
507 template <class T, class B, class U, class UB>
510 template <class T, class B,
std::three_way_comparable_with<T> U, class UB>
511 constexpr
std::compare_three_way_result_t<T, U>
516 template <class T,
mpl::boolean_like B =
bool>
531 template <
class... T>
538 using base_type::base_type;
546 constexpr explicit operator
bool() const;
557 template <
class T, mpl::
boolean_like TB,
class U, mpl::
boolean_like UB,
template <
class>
class TQual,
template <
class>
class UQual>
561 nullable<std::common_reference_t<TQual<T>, UQual<U>>, std::common_reference_t<TQual<TB>, UQual<UB>>>;
571 template <
class T, mpl::
boolean_like B>
577 template <
class T, mpl::
boolean_like B>
583 template <
class T, mpl::
boolean_like B>
589 template <
class T, mpl::
boolean_like B>
595 template <
class T, mpl::
boolean_like B>
598 if constexpr (std::is_reference_v<B>)
608 template <
class T, mpl::
boolean_like B>
611 if constexpr (std::is_reference_v<B>)
621 template <
class T, mpl::
boolean_like B>
627 template <
class T, mpl::
boolean_like B>
633 template <
class T, mpl::
boolean_like B>
636 if constexpr (std::is_reference_v<T>)
646 template <
class T, mpl::
boolean_like B>
649 if constexpr (std::is_reference_v<T>)
659 template <
class T, mpl::
boolean_like B>
666 template <
class T, mpl::
boolean_like B>
673 template <
class T, mpl::
boolean_like B>
677 return std::move(*this).get();
680 template <
class T, mpl::
boolean_like B>
684 return std::move(*this).get();
687 template <
class T, mpl::
boolean_like B>
691 return *
this ?
get() :
value_type(std::forward<U>(default_value));
694 template <
class T, mpl::
boolean_like B>
698 return *
this ?
get() :
value_type(std::forward<U>(default_value));
701 template <
class T, mpl::
boolean_like B>
705 swap(m_value, other.m_value);
706 swap(m_null_flag, other.m_null_flag);
709 template <
class T, mpl::
boolean_like B>
715 template <
class T, mpl::
boolean_like B>
716 void nullable<T, B>::throw_if_null()
const
724 template <
class T,
class B>
730 template <
class T,
class B>
736 template <
class T,
class B>
739 return lhs <=>
false;
742 template <
class T,
class B,
class U>
745 return lhs && (lhs.get() == rhs);
748 template <
class T,
class B,
class U>
752 return lhs ? lhs.
get() <=> rhs : std::strong_ordering::less;
755 template <
class T,
class B,
class U,
class UB>
758 return rhs ? lhs == rhs.
get() : !lhs;
761 template <
class T,
class B, std::three_way_comparable_with<T> U,
class UB>
762 constexpr std::compare_three_way_result_t<T, U>
765 return (lhs && rhs) ? lhs.
get() <=> rhs.get() : bool(lhs) <=> bool(rhs);
768 template <
class T, mpl::
boolean_like B>
771 return nullable<T, B>(std::forward<T>(value), std::forward<B>(flag));
774 template <std::ranges::range R,
typename T>
777 && std::is_same_v<typename std::ranges::range_value_t<R>::value_type, T>
781 for (
auto nullable_value : range)
783 if (!nullable_value.has_value())
785 nullable_value.get() = default_value;
794 template <
class... T>
798 base_type::operator=(rhs);
802 template <
class... T>
806 base_type::operator=(std::move(rhs));
810 template <
class... T>
817 template <
class... T>
824 return v.has_value();
826#if SPARROW_GCC_11_2_WORKAROUND
835#if defined(__cpp_lib_format)
837template <
typename T, sparrow::mpl::
boolean_like B>
838struct std::formatter<
sparrow::nullable<T, B>>
840 constexpr auto parse(format_parse_context& ctx)
842 auto pos = ctx.begin();
843 while (pos != ctx.end() && *pos !=
'}')
845 m_format_string.push_back(*pos);
848 m_format_string.push_back(
'}');
852 auto format(
const sparrow::nullable<T, B>& n, std::format_context& ctx)
const
856 return std::vformat_to(ctx.out(), m_format_string, std::make_format_args(n.
get()));
860 return std::format_to(ctx.out(),
"{}",
"null");
864 std::string m_format_string =
"{:";
867template <
typename T, sparrow::mpl::
boolean_like B>
868std::ostream&
operator<<(std::ostream& os,
const sparrow::nullable<T, B>& value)
870 os << std::format(
"{}", value);
875struct std::formatter<sparrow::nullable_variant<T...>>
877 constexpr auto parse(format_parse_context& ctx)
879 auto pos = ctx.begin();
880 while (pos != ctx.end() && *pos !=
'}')
882 m_format_string.push_back(*pos);
885 m_format_string.push_back(
'}');
889 auto format(
const sparrow::nullable_variant<T...>& variant, std::format_context& ctx)
const
894 [&](
const auto& value)
896 return std::vformat_to(ctx.out(), m_format_string, std::make_format_args(value));
903 return std::format_to(ctx.out(),
"{}",
"null");
907 std::string m_format_string =
"{:";
911std::ostream&
operator<<(std::ostream& os,
const sparrow::nullable_variant<T...>& value)
913 os << std::format(
"{}", value);
918struct std::formatter<sparrow::nullval_t>
920 constexpr auto parse(format_parse_context& ctx)
925 auto format(
const sparrow::nullval_t&, std::format_context& ctx)
const
927 return std::format_to(ctx.out(),
"nullval");
935 constexpr std::string_view nullval_str =
"nullval";
940#undef SPARROW_CONSTEXPR
const char * what() const noexcept override
bad_nullable_access() noexcept=default
constexpr nullable_variant(nullable_variant &&) noexcept=default
constexpr nullable_variant(const nullable_variant &)=default
constexpr bool has_value() const
std::variant< T... > base_type
The nullable class models a value or a reference that can be "null", or missing, like values traditio...
nullable_traits< bool > flag_traits
explicit(not std::convertible_to< U &&, inner_value_type >) const expr nullable(U &&value) noexcept(noexcept(inner_value_type(std::declval< U >())))
constexpr nullable(std::add_lvalue_reference_t< T > value, flag_type &&null_flag)
typename value_traits::const_reference const_reference
constexpr nullable(value_type &&value, flag_type &&null_flag)
constexpr nullable() noexcept
typename flag_traits::reference flag_reference
constexpr nullable(nullval_t) noexcept
typename flag_traits::const_reference flag_const_reference
typename flag_traits::value_type flag_type
nullable< inner_value_type, bool > self_type
constexpr reference value() &
constexpr bool has_value() const noexcept
void swap(self_type &other) noexcept
constexpr reference get() &noexcept
typename value_traits::rvalue_reference rvalue_reference
typename value_traits::value_type value_type
constexpr nullable(value_type &&value, std::add_lvalue_reference_t< B > null_flag)
constexpr self_type & operator=(const self_type &rhs) noexcept
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
constexpr self_type & operator=(nullval_t) noexcept
constexpr flag_reference null_flag() &noexcept
typename flag_traits::rvalue_reference flag_rvalue_reference
constexpr self_type & operator=(self_type &&rhs) noexcept
typename value_traits::reference reference
constexpr nullable(std::add_lvalue_reference_t< T > value, std::add_lvalue_reference_t< B > null_flag)
nullable_traits< inner_value_type > value_traits
constexpr nullable(self_type &&) noexcept=default
typename value_traits::const_rvalue_reference const_rvalue_reference
Concepts used to disambiguate the nullable class constructors.
static constexpr bool is_nullable_v
std::conditional_t< std::is_reference_v< T >, const std::decay_t< U > &, std::decay_t< U > && > conditional_ref_t
constexpr bool is_type_instance_of_v
true if T is a concrete type template instanciation of U which is a type template.
typename add_const_lvalue_reference< T >::type add_const_lvalue_reference_t
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
constexpr void zero_null_values(R &range, const T &default_value=T{})
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
constexpr nullable< T, B > make_nullable(T &&value, B &&flag=true)
std::ostream & operator<<(std::ostream &os, const sparrow::nullval_t &)
#define SPARROW_CONSTEXPR
const_reference const_rvalue_reference
reference rvalue_reference
std::add_lvalue_reference_t< value_type > reference
std::add_lvalue_reference_t< std::add_const_t< value_type > > const_reference
const value_type && const_rvalue_reference
std::add_lvalue_reference_t< value_type > reference
value_type && rvalue_reference
std::add_lvalue_reference_t< std::add_const_t< value_type > > const_reference
nullval_t is an empty class used to indicate that a nullable is null.
sparrow:: nullable< std::common_reference_t< TQual< T >, UQual< U > >, std::common_reference_t< TQual< TB >, UQual< UB > > > type