diff --git a/src/nanoarrow/common/utils_test.cc b/src/nanoarrow/common/utils_test.cc index 7c86ca51f..648b3b970 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 squares{square, 4}; + const nanoarrow::internal::RandomAccessRange 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 f0e267fff..0b235c5ad 100644 --- a/src/nanoarrow/hpp/view.hpp +++ b/src/nanoarrow/hpp/view.hpp @@ -65,6 +65,7 @@ class Maybe { template struct RandomAccessRange { Get get; + int64_t offset; int64_t size; using value_type = decltype(std::declval()(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 @@ -132,10 +133,8 @@ class ViewArrayAs { struct Get { const uint8_t* validity; const void* values; - int64_t offset; internal::Maybe operator()(int64_t i) const { - i += offset; if (validity == nullptr || ArrowBitGet(validity, i)) { if (std::is_same::value) { return ArrowBitGet(static_cast(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(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 operator()(int64_t i) const { - i += offset; auto* offsets = static_cast(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(array->buffers[0]), array->buffers[1], static_cast(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 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(array->buffers[0]), static_cast(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 e18c7c639..e4cfa499a 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(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(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)); +}