Skip to content

Commit 99984fd

Browse files
GH-46531: [C++] Add type_singleton utility function and tests. (#47922)
### Rationale for this change Introduce a `type_singleton(Type::type id)` utility to create parameter-free DataType instances (such as int32, boolean, utf8, etc.). Returns an error for parameterized types. ### Are these changes tested? Yes, by additional unit tests in `type_test.cc`. ### Are there any user-facing changes? No. * GitHub Issue: #46531 Authored-by: Harsh <kumarharsh93982@gmail.com> Signed-off-by: Antoine Pitrou <antoine@python.org>
1 parent 9cf8f33 commit 99984fd

4 files changed

Lines changed: 79 additions & 3 deletions

File tree

cpp/src/arrow/type.cc

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
#include "arrow/result.h"
3939
#include "arrow/status.h"
4040
#include "arrow/table.h"
41+
#include "arrow/type_traits.h"
4142
#include "arrow/util/checked_cast.h"
4243
#include "arrow/util/decimal.h"
4344
#include "arrow/util/hash_util.h"
@@ -3552,4 +3553,16 @@ const std::vector<Type::type>& DecimalTypeIds() {
35523553
return type_ids;
35533554
}
35543555

3556+
Result<std::shared_ptr<DataType>> type_singleton(Type::type id) {
3557+
auto visit = [](auto type) -> Result<std::shared_ptr<DataType>> {
3558+
using T = std::decay_t<decltype(*type)>;
3559+
if constexpr (TypeTraits<T>::is_parameter_free) {
3560+
return TypeTraits<T>::type_singleton();
3561+
}
3562+
return Status::TypeError("Type ", internal::ToString(T::type_id),
3563+
" is not a parameter-free type");
3564+
};
3565+
return VisitTypeId(id, visit);
3566+
}
3567+
35553568
} // namespace arrow

cpp/src/arrow/type.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2645,4 +2645,17 @@ const std::vector<std::shared_ptr<DataType>>& PrimitiveTypes();
26452645
ARROW_EXPORT
26462646
const std::vector<Type::type>& DecimalTypeIds();
26472647

2648+
/// \brief Create a data type instance from a type ID for parameter-free types
2649+
///
2650+
/// This function creates a data type instance for types that don't require
2651+
/// additional parameters (where TypeTraits<T>::is_parameter_free is true).
2652+
/// For types that require parameters (like TimestampType or ListType),
2653+
/// this function will return an error.
2654+
///
2655+
/// \param[in] id The type ID to create a type instance for
2656+
/// \return The type instance for the given type ID,
2657+
/// or a TypeError if the type requires parameters
2658+
ARROW_EXPORT
2659+
Result<std::shared_ptr<DataType>> type_singleton(Type::type id);
2660+
26482661
} // namespace arrow

cpp/src/arrow/type_test.cc

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include "arrow/memory_pool.h"
3434
#include "arrow/table.h"
3535
#include "arrow/testing/gtest_util.h"
36+
#include "arrow/testing/matchers.h"
3637
#include "arrow/testing/random.h"
3738
#include "arrow/testing/util.h"
3839
#include "arrow/type.h"
@@ -50,6 +51,29 @@ TEST(TestTypeId, AllTypeIds) {
5051
ASSERT_EQ(static_cast<int>(all_ids.size()), Type::MAX_ID);
5152
}
5253

54+
TEST(TestTypeSingleton, ParameterFreeTypes) {
55+
// Test successful cases - parameter-free types (sample a few)
56+
std::vector<std::pair<Type::type, std::shared_ptr<DataType>>> cases = {
57+
{Type::NA, null()}, {Type::BOOL, boolean()}, {Type::INT32, int32()},
58+
{Type::STRING, utf8()}, {Type::DATE32, date32()},
59+
};
60+
61+
for (const auto& test_case : cases) {
62+
ARROW_SCOPED_TRACE("Testing type: ", internal::ToString(test_case.first));
63+
auto result = type_singleton(test_case.first);
64+
ASSERT_OK_AND_ASSIGN(auto type, result);
65+
AssertTypeEqual(*type, *test_case.second);
66+
}
67+
}
68+
69+
TEST(TestTypeSingleton, ParameterizedTypes) {
70+
// Test error cases - parameterized types (test one representative)
71+
auto result = type_singleton(Type::TIMESTAMP);
72+
ASSERT_RAISES(TypeError, result);
73+
EXPECT_THAT(result.status().message(),
74+
testing::HasSubstr("is not a parameter-free type"));
75+
}
76+
5377
template <typename ReprFunc>
5478
void CheckTypeIdReprs(ReprFunc&& repr_func, bool expect_uppercase) {
5579
std::unordered_set<std::string> unique_reprs;

cpp/src/arrow/visit_type_inline.h

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,10 +71,8 @@ inline Status VisitTypeInline(const DataType& type, VISITOR* visitor, ARGS&&...
7171
/// \tparam ARGS Additional arguments, if any, will be passed to the Visit function after
7272
/// the `type` argument
7373
///
74-
/// Unlike VisitTypeInline which calls `visitor.Visit`, here `visitor`
74+
/// Unlike VisitTypeInline which calls `visitor->Visit`, here `visitor`
7575
/// itself is called.
76-
/// `visitor` must support a `const DataType&` argument as a fallback,
77-
/// in addition to concrete type classes.
7876
///
7977
/// The intent is for this to be called on a generic lambda
8078
/// that may internally use `if constexpr` or similar constructs.
@@ -114,4 +112,32 @@ inline Status VisitTypeIdInline(Type::type id, VISITOR* visitor, ARGS&&... args)
114112

115113
#undef TYPE_ID_VISIT_INLINE
116114

115+
#define TYPE_ID_VISIT_INLINE(TYPE_CLASS) \
116+
case TYPE_CLASS##Type::type_id: { \
117+
const TYPE_CLASS##Type* concrete_ptr = NULLPTR; \
118+
return std::forward<VISITOR>(visitor)(concrete_ptr, std::forward<ARGS>(args)...); \
119+
}
120+
121+
/// \brief Calls `visitor` with a nullptr of the corresponding concrete type class
122+
/// \tparam ARGS Additional arguments, if any, will be passed to the Visit function after
123+
/// the `type` argument
124+
///
125+
/// Unlike VisitTypeIdInline which calls `visitor->Visit`, here `visitor`
126+
/// itself is called.
127+
///
128+
/// The intent is for this to be called on a generic lambda
129+
/// that may internally use `if constexpr` or similar constructs.
130+
template <typename VISITOR, typename... ARGS>
131+
inline auto VisitTypeId(Type::type id, VISITOR&& visitor, ARGS&&... args)
132+
-> decltype(std::forward<VISITOR>(visitor)(std::declval<DataType*>(), args...)) {
133+
switch (id) {
134+
ARROW_GENERATE_FOR_ALL_TYPES(TYPE_ID_VISIT_INLINE);
135+
default:
136+
break;
137+
}
138+
return Status::NotImplemented("Type not implemented");
139+
}
140+
141+
#undef TYPE_ID_VISIT_INLINE
142+
117143
} // namespace arrow

0 commit comments

Comments
 (0)