diff --git a/cpp/src/arrow/array/builder_primitive.h b/cpp/src/arrow/array/builder_primitive.h index 6d79d6e9649..8f9773db56f 100644 --- a/cpp/src/arrow/array/builder_primitive.h +++ b/cpp/src/arrow/array/builder_primitive.h @@ -88,9 +88,9 @@ class NumericBuilder using ArrayType = typename TypeTraits::ArrayType; template - explicit NumericBuilder( - enable_if_parameter_free pool = default_memory_pool(), - int64_t alignment = kDefaultBufferAlignment) + requires arrow_parameter_free + explicit NumericBuilder(MemoryPool* pool = default_memory_pool(), + int64_t alignment = kDefaultBufferAlignment) : ArrayBuilder(pool, alignment), type_(TypeTraits::type_singleton()), data_builder_(pool, alignment) {} @@ -268,8 +268,9 @@ class NumericBuilder /// or null(0) values. /// \return Status template - enable_if_t::value, Status> AppendValues( - ValuesIter values_begin, ValuesIter values_end, ValidIter valid_begin) { + requires(!std::is_pointer_v) + Status AppendValues(ValuesIter values_begin, ValuesIter values_end, + ValidIter valid_begin) { static_assert(!internal::is_null_pointer::value, "Don't pass a NULLPTR directly as valid_begin, use the 2-argument " "version instead"); @@ -285,8 +286,9 @@ class NumericBuilder // Same as above, with a pointer type ValidIter template - enable_if_t::value, Status> AppendValues( - ValuesIter values_begin, ValuesIter values_end, ValidIter valid_begin) { + requires std::is_pointer_v + Status AppendValues(ValuesIter values_begin, ValuesIter values_end, + ValidIter valid_begin) { int64_t length = static_cast(std::distance(values_begin, values_end)); ARROW_RETURN_NOT_OK(Reserve(length)); data_builder_.UnsafeAppend(values_begin, values_end); @@ -624,8 +626,9 @@ class ARROW_EXPORT BooleanBuilder /// or null(0) values /// \return Status template - enable_if_t::value, Status> AppendValues( - ValuesIter values_begin, ValuesIter values_end, ValidIter valid_begin) { + requires(!std::is_pointer_v) + Status AppendValues(ValuesIter values_begin, ValuesIter values_end, + ValidIter valid_begin) { static_assert(!internal::is_null_pointer::value, "Don't pass a NULLPTR directly as valid_begin, use the 2-argument " "version instead"); @@ -643,8 +646,9 @@ class ARROW_EXPORT BooleanBuilder // Same as above, for a pointer type ValidIter template - enable_if_t::value, Status> AppendValues( - ValuesIter values_begin, ValuesIter values_end, ValidIter valid_begin) { + requires std::is_pointer_v + Status AppendValues(ValuesIter values_begin, ValuesIter values_end, + ValidIter valid_begin) { int64_t length = static_cast(std::distance(values_begin, values_end)); ARROW_RETURN_NOT_OK(Reserve(length)); data_builder_.UnsafeAppend( diff --git a/cpp/src/arrow/compute/function_internal.h b/cpp/src/arrow/compute/function_internal.h index 7bea4043a5f..aafc76f3d04 100644 --- a/cpp/src/arrow/compute/function_internal.h +++ b/cpp/src/arrow/compute/function_internal.h @@ -17,6 +17,7 @@ #pragma once +#include #include #include #include @@ -97,16 +98,16 @@ ARROW_EXPORT Result> DeserializeFunctionOptions(const Buffer& buffer); template -static inline enable_if_t::value, std::string> GenericToString( - const T& value) { + requires(!has_enum_traits::value) +static inline std::string GenericToString(const T& value) { std::stringstream ss; ss << value; return ss.str(); } template -static inline enable_if_t::value, std::string> GenericToString( - const std::optional& value) { + requires(!has_enum_traits::value) +static inline std::string GenericToString(const std::optional& value) { return value.has_value() ? GenericToString(value.value()) : "nullopt"; } @@ -119,8 +120,8 @@ static inline std::string GenericToString(const std::string& value) { } template -static inline enable_if_t::value, std::string> GenericToString( - const T value) { + requires has_enum_traits::value +static inline std::string GenericToString(const T value) { return EnumTraits::value_name(value); } @@ -256,21 +257,20 @@ GenericTypeSingleton() { } template -static inline enable_if_same, - std::shared_ptr> -GenericTypeSingleton() { + requires std::same_as> +static inline std::shared_ptr GenericTypeSingleton() { return map(binary(), binary()); } template -static inline enable_if_t::value, std::shared_ptr> -GenericTypeSingleton() { + requires has_enum_traits::value +static inline std::shared_ptr GenericTypeSingleton() { return TypeTraits::Type>::type_singleton(); } template -static inline enable_if_same> -GenericTypeSingleton() { + requires std::same_as +static inline std::shared_ptr GenericTypeSingleton() { std::vector> fields; fields.emplace_back(new Field("target", GenericTypeSingleton())); fields.emplace_back(new Field("order", GenericTypeSingleton())); @@ -294,7 +294,8 @@ static inline Result> GenericToScalar(const FieldRef& re return MakeScalar(ref.ToDotPath()); } -template ::value>> +template + requires has_enum_traits::value static inline Result> GenericToScalar(const T value) { using CType = typename EnumTraits::CType; return GenericToScalar(static_cast(value)); @@ -389,8 +390,9 @@ static inline Result> GenericToScalar( } template -static inline enable_if_primitive_ctype::ArrowType, Result> -GenericFromScalar(const std::shared_ptr& value) { + requires requires { typename CTypeTraits::ArrowType; } && + is_primitive_ctype::ArrowType>::value +static inline Result GenericFromScalar(const std::shared_ptr& value) { using ArrowType = typename CTypeTraits::ArrowType; using ScalarType = typename TypeTraits::ScalarType; if (value->type->id() != ArrowType::type_id) { @@ -403,8 +405,8 @@ GenericFromScalar(const std::shared_ptr& value) { } template -static inline enable_if_primitive_ctype::Type, Result> -GenericFromScalar(const std::shared_ptr& value) { + requires is_primitive_ctype::Type>::value +static inline Result GenericFromScalar(const std::shared_ptr& value) { ARROW_ASSIGN_OR_RAISE(auto raw_val, GenericFromScalar::CType>(value)); return ValidateEnumValue(raw_val); @@ -414,8 +416,8 @@ template using enable_if_same_result = enable_if_same>; template -static inline enable_if_same_result GenericFromScalar( - const std::shared_ptr& value) { + requires std::same_as +static inline Result GenericFromScalar(const std::shared_ptr& value) { if (!is_base_binary_like(value->type->id())) { return Status::Invalid("Expected binary-like type but got ", value->type->ToString()); } @@ -425,15 +427,15 @@ static inline enable_if_same_result GenericFromScalar( } template -static inline enable_if_same_result GenericFromScalar( - const std::shared_ptr& value) { + requires std::same_as +static inline Result GenericFromScalar(const std::shared_ptr& value) { ARROW_ASSIGN_OR_RAISE(auto path, GenericFromScalar(value)); return FieldRef::FromDotPath(path); } template -static inline enable_if_same_result GenericFromScalar( - const std::shared_ptr& value) { + requires std::same_as +static inline Result GenericFromScalar(const std::shared_ptr& value) { if (value->type->id() != Type::STRUCT) { return Status::Invalid("Expected type STRUCT but got ", value->type->id()); } @@ -447,26 +449,26 @@ static inline enable_if_same_result GenericFromScalar( } template -static inline enable_if_same_result> GenericFromScalar( - const std::shared_ptr& value) { + requires std::same_as> +static inline Result GenericFromScalar(const std::shared_ptr& value) { return value->type; } template -static inline enable_if_same_result GenericFromScalar( - const std::shared_ptr& value) { + requires std::same_as +static inline Result GenericFromScalar(const std::shared_ptr& value) { return value->type; } template -static inline enable_if_same_result> GenericFromScalar( - const std::shared_ptr& value) { + requires std::same_as> +static inline Result GenericFromScalar(const std::shared_ptr& value) { return value; } template -static inline enable_if_same_result> -GenericFromScalar(const std::shared_ptr& value) { + requires std::same_as> +static inline Result GenericFromScalar(const std::shared_ptr& value) { auto ty = GenericTypeSingleton>(); if (!value->type->Equals(ty)) { return Status::Invalid("Expected ", ty->ToString(), " but got ", @@ -486,8 +488,8 @@ GenericFromScalar(const std::shared_ptr& value) { } template -static inline enable_if_same_result GenericFromScalar( - const std::shared_ptr& value) { + requires std::same_as +static inline Result GenericFromScalar(const std::shared_ptr& value) { if (value->type->id() == Type::LIST) { const auto& holder = checked_cast(*value); return holder.value; @@ -504,8 +506,8 @@ template <> constexpr inline bool is_optional_v = true; template -static inline std::enable_if_t, Result> GenericFromScalar( - const std::shared_ptr& value) { + requires is_optional_v +static inline Result GenericFromScalar(const std::shared_ptr& value) { using value_type = typename T::value_type; if (value->type->id() == Type::NA) { return std::nullopt; @@ -514,8 +516,9 @@ static inline std::enable_if_t, Result> GenericFromScalar( } template -static enable_if_same::ArrowType, ListType, Result> -GenericFromScalar(const std::shared_ptr& value) { + requires requires { typename CTypeTraits::ArrowType; } && + std::same_as::ArrowType, ListType> +static inline Result GenericFromScalar(const std::shared_ptr& value) { using ValueType = typename T::value_type; if (value->type->id() != Type::LIST) { return Status::Invalid("Expected type LIST but got ", value->type->ToString()); diff --git a/cpp/src/arrow/compute/kernels/aggregate_internal.h b/cpp/src/arrow/compute/kernels/aggregate_internal.h index 126f2891e21..e03398584db 100644 --- a/cpp/src/arrow/compute/kernels/aggregate_internal.h +++ b/cpp/src/arrow/compute/kernels/aggregate_internal.h @@ -33,43 +33,43 @@ namespace arrow::compute::internal { template struct FindAccumulatorType {}; -template -struct FindAccumulatorType> { +template +struct FindAccumulatorType { using Type = UInt64Type; }; -template -struct FindAccumulatorType> { +template +struct FindAccumulatorType { using Type = Int64Type; }; -template -struct FindAccumulatorType> { +template +struct FindAccumulatorType { using Type = UInt64Type; }; -template -struct FindAccumulatorType> { +template +struct FindAccumulatorType { using Type = DoubleType; }; -template -struct FindAccumulatorType> { +template +struct FindAccumulatorType { using Type = Decimal32Type; }; -template -struct FindAccumulatorType> { +template +struct FindAccumulatorType { using Type = Decimal64Type; }; -template -struct FindAccumulatorType> { +template +struct FindAccumulatorType { using Type = Decimal128Type; }; -template -struct FindAccumulatorType> { +template +struct FindAccumulatorType { using Type = Decimal256Type; }; @@ -86,8 +86,8 @@ struct MultiplyTraits { } }; -template -struct MultiplyTraits> { +template +struct MultiplyTraits { using CType = typename TypeTraits::CType; constexpr static CType one(const DataType& ty) { @@ -132,18 +132,18 @@ using arrow::internal::VisitSetBitRunsVoid; template struct GetSumType; -template -struct GetSumType> { +template +struct GetSumType { using SumType = double; }; -template -struct GetSumType> { +template +struct GetSumType { using SumType = arrow::internal::int128_t; }; -template -struct GetSumType> { +template +struct GetSumType { using SumType = typename TypeTraits::CType; }; @@ -156,8 +156,8 @@ struct GetSumType> { // https://en.wikipedia.org/wiki/Pairwise_summation template -enable_if_t::value, SumType> SumArray( - const ArraySpan& data, ValueFunc&& func) { + requires std::floating_point +SumType SumArray(const ArraySpan& data, ValueFunc&& func) { using arrow::internal::VisitSetBitRunsVoid; const int64_t data_size = data.length - data.GetNullCount(); @@ -234,8 +234,8 @@ enable_if_t::value, SumType> SumArray( // naive summation for integers and decimals template -enable_if_t::value, SumType> SumArray( - const ArraySpan& data, ValueFunc&& func) { + requires(!std::floating_point) +SumType SumArray(const ArraySpan& data, ValueFunc&& func) { using arrow::internal::VisitSetBitRunsVoid; SumType sum = 0; diff --git a/cpp/src/arrow/compute/kernels/base_arithmetic_internal.h b/cpp/src/arrow/compute/kernels/base_arithmetic_internal.h index b4840061ae7..e54e0b93c68 100644 --- a/cpp/src/arrow/compute/kernels/base_arithmetic_internal.h +++ b/cpp/src/arrow/compute/kernels/base_arithmetic_internal.h @@ -18,6 +18,7 @@ #pragma once #include +#include #include #include "arrow/compute/api_scalar.h" #include "arrow/compute/kernels/common_internal.h" @@ -44,33 +45,34 @@ namespace internal { struct Add { template - static constexpr enable_if_floating_value Call(KernelContext*, Arg0 left, Arg1 right, - Status*) { + requires floating_value + static constexpr T Call(KernelContext*, Arg0 left, Arg1 right, Status*) { return left + right; } template - static constexpr enable_if_unsigned_integer_value Call(KernelContext*, Arg0 left, - Arg1 right, Status*) { + requires unsigned_integer_value + static constexpr T Call(KernelContext*, Arg0 left, Arg1 right, Status*) { return left + right; } template - static constexpr enable_if_signed_integer_value Call(KernelContext*, Arg0 left, - Arg1 right, Status*) { + requires signed_integer_value + static constexpr T Call(KernelContext*, Arg0 left, Arg1 right, Status*) { return arrow::internal::SafeSignedAdd(left, right); } template - static enable_if_decimal_value Call(KernelContext*, Arg0 left, Arg1 right, Status*) { + requires decimal_value + static T Call(KernelContext*, Arg0 left, Arg1 right, Status*) { return left + right; } }; struct AddChecked { template - static enable_if_integer_value Call(KernelContext*, Arg0 left, Arg1 right, - Status* st) { + requires integer_value + static T Call(KernelContext*, Arg0 left, Arg1 right, Status* st) { static_assert(std::is_same::value && std::is_same::value, ""); T result = 0; if (ARROW_PREDICT_FALSE(AddWithOverflow(left, right, &result))) { @@ -80,14 +82,15 @@ struct AddChecked { } template - static enable_if_floating_value Call(KernelContext*, Arg0 left, Arg1 right, - Status*) { + requires floating_value + static T Call(KernelContext*, Arg0 left, Arg1 right, Status*) { static_assert(std::is_same::value && std::is_same::value, ""); return left + right; } template - static enable_if_decimal_value Call(KernelContext*, Arg0 left, Arg1 right, Status*) { + requires decimal_value + static T Call(KernelContext*, Arg0 left, Arg1 right, Status*) { return left + right; } }; @@ -125,34 +128,34 @@ struct AddTimeDurationChecked { struct AbsoluteValue { template - static constexpr enable_if_floating_value Call(KernelContext*, Arg arg, - Status*) { + requires floating_value + static constexpr T Call(KernelContext*, Arg arg, Status*) { return std::fabs(arg); } template - static constexpr enable_if_unsigned_integer_value Call(KernelContext*, Arg arg, - Status*) { + requires unsigned_integer_value + static constexpr T Call(KernelContext*, Arg arg, Status*) { return arg; } template - static constexpr enable_if_signed_integer_value Call(KernelContext*, Arg arg, - Status* st) { + requires signed_integer_value + static constexpr T Call(KernelContext*, Arg arg, Status* st) { return (arg < 0) ? arrow::internal::SafeSignedNegate(arg) : arg; } template - static constexpr enable_if_decimal_value Call(KernelContext*, Arg arg, - Status*) { + requires decimal_value + static constexpr T Call(KernelContext*, Arg arg, Status*) { return arg.Abs(); } }; struct AbsoluteValueChecked { template - static enable_if_signed_integer_value Call(KernelContext*, Arg arg, - Status* st) { + requires signed_integer_value + static T Call(KernelContext*, Arg arg, Status* st) { static_assert(std::is_same::value, ""); if (arg == std::numeric_limits::min()) { *st = Status::Invalid("overflow"); @@ -162,57 +165,58 @@ struct AbsoluteValueChecked { } template - static enable_if_unsigned_integer_value Call(KernelContext* ctx, Arg arg, - Status* st) { + requires unsigned_integer_value + static T Call(KernelContext* ctx, Arg arg, Status* st) { static_assert(std::is_same::value, ""); return arg; } template - static constexpr enable_if_floating_value Call(KernelContext*, Arg arg, - Status* st) { + requires floating_value + static constexpr T Call(KernelContext*, Arg arg, Status* st) { static_assert(std::is_same::value, ""); return std::fabs(arg); } template - static constexpr enable_if_decimal_value Call(KernelContext*, Arg arg, - Status*) { + requires decimal_value + static constexpr T Call(KernelContext*, Arg arg, Status*) { return arg.Abs(); } }; struct Subtract { template - static constexpr enable_if_floating_value Call(KernelContext*, Arg0 left, Arg1 right, - Status*) { + requires floating_value + static constexpr T Call(KernelContext*, Arg0 left, Arg1 right, Status*) { static_assert(std::is_same::value && std::is_same::value, ""); return left - right; } template - static constexpr enable_if_unsigned_integer_value Call(KernelContext*, Arg0 left, - Arg1 right, Status*) { + requires unsigned_integer_value + static constexpr T Call(KernelContext*, Arg0 left, Arg1 right, Status*) { static_assert(std::is_same::value && std::is_same::value, ""); return left - right; } template - static constexpr enable_if_signed_integer_value Call(KernelContext*, Arg0 left, - Arg1 right, Status*) { + requires signed_integer_value + static constexpr T Call(KernelContext*, Arg0 left, Arg1 right, Status*) { return arrow::internal::SafeSignedSubtract(left, right); } template - static enable_if_decimal_value Call(KernelContext*, Arg0 left, Arg1 right, Status*) { + requires decimal_value + static T Call(KernelContext*, Arg0 left, Arg1 right, Status*) { return left + (-right); } }; struct SubtractChecked { template - static enable_if_integer_value Call(KernelContext*, Arg0 left, Arg1 right, - Status* st) { + requires integer_value + static T Call(KernelContext*, Arg0 left, Arg1 right, Status* st) { T result = 0; if (ARROW_PREDICT_FALSE(SubtractWithOverflow(left, right, &result))) { *st = Status::Invalid("overflow"); @@ -221,14 +225,15 @@ struct SubtractChecked { } template - static enable_if_floating_value Call(KernelContext*, Arg0 left, Arg1 right, - Status*) { + requires floating_value + static T Call(KernelContext*, Arg0 left, Arg1 right, Status*) { static_assert(std::is_same::value && std::is_same::value, ""); return left - right; } template - static enable_if_decimal_value Call(KernelContext*, Arg0 left, Arg1 right, Status*) { + requires decimal_value + static T Call(KernelContext*, Arg0 left, Arg1 right, Status*) { return left + (-right); } }; @@ -298,22 +303,20 @@ struct Multiply { static_assert(std::is_same::value, ""); template - static constexpr enable_if_floating_value Call(KernelContext*, T left, T right, - Status*) { + requires floating_value + static constexpr T Call(KernelContext*, T left, T right, Status*) { return left * right; } template - static constexpr enable_if_t< - is_unsigned_integer_value::value && !std::is_same::value, T> - Call(KernelContext*, T left, T right, Status*) { + requires(unsigned_integer_value && !std::is_same_v) + static constexpr T Call(KernelContext*, T left, T right, Status*) { return left * right; } template - static constexpr enable_if_t< - is_signed_integer_value::value && !std::is_same::value, T> - Call(KernelContext*, T left, T right, Status*) { + requires(signed_integer_value && !std::is_same_v) + static constexpr T Call(KernelContext*, T left, T right, Status*) { return to_unsigned(left) * to_unsigned(right); } @@ -322,26 +325,27 @@ struct Multiply { // behaviour). Therefore we first cast to 32 bit unsigned integers where overflow is // well defined. template - static constexpr enable_if_same Call(KernelContext*, int16_t left, - int16_t right, Status*) { + requires std::same_as + static constexpr T Call(KernelContext*, int16_t left, int16_t right, Status*) { return static_cast(left) * static_cast(right); } template - static constexpr enable_if_same Call(KernelContext*, uint16_t left, - uint16_t right, Status*) { + requires std::same_as + static constexpr T Call(KernelContext*, uint16_t left, uint16_t right, Status*) { return static_cast(left) * static_cast(right); } template - static enable_if_decimal_value Call(KernelContext*, Arg0 left, Arg1 right, Status*) { + requires decimal_value + static T Call(KernelContext*, Arg0 left, Arg1 right, Status*) { return left * right; } }; struct MultiplyChecked { template - static enable_if_integer_value Call(KernelContext*, Arg0 left, Arg1 right, - Status* st) { + requires integer_value + static T Call(KernelContext*, Arg0 left, Arg1 right, Status* st) { static_assert(std::is_same::value && std::is_same::value, ""); T result = 0; if (ARROW_PREDICT_FALSE(MultiplyWithOverflow(left, right, &result))) { @@ -351,28 +355,29 @@ struct MultiplyChecked { } template - static enable_if_floating_value Call(KernelContext*, Arg0 left, Arg1 right, - Status*) { + requires floating_value + static T Call(KernelContext*, Arg0 left, Arg1 right, Status*) { static_assert(std::is_same::value && std::is_same::value, ""); return left * right; } template - static enable_if_decimal_value Call(KernelContext*, Arg0 left, Arg1 right, Status*) { + requires decimal_value + static T Call(KernelContext*, Arg0 left, Arg1 right, Status*) { return left * right; } }; struct Divide { template - static enable_if_floating_value Call(KernelContext*, Arg0 left, Arg1 right, - Status*) { + requires floating_value + static T Call(KernelContext*, Arg0 left, Arg1 right, Status*) { return left / right; } template - static enable_if_integer_value Call(KernelContext*, Arg0 left, Arg1 right, - Status* st) { + requires integer_value + static T Call(KernelContext*, Arg0 left, Arg1 right, Status* st) { T result; if (ARROW_PREDICT_FALSE(DivideWithOverflow(left, right, &result))) { if (right == 0) { @@ -385,8 +390,8 @@ struct Divide { } template - static enable_if_decimal_value Call(KernelContext*, Arg0 left, Arg1 right, - Status* st) { + requires decimal_value + static T Call(KernelContext*, Arg0 left, Arg1 right, Status* st) { if (right == Arg1()) { *st = Status::Invalid("Divide by zero"); return T(); @@ -398,8 +403,8 @@ struct Divide { struct DivideChecked { template - static enable_if_integer_value Call(KernelContext*, Arg0 left, Arg1 right, - Status* st) { + requires integer_value + static T Call(KernelContext*, Arg0 left, Arg1 right, Status* st) { static_assert(std::is_same::value && std::is_same::value, ""); T result; if (ARROW_PREDICT_FALSE(DivideWithOverflow(left, right, &result))) { @@ -413,8 +418,8 @@ struct DivideChecked { } template - static enable_if_floating_value Call(KernelContext*, Arg0 left, Arg1 right, - Status* st) { + requires floating_value + static T Call(KernelContext*, Arg0 left, Arg1 right, Status* st) { static_assert(std::is_same::value && std::is_same::value, ""); if (ARROW_PREDICT_FALSE(right == 0)) { *st = Status::Invalid("divide by zero"); @@ -424,22 +429,22 @@ struct DivideChecked { } template - static enable_if_decimal_value Call(KernelContext* ctx, Arg0 left, Arg1 right, - Status* st) { + requires decimal_value + static T Call(KernelContext* ctx, Arg0 left, Arg1 right, Status* st) { return Divide::Call(ctx, left, right, st); } }; struct FloatingDivide { template - static enable_if_floating_value Call(KernelContext*, Arg0 left, Arg1 right, - Status*) { + requires floating_value + static Arg0 Call(KernelContext*, Arg0 left, Arg1 right, Status*) { return left / right; } template - static enable_if_integer_value Call(KernelContext* ctx, Arg0 left, - Arg1 right, Status* st) { + requires integer_value + static double Call(KernelContext* ctx, Arg0 left, Arg1 right, Status* st) { static_assert(std::is_same::value); return Call(ctx, static_cast(left), static_cast(right), st); } @@ -449,8 +454,8 @@ struct FloatingDivide { struct FloatingDivideChecked { template - static enable_if_floating_value Call(KernelContext*, Arg0 left, Arg1 right, - Status* st) { + requires floating_value + static Arg0 Call(KernelContext*, Arg0 left, Arg1 right, Status* st) { static_assert(std::is_same::value && std::is_same::value); if (ARROW_PREDICT_FALSE(right == 0)) { *st = Status::Invalid("divide by zero"); @@ -460,8 +465,8 @@ struct FloatingDivideChecked { } template - static enable_if_integer_value Call(KernelContext* ctx, Arg0 left, - Arg1 right, Status* st) { + requires integer_value + static double Call(KernelContext* ctx, Arg0 left, Arg1 right, Status* st) { static_assert(std::is_same::value); return Call(ctx, static_cast(left), static_cast(right), st); } @@ -470,38 +475,40 @@ struct FloatingDivideChecked { struct Negate { template - static constexpr enable_if_floating_value Call(KernelContext*, Arg arg, Status*) { + requires floating_value + static constexpr T Call(KernelContext*, Arg arg, Status*) { return -arg; } template - static constexpr enable_if_half_float_value Call(KernelContext*, Arg arg, Status*) { + requires half_float_value + static constexpr T Call(KernelContext*, Arg arg, Status*) { return -arg; } template - static constexpr enable_if_unsigned_integer_value Call(KernelContext*, Arg arg, - Status*) { + requires unsigned_integer_value + static constexpr T Call(KernelContext*, Arg arg, Status*) { return ~arg + 1; } template - static constexpr enable_if_signed_integer_value Call(KernelContext*, Arg arg, - Status*) { + requires signed_integer_value + static constexpr T Call(KernelContext*, Arg arg, Status*) { return arrow::internal::SafeSignedNegate(arg); } template - static constexpr enable_if_decimal_value Call(KernelContext*, Arg arg, - Status*) { + requires decimal_value + static constexpr T Call(KernelContext*, Arg arg, Status*) { return arg.Negate(); } }; struct NegateChecked { template - static enable_if_signed_integer_value Call(KernelContext*, Arg arg, - Status* st) { + requires signed_integer_value + static T Call(KernelContext*, Arg arg, Status* st) { static_assert(std::is_same::value, ""); T result = 0; if (ARROW_PREDICT_FALSE(NegateWithOverflow(arg, &result))) { @@ -511,8 +518,8 @@ struct NegateChecked { } template - static enable_if_unsigned_integer_value Call(KernelContext* ctx, Arg arg, - Status* st) { + requires unsigned_integer_value + static T Call(KernelContext* ctx, Arg arg, Status* st) { static_assert(std::is_same::value, ""); ARROW_DCHECK(false) << "This is included only for the purposes of instantiability " "from the arithmetic kernel generator"; @@ -520,21 +527,22 @@ struct NegateChecked { } template - static constexpr enable_if_floating_value Call(KernelContext*, Arg arg, - Status* st) { + requires floating_value + static constexpr T Call(KernelContext*, Arg arg, Status* st) { static_assert(std::is_same::value, ""); return -arg; } template - static constexpr enable_if_half_float_value Call(KernelContext*, Arg arg, Status*) { + requires half_float_value + static constexpr T Call(KernelContext*, Arg arg, Status*) { static_assert(std::is_same::value, ""); return -arg; } template - static constexpr enable_if_decimal_value Call(KernelContext*, Arg arg, - Status*) { + requires decimal_value + static constexpr T Call(KernelContext*, Arg arg, Status*) { return arg.Negate(); } }; @@ -569,7 +577,8 @@ struct Power { } template - static enable_if_integer_value Call(KernelContext*, T base, T exp, Status* st) { + requires integer_value + static T Call(KernelContext*, T base, T exp, Status* st) { if (exp < 0) { *st = Status::Invalid("integers to negative integer powers are not allowed"); return 0; @@ -578,15 +587,16 @@ struct Power { } template - static enable_if_floating_value Call(KernelContext*, T base, T exp, Status*) { + requires floating_value + static T Call(KernelContext*, T base, T exp, Status*) { return std::pow(base, exp); } }; struct PowerChecked { template - static enable_if_integer_value Call(KernelContext*, Arg0 base, Arg1 exp, - Status* st) { + requires integer_value + static T Call(KernelContext*, Arg0 base, Arg1 exp, Status* st) { if (exp < 0) { *st = Status::Invalid("integers to negative integer powers are not allowed"); return 0; @@ -611,7 +621,8 @@ struct PowerChecked { } template - static enable_if_floating_value Call(KernelContext*, Arg0 base, Arg1 exp, Status*) { + requires floating_value + static T Call(KernelContext*, Arg0 base, Arg1 exp, Status*) { static_assert(std::is_same::value && std::is_same::value, ""); return std::pow(base, exp); } @@ -619,7 +630,8 @@ struct PowerChecked { struct SquareRoot { template - static enable_if_floating_value Call(KernelContext*, Arg arg, Status*) { + requires floating_value + static T Call(KernelContext*, Arg arg, Status*) { static_assert(std::is_same::value, ""); if (arg < 0.0) { return std::numeric_limits::quiet_NaN(); @@ -630,7 +642,8 @@ struct SquareRoot { struct SquareRootChecked { template - static enable_if_floating_value Call(KernelContext*, Arg arg, Status* st) { + requires floating_value + static T Call(KernelContext*, Arg arg, Status* st) { static_assert(std::is_same::value, ""); if (arg < 0.0) { *st = Status::Invalid("square root of negative number"); @@ -642,14 +655,14 @@ struct SquareRootChecked { struct Sign { template - static constexpr enable_if_floating_value Call(KernelContext*, Arg arg, - Status*) { + requires floating_value + static constexpr T Call(KernelContext*, Arg arg, Status*) { return std::isnan(arg) ? arg : ((arg == 0) ? 0 : (std::signbit(arg) ? -1 : 1)); } template - static constexpr enable_if_half_float_value Call(KernelContext*, Arg arg, - Status*) { + requires half_float_value + static constexpr T Call(KernelContext*, Arg arg, Status*) { return arg.is_nan() ? arg : (arg.is_zero() ? Float16::zero() @@ -657,35 +670,35 @@ struct Sign { } template - static constexpr enable_if_unsigned_integer_value Call(KernelContext*, Arg arg, - Status*) { + requires unsigned_integer_value + static constexpr T Call(KernelContext*, Arg arg, Status*) { return (arg > 0) ? 1 : 0; } template - static constexpr enable_if_signed_integer_value Call(KernelContext*, Arg arg, - Status*) { + requires signed_integer_value + static constexpr T Call(KernelContext*, Arg arg, Status*) { return (arg > 0) ? 1 : ((arg == 0) ? 0 : -1); } template - static constexpr enable_if_decimal_value Call(KernelContext*, Arg arg, - Status*) { + requires decimal_value + static constexpr T Call(KernelContext*, Arg arg, Status*) { return (arg == 0) ? 0 : arg.Sign(); } }; struct Max { template - static constexpr enable_if_not_floating_value Call(KernelContext*, Arg0 arg0, - Arg1 arg1, Status*) { + requires(!std::floating_point) + static constexpr T Call(KernelContext*, Arg0 arg0, Arg1 arg1, Status*) { static_assert(std::is_same::value && std::is_same::value); return std::max(arg0, arg1); } template - static constexpr enable_if_floating_value Call(KernelContext*, Arg0 left, Arg1 right, - Status*) { + requires floating_value + static constexpr T Call(KernelContext*, Arg0 left, Arg1 right, Status*) { static_assert(std::is_same::value && std::is_same::value); if (std::isnan(left)) { return right; @@ -699,15 +712,15 @@ struct Max { struct Min { template - static constexpr enable_if_not_floating_value Call(KernelContext*, Arg0 arg0, - Arg1 arg1, Status*) { + requires(!std::floating_point) + static constexpr T Call(KernelContext*, Arg0 arg0, Arg1 arg1, Status*) { static_assert(std::is_same::value && std::is_same::value); return std::min(arg0, arg1); } template - static constexpr enable_if_floating_value Call(KernelContext*, Arg0 left, Arg1 right, - Status*) { + requires floating_value + static constexpr T Call(KernelContext*, Arg0 left, Arg1 right, Status*) { static_assert(std::is_same::value && std::is_same::value); if (std::isnan(left)) { return right; diff --git a/cpp/src/arrow/compute/kernels/codegen_internal.h b/cpp/src/arrow/compute/kernels/codegen_internal.h index 15a946fbdbb..ca86997cf05 100644 --- a/cpp/src/arrow/compute/kernels/codegen_internal.h +++ b/cpp/src/arrow/compute/kernels/codegen_internal.h @@ -126,8 +126,8 @@ struct KernelStateFromFunctionOptions : public KernelState { template struct GetViewType; -template -struct GetViewType> { +template +struct GetViewType { using T = typename Type::c_type; using PhysicalType = T; @@ -143,9 +143,9 @@ struct GetViewType { }; template -struct GetViewType::value || - is_fixed_size_binary_type::value || - is_binary_view_like_type::value>> { + requires(arrow_base_binary || arrow_fixed_size_binary || + arrow_binary_view_like) +struct GetViewType { using T = std::string_view; using PhysicalType = T; @@ -203,8 +203,8 @@ struct GetViewType { template struct GetOutputType; -template -struct GetOutputType> { +template +struct GetOutputType { using T = typename Type::c_type; }; @@ -213,8 +213,8 @@ struct GetOutputType { using T = Float16; }; -template -struct GetOutputType::value>> { +template +struct GetOutputType { using T = std::string; }; @@ -283,6 +283,26 @@ using enable_if_decimal_value = std::is_same::value, R>; +// C++20 concept equivalents for C-value types +template +concept signed_integer_value = is_signed_integer_value::value; + +template +concept unsigned_integer_value = is_unsigned_integer_value::value; + +template +concept integer_value = signed_integer_value || unsigned_integer_value; + +template +concept floating_value = std::floating_point; + +template +concept half_float_value = std::same_as; + +template +concept decimal_value = std::same_as || std::same_as || + std::same_as || std::same_as; + // ---------------------------------------------------------------------- // Iteration / value access utilities @@ -290,13 +310,18 @@ template using enable_if_c_number_or_decimal = enable_if_t< (has_c_type::value && !is_boolean_type::value) || is_decimal_type::value, R>; +/// \brief Concept for Arrow types stored as a C number or decimal in memory +template +concept arrow_c_number_or_decimal = + (arrow_has_c_type && !arrow_boolean) || arrow_decimal; + // Iterator over various input array types, yielding a GetViewType template struct ArrayIterator; -template -struct ArrayIterator> { +template +struct ArrayIterator { using T = typename TypeTraits::ScalarType::ValueType; const T* values; @@ -313,8 +338,8 @@ struct ArrayIterator { T operator()() { return *values++; } }; -template -struct ArrayIterator> { +template +struct ArrayIterator { BitmapReader reader; explicit ArrayIterator(const ArraySpan& arr) @@ -326,8 +351,8 @@ struct ArrayIterator> { } }; -template -struct ArrayIterator> { +template +struct ArrayIterator { using offset_type = typename Type::offset_type; const ArraySpan& arr; const offset_type* offsets; @@ -375,8 +400,8 @@ struct ArrayIterator { template struct OutputArrayWriter; -template -struct OutputArrayWriter> { +template +struct OutputArrayWriter { using T = typename TypeTraits::ScalarType::ValueType; T* values; @@ -398,8 +423,8 @@ struct OutputArrayWriter> { template struct UnboxScalar; -template -struct UnboxScalar> { +template +struct UnboxScalar { using T = typename Type::c_type; static T Unbox(const Scalar& val) { std::string_view view = @@ -417,8 +442,8 @@ struct UnboxScalar { } }; -template -struct UnboxScalar> { +template +struct UnboxScalar { using T = std::string_view; static T Unbox(const Scalar& val) { if (!val.is_valid) return std::string_view(); @@ -585,8 +610,8 @@ static Status SimpleBinary(KernelContext* ctx, const ExecSpan& batch, ExecResult template struct OutputAdapter; -template -struct OutputAdapter> { +template +struct OutputAdapter { template static Status Write(KernelContext*, ArraySpan* out, Generator&& generator) { GenerateBitsUnrolled(out->buffers[1].data, out->offset, out->length, @@ -595,8 +620,8 @@ struct OutputAdapter> { } }; -template -struct OutputAdapter> { +template +struct OutputAdapter { using T = std::conditional_t, Float16, typename TypeTraits::ScalarType::ValueType>; @@ -611,8 +636,8 @@ struct OutputAdapter> { } }; -template -struct OutputAdapter> { +template +struct OutputAdapter { template static Status Write(KernelContext* ctx, ArraySpan* out, Generator&& generator) { return Status::NotImplemented("NYI"); @@ -678,8 +703,8 @@ struct ScalarUnaryNotNullStateful { } }; - template - struct ArrayExec> { + template + struct ArrayExec { static Status Exec(const ThisType& functor, KernelContext* ctx, const ArraySpan& arg0, ExecResult* out) { Status st = Status::OK(); @@ -697,8 +722,8 @@ struct ScalarUnaryNotNullStateful { } }; - template - struct ArrayExec> { + template + struct ArrayExec { static Status Exec(const ThisType& functor, KernelContext* ctx, const ArraySpan& arg0, ExecResult* out) { // NOTE: This code is not currently used by any kernels and has @@ -719,8 +744,8 @@ struct ScalarUnaryNotNullStateful { } }; - template - struct ArrayExec::value>> { + template + struct ArrayExec { static Status Exec(const ThisType& functor, KernelContext* ctx, const ArraySpan& arg0, ExecResult* out) { Status st = Status::OK(); diff --git a/cpp/src/arrow/type_traits.h b/cpp/src/arrow/type_traits.h index 1b7a02e1085..edab499c9e0 100644 --- a/cpp/src/arrow/type_traits.h +++ b/cpp/src/arrow/type_traits.h @@ -17,6 +17,7 @@ #pragma once +#include #include #include #include @@ -998,6 +999,181 @@ template using enable_if_physical_floating_point = enable_if_t::value, R>; +// +// C++20 concepts for Arrow type predicates +// + +/// \addtogroup type-concepts +/// @{ + +// -- Primitive type concepts -- + +template +concept arrow_null = is_null_type::value; + +template +concept arrow_boolean = is_boolean_type::value; + +template +concept arrow_number = is_number_type::value; + +template +concept arrow_integer = is_integer_type::value; + +template +concept arrow_signed_integer = is_signed_integer_type::value; + +template +concept arrow_unsigned_integer = is_unsigned_integer_type::value; + +template +concept arrow_floating_point = is_floating_type::value; + +template +concept arrow_half_float = is_half_float_type::value; + +template +concept arrow_8bit_int = is_8bit_int::value; + +// -- Binary / String type concepts -- + +template +concept arrow_base_binary = is_base_binary_type::value; + +template +concept arrow_binary = is_binary_type::value; + +template +concept arrow_string = is_string_type::value; + +template +concept arrow_binary_view_like = is_binary_view_like_type::value; + +template +concept arrow_binary_view = is_binary_view_type::value; + +template +concept arrow_string_view = is_string_view_type::value; + +template +concept arrow_string_like = is_string_like_type::value; + +template +concept arrow_binary_like = is_binary_like_type::value; + +template +concept arrow_fixed_size_binary = is_fixed_size_binary_type::value; + +template +concept arrow_fixed_width = is_fixed_width_type::value; + +// -- Decimal type concepts -- + +template +concept arrow_decimal = is_decimal_type::value; + +template +concept arrow_decimal32 = is_decimal32_type::value; + +template +concept arrow_decimal64 = is_decimal64_type::value; + +template +concept arrow_decimal128 = is_decimal128_type::value; + +template +concept arrow_decimal256 = is_decimal256_type::value; + +// -- Nested type concepts -- + +template +concept arrow_nested = is_nested_type::value; + +template +concept arrow_var_length_list = is_var_length_list_type::value; + +template +concept arrow_fixed_size_list = is_fixed_size_list_type::value; + +template +concept arrow_list = is_list_type::value; + +template +concept arrow_list_view = is_list_view_type::value; + +template +concept arrow_list_like = is_list_like_type::value; + +template +concept arrow_var_length_list_like = is_var_length_list_like_type::value; + +template +concept arrow_struct = is_struct_type::value; + +template +concept arrow_union = is_union_type::value; + +// -- Temporal type concepts -- + +template +concept arrow_temporal = is_temporal_type::value; + +template +concept arrow_date = is_date_type::value; + +template +concept arrow_time = is_time_type::value; + +template +concept arrow_timestamp = is_timestamp_type::value; + +template +concept arrow_duration = is_duration_type::value; + +template +concept arrow_interval = is_interval_type::value; + +// -- Special type concepts -- + +template +concept arrow_run_end_encoded = is_run_end_encoded_type::value; + +template +concept arrow_dictionary = is_dictionary_type::value; + +template +concept arrow_extension = is_extension_type::value; + +// -- Attribute-based concepts -- + +template +concept arrow_primitive_ctype = is_primitive_ctype::value; + +template +concept arrow_has_c_type = has_c_type::value; + +template +concept arrow_has_string_view = has_string_view::value; + +template +concept arrow_parameter_free = is_parameter_free_type::value; + +// -- Physical representation concepts -- + +template +concept arrow_physical_signed_integer = is_physical_signed_integer_type::value; + +template +concept arrow_physical_unsigned_integer = is_physical_unsigned_integer_type::value; + +template +concept arrow_physical_integer = is_physical_integer_type::value; + +template +concept arrow_physical_floating_point = is_physical_floating_type::value; + +/// @} + /// @} /// \addtogroup runtime-type-predicates diff --git a/cpp/src/arrow/util/formatting.h b/cpp/src/arrow/util/formatting.h index 844b6fb91a8..0d5ed37451c 100644 --- a/cpp/src/arrow/util/formatting.h +++ b/cpp/src/arrow/util/formatting.h @@ -59,6 +59,9 @@ struct is_formattable { template using enable_if_formattable = enable_if_t::value, R>; +template +concept arrow_formattable = is_formattable::value; + template using Return = decltype(std::declval()(std::string_view{})); @@ -546,8 +549,8 @@ class StringFormatter { std::string timezone_; }; -template -class StringFormatter> { +template +class StringFormatter { public: using value_type = typename T::c_type;