Repository: apache/arrow
Pull request #46381: GH-46380: [GLib] Add GArrowFixedShapeDataType#shape
Author: login: hiroyuki-sato
Labels: name: Component: GLib
name: awaiting merge
description: Awaiting merge
Created: 2025-05-09T16:07:37Z | Merged: 2025-05-11T14:28:58Z

### Rationale for this change

The C++ API implemented `FixedShapeTensor::shape()` instance method. GLib was not yet supported.

### What changes are included in this PR?

Add `GArrowFixedShapeTensorDataType#shape`  instance method.

### Are these changes tested?

Yes.

### Are there any user-facing changes?

Yes.

* GitHub Issue: #46380


Diff:
diff --git a/c_glib/arrow-glib/basic-data-type.cpp b/c_glib/arrow-glib/basic-data-type.cpp
index 1dc6b1de6e82..cadaec5559f8 100644
--- a/c_glib/arrow-glib/basic-data-type.cpp
+++ b/c_glib/arrow-glib/basic-data-type.cpp
@@ -2347,6 +2347,25 @@ garrow_fixed_shape_tensor_data_type_new(GArrowDataType *value_type,
   return data_type;
 }
 
+/**
+ * garrow_fixed_shape_tensor_data_type_get_shape:
+ * @data_type: A #GArrowFixedShapeTensorDataType.
+ * @length: (out): Return location for the number of dimensions of the tensor.
+ *
+ * Returns: (array length=length): Shape of the tensor.
+ */
+const gint64 *
+garrow_fixed_shape_tensor_data_type_get_shape(GArrowFixedShapeTensorDataType *data_type,
+                                              gsize *length)
+{
+  auto arrow_data_type = std::static_pointer_cast<arrow::extension::FixedShapeTensorType>(
+    garrow_data_type_get_raw(GARROW_DATA_TYPE(data_type)));
+
+  const auto &arrow_shape = arrow_data_type->shape();
+  *length = arrow_shape.size();
+  return arrow_shape.data();
+}
+
 G_END_DECLS
 
 GArrowDataType *
diff --git a/c_glib/arrow-glib/basic-data-type.h b/c_glib/arrow-glib/basic-data-type.h
index 10353debdfed..86f5259e42ef 100644
--- a/c_glib/arrow-glib/basic-data-type.h
+++ b/c_glib/arrow-glib/basic-data-type.h
@@ -826,4 +826,8 @@ garrow_fixed_shape_tensor_data_type_new(GArrowDataType *value_type,
                                         gsize n_dim_names,
                                         GError **error);
 
+GARROW_AVAILABLE_IN_21_0
+const gint64 *
+garrow_fixed_shape_tensor_data_type_get_shape(GArrowFixedShapeTensorDataType *data_type,
+                                              gsize *length);
 G_END_DECLS
diff --git a/c_glib/test/test-fixed-shape-tensor-data-type.rb b/c_glib/test/test-fixed-shape-tensor-data-type.rb
index 2e7bc2cbf119..40b3ed2fc503 100644
--- a/c_glib/test/test-fixed-shape-tensor-data-type.rb
+++ b/c_glib/test/test-fixed-shape-tensor-data-type.rb
@@ -16,30 +16,29 @@
 # under the License.
 
 class TestFixedShapeTensorDataType < Test::Unit::TestCase
+  def setup
+    @data_type = Arrow::FixedShapeTensorDataType.new(Arrow::UInt64DataType.new,
+                                                     [3, 4],
+                                                     [1, 0],
+                                                     ["x", "y"])
+  end
+
   def test_id
-    data_type = Arrow::FixedShapeTensorDataType.new(Arrow::UInt64DataType.new,
-                                                    [3, 4],
-                                                    [1, 0],
-                                                    ["x", "y"])
-    assert_equal(Arrow::Type::EXTENSION, data_type.id)
+    assert_equal(Arrow::Type::EXTENSION, @data_type.id)
   end
 
   def test_name
-    data_type = Arrow::FixedShapeTensorDataType.new(Arrow::UInt64DataType.new,
-                                                    [3, 4],
-                                                    [1, 0],
-                                                    ["x", "y"])
     assert_equal(["extension", "arrow.fixed_shape_tensor"],
-                 [data_type.name, data_type.extension_name])
+                 [@data_type.name, @data_type.extension_name])
+  end
+
+  def test_shape
+    assert_equal([3, 4], @data_type.shape)
   end
 
   def test_to_s
-    data_type = Arrow::FixedShapeTensorDataType.new(Arrow::UInt64DataType.new,
-                                                    [3, 4],
-                                                    [1, 0],
-                                                    ["x", "y"])
     assert do
-      data_type.to_s.start_with?("extension<arrow.fixed_shape_tensor")
+      @data_type.to_s.start_with?("extension<arrow.fixed_shape_tensor")
     end
   end
 


Reviews:
user: login: kou
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-10T02:21:03Z
user: login: kou
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-10T06:59:41Z
user: login: kou
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-11T07:36:05Z
user: login: kou
body: +1
state: APPROVED
author_association: MEMBER
submitted_at: 2025-05-11T14:28:40Z

Review comments:
diff_hunk: @@ -2347,6 +2347,34 @@ garrow_fixed_shape_tensor_data_type_new(GArrowDataType *value_type,
   return data_type;
 }
 
+/**
+ * garrow_fixed_shape_tensor_data_type_get_shape:
+ * @object: A #GArrowDataType of individual tensor elements.
+ * @length: (out) (optional): return location for the number of elements in the returned
+ *   array
path: c_glib/arrow-glib/basic-data-type.cpp
user: login: kou
body: ```suggestion
 * @length: (out): return location for the number of elements in the returned array.
```
created_at: 2025-05-10T02:16:08Z
author_association: MEMBER
diff_hunk: @@ -2347,6 +2347,34 @@ garrow_fixed_shape_tensor_data_type_new(GArrowDataType *value_type,
   return data_type;
 }
 
+/**
+ * garrow_fixed_shape_tensor_data_type_get_shape:
+ * @object: A #GArrowDataType of individual tensor elements.
+ * @length: (out) (optional): return location for the number of elements in the returned
+ *   array
+ *
+ * Returns: (transfer full) (array length=length): Shape of tensor elements.
+ */
+gint64 *
+garrow_fixed_shape_tensor_data_type_get_shape(GArrowFixedShapeTensorDataType *object,
+                                              gsize *length)
+{
+  const auto priv = GARROW_DATA_TYPE_GET_PRIVATE(object);
+  auto arrow_data_type =
+    std::static_pointer_cast<arrow::extension::FixedShapeTensorType>(priv->data_type);
+  auto arrow_shape = arrow_data_type->shape();
+
+  gsize n_shape = arrow_shape.size();
path: c_glib/arrow-glib/basic-data-type.cpp
user: login: kou
body: ```suggestion
  *length = arrow_shape.size();
```
created_at: 2025-05-10T02:16:50Z
author_association: MEMBER
diff_hunk: @@ -2347,6 +2347,34 @@ garrow_fixed_shape_tensor_data_type_new(GArrowDataType *value_type,
   return data_type;
 }
 
+/**
+ * garrow_fixed_shape_tensor_data_type_get_shape:
+ * @object: A #GArrowDataType of individual tensor elements.
+ * @length: (out) (optional): return location for the number of elements in the returned
+ *   array
+ *
+ * Returns: (transfer full) (array length=length): Shape of tensor elements.
+ */
+gint64 *
path: c_glib/arrow-glib/basic-data-type.cpp
user: login: kou
body: Let's use shape in C++ directly:

```suggestion
 * Returns: (array length=length): Shape of tensor elements.
 */
const gint64 *
```
created_at: 2025-05-10T02:20:20Z
author_association: MEMBER
diff_hunk: @@ -2347,6 +2347,34 @@ garrow_fixed_shape_tensor_data_type_new(GArrowDataType *value_type,
   return data_type;
 }
 
+/**
+ * garrow_fixed_shape_tensor_data_type_get_shape:
+ * @object: A #GArrowDataType of individual tensor elements.
+ * @length: (out) (optional): return location for the number of elements in the returned
+ *   array
+ *
+ * Returns: (transfer full) (array length=length): Shape of tensor elements.
+ */
+gint64 *
+garrow_fixed_shape_tensor_data_type_get_shape(GArrowFixedShapeTensorDataType *object,
+                                              gsize *length)
+{
+  const auto priv = GARROW_DATA_TYPE_GET_PRIVATE(object);
+  auto arrow_data_type =
+    std::static_pointer_cast<arrow::extension::FixedShapeTensorType>(priv->data_type);
+  auto arrow_shape = arrow_data_type->shape();
+
+  gsize n_shape = arrow_shape.size();
+  auto shape = static_cast<gint64 *>(g_malloc_n(sizeof(gint64), n_shape));
+
+  for (gsize i = 0; i < n_shape; ++i) {
+    shape[i] = arrow_shape[i];
+  }
+
+  *length = n_shape;
+  return shape;
path: c_glib/arrow-glib/basic-data-type.cpp
user: login: kou
body: ```suggestion
  return arrow_shape.data();
```
created_at: 2025-05-10T02:20:46Z
author_association: MEMBER
diff_hunk: @@ -2347,6 +2347,25 @@ garrow_fixed_shape_tensor_data_type_new(GArrowDataType *value_type,
   return data_type;
 }
 
+/**
+ * garrow_fixed_shape_tensor_data_type_get_shape:
+ * @object: A #GArrowDataType of individual tensor elements.
+ * @length: (out): return location for the number of elements in the returned array.
+ *
+ * Returns: (array length=length): Shape of tensor elements.
+ */
+const gint64 *
+garrow_fixed_shape_tensor_data_type_get_shape(GArrowFixedShapeTensorDataType *object,
path: c_glib/arrow-glib/basic-data-type.cpp
user: login: kou
body: ```suggestion
garrow_fixed_shape_tensor_data_type_get_shape(GArrowFixedShapeTensorDataType *data_type,
```
created_at: 2025-05-10T06:55:00Z
author_association: MEMBER
diff_hunk: @@ -2347,6 +2347,25 @@ garrow_fixed_shape_tensor_data_type_new(GArrowDataType *value_type,
   return data_type;
 }
 
+/**
+ * garrow_fixed_shape_tensor_data_type_get_shape:
+ * @object: A #GArrowDataType of individual tensor elements.
+ * @length: (out): return location for the number of elements in the returned array.
+ *
+ * Returns: (array length=length): Shape of tensor elements.
+ */
+const gint64 *
+garrow_fixed_shape_tensor_data_type_get_shape(GArrowFixedShapeTensorDataType *object,
+                                              gsize *length)
+{
+  const auto priv = GARROW_DATA_TYPE_GET_PRIVATE(object);
+  auto arrow_data_type =
+    std::static_pointer_cast<arrow::extension::FixedShapeTensorType>(priv->data_type);
path: c_glib/arrow-glib/basic-data-type.cpp
user: login: kou
body: ```suggestion
  auto arrow_data_type =
    std::static_pointer_cast<arrow::extension::FixedShapeTensorType>(garrow_data_type_get_raw(data_type));
```
created_at: 2025-05-10T06:55:13Z
author_association: MEMBER
diff_hunk: @@ -2347,6 +2347,25 @@ garrow_fixed_shape_tensor_data_type_new(GArrowDataType *value_type,
   return data_type;
 }
 
+/**
+ * garrow_fixed_shape_tensor_data_type_get_shape:
+ * @object: A #GArrowDataType of individual tensor elements.
+ * @length: (out): return location for the number of elements in the returned array.
+ *
+ * Returns: (array length=length): Shape of tensor elements.
+ */
+const gint64 *
+garrow_fixed_shape_tensor_data_type_get_shape(GArrowFixedShapeTensorDataType *object,
+                                              gsize *length)
+{
+  const auto priv = GARROW_DATA_TYPE_GET_PRIVATE(object);
+  auto arrow_data_type =
+    std::static_pointer_cast<arrow::extension::FixedShapeTensorType>(priv->data_type);
+
+  *length = arrow_data_type->shape().size();
+  return arrow_data_type->shape().data();
path: c_glib/arrow-glib/basic-data-type.cpp
user: login: kou
body: ```suggestion
  const auto& arrow_shape = arrow_data_type->shape();
  *length = shape.size();
  return shape.data();
```
created_at: 2025-05-10T06:55:53Z
author_association: MEMBER
diff_hunk: @@ -2347,6 +2347,25 @@ garrow_fixed_shape_tensor_data_type_new(GArrowDataType *value_type,
   return data_type;
 }
 
+/**
+ * garrow_fixed_shape_tensor_data_type_get_shape:
+ * @object: A #GArrowDataType of individual tensor elements.
path: c_glib/arrow-glib/basic-data-type.cpp
user: login: kou
body: ```suggestion
 * @data_type: A #GArrowFixedShapeTensorDataType.
```
created_at: 2025-05-10T06:56:13Z
author_association: MEMBER
diff_hunk: @@ -2347,6 +2347,25 @@ garrow_fixed_shape_tensor_data_type_new(GArrowDataType *value_type,
   return data_type;
 }
 
+/**
+ * garrow_fixed_shape_tensor_data_type_get_shape:
+ * @object: A #GArrowDataType of individual tensor elements.
+ * @length: (out): return location for the number of elements in the returned array.
path: c_glib/arrow-glib/basic-data-type.cpp
user: login: kou
body: ```suggestion
 * @length: (out): Return location for the number of dimensions of the tensor.
```
created_at: 2025-05-10T06:58:08Z
author_association: MEMBER
diff_hunk: @@ -2347,6 +2347,25 @@ garrow_fixed_shape_tensor_data_type_new(GArrowDataType *value_type,
   return data_type;
 }
 
+/**
+ * garrow_fixed_shape_tensor_data_type_get_shape:
+ * @object: A #GArrowDataType of individual tensor elements.
+ * @length: (out): return location for the number of elements in the returned array.
+ *
+ * Returns: (array length=length): Shape of tensor elements.
path: c_glib/arrow-glib/basic-data-type.cpp
user: login: kou
body: ```suggestion
 * Returns: (array length=length): Shape of the tensor.
```
created_at: 2025-05-10T06:58:43Z
author_association: MEMBER
diff_hunk: @@ -16,30 +16,29 @@
 # under the License.
 
 class TestFixedShapeTensorDataType < Test::Unit::TestCase
+  def setup
+    @data_type = Arrow::FixedShapeTensorDataType.new(Arrow::UInt64DataType.new,
+                                                     [3, 4],
+                                                     [1, 0],
+                                                     ["x", "y"])
+  end
+
   def test_id
-    data_type = Arrow::FixedShapeTensorDataType.new(Arrow::UInt64DataType.new,
-                                                    [3, 4],
-                                                    [1, 0],
-                                                    ["x", "y"])
-    assert_equal(Arrow::Type::EXTENSION, data_type.id)
+    assert_equal(Arrow::Type::EXTENSION, @data_type.id)
   end
 
   def test_name
-    data_type = Arrow::FixedShapeTensorDataType.new(Arrow::UInt64DataType.new,
-                                                    [3, 4],
-                                                    [1, 0],
-                                                    ["x", "y"])
     assert_equal(["extension", "arrow.fixed_shape_tensor"],
-                 [data_type.name, data_type.extension_name])
+                 [@data_type.name, @data_type.extension_name])
+  end
+
+  def test_shape_size
path: c_glib/test/test-fixed-shape-tensor-data-type.rb
user: login: kou
body: ```suggestion
  def test_shape
```
created_at: 2025-05-11T07:36:05Z
author_association: MEMBER

PR comments:
user: login: github-actions[bot]
created_at: 2025-05-09T16:08:01Z
body: :warning: GitHub issue #46380 **has been automatically assigned in GitHub** to PR creator.
author_association: NONE
user: login: hiroyuki-sato
created_at: 2025-05-10T03:04:02Z
body: @kou Thanks! I applied all of suggested changes.

I have two concerns.

* Compiler warning.
* Test failed.

Do we need to copy values?

```
../c_glib/arrow-glib/basic-data-type.cpp:2367:10: warning: address of stack memory associated with local variable 'arrow_shape' returned [-Wreturn-stack-address]
 2367 |   return arrow_shape.data();
      |          ^~~~~~~~~~~
1 warning generated.
```

```
============================================================================================================================================================================
Failure: test_shape_size(TestFixedShapeTensorDataType)
arrow/arrow/c_glib/test/test-fixed-shape-tensor-data-type.rb:36:in 'TestFixedShapeTensorDataType#test_shape_size'
     33:   end
     34:
     35:   def test_shape_size
  => 36:     assert_equal([3, 4], @data_type.shape)
     37:   end
     38:
     39:   def test_to_s
<[3, 4]> expected but was
<[134527526204240, 2043]>

diff:
? [134527526204240, 2043]
============================================================================================================================================================================
Finished in 0.015831 seconds.
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
8 tests, 10 assertions, 1 failures, 0 errors, 0 pendings, 0 omissions, 0 notifications
87.5% passed
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
505.34 tests/s, 631.67 assertions/s
```

author_association: COLLABORATOR
user: login: hiroyuki-sato
created_at: 2025-05-10T04:58:35Z
body: Changed like this 

```diff
diff --git a/c_glib/arrow-glib/basic-data-type.cpp b/c_glib/arrow-glib/basic-data-type.cpp
index 113c2f103..c572c15f8 100644
--- a/c_glib/arrow-glib/basic-data-type.cpp
+++ b/c_glib/arrow-glib/basic-data-type.cpp
@@ -2361,10 +2361,9 @@ garrow_fixed_shape_tensor_data_type_get_shape(GArrowFixedShapeTensorDataType *ob
   const auto priv = GARROW_DATA_TYPE_GET_PRIVATE(object);
   auto arrow_data_type =
     std::static_pointer_cast<arrow::extension::FixedShapeTensorType>(priv->data_type);
-  auto arrow_shape = arrow_data_type->shape();

-  *length = arrow_shape.size();
-  return arrow_shape.data();
+  *length = arrow_data_type->shape().size();
+  return arrow_data_type->shape().data();
 }

 G_END_DECLS
``
author_association: COLLABORATOR
user: login: hiroyuki-sato
created_at: 2025-05-10T13:12:50Z
body: I applied all your suggested change. Then, changed to `garrow_data_type_get_raw(GARROW_DATA_TYPE(data_type))` instead of `garrow_data_type_get_raw(data_type)` for avoiding the following error.

```
../c_glib/arrow-glib/basic-data-type.cpp:2362:5: error: no matching function for call to 'garrow_data_type_get_raw'
 2362 |     garrow_data_type_get_raw(data_type));
      |     ^~~~~~~~~~~~~~~~~~~~~~~~
../c_glib/arrow-glib/basic-data-type.hpp:29:1: note: candidate function not viable: no known conversion from 'GArrowFixedShapeTensorDataType *' (aka '_GArrowFixedShapeTensorDataType *') to 'GArrowDataType *' (aka '_GArrowDataType *') for 1st argument
   29 | garrow_data_type_get_raw(GArrowDataType *data_type);
      | ^                        ~~~~~~~~~~~~~~~~~~~~~~~~~
1 error generated.
```
author_association: COLLABORATOR
user: login: hiroyuki-sato
created_at: 2025-05-11T14:18:53Z
body: Thanks! Suggested change applied!
author_association: COLLABORATOR
user: login: conbench-apache-arrow[bot]
created_at: 2025-05-11T22:07:33Z
body: After merging your PR, Conbench analyzed the 4 benchmarking runs that have been run so far on merge-commit fae65cdb9deea5469d3eed8d6012f3d24ffdc8dd.

There were no benchmark performance regressions. 🎉

The [full Conbench report](https://github.com/apache/arrow/runs/42020964068) has more details.
author_association: NONE