21#if __has_include(<format>)
32#if defined(SPARROW_CONSTEXPR)
33# error "SPARROW_CONSTEXPR already defined"
40#if defined(__clang__) && not defined(_LIBCPP_VERSION)
41# define SPARROW_CONSTEXPR
43# define SPARROW_CONSTEXPR constexpr
48 template <
class T, mpl::
boolean_like B>
56 template <
class T, mpl::
boolean_like B>
64 template <
class N,
class T>
67 template <
class N,
class T>
69 && std::convertible_to<typename N::stored_value_type, T>;
78 template <
class RangeOfNullables>
88 constexpr decltype(
auto)
operator()(N&& nullable_value)
const
90 if constexpr (std::is_lvalue_reference_v<N&&>)
92 return std::forward<N>(nullable_value).get();
96 using value_type = std::remove_cvref_t<decltype(std::forward<N>(nullable_value).get())>;
97 return value_type(std::forward<N>(nullable_value).get());
124 using reference = std::add_lvalue_reference_t<value_type>;
134 using reference = std::add_lvalue_reference_t<value_type>;
161 [[nodiscard]] const
char*
what() const noexcept
override
168 static constexpr const char* message =
"Invalid access to nullable underlying value";
207 template <
class T,
class TArgs,
class U,
class UArgs>
209 and std::constructible_from<U, mpl::add_const_lvalue_reference_t<UArgs>>;
211 template <
class To1,
class From1,
class To2,
class From2>
213 and std::convertible_to<mpl::add_const_lvalue_reference_t<From2>, To2>;
215 template <
class T,
class... Args>
218 template <
class T,
class... Args>
221 template <
class T,
class... Args>
224 template <
class T,
class Arg>
230 template <
class To,
class... Args>
233 template <
class T,
class Arg>
236 template <
class T,
class U>
237 using conditional_ref_t = std::conditional_t<std::is_reference_v<T>,
const std::decay_t<U>&, std::decay_t<U>&&>;
239 template <
class T,
class Targs,
class U,
class UArgs>
241 and std::constructible_from<U, conditional_ref_t<U, UArgs>>;
243 template <
class To1,
class From1,
class To2,
class From2>
245 and std::convertible_to<conditional_ref_t<To2, From2>, To2>;
247 template <
class To1,
class From1,
class To2,
class From2>
249 std::add_lvalue_reference_t<To1>,
251 and std::is_assignable_v<
252 std::add_lvalue_reference_t<To2>,
255 template <
class To1,
class From1,
class To2,
class From2>
257 std::add_lvalue_reference_t<To1>,
259 and std::is_assignable_v<
260 std::add_lvalue_reference_t<To2>,
310 template <
class T, mpl::
boolean_like B =
bool>
341 template <std::default_initializable U = T, std::default_initializable BB = B>
359 template <std::default_initializable U = T, std::default_initializable BB = B>
379 requires(not std::same_as<self_type, std::decay_t<U>> and std::constructible_from<T, U &&>)
380 explicit(not std::convertible_to<U&&, T>)
constexpr nullable(U&&
value)
noexcept(
381 noexcept(T(std::declval<U>()))
414 template <
class TO, mpl::
boolean_like BO>
446 template <
class TO, mpl::
boolean_like BO>
483 template <
class TO, mpl::
boolean_like BO>
516 template <
class TO, mpl::
boolean_like BO>
518 and std::same_as<std::decay_t<T>,
bool>)
599 template <
class U,
class V>
600 requires(std::same_as<std::remove_cvref_t<U>, T> && std::same_as<std::remove_cvref_t<V>, B>
601 && std::is_const_v<std::remove_reference_t<U>>
602 && not std::is_const_v<std::remove_reference_t<V>> && not std::is_reference_v<T>
603 && not std::is_reference_v<B> && std::is_lvalue_reference_v<U &&>
604 && std::is_lvalue_reference_v<V &&>)
624 template <
class U,
class V>
625 requires(std::same_as<std::remove_cvref_t<U>, T> && std::same_as<std::remove_cvref_t<V>, B>
626 && not std::is_reference_v<T> && not std::is_reference_v<B>
627 && (std::is_const_v<std::remove_reference_t<U>>
628 || std::is_const_v<std::remove_reference_t<V>>) )
665 requires(not std::same_as<self_type, TO> and std::assignable_from<std::add_lvalue_reference_t<T>, TO>)
668 m_value = std::forward<TO>(
rhs);
687 m_null_flag =
rhs.null_flag();
706 template <
class TO, mpl::
boolean_like BO>
732 m_value = std::move(
rhs).get();
733 m_null_flag = std::move(
rhs).null_flag();
752 template <
class TO, mpl::
boolean_like BO>
760 m_value = std::move(
rhs).get();
761 m_null_flag = std::move(
rhs).null_flag();
773 constexpr explicit operator bool() const noexcept;
783 [[nodiscard]] constexpr
bool has_value() const noexcept;
968 void throw_if_null() const;
973 template <class TO,
mpl::boolean_like BO>
988 template <class T, class B>
1002 template <class T, class B>
1017 template <class T,
mpl::boolean_like B>
1018 constexpr
std::strong_ordering operator<=>(const
nullable<T, B>& lhs,
nullval_t dummy) noexcept;
1033 template <class T, class B, class U>
1035 constexpr
bool operator==(const
nullable<T, B>& lhs, const U&
rhs) noexcept;
1051 template <class T, class B, class U>
1053 constexpr
std::compare_three_way_result_t<T, U>
1054 operator<=>(const
nullable<T, B>& lhs, const U&
rhs) noexcept;
1071 template <class T, class B, class U, class UB>
1072 requires(
mpl::weakly_equality_comparable_with<T, U>)
1073 constexpr
bool operator==(const
nullable<T, B>& lhs, const
nullable<U, UB>&
rhs) noexcept;
1091 template <class T, class B,
std::three_way_comparable_with<T> U, class UB>
1092 constexpr
std::compare_three_way_result_t<T, U>
1107 template <class T,
mpl::boolean_like B =
bool>
1140 template <
class... T>
1147 using base_type::base_type;
1149 template <
class U, mpl::
boolean_like B>
1150 requires((std::same_as<nullable<U, B>, T> || ...))
1188 constexpr explicit operator
bool() const;
1205 template <
class... T>
1220 template <
class T, mpl::
boolean_like TB,
class U, mpl::
boolean_like UB,
template <
class>
class TQual,
template <
class>
class UQual>
1221 requires std::common_reference_with<T, U> && std::common_reference_with<TB, UB>
1225 nullable<std::common_reference_t<TQual<T>, UQual<U>>, std::common_reference_t<TQual<TB>, UQual<UB>>>;
1235 template <
class T, mpl::
boolean_like B>
1241 template <
class T, mpl::
boolean_like B>
1247 template <
class T, mpl::
boolean_like B>
1253 template <
class T, mpl::
boolean_like B>
1259 template <
class T, mpl::
boolean_like B>
1262 if constexpr (std::is_reference_v<B>)
1272 template <
class T, mpl::
boolean_like B>
1275 if constexpr (std::is_reference_v<B>)
1285 template <
class T, mpl::
boolean_like B>
1291 template <
class T, mpl::
boolean_like B>
1297 template <
class T, mpl::
boolean_like B>
1300 if constexpr (std::is_reference_v<T>)
1310 template <
class T, mpl::
boolean_like B>
1313 if constexpr (std::is_reference_v<T>)
1323 template <
class T, mpl::
boolean_like B>
1330 template <
class T, mpl::
boolean_like B>
1337 template <
class T, mpl::
boolean_like B>
1341 return std::move(*this).get();
1344 template <
class T, mpl::
boolean_like B>
1348 return std::move(*this).get();
1351 template <
class T, mpl::
boolean_like B>
1355 return *
this ?
get() :
value_type(std::forward<U>(default_value));
1358 template <
class T, mpl::
boolean_like B>
1362 return *
this ?
get() :
value_type(std::forward<U>(default_value));
1365 template <
class T, mpl::
boolean_like B>
1369 swap(m_value, other.m_value);
1370 swap(m_null_flag, other.m_null_flag);
1373 template <
class T, mpl::
boolean_like B>
1376 m_null_flag =
false;
1379 template <
class T, mpl::
boolean_like B>
1380 void nullable<T, B>::throw_if_null()
const
1388 template <
class T,
class B>
1394 template <
class T,
class B>
1400 template <
class T,
class B>
1403 return lhs <=>
false;
1406 template <
class T,
class B,
class U>
1410 return lhs && (lhs.
get() == rhs);
1413 template <
class T,
class B,
class U>
1417 return lhs ? lhs.
get() <=> rhs : std::strong_ordering::less;
1420 template <
class T,
class B,
class U,
class UB>
1421 requires(mpl::weakly_equality_comparable_with<T, U>)
1424 return rhs ? lhs == rhs.
get() : !lhs;
1427 template <
class T,
class B, std::three_way_comparable_with<T> U,
class UB>
1428 constexpr std::compare_three_way_result_t<T, U>
1431 return (lhs && rhs) ? lhs.
get() <=> rhs.
get() : bool(lhs) <=> bool(rhs);
1434 template <
class T, mpl::
boolean_like B>
1437 return nullable<T, B>(std::forward<T>(value), std::forward<B>(flag));
1440 template <std::ranges::range R,
typename T>
1441 requires(nullable_of<std::ranges::range_value_t<R>, T>)
1444 for (
auto nullable_value : range)
1446 if (!nullable_value.has_value())
1448 nullable_value.get() = default_value;
1457 template <
class... T>
1461 base_type::operator=(rhs);
1465 template <
class... T>
1469 base_type::operator=(std::move(rhs));
1473 template <
class... T>
1480 template <
class... T>
1487 return v.has_value();
1489#if SPARROW_GCC_11_2_WORKAROUND
1498#if defined(__cpp_lib_format)
1500template <
typename T, sparrow::mpl::
boolean_like B>
1501struct std::formatter<
sparrow::nullable<T, B>>
1503 constexpr auto parse(format_parse_context& ctx)
1505 auto pos = ctx.begin();
1506 while (pos != ctx.end() && *pos !=
'}')
1508 m_format_string.push_back(*pos);
1511 m_format_string.push_back(
'}');
1515 auto format(
const sparrow::nullable<T, B>& n, std::format_context& ctx)
const
1519 return std::vformat_to(ctx.out(), m_format_string, std::make_format_args(n.
get()));
1523 return std::format_to(ctx.out(),
"{}",
"null");
1527 std::string m_format_string =
"{:";
1532 template <
typename T, mpl::
boolean_like B>
1533 std::ostream&
operator<<(std::ostream& os,
const nullable<T, B>& value)
1535 os << std::format(
"{}", value);
1540template <
class... T>
1541struct std::formatter<sparrow::nullable_variant<T...>>
1543 constexpr auto parse(format_parse_context& ctx)
1545 auto pos = ctx.begin();
1546 while (pos != ctx.end() && *pos !=
'}')
1548 m_format_string.push_back(*pos);
1551 m_format_string.push_back(
'}');
1555 auto format(
const sparrow::nullable_variant<T...>& variant, std::format_context& ctx)
const
1560 [&](
const auto& value)
1562 return std::vformat_to(ctx.out(), m_format_string, std::make_format_args(value));
1569 return std::vformat_to(ctx.out(), m_format_string, std::make_format_args(
"null"));
1573 std::string m_format_string =
"{:";
1578 template <
class... T>
1579 std::ostream&
operator<<(std::ostream& os,
const nullable_variant<T...>& value)
1581 os << std::format(
"{}", value);
1587struct std::formatter<sparrow::nullval_t>
1589 constexpr auto parse(format_parse_context& ctx)
1594 auto format(
const sparrow::nullval_t&, std::format_context& ctx)
const
1596 return std::format_to(ctx.out(),
"nullval");
1606 constexpr std::string_view nullval_str =
"nullval";
1612#undef SPARROW_CONSTEXPR
Exception thrown when accessing a null nullable value.
const char * what() const noexcept override
Gets the descriptive error message.
bad_nullable_access() noexcept=default
Variant of nullable types with has_value() convenience method.
constexpr nullable_variant(nullable_variant &&) noexcept=default
constexpr nullable_variant(const nullable_variant &)=default
constexpr bool has_value() const
Checks whether the active alternative contains a valid value.
std::variant< T... > base_type
constexpr nullable_variant(const nullable< U, B > &value)
constexpr nullable(const self_type &rhs)=default
Default copy constructor.
nullable_traits< B > flag_traits
constexpr nullable(std::add_lvalue_reference_t< T > value, flag_type &&null_flag)
Constructor from value reference and moved flag.
constexpr nullable(U &value, V &null_flag)
Constructor from const value and non-const flag reference (for non-reference types only).
typename value_traits::const_reference const_reference
constexpr nullable(value_type &&value, flag_type &&null_flag)
Constructor from value and flag.
constexpr nullable() noexcept
Default constructor creating a null nullable.
typename flag_traits::reference flag_reference
constexpr nullable(nullval_t) noexcept
Constructor from nullval_t creating a null nullable.
typename flag_traits::const_reference flag_const_reference
typename flag_traits::value_type flag_type
constexpr nullable(U &&value, V &&null_flag)
Constructor from two forwarding references (for value types with const qualifiers).
nullable< inner_const_reference, B > self_type
constexpr reference value() &
inner_const_reference stored_value_type
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)
Constructor from moved value and flag reference.
constexpr self_type & operator=(const self_type &rhs) noexcept
Default copy assignment operator.
constexpr value_type value_or(U &&default_value) const &
constexpr nullable(self_type &&rhs) noexcept=default
Default move constructor.
typename flag_traits::const_rvalue_reference flag_const_rvalue_reference
constexpr self_type & operator=(nullval_t) noexcept
Assignment from nullval_t, setting nullable to null state.
constexpr flag_reference null_flag() &noexcept
typename flag_traits::rvalue_reference flag_rvalue_reference
constexpr self_type & operator=(self_type &&rhs) noexcept
Default move assignment operator.
typename value_traits::reference reference
constexpr nullable(std::add_lvalue_reference_t< T > value, std::add_lvalue_reference_t< B > null_flag)
Constructor from lvalue references (for reference semantics).
nullable_traits< inner_const_reference > value_traits
typename value_traits::const_rvalue_reference const_rvalue_reference
Concepts used to disambiguate the nullable class constructors.
std::ostream & operator<<(std::ostream &stream, primesum::uint128_t n)
The __int128_t type (GCC/Clang) is not well supported by the C++ standard library (in 2016) so we hav...
std::conditional_t< std::is_reference_v< T >, const std::decay_t< U > &, std::decay_t< U > && > conditional_ref_t
typename add_const_lvalue_reference< T >::type add_const_lvalue_reference_t
Convenience alias for add_const_lvalue_reference.
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{})
Sets null values in a range to a default value.
SPARROW_API bool operator==(const array &lhs, const array &rhs)
Compares the content of two arrays.
constexpr nullval_t nullval(0)
constexpr nullable_get_fn nullable_get
constexpr bool is_nullable_variant_v
constexpr bool is_nullable_v
std::ostream & operator<<(std::ostream &os, const nullval_t &)
SPARROW_API void swap(ArrowArray &lhs, ArrowArray &rhs) noexcept
Swaps the contents of the two ArrowArray objects.
constexpr nullable< T, B > make_nullable(T &&value, B &&flag=true)
Creates a nullable object with deduced types.
Extensions to the C++ standard library.
#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
Sentinel type to indicate a nullable value is null.
constexpr nullval_t(int)
Private constructor to prevent default construction.
sparrow:: nullable< std::common_reference_t< TQual< T >, UQual< U > >, std::common_reference_t< TQual< TB >, UQual< UB > > > type