diff --git a/cpp/src/arrow/type_test.cc b/cpp/src/arrow/type_test.cc index cb17f1ac3fc..344398bb2cf 100644 --- a/cpp/src/arrow/type_test.cc +++ b/cpp/src/arrow/type_test.cc @@ -32,10 +32,12 @@ #include "arrow/memory_pool.h" #include "arrow/table.h" #include "arrow/testing/gtest_util.h" +#include "arrow/testing/matchers.h" #include "arrow/testing/random.h" #include "arrow/testing/util.h" #include "arrow/type.h" #include "arrow/type_traits.h" +#include "arrow/util/logging.h" #include "arrow/util/checked_cast.h" #include "arrow/util/key_value_metadata.h" @@ -49,6 +51,66 @@ TEST(TestTypeId, AllTypeIds) { ASSERT_EQ(static_cast(all_ids.size()), Type::MAX_ID); } +TEST(TestTypeSingleton, ParameterFreeTypes) { + // Test successful cases - parameter-free types + std::vector>> cases = { + {Type::NA, null()}, + {Type::BOOL, boolean()}, + {Type::INT8, int8()}, + {Type::INT16, int16()}, + {Type::INT32, int32()}, + {Type::INT64, int64()}, + {Type::UINT8, uint8()}, + {Type::UINT16, uint16()}, + {Type::UINT32, uint32()}, + {Type::UINT64, uint64()}, + {Type::HALF_FLOAT, float16()}, + {Type::FLOAT, float32()}, + {Type::DOUBLE, float64()}, + {Type::STRING, utf8()}, + {Type::BINARY, binary()}, + {Type::LARGE_STRING, large_utf8()}, + {Type::LARGE_BINARY, large_binary()}, + {Type::DATE32, date32()}, + }; + + for (const auto& test_case : cases) { + SCOPED_TRACE("Testing type: " + std::to_string(static_cast(test_case.first))); + auto result = type_singleton(test_case.first); + ASSERT_OK_AND_ASSIGN(auto type, result); + ASSERT_TRUE(type->Equals(*test_case.second)) + << "Failed on type " << test_case.first << ". Expected " + << test_case.second->ToString() << " but got " << type->ToString(); + } +} + +TEST(TestTypeSingleton, ParameterizedTypes) { + // Test error cases - parameterized types + std::vector parameterized_types = { + Type::TIMESTAMP, Type::TIME32, Type::TIME64, + Type::DURATION, Type::FIXED_SIZE_BINARY, Type::DECIMAL128, + Type::LIST, Type::LARGE_LIST, Type::FIXED_SIZE_LIST, + Type::STRUCT, Type::DICTIONARY, Type::MAP, + Type::EXTENSION + }; + + for (const auto type_id : parameterized_types) { + SCOPED_TRACE("Testing type: " + std::to_string(static_cast(type_id))); + auto result = type_singleton(type_id); + ASSERT_FALSE(result.ok()); + const auto& status = result.status(); + EXPECT_THAT(status.message(), testing::HasSubstr("is not a parameter-free singleton type")); + } +} + +TEST(TestTypeSingleton, InvalidType) { + // Test with an invalid type ID + auto result = type_singleton(static_cast(9999)); + ASSERT_FALSE(result.ok()); + const auto& status = result.status(); + EXPECT_THAT(status.message(), testing::HasSubstr("requires parameters or is not supported")); +} + template void CheckTypeIdReprs(ReprFunc&& repr_func, bool expect_uppercase) { std::unordered_set unique_reprs; diff --git a/cpp/src/arrow/type_traits.cc b/cpp/src/arrow/type_traits.cc index 80571e0248d..c032c2ae01c 100644 --- a/cpp/src/arrow/type_traits.cc +++ b/cpp/src/arrow/type_traits.cc @@ -17,10 +17,73 @@ #include "arrow/type_traits.h" +#include "arrow/result.h" +#include "arrow/status.h" +#include "arrow/type.h" #include "arrow/util/logging_internal.h" namespace arrow { +Result> type_singleton(Type::type id) { + switch (id) { + case Type::NA: + return null(); + case Type::BOOL: + return boolean(); + case Type::INT8: + return int8(); + case Type::INT16: + return int16(); + case Type::INT32: + return int32(); + case Type::INT64: + return int64(); + case Type::UINT8: + return uint8(); + case Type::UINT16: + return uint16(); + case Type::UINT32: + return uint32(); + case Type::UINT64: + return uint64(); + case Type::HALF_FLOAT: + return float16(); + case Type::FLOAT: + return float32(); + case Type::DOUBLE: + return float64(); + case Type::STRING: + return utf8(); + case Type::BINARY: + return binary(); + case Type::LARGE_STRING: + return large_utf8(); + case Type::LARGE_BINARY: + return large_binary(); + case Type::DATE32: + return date32(); + + // Explicitly handle known parameterized types + case Type::TIMESTAMP: + case Type::TIME32: + case Type::TIME64: + case Type::DURATION: + case Type::FIXED_SIZE_BINARY: + case Type::DECIMAL128: + case Type::LIST: + case Type::LARGE_LIST: + case Type::FIXED_SIZE_LIST: + case Type::STRUCT: + case Type::DICTIONARY: + case Type::MAP: + case Type::EXTENSION: + return Status::Invalid("Type ", id, " is not a parameter-free singleton type."); + + default: + return Status::Invalid("Type ", id, " requires parameters or is not supported"); + } +} + int RequiredValueAlignmentForBuffer(Type::type type_id, int buffer_index) { if (buffer_index == 2 && type_id == Type::DENSE_UNION) { // A dense union array is the only array (so far) that requires alignment diff --git a/cpp/src/arrow/type_traits.h b/cpp/src/arrow/type_traits.h index 1b7a02e1085..4bb61abd468 100644 --- a/cpp/src/arrow/type_traits.h +++ b/cpp/src/arrow/type_traits.h @@ -22,8 +22,10 @@ #include #include +#include "arrow/result.h" #include "arrow/type.h" #include "arrow/util/bit_util.h" +#include "arrow/util/macros.h" namespace arrow { @@ -596,6 +598,19 @@ struct TypeTraits { }; /// @} +/// \brief Create a data type instance from a type ID for parameter-free types +/// +/// This function creates a data type instance for types that don't require +/// additional parameters (where TypeTraits::is_parameter_free is true). +/// For types that require parameters (like TimestampType or ListType), +/// this function will return an error. +/// +/// \param[in] id The type ID to create a type instance for +/// \return Result with a shared pointer to the created DataType instance, +/// or an error if the type requires parameters +ARROW_EXPORT +Result> type_singleton(Type::type id); + namespace internal { template