Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions cpp/src/arrow/type.cc
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
#include "arrow/result.h"
#include "arrow/status.h"
#include "arrow/table.h"
#include "arrow/type_traits.h"
#include "arrow/util/checked_cast.h"
#include "arrow/util/decimal.h"
#include "arrow/util/hash_util.h"
Expand Down Expand Up @@ -3552,4 +3553,16 @@ const std::vector<Type::type>& DecimalTypeIds() {
return type_ids;
}

Result<std::shared_ptr<DataType>> type_singleton(Type::type id) {
auto visit = [](auto type) -> Result<std::shared_ptr<DataType>> {
using T = std::decay_t<decltype(*type)>;
if constexpr (TypeTraits<T>::is_parameter_free) {
return TypeTraits<T>::type_singleton();
}
return Status::TypeError("Type ", internal::ToString(T::type_id),
" is not a parameter-free type");
};
return VisitTypeId(id, visit);
}

} // namespace arrow
13 changes: 13 additions & 0 deletions cpp/src/arrow/type.h
Original file line number Diff line number Diff line change
Expand Up @@ -2645,4 +2645,17 @@ const std::vector<std::shared_ptr<DataType>>& PrimitiveTypes();
ARROW_EXPORT
const std::vector<Type::type>& DecimalTypeIds();

/// \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<T>::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 The type instance for the given type ID,
/// or a TypeError if the type requires parameters
ARROW_EXPORT
Result<std::shared_ptr<DataType>> type_singleton(Type::type id);

} // namespace arrow
24 changes: 24 additions & 0 deletions cpp/src/arrow/type_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#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"
Expand All @@ -50,6 +51,29 @@ TEST(TestTypeId, AllTypeIds) {
ASSERT_EQ(static_cast<int>(all_ids.size()), Type::MAX_ID);
}

TEST(TestTypeSingleton, ParameterFreeTypes) {
// Test successful cases - parameter-free types (sample a few)
std::vector<std::pair<Type::type, std::shared_ptr<DataType>>> cases = {
{Type::NA, null()}, {Type::BOOL, boolean()}, {Type::INT32, int32()},
{Type::STRING, utf8()}, {Type::DATE32, date32()},
};

for (const auto& test_case : cases) {
ARROW_SCOPED_TRACE("Testing type: ", internal::ToString(test_case.first));
auto result = type_singleton(test_case.first);
ASSERT_OK_AND_ASSIGN(auto type, result);
AssertTypeEqual(*type, *test_case.second);
}
}

TEST(TestTypeSingleton, ParameterizedTypes) {
// Test error cases - parameterized types (test one representative)
auto result = type_singleton(Type::TIMESTAMP);
ASSERT_RAISES(TypeError, result);
EXPECT_THAT(result.status().message(),
testing::HasSubstr("is not a parameter-free type"));
}

template <typename ReprFunc>
void CheckTypeIdReprs(ReprFunc&& repr_func, bool expect_uppercase) {
std::unordered_set<std::string> unique_reprs;
Expand Down
32 changes: 29 additions & 3 deletions cpp/src/arrow/visit_type_inline.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,8 @@ inline Status VisitTypeInline(const DataType& type, VISITOR* visitor, ARGS&&...
/// \tparam ARGS Additional arguments, if any, will be passed to the Visit function after
/// the `type` argument
///
/// Unlike VisitTypeInline which calls `visitor.Visit`, here `visitor`
/// Unlike VisitTypeInline which calls `visitor->Visit`, here `visitor`
/// itself is called.
/// `visitor` must support a `const DataType&` argument as a fallback,
/// in addition to concrete type classes.
///
/// The intent is for this to be called on a generic lambda
/// that may internally use `if constexpr` or similar constructs.
Expand Down Expand Up @@ -114,4 +112,32 @@ inline Status VisitTypeIdInline(Type::type id, VISITOR* visitor, ARGS&&... args)

#undef TYPE_ID_VISIT_INLINE

#define TYPE_ID_VISIT_INLINE(TYPE_CLASS) \
case TYPE_CLASS##Type::type_id: { \
const TYPE_CLASS##Type* concrete_ptr = NULLPTR; \
return std::forward<VISITOR>(visitor)(concrete_ptr, std::forward<ARGS>(args)...); \
}

/// \brief Calls `visitor` with a nullptr of the corresponding concrete type class
/// \tparam ARGS Additional arguments, if any, will be passed to the Visit function after
/// the `type` argument
///
/// Unlike VisitTypeIdInline which calls `visitor->Visit`, here `visitor`
/// itself is called.
///
/// The intent is for this to be called on a generic lambda
/// that may internally use `if constexpr` or similar constructs.
template <typename VISITOR, typename... ARGS>
inline auto VisitTypeId(Type::type id, VISITOR&& visitor, ARGS&&... args)
-> decltype(std::forward<VISITOR>(visitor)(std::declval<DataType*>(), args...)) {
switch (id) {
ARROW_GENERATE_FOR_ALL_TYPES(TYPE_ID_VISIT_INLINE);
default:
break;
}
return Status::NotImplemented("Type not implemented");
}

#undef TYPE_ID_VISIT_INLINE

} // namespace arrow
Loading