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

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


The following commit(s) were added to refs/heads/main by this push:
     new 7a808701 fix(cpp): Fix offset handling in ViewArrayAs Range Helpers 
(#702)
7a808701 is described below

commit 7a808701819cb4c5f6b6ddf7c51c09389cd097ff
Author: William Ayd <[email protected]>
AuthorDate: Wed Jan 8 15:16:16 2025 -0500

    fix(cpp): Fix offset handling in ViewArrayAs Range Helpers (#702)
---
 src/nanoarrow/common/utils_test.cc |  2 +-
 src/nanoarrow/hpp/view.hpp         | 23 ++++------
 src/nanoarrow/hpp/view_test.cc     | 88 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 98 insertions(+), 15 deletions(-)

diff --git a/src/nanoarrow/common/utils_test.cc 
b/src/nanoarrow/common/utils_test.cc
index 7c86ca51..648b3b97 100644
--- a/src/nanoarrow/common/utils_test.cc
+++ b/src/nanoarrow/common/utils_test.cc
@@ -739,7 +739,7 @@ TEST(RandomAccessRangeTest, ConstructionAndPrinting) {
   auto square = [](int64_t i) { return i * i; };
 
   // the range is usable as a constant
-  const nanoarrow::internal::RandomAccessRange<decltype(square)> 
squares{square, 4};
+  const nanoarrow::internal::RandomAccessRange<decltype(square)> 
squares{square, 0, 4};
 
   // gtest recognizes the range as a container and can print it
   EXPECT_THAT(squares, testing::ElementsAre(0, 1, 4, 9));
diff --git a/src/nanoarrow/hpp/view.hpp b/src/nanoarrow/hpp/view.hpp
index f0e267ff..0b235c5a 100644
--- a/src/nanoarrow/hpp/view.hpp
+++ b/src/nanoarrow/hpp/view.hpp
@@ -65,6 +65,7 @@ class Maybe {
 template <typename Get>
 struct RandomAccessRange {
   Get get;
+  int64_t offset;
   int64_t size;
 
   using value_type = decltype(std::declval<Get>()(0));
@@ -78,8 +79,8 @@ struct RandomAccessRange {
     value_type operator*() const { return range->get(i); }
   };
 
-  const_iterator begin() const { return {0, this}; }
-  const_iterator end() const { return {size, this}; }
+  const_iterator begin() const { return {offset, this}; }
+  const_iterator end() const { return {offset + size, this}; }
 };
 
 template <typename Next>
@@ -132,10 +133,8 @@ class ViewArrayAs {
   struct Get {
     const uint8_t* validity;
     const void* values;
-    int64_t offset;
 
     internal::Maybe<T> operator()(int64_t i) const {
-      i += offset;
       if (validity == nullptr || ArrowBitGet(validity, i)) {
         if (std::is_same<T, bool>::value) {
           return ArrowBitGet(static_cast<const uint8_t*>(values), i);
@@ -155,8 +154,8 @@ class ViewArrayAs {
             Get{
                 array_view->buffer_views[0].data.as_uint8,
                 array_view->buffer_views[1].data.data,
-                array_view->offset,
             },
+            array_view->offset,
             array_view->length,
         } {}
 
@@ -165,8 +164,8 @@ class ViewArrayAs {
             Get{
                 static_cast<const uint8_t*>(array->buffers[0]),
                 array->buffers[1],
-                /*offset=*/0,
             },
+            array->offset,
             array->length,
         } {}
 
@@ -193,10 +192,8 @@ class ViewArrayAsBytes {
     const uint8_t* validity;
     const void* offsets;
     const char* data;
-    int64_t offset;
 
     internal::Maybe<ArrowStringView> operator()(int64_t i) const {
-      i += offset;
       auto* offsets = static_cast<const OffsetType*>(this->offsets);
       if (validity == nullptr || ArrowBitGet(validity, i)) {
         return ArrowStringView{data + offsets[i], offsets[i + 1] - offsets[i]};
@@ -214,8 +211,8 @@ class ViewArrayAsBytes {
                 array_view->buffer_views[0].data.as_uint8,
                 array_view->buffer_views[1].data.data,
                 array_view->buffer_views[2].data.as_char,
-                array_view->offset,
             },
+            array_view->offset,
             array_view->length,
         } {}
 
@@ -225,8 +222,8 @@ class ViewArrayAsBytes {
                 static_cast<const uint8_t*>(array->buffers[0]),
                 array->buffers[1],
                 static_cast<const char*>(array->buffers[2]),
-                /*offset=*/0,
             },
+            array->offset,
             array->length,
         } {}
 
@@ -246,11 +243,9 @@ class ViewArrayAsFixedSizeBytes {
   struct Get {
     const uint8_t* validity;
     const char* data;
-    int64_t offset;
     int fixed_size;
 
     internal::Maybe<ArrowStringView> operator()(int64_t i) const {
-      i += offset;
       if (validity == nullptr || ArrowBitGet(validity, i)) {
         return ArrowStringView{data + i * fixed_size, fixed_size};
       }
@@ -266,9 +261,9 @@ class ViewArrayAsFixedSizeBytes {
             Get{
                 array_view->buffer_views[0].data.as_uint8,
                 array_view->buffer_views[1].data.as_char,
-                array_view->offset,
                 fixed_size,
             },
+            array_view->offset,
             array_view->length,
         } {}
 
@@ -277,9 +272,9 @@ class ViewArrayAsFixedSizeBytes {
             Get{
                 static_cast<const uint8_t*>(array->buffers[0]),
                 static_cast<const char*>(array->buffers[1]),
-                /*offset=*/0,
                 fixed_size,
             },
+            array->offset,
             array->length,
         } {}
 
diff --git a/src/nanoarrow/hpp/view_test.cc b/src/nanoarrow/hpp/view_test.cc
index e18c7c63..e4cfa499 100644
--- a/src/nanoarrow/hpp/view_test.cc
+++ b/src/nanoarrow/hpp/view_test.cc
@@ -135,3 +135,91 @@ TEST(NanoarrowHppTest, NanoarrowHppViewArrayStreamTest) {
   EXPECT_EQ(stream_view.code(), ENOMEM);
   EXPECT_STREQ(stream_view.error()->message, "foo bar");
 }
+
+TEST(NanoarrowHppTest, NanoarrowHppViewArrayOffsetTest) {
+  nanoarrow::UniqueSchema schema{};
+  ArrowSchemaInit(schema.get());
+  ASSERT_EQ(ArrowSchemaSetType(schema.get(), NANOARROW_TYPE_INT32), 
NANOARROW_OK);
+
+  nanoarrow::UniqueArray array{};
+  ASSERT_EQ(ArrowArrayInitFromSchema(array.get(), schema.get(), nullptr), 
NANOARROW_OK);
+  ASSERT_EQ(ArrowArrayStartAppending(array.get()), NANOARROW_OK);
+  ASSERT_EQ(ArrowArrayAppendInt(array.get(), 0), NANOARROW_OK);
+  ASSERT_EQ(ArrowArrayAppendInt(array.get(), 1), NANOARROW_OK);
+  ASSERT_EQ(ArrowArrayAppendInt(array.get(), 2), NANOARROW_OK);
+  ASSERT_EQ(ArrowArrayAppendInt(array.get(), 3), NANOARROW_OK);
+  ASSERT_EQ(ArrowArrayFinishBuildingDefault(array.get(), nullptr), 
NANOARROW_OK);
+  array->offset = 2;
+  array->length = 2;
+
+  EXPECT_THAT(nanoarrow::ViewArrayAs<int32_t>(array.get()), 
testing::ElementsAre(2, 3));
+
+  nanoarrow::UniqueArrayView array_view{};
+  ASSERT_EQ(ArrowArrayViewInitFromSchema(array_view.get(), schema.get(), 
nullptr),
+            NANOARROW_OK);
+  ASSERT_EQ(ArrowArrayViewSetArray(array_view.get(), array.get(), nullptr), 
NANOARROW_OK);
+
+  EXPECT_THAT(nanoarrow::ViewArrayAs<int32_t>(array_view.get()),
+              testing::ElementsAre(2, 3));
+}
+
+TEST(NanoarrowHppTest, NanoarrowHppViewArrayAsBytesOffsetTest) {
+  using namespace nanoarrow::literals;
+
+  nanoarrow::UniqueSchema schema{};
+  ArrowSchemaInit(schema.get());
+  ASSERT_EQ(ArrowSchemaSetType(schema.get(), NANOARROW_TYPE_STRING), 
NANOARROW_OK);
+
+  nanoarrow::UniqueArray array{};
+  ASSERT_EQ(ArrowArrayInitFromSchema(array.get(), schema.get(), nullptr), 
NANOARROW_OK);
+  ASSERT_EQ(ArrowArrayStartAppending(array.get()), NANOARROW_OK);
+  ASSERT_EQ(ArrowArrayAppendString(array.get(), "foo"_asv), NANOARROW_OK);
+  ASSERT_EQ(ArrowArrayAppendString(array.get(), "bar"_asv), NANOARROW_OK);
+  ASSERT_EQ(ArrowArrayAppendString(array.get(), "baz"_asv), NANOARROW_OK);
+  ASSERT_EQ(ArrowArrayAppendString(array.get(), "qux"_asv), NANOARROW_OK);
+  ASSERT_EQ(ArrowArrayFinishBuildingDefault(array.get(), nullptr), 
NANOARROW_OK);
+  array->offset = 2;
+  array->length = 2;
+
+  EXPECT_THAT(nanoarrow::ViewArrayAsBytes<32>(array.get()),
+              testing::ElementsAre("baz"_asv, "qux"_asv));
+
+  nanoarrow::UniqueArrayView array_view{};
+  ASSERT_EQ(ArrowArrayViewInitFromSchema(array_view.get(), schema.get(), 
nullptr),
+            NANOARROW_OK);
+  ASSERT_EQ(ArrowArrayViewSetArray(array_view.get(), array.get(), nullptr), 
NANOARROW_OK);
+  EXPECT_THAT(nanoarrow::ViewArrayAsBytes<32>(array_view.get()),
+              testing::ElementsAre("baz"_asv, "qux"_asv));
+}
+
+TEST(NanoarrowHppTest, NanoarrowHppViewArrayAsFixedSizeBytesOffsetTest) {
+  using namespace nanoarrow::literals;
+
+  constexpr int32_t FixedSize = 3;
+  nanoarrow::UniqueSchema schema{};
+  ArrowSchemaInit(schema.get());
+  ASSERT_EQ(ArrowSchemaSetTypeFixedSize(schema.get(), 
NANOARROW_TYPE_FIXED_SIZE_BINARY,
+                                        FixedSize),
+            NANOARROW_OK);
+
+  nanoarrow::UniqueArray array{};
+  ASSERT_EQ(ArrowArrayInitFromSchema(array.get(), schema.get(), nullptr), 
NANOARROW_OK);
+  ASSERT_EQ(ArrowArrayStartAppending(array.get()), NANOARROW_OK);
+  ASSERT_EQ(ArrowArrayAppendBytes(array.get(), {{"foo"}, FixedSize}), 
NANOARROW_OK);
+  ASSERT_EQ(ArrowArrayAppendBytes(array.get(), {{"bar"}, FixedSize}), 
NANOARROW_OK);
+  ASSERT_EQ(ArrowArrayAppendBytes(array.get(), {{"baz"}, FixedSize}), 
NANOARROW_OK);
+  ASSERT_EQ(ArrowArrayAppendBytes(array.get(), {{"qux"}, FixedSize}), 
NANOARROW_OK);
+  ASSERT_EQ(ArrowArrayFinishBuildingDefault(array.get(), nullptr), 
NANOARROW_OK);
+  array->offset = 2;
+  array->length = 2;
+
+  EXPECT_THAT(nanoarrow::ViewArrayAsFixedSizeBytes(array.get(), FixedSize),
+              testing::ElementsAre("baz"_asv, "qux"_asv));
+
+  nanoarrow::UniqueArrayView array_view{};
+  ASSERT_EQ(ArrowArrayViewInitFromSchema(array_view.get(), schema.get(), 
nullptr),
+            NANOARROW_OK);
+  ASSERT_EQ(ArrowArrayViewSetArray(array_view.get(), array.get(), nullptr), 
NANOARROW_OK);
+  EXPECT_THAT(nanoarrow::ViewArrayAsFixedSizeBytes(array_view.get(), 
FixedSize),
+              testing::ElementsAre("baz"_asv, "qux"_asv));
+}

Reply via email to