// Licensed to the Apache Software Foundation (ASF) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. #pragma once #include #include #include #include #include "arrow/type.h" #include "arrow/util/bit_util.h" namespace arrow { // // Per-type id type lookup // template struct TypeIdTraits {}; #define TYPE_ID_TRAIT(_id, _typeclass) \ template <> \ struct TypeIdTraits { \ using Type = _typeclass; \ }; TYPE_ID_TRAIT(NA, NullType) TYPE_ID_TRAIT(BOOL, BooleanType) TYPE_ID_TRAIT(INT8, Int8Type) TYPE_ID_TRAIT(INT16, Int16Type) TYPE_ID_TRAIT(INT32, Int32Type) TYPE_ID_TRAIT(INT64, Int64Type) TYPE_ID_TRAIT(UINT8, UInt8Type) TYPE_ID_TRAIT(UINT16, UInt16Type) TYPE_ID_TRAIT(UINT32, UInt32Type) TYPE_ID_TRAIT(UINT64, UInt64Type) TYPE_ID_TRAIT(HALF_FLOAT, HalfFloatType) TYPE_ID_TRAIT(FLOAT, FloatType) TYPE_ID_TRAIT(DOUBLE, DoubleType) TYPE_ID_TRAIT(STRING, StringType) TYPE_ID_TRAIT(BINARY, BinaryType) TYPE_ID_TRAIT(LARGE_STRING, LargeStringType) TYPE_ID_TRAIT(LARGE_BINARY, LargeBinaryType) TYPE_ID_TRAIT(FIXED_SIZE_BINARY, FixedSizeBinaryType) TYPE_ID_TRAIT(DATE32, Date32Type) TYPE_ID_TRAIT(DATE64, Date64Type) TYPE_ID_TRAIT(TIME32, Time32Type) TYPE_ID_TRAIT(TIME64, Time64Type) TYPE_ID_TRAIT(TIMESTAMP, TimestampType) TYPE_ID_TRAIT(INTERVAL_DAY_TIME, DayTimeIntervalType) TYPE_ID_TRAIT(INTERVAL_MONTH_DAY_NANO, MonthDayNanoIntervalType) TYPE_ID_TRAIT(INTERVAL_MONTHS, MonthIntervalType) TYPE_ID_TRAIT(DURATION, DurationType) TYPE_ID_TRAIT(DECIMAL32, Decimal32Type) TYPE_ID_TRAIT(DECIMAL64, Decimal64Type) TYPE_ID_TRAIT(DECIMAL128, Decimal128Type) TYPE_ID_TRAIT(DECIMAL256, Decimal256Type) TYPE_ID_TRAIT(STRUCT, StructType) TYPE_ID_TRAIT(LIST, ListType) TYPE_ID_TRAIT(LARGE_LIST, LargeListType) TYPE_ID_TRAIT(FIXED_SIZE_LIST, FixedSizeListType) TYPE_ID_TRAIT(MAP, MapType) TYPE_ID_TRAIT(DENSE_UNION, DenseUnionType) TYPE_ID_TRAIT(SPARSE_UNION, SparseUnionType) TYPE_ID_TRAIT(DICTIONARY, DictionaryType) TYPE_ID_TRAIT(EXTENSION, ExtensionType) #undef TYPE_ID_TRAIT // // Per-type type traits // /// \addtogroup type-traits /// \brief Base template for type traits of Arrow data types /// Type traits provide various information about a type at compile time, such /// as the associated ArrayType, BuilderType, and ScalarType. Not all types /// provide all information. /// \tparam T An Arrow data type template struct TypeTraits {}; /// \brief Base template for type traits of C++ types /// \tparam T A standard C++ type template struct CTypeTraits {}; /// \addtogroup type-traits /// @{ template <> struct TypeTraits { using ArrayType = NullArray; using BuilderType = NullBuilder; using ScalarType = NullScalar; static constexpr int64_t bytes_required(int64_t) { return 0; } constexpr static bool is_parameter_free = true; static inline std::shared_ptr type_singleton() { return null(); } }; template <> struct TypeTraits { using ArrayType = BooleanArray; using BuilderType = BooleanBuilder; using ScalarType = BooleanScalar; using CType = bool; static constexpr int64_t bytes_required(int64_t elements) { return bit_util::BytesForBits(elements); } constexpr static bool is_parameter_free = true; static inline std::shared_ptr type_singleton() { return boolean(); } }; /// @} /// \addtogroup c-type-traits template <> struct CTypeTraits : public TypeTraits { using ArrowType = BooleanType; }; #define PRIMITIVE_TYPE_TRAITS_DEF_(CType_, ArrowType_, ArrowArrayType, ArrowBuilderType, \ ArrowScalarType, ArrowTensorType, SingletonFn) \ template <> \ struct TypeTraits { \ using ArrayType = ArrowArrayType; \ using BuilderType = ArrowBuilderType; \ using ScalarType = ArrowScalarType; \ using TensorType = ArrowTensorType; \ using CType = ArrowType_::c_type; \ static constexpr int64_t bytes_required(int64_t elements) { \ return elements * static_cast(sizeof(CType)); \ } \ constexpr static bool is_parameter_free = true; \ static inline std::shared_ptr type_singleton() { return SingletonFn(); } \ }; \ \ template <> \ struct CTypeTraits : public TypeTraits { \ using ArrowType = ArrowType_; \ }; #define PRIMITIVE_TYPE_TRAITS_DEF(CType, ArrowShort, SingletonFn) \ PRIMITIVE_TYPE_TRAITS_DEF_( \ CType, ARROW_CONCAT(ArrowShort, Type), ARROW_CONCAT(ArrowShort, Array), \ ARROW_CONCAT(ArrowShort, Builder), ARROW_CONCAT(ArrowShort, Scalar), \ ARROW_CONCAT(ArrowShort, Tensor), SingletonFn) PRIMITIVE_TYPE_TRAITS_DEF(uint8_t, UInt8, uint8) PRIMITIVE_TYPE_TRAITS_DEF(int8_t, Int8, int8) PRIMITIVE_TYPE_TRAITS_DEF(uint16_t, UInt16, uint16) PRIMITIVE_TYPE_TRAITS_DEF(int16_t, Int16, int16) PRIMITIVE_TYPE_TRAITS_DEF(uint32_t, UInt32, uint32) PRIMITIVE_TYPE_TRAITS_DEF(int32_t, Int32, int32) PRIMITIVE_TYPE_TRAITS_DEF(uint64_t, UInt64, uint64) PRIMITIVE_TYPE_TRAITS_DEF(int64_t, Int64, int64) PRIMITIVE_TYPE_TRAITS_DEF(float, Float, float32) PRIMITIVE_TYPE_TRAITS_DEF(double, Double, float64) #undef PRIMITIVE_TYPE_TRAITS_DEF #undef PRIMITIVE_TYPE_TRAITS_DEF_ /// \addtogroup type-traits /// @{ template <> struct TypeTraits { using ArrayType = Date64Array; using BuilderType = Date64Builder; using ScalarType = Date64Scalar; using CType = Date64Type::c_type; static constexpr int64_t bytes_required(int64_t elements) { return elements * static_cast(sizeof(int64_t)); } constexpr static bool is_parameter_free = true; static inline std::shared_ptr type_singleton() { return date64(); } }; template <> struct TypeTraits { using ArrayType = Date32Array; using BuilderType = Date32Builder; using ScalarType = Date32Scalar; using CType = Date32Type::c_type; static constexpr int64_t bytes_required(int64_t elements) { return elements * static_cast(sizeof(int32_t)); } constexpr static bool is_parameter_free = true; static inline std::shared_ptr type_singleton() { return date32(); } }; template <> struct TypeTraits { using ArrayType = TimestampArray; using BuilderType = TimestampBuilder; using ScalarType = TimestampScalar; using CType = TimestampType::c_type; static constexpr int64_t bytes_required(int64_t elements) { return elements * static_cast(sizeof(int64_t)); } constexpr static bool is_parameter_free = false; }; template <> struct TypeTraits { using ArrayType = DurationArray; using BuilderType = DurationBuilder; using ScalarType = DurationScalar; using CType = DurationType::c_type; static constexpr int64_t bytes_required(int64_t elements) { return elements * static_cast(sizeof(int64_t)); } constexpr static bool is_parameter_free = false; }; template <> struct TypeTraits { using ArrayType = DayTimeIntervalArray; using BuilderType = DayTimeIntervalBuilder; using ScalarType = DayTimeIntervalScalar; using CType = DayTimeIntervalType::c_type; static constexpr int64_t bytes_required(int64_t elements) { return elements * static_cast(sizeof(DayTimeIntervalType::DayMilliseconds)); } constexpr static bool is_parameter_free = true; static std::shared_ptr type_singleton() { return day_time_interval(); } }; template <> struct TypeTraits { using ArrayType = MonthDayNanoIntervalArray; using BuilderType = MonthDayNanoIntervalBuilder; using ScalarType = MonthDayNanoIntervalScalar; using CType = MonthDayNanoIntervalType::c_type; static constexpr int64_t bytes_required(int64_t elements) { return elements * static_cast(sizeof(MonthDayNanoIntervalType::MonthDayNanos)); } constexpr static bool is_parameter_free = true; static std::shared_ptr type_singleton() { return month_day_nano_interval(); } }; template <> struct TypeTraits { using ArrayType = MonthIntervalArray; using BuilderType = MonthIntervalBuilder; using ScalarType = MonthIntervalScalar; using CType = MonthIntervalType::c_type; static constexpr int64_t bytes_required(int64_t elements) { return elements * static_cast(sizeof(int32_t)); } constexpr static bool is_parameter_free = true; static std::shared_ptr type_singleton() { return month_interval(); } }; template <> struct TypeTraits { using ArrayType = Time32Array; using BuilderType = Time32Builder; using ScalarType = Time32Scalar; using CType = Time32Type::c_type; static constexpr int64_t bytes_required(int64_t elements) { return elements * static_cast(sizeof(int32_t)); } constexpr static bool is_parameter_free = false; }; template <> struct TypeTraits { using ArrayType = Time64Array; using BuilderType = Time64Builder; using ScalarType = Time64Scalar; using CType = Time64Type::c_type; static constexpr int64_t bytes_required(int64_t elements) { return elements * static_cast(sizeof(int64_t)); } constexpr static bool is_parameter_free = false; }; template <> struct TypeTraits { using ArrayType = HalfFloatArray; using BuilderType = HalfFloatBuilder; using ScalarType = HalfFloatScalar; using TensorType = HalfFloatTensor; using CType = uint16_t; static constexpr int64_t bytes_required(int64_t elements) { return elements * static_cast(sizeof(uint16_t)); } constexpr static bool is_parameter_free = true; static inline std::shared_ptr type_singleton() { return float16(); } }; template <> struct CTypeTraits : public TypeTraits { using ArrowType = HalfFloatType; }; template <> struct TypeTraits { using ArrayType = Decimal32Array; using BuilderType = Decimal32Builder; using ScalarType = Decimal32Scalar; using CType = Decimal32; constexpr static bool is_parameter_free = false; }; template <> struct TypeTraits { using ArrayType = Decimal64Array; using BuilderType = Decimal64Builder; using ScalarType = Decimal64Scalar; using CType = Decimal64; constexpr static bool is_parameter_free = false; }; template <> struct TypeTraits { using ArrayType = Decimal128Array; using BuilderType = Decimal128Builder; using ScalarType = Decimal128Scalar; using CType = Decimal128; constexpr static bool is_parameter_free = false; }; template <> struct TypeTraits { using ArrayType = Decimal256Array; using BuilderType = Decimal256Builder; using ScalarType = Decimal256Scalar; using CType = Decimal256; constexpr static bool is_parameter_free = false; }; template <> struct TypeTraits { using ArrayType = BinaryArray; using BuilderType = BinaryBuilder; using ScalarType = BinaryScalar; using OffsetType = Int32Type; constexpr static bool is_parameter_free = true; static inline std::shared_ptr type_singleton() { return binary(); } }; template <> struct TypeTraits { using ArrayType = BinaryViewArray; using BuilderType = BinaryViewBuilder; using ScalarType = BinaryViewScalar; using CType = BinaryViewType::c_type; constexpr static bool is_parameter_free = true; static inline std::shared_ptr type_singleton() { return binary_view(); } }; template <> struct TypeTraits { using ArrayType = LargeBinaryArray; using BuilderType = LargeBinaryBuilder; using ScalarType = LargeBinaryScalar; using OffsetType = Int64Type; constexpr static bool is_parameter_free = true; static inline std::shared_ptr type_singleton() { return large_binary(); } }; template <> struct TypeTraits { using ArrayType = FixedSizeBinaryArray; using BuilderType = FixedSizeBinaryBuilder; using ScalarType = FixedSizeBinaryScalar; // FixedSizeBinary doesn't have offsets per se, but string length is int32 sized using OffsetType = Int32Type; constexpr static bool is_parameter_free = false; }; template <> struct TypeTraits { using ArrayType = StringArray; using BuilderType = StringBuilder; using ScalarType = StringScalar; using OffsetType = Int32Type; constexpr static bool is_parameter_free = true; static inline std::shared_ptr type_singleton() { return utf8(); } }; template <> struct TypeTraits { using ArrayType = StringViewArray; using BuilderType = StringViewBuilder; using ScalarType = StringViewScalar; using CType = BinaryViewType::c_type; constexpr static bool is_parameter_free = true; static inline std::shared_ptr type_singleton() { return utf8_view(); } }; template <> struct TypeTraits { using ArrayType = LargeStringArray; using BuilderType = LargeStringBuilder; using ScalarType = LargeStringScalar; using OffsetType = Int64Type; constexpr static bool is_parameter_free = true; static inline std::shared_ptr type_singleton() { return large_utf8(); } }; template <> struct TypeTraits { using ArrayType = RunEndEncodedArray; using BuilderType = RunEndEncodedBuilder; using ScalarType = RunEndEncodedScalar; constexpr static bool is_parameter_free = false; }; /// @} /// \addtogroup c-type-traits /// @{ template <> struct CTypeTraits : public TypeTraits { using ArrowType = StringType; }; template <> struct CTypeTraits : public TypeTraits { using ArrowType = BinaryViewType; }; template <> struct CTypeTraits : public CTypeTraits {}; template struct CTypeTraits : public CTypeTraits {}; template <> struct CTypeTraits : public TypeTraits { using ArrowType = DayTimeIntervalType; }; /// @} /// \addtogroup type-traits /// @{ template <> struct TypeTraits { using ArrayType = ListArray; using BuilderType = ListBuilder; using ScalarType = ListScalar; using OffsetType = Int32Type; using OffsetArrayType = Int32Array; using OffsetBuilderType = Int32Builder; using OffsetScalarType = Int32Scalar; constexpr static bool is_parameter_free = false; using LargeType = LargeListType; }; template <> struct TypeTraits { using ArrayType = LargeListArray; using BuilderType = LargeListBuilder; using ScalarType = LargeListScalar; using OffsetType = Int64Type; using OffsetArrayType = Int64Array; using OffsetBuilderType = Int64Builder; using OffsetScalarType = Int64Scalar; constexpr static bool is_parameter_free = false; }; template <> struct TypeTraits { using ArrayType = ListViewArray; using BuilderType = ListViewBuilder; using ScalarType = ListViewScalar; using OffsetType = Int32Type; using OffsetArrayType = Int32Array; using OffsetBuilderType = Int32Builder; using OffsetScalarType = Int32Scalar; constexpr static bool is_parameter_free = false; using LargeType = LargeListViewType; }; template <> struct TypeTraits { using ArrayType = LargeListViewArray; using BuilderType = LargeListViewBuilder; using ScalarType = LargeListViewScalar; using OffsetType = Int64Type; using OffsetArrayType = Int64Array; using OffsetBuilderType = Int64Builder; using OffsetScalarType = Int64Scalar; constexpr static bool is_parameter_free = false; }; template <> struct TypeTraits { using ArrayType = MapArray; using BuilderType = MapBuilder; using ScalarType = MapScalar; using OffsetType = Int32Type; using OffsetArrayType = Int32Array; using OffsetBuilderType = Int32Builder; constexpr static bool is_parameter_free = false; }; template <> struct TypeTraits { using ArrayType = FixedSizeListArray; using BuilderType = FixedSizeListBuilder; using ScalarType = FixedSizeListScalar; constexpr static bool is_parameter_free = false; }; /// @} /// \addtogroup c-type-traits template struct CTypeTraits> : public TypeTraits { using ArrowType = ListType; static inline std::shared_ptr type_singleton() { return list(CTypeTraits::type_singleton()); } }; /// \addtogroup c-type-traits template struct CTypeTraits> : public TypeTraits { using ArrowType = FixedSizeListType; static auto type_singleton() { return fixed_size_list(CTypeTraits::type_singleton(), N); } }; /// \addtogroup type-traits /// @{ template <> struct TypeTraits { using ArrayType = StructArray; using BuilderType = StructBuilder; using ScalarType = StructScalar; constexpr static bool is_parameter_free = false; }; template <> struct TypeTraits { using ArrayType = SparseUnionArray; using BuilderType = SparseUnionBuilder; using ScalarType = SparseUnionScalar; constexpr static bool is_parameter_free = false; }; template <> struct TypeTraits { using ArrayType = DenseUnionArray; using BuilderType = DenseUnionBuilder; using ScalarType = DenseUnionScalar; constexpr static bool is_parameter_free = false; }; template <> struct TypeTraits { using ArrayType = DictionaryArray; using ScalarType = DictionaryScalar; constexpr static bool is_parameter_free = false; }; template <> struct TypeTraits { using ArrayType = ExtensionArray; using ScalarType = ExtensionScalar; constexpr static bool is_parameter_free = false; }; /// @} namespace internal { template struct make_void { using type = void; }; template using void_t = typename make_void::type; } // namespace internal // // Useful type predicates // /// \addtogroup type-predicates /// @{ // only in C++14 template using enable_if_t = typename std::enable_if::type; template using is_null_type = std::is_same; template using enable_if_null = enable_if_t::value, R>; template using is_boolean_type = std::is_same; template using enable_if_boolean = enable_if_t::value, R>; template using is_number_type = std::is_base_of; template using enable_if_number = enable_if_t::value, R>; template using is_integer_type = std::is_base_of; template using enable_if_integer = enable_if_t::value, R>; template using is_signed_integer_type = std::integral_constant::value && std::is_signed::value>; template using enable_if_signed_integer = enable_if_t::value, R>; template using is_unsigned_integer_type = std::integral_constant::value && std::is_unsigned::value>; template using enable_if_unsigned_integer = enable_if_t::value, R>; // Note this will also include HalfFloatType which is represented by a // non-floating point primitive (uint16_t). template using is_floating_type = std::is_base_of; template using enable_if_floating_point = enable_if_t::value, R>; // Half floats are special in that they behave physically like an unsigned // integer. template using is_half_float_type = std::is_same; template using enable_if_half_float = enable_if_t::value, R>; // Binary Types // Base binary refers to Binary/LargeBinary/String/LargeString template using is_base_binary_type = std::is_base_of; template using enable_if_base_binary = enable_if_t::value, R>; // Any binary excludes string from Base binary template using is_binary_type = std::integral_constant::value || std::is_same::value>; template using enable_if_binary = enable_if_t::value, R>; template using is_string_type = std::integral_constant::value || std::is_same::value>; template using enable_if_string = enable_if_t::value, R>; template using is_binary_view_like_type = std::is_base_of; template using is_binary_view_type = std::is_same; template using is_string_view_type = std::is_same; template using enable_if_binary_view_like = enable_if_t::value, R>; template using enable_if_binary_view = enable_if_t::value, R>; template using enable_if_string_view = enable_if_t::value, R>; template using is_string_like_type = std::integral_constant::value && T::is_utf8>; template using enable_if_string_like = enable_if_t::value, R>; template using enable_if_same = enable_if_t::value, R>; // Note that this also includes DecimalType template using is_fixed_size_binary_type = std::is_base_of; template using enable_if_fixed_size_binary = enable_if_t::value, R>; // This includes primitive, dictionary, and fixed-size-binary types template using is_fixed_width_type = std::is_base_of; template using enable_if_fixed_width_type = enable_if_t::value, R>; template using is_binary_like_type = std::integral_constant::value && !is_string_like_type::value) || is_fixed_size_binary_type::value>; template using enable_if_binary_like = enable_if_t::value, R>; template using is_decimal_type = std::is_base_of; template using enable_if_decimal = enable_if_t::value, R>; template using is_decimal32_type = std::is_base_of; template using enable_if_decimal32 = enable_if_t::value, R>; template using is_decimal64_type = std::is_base_of; template using enable_if_decimal64 = enable_if_t::value, R>; template using is_decimal128_type = std::is_base_of; template using enable_if_decimal128 = enable_if_t::value, R>; template using is_decimal256_type = std::is_base_of; template using enable_if_decimal256 = enable_if_t::value, R>; // Nested Types template using is_nested_type = std::is_base_of; template using enable_if_nested = enable_if_t::value, R>; template using enable_if_not_nested = enable_if_t::value, R>; template using is_var_length_list_type = std::integral_constant::value || std::is_base_of::value>; template using enable_if_var_size_list = enable_if_t::value, R>; // DEPRECATED use is_var_length_list_type. template using is_base_list_type = is_var_length_list_type; // DEPRECATED use enable_if_var_size_list template using enable_if_base_list = enable_if_var_size_list; template using is_fixed_size_list_type = std::is_same; template using enable_if_fixed_size_list = enable_if_t::value, R>; template using is_list_type = std::integral_constant::value || std::is_same::value || std::is_same::value>; template using enable_if_list_type = enable_if_t::value, R>; template using is_list_view_type = std::disjunction, std::is_same>; template using enable_if_list_view = enable_if_t::value, R>; template using is_list_like_type = std::integral_constant::value || is_fixed_size_list_type::value>; template using enable_if_list_like = enable_if_t::value, R>; template using is_var_length_list_like_type = std::disjunction, is_list_view_type>; template using enable_if_var_length_list_like = enable_if_t::value, R>; template using is_struct_type = std::is_base_of; template using enable_if_struct = enable_if_t::value, R>; template using is_union_type = std::is_base_of; template using enable_if_union = enable_if_t::value, R>; // TemporalTypes template using is_temporal_type = std::is_base_of; template using enable_if_temporal = enable_if_t::value, R>; template using is_date_type = std::is_base_of; template using enable_if_date = enable_if_t::value, R>; template using is_time_type = std::is_base_of; template using enable_if_time = enable_if_t::value, R>; template using is_timestamp_type = std::is_base_of; template using enable_if_timestamp = enable_if_t::value, R>; template using is_duration_type = std::is_base_of; template using enable_if_duration = enable_if_t::value, R>; template using is_interval_type = std::is_base_of; template using enable_if_interval = enable_if_t::value, R>; template using is_run_end_encoded_type = std::is_base_of; template using enable_if_run_end_encoded = enable_if_t::value, R>; template using is_dictionary_type = std::is_base_of; template using enable_if_dictionary = enable_if_t::value, R>; template using is_extension_type = std::is_base_of; template using enable_if_extension = enable_if_t::value, R>; // Attribute differentiation template using is_primitive_ctype = std::is_base_of; template using enable_if_primitive_ctype = enable_if_t::value, R>; template using has_c_type = std::integral_constant::value || is_temporal_type::value>; template using enable_if_has_c_type = enable_if_t::value, R>; template using has_string_view = std::integral_constant::value || std::is_same::value || std::is_same::value || std::is_same::value || std::is_same::value || std::is_same::value || std::is_same::value>; template using enable_if_has_string_view = enable_if_t::value, R>; template using is_8bit_int = std::integral_constant::value || std::is_same::value>; template using enable_if_8bit_int = enable_if_t::value, R>; template using is_parameter_free_type = std::integral_constant::is_parameter_free>; template using enable_if_parameter_free = enable_if_t::value, R>; // Physical representation quirks template using is_physical_signed_integer_type = std::integral_constant::value || (is_temporal_type::value && has_c_type::value && std::is_integral::value)>; template using enable_if_physical_signed_integer = enable_if_t::value, R>; template using is_physical_unsigned_integer_type = std::integral_constant::value || is_half_float_type::value>; template using enable_if_physical_unsigned_integer = enable_if_t::value, R>; template using is_physical_integer_type = std::integral_constant::value || is_physical_signed_integer_type::value>; template using enable_if_physical_integer = enable_if_t::value, R>; // Like is_floating_type but excluding half-floats which don't have a // float-like c type. template using is_physical_floating_type = std::integral_constant::value && !is_half_float_type::value>; template using enable_if_physical_floating_point = enable_if_t::value, R>; /// @} /// \addtogroup runtime-type-predicates /// @{ /// \brief Check for an integer type (signed or unsigned) /// /// \param[in] type_id the type-id to check /// \return whether type-id is an integer type one constexpr bool is_integer(Type::type type_id) { switch (type_id) { case Type::UINT8: case Type::INT8: case Type::UINT16: case Type::INT16: case Type::UINT32: case Type::INT32: case Type::UINT64: case Type::INT64: return true; default: break; } return false; } /// \brief Check for a signed integer type /// /// \param[in] type_id the type-id to check /// \return whether type-id is a signed integer type one constexpr bool is_signed_integer(Type::type type_id) { switch (type_id) { case Type::INT8: case Type::INT16: case Type::INT32: case Type::INT64: return true; default: break; } return false; } /// \brief Check for an unsigned integer type /// /// \param[in] type_id the type-id to check /// \return whether type-id is an unsigned integer type one constexpr bool is_unsigned_integer(Type::type type_id) { switch (type_id) { case Type::UINT8: case Type::UINT16: case Type::UINT32: case Type::UINT64: return true; default: break; } return false; } /// \brief Check for a floating point type /// /// \param[in] type_id the type-id to check /// \return whether type-id is a floating point type one constexpr bool is_floating(Type::type type_id) { switch (type_id) { case Type::HALF_FLOAT: case Type::FLOAT: case Type::DOUBLE: return true; default: break; } return false; } /// \brief Check for a physical floating point type /// /// This predicate matches floating-point types, except half-float. constexpr bool is_physical_floating(Type::type type_id) { return is_floating(type_id) && type_id != Type::HALF_FLOAT; } /// \brief Check for a numeric type /// /// This predicate doesn't match decimals (see `is_decimal`). /// /// \param[in] type_id the type-id to check /// \return whether type-id is a numeric type one constexpr bool is_numeric(Type::type type_id) { switch (type_id) { case Type::UINT8: case Type::INT8: case Type::UINT16: case Type::INT16: case Type::UINT32: case Type::INT32: case Type::UINT64: case Type::INT64: case Type::HALF_FLOAT: case Type::FLOAT: case Type::DOUBLE: return true; default: break; } return false; } /// \brief Check for a decimal type /// /// \param[in] type_id the type-id to check /// \return whether type-id is a decimal type one constexpr bool is_decimal(Type::type type_id) { switch (type_id) { case Type::DECIMAL32: case Type::DECIMAL64: case Type::DECIMAL128: case Type::DECIMAL256: return true; default: break; } return false; } /// \brief Check for a type that can be used as a run-end in Run-End Encoded /// arrays /// /// \param[in] type_id the type-id to check /// \return whether type-id can represent a run-end value constexpr bool is_run_end_type(Type::type type_id) { switch (type_id) { case Type::INT16: case Type::INT32: case Type::INT64: return true; default: break; } return false; } /// \brief Check for a primitive type /// /// This predicate doesn't match null, decimals and binary-like types. /// /// \param[in] type_id the type-id to check /// \return whether type-id is a primitive type one constexpr bool is_primitive(Type::type type_id) { switch (type_id) { case Type::BOOL: case Type::UINT8: case Type::INT8: case Type::UINT16: case Type::INT16: case Type::UINT32: case Type::INT32: case Type::UINT64: case Type::INT64: case Type::HALF_FLOAT: case Type::FLOAT: case Type::DOUBLE: case Type::DATE32: case Type::DATE64: case Type::TIME32: case Type::TIME64: case Type::TIMESTAMP: case Type::DURATION: case Type::INTERVAL_MONTHS: case Type::INTERVAL_MONTH_DAY_NANO: case Type::INTERVAL_DAY_TIME: return true; default: break; } return false; } /// \brief Check for a base-binary-like type /// /// This predicate doesn't match fixed-size binary types and will otherwise /// match all binary- and string-like types regardless of offset width. /// /// \param[in] type_id the type-id to check /// \return whether type-id is a base-binary-like type one constexpr bool is_base_binary_like(Type::type type_id) { switch (type_id) { case Type::BINARY: case Type::LARGE_BINARY: case Type::STRING: case Type::LARGE_STRING: return true; default: break; } return false; } /// \brief Check for a binary-like type (i.e. with 32-bit offsets) /// /// \param[in] type_id the type-id to check /// \return whether type-id is a binary-like type one constexpr bool is_binary_like(Type::type type_id) { switch (type_id) { case Type::BINARY: case Type::STRING: return true; default: break; } return false; } /// \brief Check for a large-binary-like type (i.e. with 64-bit offsets) /// /// \param[in] type_id the type-id to check /// \return whether type-id is a large-binary-like type one constexpr bool is_large_binary_like(Type::type type_id) { switch (type_id) { case Type::LARGE_BINARY: case Type::LARGE_STRING: return true; default: break; } return false; } /// \brief Check for a binary (non-string) type /// /// \param[in] type_id the type-id to check /// \return whether type-id is a binary type one constexpr bool is_binary(Type::type type_id) { switch (type_id) { case Type::BINARY: case Type::LARGE_BINARY: return true; default: break; } return false; } /// \brief Check for a binary or binary view (non-string) type /// /// \param[in] type_id the type-id to check /// \return whether type-id is a binary type one constexpr bool is_binary_or_binary_view(Type::type type_id) { switch (type_id) { case Type::BINARY: case Type::LARGE_BINARY: case Type::BINARY_VIEW: return true; default: break; } return false; } /// \brief Check for a string type /// /// \param[in] type_id the type-id to check /// \return whether type-id is a string type one constexpr bool is_string(Type::type type_id) { switch (type_id) { case Type::STRING: case Type::LARGE_STRING: return true; default: break; } return false; } /// \brief Check for a string or string view type /// /// \param[in] type_id the type-id to check /// \return whether type-id is a string type one constexpr bool is_string_or_string_view(Type::type type_id) { switch (type_id) { case Type::STRING: case Type::LARGE_STRING: case Type::STRING_VIEW: return true; default: break; } return false; } /// \brief Check for a binary-view-like type (i.e. string view and binary view) /// /// \param[in] type_id the type-id to check /// \return whether type-id is a binary-view-like type one constexpr bool is_binary_view_like(Type::type type_id) { switch (type_id) { case Type::STRING_VIEW: case Type::BINARY_VIEW: return true; default: break; } return false; } /// \brief Check for a temporal type /// /// \param[in] type_id the type-id to check /// \return whether type-id is a temporal type one constexpr bool is_temporal(Type::type type_id) { switch (type_id) { case Type::DATE32: case Type::DATE64: case Type::TIME32: case Type::TIME64: case Type::TIMESTAMP: return true; default: break; } return false; } /// \brief Check for a time type /// /// \param[in] type_id the type-id to check /// \return whether type-id is a primitive type one constexpr bool is_time(Type::type type_id) { switch (type_id) { case Type::TIME32: case Type::TIME64: return true; default: break; } return false; } /// \brief Check for a date type /// /// \param[in] type_id the type-id to check /// \return whether type-id is a primitive type one constexpr bool is_date(Type::type type_id) { switch (type_id) { case Type::DATE32: case Type::DATE64: return true; default: break; } return false; } /// \brief Check for an interval type /// /// \param[in] type_id the type-id to check /// \return whether type-id is an interval type one constexpr bool is_interval(Type::type type_id) { switch (type_id) { case Type::INTERVAL_MONTHS: case Type::INTERVAL_DAY_TIME: case Type::INTERVAL_MONTH_DAY_NANO: return true; default: break; } return false; } /// \brief Check for a dictionary type /// /// \param[in] type_id the type-id to check /// \return whether type-id is a dictionary type one constexpr bool is_dictionary(Type::type type_id) { return type_id == Type::DICTIONARY; } /// \brief Check for a fixed-size-binary type /// /// This predicate also matches decimals. /// \param[in] type_id the type-id to check /// \return whether type-id is a fixed-size-binary type one constexpr bool is_fixed_size_binary(Type::type type_id) { switch (type_id) { case Type::DECIMAL32: case Type::DECIMAL64: case Type::DECIMAL128: case Type::DECIMAL256: case Type::FIXED_SIZE_BINARY: return true; default: break; } return false; } /// \brief Check for a fixed-width type /// /// \param[in] type_id the type-id to check /// \return whether type-id is a fixed-width type one constexpr bool is_fixed_width(Type::type type_id) { return is_primitive(type_id) || is_dictionary(type_id) || is_fixed_size_binary(type_id); } /// \brief Check for a variable-length list type /// /// \param[in] type_id the type-id to check /// \return whether type-id is a variable-length list type one constexpr bool is_var_length_list(Type::type type_id) { switch (type_id) { case Type::LIST: case Type::LARGE_LIST: case Type::MAP: return true; default: break; } return false; } /// \brief Check for a list type /// /// \param[in] type_id the type-id to check /// \return whether type-id is a list type one constexpr bool is_list(Type::type type_id) { switch (type_id) { case Type::LIST: case Type::LARGE_LIST: case Type::FIXED_SIZE_LIST: return true; default: break; } return false; } /// \brief Check for a list-like type /// /// \param[in] type_id the type-id to check /// \return whether type-id is a list-like type one constexpr bool is_list_like(Type::type type_id) { switch (type_id) { case Type::LIST: case Type::LARGE_LIST: case Type::FIXED_SIZE_LIST: case Type::MAP: return true; default: break; } return false; } /// \brief Check for a var-length list or list-view like type /// /// \param[in] type_id the type-id to check /// \return whether type-id is a var-length list or list-view like type constexpr bool is_var_length_list_like(Type::type type_id) { switch (type_id) { case Type::LIST: case Type::LARGE_LIST: case Type::LIST_VIEW: case Type::LARGE_LIST_VIEW: case Type::MAP: return true; default: break; } return false; } /// \brief Check for a list-view type /// /// \param[in] type_id the type-id to check /// \return whether type-id is a list-view type one constexpr bool is_list_view(Type::type type_id) { switch (type_id) { case Type::LIST_VIEW: case Type::LARGE_LIST_VIEW: return true; default: break; } return false; } /// \brief Check for a nested type /// /// \param[in] type_id the type-id to check /// \return whether type-id is a nested type one constexpr bool is_nested(Type::type type_id) { switch (type_id) { case Type::LIST: case Type::LARGE_LIST: case Type::LIST_VIEW: case Type::LARGE_LIST_VIEW: case Type::FIXED_SIZE_LIST: case Type::MAP: case Type::STRUCT: case Type::SPARSE_UNION: case Type::DENSE_UNION: case Type::RUN_END_ENCODED: return true; default: break; } return false; } /// \brief Check for a union type /// /// \param[in] type_id the type-id to check /// \return whether type-id is a union type one constexpr bool is_union(Type::type type_id) { switch (type_id) { case Type::SPARSE_UNION: case Type::DENSE_UNION: return true; default: break; } return false; } /// \brief Return the values bit width of a type /// /// \param[in] type_id the type-id to check /// \return the values bit width, or 0 if the type does not have fixed-width values /// /// For Type::FIXED_SIZE_BINARY, you will instead need to inspect the concrete /// DataType to get this information. constexpr int bit_width(Type::type type_id) { switch (type_id) { case Type::BOOL: return 1; case Type::UINT8: case Type::INT8: return 8; case Type::UINT16: case Type::INT16: return 16; case Type::UINT32: case Type::INT32: case Type::DATE32: case Type::TIME32: return 32; case Type::UINT64: case Type::INT64: case Type::DATE64: case Type::TIME64: case Type::TIMESTAMP: case Type::DURATION: return 64; case Type::HALF_FLOAT: return 16; case Type::FLOAT: return 32; case Type::DOUBLE: return 64; case Type::INTERVAL_MONTHS: return 32; case Type::INTERVAL_DAY_TIME: return 64; case Type::INTERVAL_MONTH_DAY_NANO: return 128; case Type::DECIMAL32: return 32; case Type::DECIMAL64: return 64; case Type::DECIMAL128: return 128; case Type::DECIMAL256: return 256; default: break; } return 0; } /// \brief Return the offsets bit width of a type /// /// \param[in] type_id the type-id to check /// \return the offsets bit width, or 0 if the type does not have offsets constexpr int offset_bit_width(Type::type type_id) { switch (type_id) { case Type::STRING: case Type::BINARY: case Type::LIST: case Type::LIST_VIEW: case Type::MAP: case Type::DENSE_UNION: return 32; case Type::LARGE_STRING: case Type::LARGE_BINARY: case Type::LARGE_LIST: case Type::LARGE_LIST_VIEW: return 64; default: break; } return 0; } /// \brief Get the alignment a buffer should have to be considered "value aligned" /// /// Some buffers are frequently type-punned. For example, in an int32 array the /// values buffer is frequently cast to int32_t* /// /// This sort of punning is technically only valid if the pointer is aligned to a /// proper width (e.g. 4 bytes in the case of int32). However, most modern compilers /// are quite permissive if we get this wrong. Note that this alignment is something /// that is guaranteed by malloc (e.g. new int32_t[] will return a buffer that is 4 /// byte aligned) or common libraries (e.g. numpy) but it is not currently guaranteed /// by flight (GH-32276). /// /// We call this "value aligned" and this method will calculate that required alignment. /// /// \param type_id the type of the array containing the buffer /// Note: this should be the indices type for a dictionary array since /// A dictionary array's buffers are indices. It should be the storage /// type for an extension array. /// \param buffer_index the index of the buffer to check, for example 0 will typically /// give you the alignment expected of the validity buffer /// \return the required value alignment in bytes (1 if no alignment required) int RequiredValueAlignmentForBuffer(Type::type type_id, int buffer_index); /// \brief Check for an integer type (signed or unsigned) /// /// \param[in] type the type to check /// \return whether type is an integer type /// /// Convenience for checking using the type's id constexpr bool is_integer(const DataType& type) { return is_integer(type.id()); } /// \brief Check for a signed integer type /// /// \param[in] type the type to check /// \return whether type is a signed integer type /// /// Convenience for checking using the type's id constexpr bool is_signed_integer(const DataType& type) { return is_signed_integer(type.id()); } /// \brief Check for an unsigned integer type /// /// \param[in] type the type to check /// \return whether type is an unsigned integer type /// /// Convenience for checking using the type's id constexpr bool is_unsigned_integer(const DataType& type) { return is_unsigned_integer(type.id()); } /// \brief Check for a floating point type /// /// \param[in] type the type to check /// \return whether type is a floating point type /// /// Convenience for checking using the type's id constexpr bool is_floating(const DataType& type) { return is_floating(type.id()); } /// \brief Check for a numeric type (number except boolean type) /// /// \param[in] type the type to check /// \return whether type is a numeric type /// /// Convenience for checking using the type's id constexpr bool is_numeric(const DataType& type) { return is_numeric(type.id()); } /// \brief Check for a decimal type /// /// \param[in] type the type to check /// \return whether type is a decimal type /// /// Convenience for checking using the type's id constexpr bool is_decimal(const DataType& type) { return is_decimal(type.id()); } /// \brief Check for a primitive type /// /// \param[in] type the type to check /// \return whether type is a primitive type /// /// Convenience for checking using the type's id constexpr bool is_primitive(const DataType& type) { return is_primitive(type.id()); } /// \brief Check for a binary or string-like type (except fixed-size binary) /// /// \param[in] type the type to check /// \return whether type is a binary or string-like type /// /// Convenience for checking using the type's id constexpr bool is_base_binary_like(const DataType& type) { return is_base_binary_like(type.id()); } /// \brief Check for a binary-like type /// /// \param[in] type the type to check /// \return whether type is a binary-like type /// /// Convenience for checking using the type's id constexpr bool is_binary_like(const DataType& type) { return is_binary_like(type.id()); } /// \brief Check for a large-binary-like type /// /// \param[in] type the type to check /// \return whether type is a large-binary-like type /// /// Convenience for checking using the type's id constexpr bool is_large_binary_like(const DataType& type) { return is_large_binary_like(type.id()); } /// \brief Check for a binary type /// /// \param[in] type the type to check /// \return whether type is a binary type /// /// Convenience for checking using the type's id constexpr bool is_binary(const DataType& type) { return is_binary(type.id()); } /// \brief Check for a string type /// /// \param[in] type the type to check /// \return whether type is a string type /// /// Convenience for checking using the type's id constexpr bool is_string(const DataType& type) { return is_string(type.id()); } /// \brief Check for a binary-view-like type /// /// \param[in] type the type to check /// \return whether type is a binary-view-like type /// /// Convenience for checking using the type's id constexpr bool is_binary_view_like(const DataType& type) { return is_binary_view_like(type.id()); } /// \brief Check for a temporal type, including time and timestamps for each unit /// /// \param[in] type the type to check /// \return whether type is a temporal type /// /// Convenience for checking using the type's id constexpr bool is_temporal(const DataType& type) { return is_temporal(type.id()); } /// \brief Check for an interval type /// /// \param[in] type the type to check /// \return whether type is a interval type /// /// Convenience for checking using the type's id constexpr bool is_interval(const DataType& type) { return is_interval(type.id()); } /// \brief Check for a dictionary type /// /// \param[in] type the type to check /// \return whether type is a dictionary type /// /// Convenience for checking using the type's id constexpr bool is_dictionary(const DataType& type) { return is_dictionary(type.id()); } /// \brief Check for a fixed-size-binary type /// /// \param[in] type the type to check /// \return whether type is a fixed-size-binary type /// /// Convenience for checking using the type's id constexpr bool is_fixed_size_binary(const DataType& type) { return is_fixed_size_binary(type.id()); } /// \brief Check for a fixed-width type /// /// \param[in] type the type to check /// \return whether type is a fixed-width type /// /// Convenience for checking using the type's id constexpr bool is_fixed_width(const DataType& type) { return is_fixed_width(type.id()); } /// \brief Check for a variable-length list type /// /// \param[in] type the type to check /// \return whether type is a variable-length list type /// /// Convenience for checking using the type's id constexpr bool is_var_length_list(const DataType& type) { return is_var_length_list(type.id()); } /// \brief Check for a list-like type /// /// \param[in] type the type to check /// \return whether type is a list-like type /// /// Convenience for checking using the type's id constexpr bool is_list_like(const DataType& type) { return is_list_like(type.id()); } /// \brief Check for a var-length list or list-view like type /// /// \param[in] type the type to check /// \return whether type is a var-length list or list-view like type /// /// Convenience for checking using the type's id constexpr bool is_var_length_list_like(const DataType& type) { return is_var_length_list_like(type.id()); } /// \brief Check for a list-view type /// /// \param[in] type the type to check /// \return whether type is a list-view type /// /// Convenience for checking using the type's id constexpr bool is_list_view(const DataType& type) { return is_list_view(type.id()); } /// \brief Check for a nested type /// /// \param[in] type the type to check /// \return whether type is a nested type /// /// Convenience for checking using the type's id constexpr bool is_nested(const DataType& type) { return is_nested(type.id()); } /// \brief Check for a union type /// /// \param[in] type the type to check /// \return whether type is a union type /// /// Convenience for checking using the type's id constexpr bool is_union(const DataType& type) { return is_union(type.id()); } /// @} } // namespace arrow