This is an automated email from the ASF dual-hosted git repository.

apitrou pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow.git


The following commit(s) were added to refs/heads/main by this push:
     new 99984fd256 GH-46531: [C++] Add type_singleton utility function and 
tests. (#47922)
99984fd256 is described below

commit 99984fd256c473cbdec461abdbddcca80b08b941
Author: Harshkumar Thakur <[email protected]>
AuthorDate: Wed Feb 18 22:33:10 2026 +0530

    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 <[email protected]>
    Signed-off-by: Antoine Pitrou <[email protected]>
---
 cpp/src/arrow/type.cc             | 13 +++++++++++++
 cpp/src/arrow/type.h              | 13 +++++++++++++
 cpp/src/arrow/type_test.cc        | 24 ++++++++++++++++++++++++
 cpp/src/arrow/visit_type_inline.h | 32 +++++++++++++++++++++++++++++---
 4 files changed, 79 insertions(+), 3 deletions(-)

diff --git a/cpp/src/arrow/type.cc b/cpp/src/arrow/type.cc
index cba4a0ecd3..b9fe6746f9 100644
--- a/cpp/src/arrow/type.cc
+++ b/cpp/src/arrow/type.cc
@@ -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"
@@ -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
diff --git a/cpp/src/arrow/type.h b/cpp/src/arrow/type.h
index e3582056ea..5d41a45b6f 100644
--- a/cpp/src/arrow/type.h
+++ b/cpp/src/arrow/type.h
@@ -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
diff --git a/cpp/src/arrow/type_test.cc b/cpp/src/arrow/type_test.cc
index e9b1d30e6e..6197ad58eb 100644
--- a/cpp/src/arrow/type_test.cc
+++ b/cpp/src/arrow/type_test.cc
@@ -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"
@@ -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;
diff --git a/cpp/src/arrow/visit_type_inline.h 
b/cpp/src/arrow/visit_type_inline.h
index 30f5bb5416..84d162d15c 100644
--- a/cpp/src/arrow/visit_type_inline.h
+++ b/cpp/src/arrow/visit_type_inline.h
@@ -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.
@@ -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

Reply via email to