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

paleolimbot 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 86c200e  C++ helpers (#60)
86c200e is described below

commit 86c200e4d938b85ef65d19c96b242b4daf8df8df
Author: Dewey Dunnington <[email protected]>
AuthorDate: Mon Oct 24 21:05:29 2022 -0300

    C++ helpers (#60)
    
    * start hpp version
    
    * add test
    
    * start on unique array and schema
    
    * test unique array stream
    
    * add nanoarrow.hpp to the bundled build
    
    * some doxygen for nanoarrow.hpp
    
    * document stream utils
    
    * test vector array stream
    
    * remember about virtual deleters
    
    * skelton other wrappers
    
    * simplify unique implementations
    
    * remember to make pointer ops inline
    
    * remember to delete the copy constructor
    
    * test unique bitmap
    
    * test array view
    
    * use the uniquearrayview in a test
    
    * add hpp to dist/ bundle
    
    * maybe get coverage for nanoarrow.hpp
    
    * maybe this will get the coverage in
    
    * one more go
    
    * fix typo
    
    * different approach
    
    * change ordering of files
    
    * revert codecov changes for now
---
 .github/workflows/build-and-test.yaml |   6 +-
 CMakeLists.txt                        |   9 +
 docs/source/c.rst                     |   2 +
 docs/source/{index.rst => cpp.rst}    |  23 ++-
 docs/source/index.rst                 |   1 +
 src/nanoarrow/nanoarrow.hpp           | 308 ++++++++++++++++++++++++++++++++++
 src/nanoarrow/nanoarrow_hpp_test.cc   | 210 +++++++++++++++++++++++
 7 files changed, 550 insertions(+), 9 deletions(-)

diff --git a/.github/workflows/build-and-test.yaml 
b/.github/workflows/build-and-test.yaml
index b0ec3a2..0928563 100644
--- a/.github/workflows/build-and-test.yaml
+++ b/.github/workflows/build-and-test.yaml
@@ -68,7 +68,7 @@ jobs:
           cd build
           cmake .. -DCMAKE_BUILD_TYPE=Debug -DNANOARROW_CODE_COVERAGE=ON 
-DNANOARROW_BUILD_TESTS=ON
           cmake --build .
-      
+
       - name: Build nanoarrow (namespaced)
         if: matrix.config.label == 'namespaced-build'
         run: |
@@ -88,7 +88,7 @@ jobs:
           cd build
           cmake .. -DCMAKE_BUILD_TYPE=Debug -DNANOARROW_CODE_COVERAGE=ON 
-DNANOARROW_BUILD_TESTS=ON -DNANOARROW_BUNDLE=ON
           cmake --build .
-    
+
       - name: Check for non-namespaced symbols in namespaced build
         if: matrix.config.label == 'namespaced-build'
         run: |
@@ -209,7 +209,7 @@ jobs:
         with:
           name: nanoarrow-latest
           path: nanoarrow-latest.zip
-      
+
       - name: Commit bundle to dist/
         if: success() && github.repository == 'apache/arrow-nanoarrow' && 
github.ref == 'refs/heads/main'
         run: |
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 7c5e1f1..64f14cf 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -61,6 +61,10 @@ if(NANOARROW_BUNDLE)
     string(REGEX REPLACE "#include \"[a-z_.]+\"" "" SRC_FILE_CONTENTS 
"${SRC_FILE_CONTENTS}")
     file(WRITE ${NANOARROW_H_TEMP} "${SRC_FILE_CONTENTS}")
 
+    # Copy nanoarrow.hpp too
+    file(READ src/nanoarrow/nanoarrow.hpp SRC_FILE_CONTENTS)
+    file(WRITE ${CMAKE_BINARY_DIR}/amalgamation/nanoarrow/nanoarrow.hpp 
"${SRC_FILE_CONTENTS}")
+
     # Combine all source files into amalgamation/nanoarrow.c in the build 
directory
     set(NANOARROW_C_TEMP 
${CMAKE_BINARY_DIR}/amalgamation/nanoarrow/nanoarrow.c)
     file(READ src/nanoarrow/utils.c SRC_FILE_CONTENTS)
@@ -144,21 +148,26 @@ if(NANOARROW_BUILD_TESTS)
     add_executable(buffer_test src/nanoarrow/buffer_test.cc)
     add_executable(array_test src/nanoarrow/array_test.cc)
     add_executable(schema_test src/nanoarrow/schema_test.cc)
+    add_executable(nanoarrow_hpp_test src/nanoarrow/nanoarrow_hpp_test.cc)
 
     if(NANOARROW_CODE_COVERAGE)
         target_compile_options(coverage_config INTERFACE -O0 -g --coverage)
         target_link_options(coverage_config INTERFACE --coverage)
         target_link_libraries(nanoarrow coverage_config)
+        # Because nanoarrow.hpp is header-only we have to link the test here 
to get coverage
+        target_link_libraries(nanoarrow_hpp_test coverage_config)
     endif()
 
     target_link_libraries(utils_test nanoarrow GTest::gtest_main arrow_shared)
     target_link_libraries(buffer_test nanoarrow GTest::gtest_main)
     target_link_libraries(array_test nanoarrow GTest::gtest_main arrow_shared)
     target_link_libraries(schema_test nanoarrow GTest::gtest_main arrow_shared)
+    target_link_libraries(nanoarrow_hpp_test nanoarrow GTest::gtest_main)
 
     include(GoogleTest)
     gtest_discover_tests(utils_test)
     gtest_discover_tests(buffer_test)
     gtest_discover_tests(array_test)
     gtest_discover_tests(schema_test)
+    gtest_discover_tests(nanoarrow_hpp_test)
 endif()
diff --git a/docs/source/c.rst b/docs/source/c.rst
index 9bed1c8..352d0e9 100644
--- a/docs/source/c.rst
+++ b/docs/source/c.rst
@@ -18,6 +18,8 @@
 C API Reference
 ==================
 
+.. doxygengroup:: nanoarrow
+
 Creating schemas
 ------------------
 .. doxygengroup:: nanoarrow-schema
diff --git a/docs/source/index.rst b/docs/source/cpp.rst
similarity index 67%
copy from docs/source/index.rst
copy to docs/source/cpp.rst
index 567d0e9..44b7b4e 100644
--- a/docs/source/index.rst
+++ b/docs/source/cpp.rst
@@ -15,12 +15,23 @@
 .. specific language governing permissions and limitations
 .. under the License.
 
-.. include:: README_generated.rst
+C++ API Reference
+==================
 
-Contents
---------
+.. doxygengroup:: nanoarrow_hpp
 
-.. toctree::
-   :maxdepth: 2
+Owning object wrappers
+----------------------
+.. doxygengroup:: nanoarrow_hpp-unique
+   :members:
 
-   C API Reference <c>
+Array Stream utilities
+----------------------
+
+.. doxygengroup:: nanoarrow_hpp-array-stream
+   :members:
+
+Base classes and utilities
+--------------------------
+.. doxygengroup:: nanoarrow_hpp-unique_base
+   :members:
diff --git a/docs/source/index.rst b/docs/source/index.rst
index 567d0e9..747e97a 100644
--- a/docs/source/index.rst
+++ b/docs/source/index.rst
@@ -24,3 +24,4 @@ Contents
    :maxdepth: 2
 
    C API Reference <c>
+   C++ API Reference <cpp>
diff --git a/src/nanoarrow/nanoarrow.hpp b/src/nanoarrow/nanoarrow.hpp
new file mode 100644
index 0000000..50d427e
--- /dev/null
+++ b/src/nanoarrow/nanoarrow.hpp
@@ -0,0 +1,308 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#include <vector>
+
+#include "nanoarrow.h"
+
+#ifndef NANOARROW_HPP_INCLUDED
+#define NANOARROW_HPP_INCLUDED
+
+/// \defgroup nanoarrow_hpp
+///
+/// The utilities provided in this file are intended to support C++ users
+/// of the nanoarrow C library such that C++-style resource allocation
+/// and error handling can be used with nanoarrow data structures.
+/// These utilities are not intended to mirror the nanoarrow C API.
+
+namespace nanoarrow {
+
+namespace internal {
+
+/// \defgroup nanoarrow_hpp-unique_base Base classes for Unique wrappers
+///
+/// @{
+
+static inline void init_pointer(struct ArrowSchema* data) { data->release = 
nullptr; }
+
+static inline void move_pointer(struct ArrowSchema* src, struct ArrowSchema* 
dst) {
+  memcpy(dst, src, sizeof(struct ArrowSchema));
+  src->release = nullptr;
+}
+
+static inline void release_pointer(struct ArrowSchema* data) {
+  if (data->release != nullptr) {
+    data->release(data);
+  }
+}
+
+static inline void init_pointer(struct ArrowArray* data) { data->release = 
nullptr; }
+
+static inline void move_pointer(struct ArrowArray* src, struct ArrowArray* 
dst) {
+  memcpy(dst, src, sizeof(struct ArrowArray));
+  src->release = nullptr;
+}
+
+static inline void release_pointer(struct ArrowArray* data) {
+  if (data->release != nullptr) {
+    data->release(data);
+  }
+}
+
+static inline void init_pointer(struct ArrowArrayStream* data) {
+  data->release = nullptr;
+}
+
+static inline void move_pointer(struct ArrowArrayStream* src,
+                                struct ArrowArrayStream* dst) {
+  memcpy(dst, src, sizeof(struct ArrowArrayStream));
+  src->release = nullptr;
+}
+
+static inline void release_pointer(ArrowArrayStream* data) {
+  if (data->release != nullptr) {
+    data->release(data);
+  }
+}
+
+static inline void init_pointer(struct ArrowBuffer* data) { 
ArrowBufferInit(data); }
+
+static inline void move_pointer(struct ArrowBuffer* src, struct ArrowBuffer* 
dst) {
+  ArrowBufferMove(src, dst);
+}
+
+static inline void release_pointer(struct ArrowBuffer* data) { 
ArrowBufferReset(data); }
+
+static inline void init_pointer(struct ArrowBitmap* data) { 
ArrowBitmapInit(data); }
+
+static inline void move_pointer(struct ArrowBitmap* src, struct ArrowBitmap* 
dst) {
+  ArrowBufferMove(&src->buffer, &dst->buffer);
+  dst->size_bits = src->size_bits;
+  src->size_bits = 0;
+}
+
+static inline void release_pointer(struct ArrowBitmap* data) { 
ArrowBitmapReset(data); }
+
+static inline void init_pointer(struct ArrowArrayView* data) {
+  ArrowArrayViewInit(data, NANOARROW_TYPE_UNINITIALIZED);
+}
+
+static inline void move_pointer(struct ArrowArrayView* src, struct 
ArrowArrayView* dst) {
+  memcpy(dst, src, sizeof(struct ArrowArrayView));
+  init_pointer(src);
+}
+
+static inline void release_pointer(struct ArrowArrayView* data) {
+  ArrowArrayViewReset(data);
+}
+
+/// \brief A unique_ptr-like base class for stack-allocatable objects
+/// \tparam T The object type
+template <typename T>
+class Unique {
+ public:
+  /// \brief Construct an invalid instance of T holding no resources
+  Unique() { init_pointer(&data_); }
+
+  /// \brief Move and take ownership of data
+  Unique(T* data) { move_pointer(data, &data_); }
+
+  /// \brief Move and take ownership of data wrapped by rhs
+  Unique(Unique&& rhs) : Unique(rhs.get()) {}
+
+  // These objects are not copyable
+  Unique(Unique& rhs) = delete;
+
+  /// \brief Get a pointer to the data owned by this object
+  T* get() noexcept { return &data_; }
+
+  /// \brief Use the pointer operator to access fields of this object
+  T* operator->() { return &data_; }
+
+  /// \brief Call data's release callback if valid
+  void reset() { release_pointer(&data_); }
+
+  /// \brief Call data's release callback if valid and move ownership of the 
data
+  /// pointed to by data
+  void reset(T* data) {
+    reset();
+    move_pointer(data, &data_);
+  }
+
+  /// \brief Move ownership of this object to the data pointed to by out
+  void move(T* out) { move_pointer(&data_, out); }
+
+  ~Unique() { reset(); }
+
+ protected:
+  T data_;
+};
+
+/// @}
+
+}  // namespace internal
+
+/// \defgroup nanoarrow_hpp-unique
+///
+/// The Arrow C Data interface, the Arrow C Stream interface, and the
+/// nanoarrow C library use stack-allocatable objects, some of which
+/// require initialization or cleanup.
+///
+/// @{
+
+/// \brief Class wrapping a unique struct ArrowSchema
+using UniqueSchema = internal::Unique<struct ArrowSchema>;
+
+/// \brief Class wrapping a unique struct ArrowArray
+using UniqueArray = internal::Unique<struct ArrowArray>;
+
+/// \brief Class wrapping a unique struct ArrowArrayStream
+using UniqueArrayStream = internal::Unique<struct ArrowArrayStream>;
+
+/// \brief Class wrapping a unique struct ArrowBuffer
+using UniqueBuffer = internal::Unique<struct ArrowBuffer>;
+
+/// \brief Class wrapping a unique struct ArrowBitmap
+using UniqueBitmap = internal::Unique<struct ArrowBitmap>;
+
+/// \brief Class wrapping a unique struct ArrowArrayView
+using UniqueArrayView = internal::Unique<struct ArrowArrayView>;
+
+/// @}
+
+/// \defgroup nanoarrow_hpp-array-stream ArrayStream helpers
+///
+/// These classes provide simple struct ArrowArrayStream implementations that
+/// can be extended to help simplify the process of creating a valid
+/// ArrowArrayStream implementation or used as-is for testing.
+///
+/// @{
+
+/// \brief An empty array stream
+///
+/// This class can be constructed from an enum ArrowType or
+/// struct ArrowSchema and implements a default get_next() method that
+/// always marks the output ArrowArray as released. This class can
+/// be extended with an implementation of get_next() for a custom
+/// source.
+class EmptyArrayStream {
+ public:
+  /// \brief Create an empty UniqueArrayStream from a struct ArrowSchema
+  ///
+  /// This object takes ownership of the schema and marks the source schema
+  /// as released.
+  static UniqueArrayStream MakeUnique(struct ArrowSchema* schema) {
+    UniqueArrayStream stream;
+    (new EmptyArrayStream(schema))->MakeStream(stream.get());
+    return stream;
+  }
+
+  virtual ~EmptyArrayStream() {}
+
+ protected:
+  UniqueSchema schema_;
+  struct ArrowError error_;
+
+  EmptyArrayStream(struct ArrowSchema* schema) : schema_(schema) {
+    error_.message[0] = '\0';
+  }
+
+  void MakeStream(struct ArrowArrayStream* stream) {
+    stream->get_schema = &get_schema_wrapper;
+    stream->get_next = &get_next_wrapper;
+    stream->get_last_error = &get_last_error_wrapper;
+    stream->release = &release_wrapper;
+    stream->private_data = this;
+  }
+
+  virtual int get_schema(struct ArrowSchema* schema) {
+    return ArrowSchemaDeepCopy(schema_.get(), schema);
+  }
+
+  virtual int get_next(struct ArrowArray* array) {
+    array->release = nullptr;
+    return NANOARROW_OK;
+  }
+
+  virtual const char* get_last_error() { return error_.message; }
+
+ private:
+  static int get_schema_wrapper(struct ArrowArrayStream* stream,
+                                struct ArrowSchema* schema) {
+    return 
reinterpret_cast<EmptyArrayStream*>(stream->private_data)->get_schema(schema);
+  }
+
+  static int get_next_wrapper(struct ArrowArrayStream* stream, struct 
ArrowArray* array) {
+    return 
reinterpret_cast<EmptyArrayStream*>(stream->private_data)->get_next(array);
+  }
+
+  static const char* get_last_error_wrapper(struct ArrowArrayStream* stream) {
+    return 
reinterpret_cast<EmptyArrayStream*>(stream->private_data)->get_last_error();
+  }
+
+  static void release_wrapper(struct ArrowArrayStream* stream) {
+    delete reinterpret_cast<EmptyArrayStream*>(stream->private_data);
+  }
+};
+
+/// \brief Implementation of an ArrowArrayStream backed by a vector of 
ArrowArray objects
+class VectorArrayStream : public EmptyArrayStream {
+ public:
+  /// \brief Create a UniqueArrowArrayStream from an existing array
+  ///
+  /// Takes ownership of the schema and the array.
+  static UniqueArrayStream MakeUnique(struct ArrowSchema* schema,
+                                      struct ArrowArray* array) {
+    std::vector<UniqueArray> arrays;
+    arrays.emplace_back(array);
+    return MakeUnique(schema, std::move(arrays));
+  }
+
+  /// \brief Create a UniqueArrowArrayStream from existing arrays
+  ///
+  /// This object takes ownership of the schema and arrays.
+  static UniqueArrayStream MakeUnique(struct ArrowSchema* schema,
+                                      std::vector<UniqueArray> arrays) {
+    UniqueArrayStream stream;
+    (new VectorArrayStream(schema, 
std::move(arrays)))->MakeStream(stream.get());
+    return stream;
+  }
+
+ protected:
+  VectorArrayStream(struct ArrowSchema* schema, std::vector<UniqueArray> 
arrays)
+      : EmptyArrayStream(schema), offset_(0), arrays_(std::move(arrays)) {}
+
+  int get_next(struct ArrowArray* array) {
+    if (offset_ < arrays_.size()) {
+      arrays_[offset_++].move(array);
+    } else {
+      array->release = nullptr;
+    }
+
+    return NANOARROW_OK;
+  }
+
+ private:
+  std::vector<UniqueArray> arrays_;
+  int64_t offset_;
+};
+
+/// @}
+
+}  // namespace nanoarrow
+
+#endif
diff --git a/src/nanoarrow/nanoarrow_hpp_test.cc 
b/src/nanoarrow/nanoarrow_hpp_test.cc
new file mode 100644
index 0000000..d8c9033
--- /dev/null
+++ b/src/nanoarrow/nanoarrow_hpp_test.cc
@@ -0,0 +1,210 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#include <gtest/gtest.h>
+
+#include "nanoarrow/nanoarrow.hpp"
+
+TEST(NanoarrowHppTest, NanoarrowHppUniqueArrayTest) {
+  nanoarrow::UniqueArray array;
+  EXPECT_EQ(array->release, nullptr);
+
+  ArrowArrayInit(array.get(), NANOARROW_TYPE_INT32);
+  ASSERT_EQ(ArrowArrayStartAppending(array.get()), NANOARROW_OK);
+  ASSERT_EQ(ArrowArrayAppendInt(array.get(), 123), NANOARROW_OK);
+  ASSERT_EQ(ArrowArrayFinishBuilding(array.get(), nullptr), NANOARROW_OK);
+
+  EXPECT_NE(array->release, nullptr);
+  EXPECT_EQ(array->length, 1);
+
+  // move constructor
+  nanoarrow::UniqueArray array2 = std::move(array);
+  EXPECT_EQ(array->release, nullptr);
+  EXPECT_NE(array2->release, nullptr);
+  EXPECT_EQ(array2->length, 1);
+
+  // pointer constructor
+  nanoarrow::UniqueArray array3(array2.get());
+  EXPECT_EQ(array2->release, nullptr);
+  EXPECT_NE(array3->release, nullptr);
+  EXPECT_EQ(array3->length, 1);
+}
+
+TEST(NanoarrowHppTest, NanoarrowHppUniqueSchemaTest) {
+  nanoarrow::UniqueSchema schema;
+  EXPECT_EQ(schema->release, nullptr);
+
+  ArrowSchemaInit(schema.get(), NANOARROW_TYPE_INT32);
+  EXPECT_NE(schema->release, nullptr);
+  EXPECT_STREQ(schema->format, "i");
+
+  // move constructor
+  nanoarrow::UniqueSchema schema2 = std::move(schema);
+  EXPECT_EQ(schema->release, nullptr);
+  EXPECT_NE(schema2->release, nullptr);
+  EXPECT_STREQ(schema2->format, "i");
+
+  // pointer constructor
+  nanoarrow::UniqueSchema schema3(schema2.get());
+  EXPECT_EQ(schema2->release, nullptr);
+  EXPECT_NE(schema3->release, nullptr);
+  EXPECT_STREQ(schema3->format, "i");
+}
+
+TEST(NanoarrowHppTest, NanoarrowHppUniqueArrayStreamTest) {
+  nanoarrow::UniqueSchema schema;
+  schema->format = NULL;
+
+  nanoarrow::UniqueArrayStream array_stream_default;
+  EXPECT_EQ(array_stream_default->release, nullptr);
+
+  nanoarrow::UniqueSchema schema_in;
+  EXPECT_EQ(ArrowSchemaInit(schema_in.get(), NANOARROW_TYPE_INT32), 
NANOARROW_OK);
+  auto array_stream = nanoarrow::EmptyArrayStream::MakeUnique(schema_in.get());
+  EXPECT_NE(array_stream->release, nullptr);
+  EXPECT_EQ(array_stream->get_schema(array_stream.get(), schema.get()), 
NANOARROW_OK);
+  EXPECT_STREQ(schema->format, "i");
+  schema.reset();
+  schema->format = NULL;
+
+  // move constructor
+  nanoarrow::UniqueArrayStream array_stream2 = std::move(array_stream);
+  EXPECT_EQ(array_stream->release, nullptr);
+  EXPECT_NE(array_stream2->release, nullptr);
+  EXPECT_EQ(array_stream2->get_schema(array_stream2.get(), schema.get()), 
NANOARROW_OK);
+  EXPECT_STREQ(schema->format, "i");
+  schema.reset();
+  schema->format = NULL;
+
+  // pointer constructor
+  nanoarrow::UniqueArrayStream array_stream3(array_stream2.get());
+  EXPECT_EQ(array_stream2->release, nullptr);
+  EXPECT_NE(array_stream3->release, nullptr);
+  EXPECT_EQ(array_stream3->get_schema(array_stream2.get(), schema.get()), 
NANOARROW_OK);
+  EXPECT_STREQ(schema->format, "i");
+}
+
+TEST(NanoarrowHppTest, NanoarrowHppUniqueBufferTest) {
+  nanoarrow::UniqueBuffer buffer;
+  EXPECT_EQ(buffer->data, nullptr);
+  EXPECT_EQ(buffer->size_bytes, 0);
+
+  ASSERT_EQ(ArrowBufferAppendFill(buffer.get(), 0xff, 123), NANOARROW_OK);
+  EXPECT_NE(buffer->data, nullptr);
+  EXPECT_EQ(buffer->size_bytes, 123);
+
+  // move constructor
+  nanoarrow::UniqueBuffer buffer2 = std::move(buffer);
+  EXPECT_EQ(buffer->data, nullptr);
+  EXPECT_EQ(buffer->size_bytes, 0);
+  EXPECT_NE(buffer2->data, nullptr);
+  EXPECT_EQ(buffer2->size_bytes, 123);
+
+  // pointer constructor
+  nanoarrow::UniqueBuffer buffer3(buffer2.get());
+  EXPECT_EQ(buffer2->data, nullptr);
+  EXPECT_EQ(buffer2->size_bytes, 0);
+  EXPECT_NE(buffer3->data, nullptr);
+  EXPECT_EQ(buffer3->size_bytes, 123);
+}
+
+TEST(NanoarrowHppTest, NanoarrowHppUniqueBitmapTest) {
+  nanoarrow::UniqueBitmap bitmap;
+  EXPECT_EQ(bitmap->buffer.data, nullptr);
+  EXPECT_EQ(bitmap->size_bits, 0);
+
+  ASSERT_EQ(ArrowBitmapAppend(bitmap.get(), true, 123), NANOARROW_OK);
+  EXPECT_NE(bitmap->buffer.data, nullptr);
+  EXPECT_EQ(bitmap->size_bits, 123);
+
+  // move constructor
+  nanoarrow::UniqueBitmap bitmap2 = std::move(bitmap);
+  EXPECT_EQ(bitmap->buffer.data, nullptr);
+  EXPECT_EQ(bitmap->size_bits, 0);
+  EXPECT_NE(bitmap2->buffer.data, nullptr);
+  EXPECT_EQ(bitmap2->size_bits, 123);
+
+  // pointer constructor
+  nanoarrow::UniqueBitmap bitmap3(bitmap2.get());
+  EXPECT_EQ(bitmap2->buffer.data, nullptr);
+  EXPECT_EQ(bitmap2->size_bits, 0);
+  EXPECT_NE(bitmap3->buffer.data, nullptr);
+  EXPECT_EQ(bitmap3->size_bits, 123);
+}
+
+TEST(NanoarrowHppTest, NanoarrowHppUniqueArrayViewTest) {
+  nanoarrow::UniqueArrayView array_view;
+  EXPECT_EQ(array_view->storage_type, NANOARROW_TYPE_UNINITIALIZED);
+
+  // Use an ArrayView with children, since an ArrayView with no children
+  // doesn't hold any resources
+  ArrowArrayViewInit(array_view.get(), NANOARROW_TYPE_STRUCT);
+  ArrowArrayViewAllocateChildren(array_view.get(), 2);
+  EXPECT_EQ(array_view->storage_type, NANOARROW_TYPE_STRUCT);
+
+  // move constructor
+  nanoarrow::UniqueArrayView array_view2 = std::move(array_view);
+  EXPECT_EQ(array_view->storage_type, NANOARROW_TYPE_UNINITIALIZED);
+  EXPECT_EQ(array_view2->storage_type, NANOARROW_TYPE_STRUCT);
+
+  // pointer constructor
+  nanoarrow::UniqueArrayView array_view3(array_view2.get());
+  EXPECT_EQ(array_view2->storage_type, NANOARROW_TYPE_UNINITIALIZED);
+  EXPECT_EQ(array_view3->storage_type, NANOARROW_TYPE_STRUCT);
+}
+
+TEST(NanoarrowHppTest, NanoarrowHppEmptyArrayStreamTest) {
+  nanoarrow::UniqueSchema schema;
+  struct ArrowArray array;
+
+  nanoarrow::UniqueSchema schema_in;
+  EXPECT_EQ(ArrowSchemaInit(schema_in.get(), NANOARROW_TYPE_INT32), 
NANOARROW_OK);
+  auto array_stream = nanoarrow::EmptyArrayStream::MakeUnique(schema_in.get());
+
+  EXPECT_EQ(array_stream->get_schema(array_stream.get(), schema.get()), 
NANOARROW_OK);
+  EXPECT_STREQ(schema->format, "i");
+  EXPECT_EQ(array_stream->get_next(array_stream.get(), &array), NANOARROW_OK);
+  EXPECT_EQ(array.release, nullptr);
+  EXPECT_STREQ(array_stream->get_last_error(array_stream.get()), "");
+}
+
+TEST(NanoarrowHppTest, NanoarrowHppVectorArrayStreamTest) {
+  nanoarrow::UniqueSchema schema;
+  nanoarrow::UniqueArray array;
+  nanoarrow::UniqueArrayView array_view;
+
+  nanoarrow::UniqueArray array_in;
+  EXPECT_EQ(ArrowArrayInit(array_in.get(), NANOARROW_TYPE_INT32), 
NANOARROW_OK);
+  EXPECT_EQ(ArrowArrayStartAppending(array_in.get()), NANOARROW_OK);
+  EXPECT_EQ(ArrowArrayAppendInt(array_in.get(), 1234), NANOARROW_OK);
+  EXPECT_EQ(ArrowArrayFinishBuilding(array_in.get(), nullptr), NANOARROW_OK);
+
+  nanoarrow::UniqueSchema schema_in;
+  EXPECT_EQ(ArrowSchemaInit(schema_in.get(), NANOARROW_TYPE_INT32), 
NANOARROW_OK);
+
+  auto array_stream =
+      nanoarrow::VectorArrayStream::MakeUnique(schema_in.get(), 
array_in.get());
+
+  EXPECT_EQ(array_stream->get_next(array_stream.get(), array.get()), 
NANOARROW_OK);
+  ArrowArrayViewInit(array_view.get(), NANOARROW_TYPE_INT32);
+  ASSERT_EQ(ArrowArrayViewSetArray(array_view.get(), array.get(), nullptr), 
NANOARROW_OK);
+  EXPECT_EQ(ArrowArrayViewGetIntUnsafe(array_view.get(), 0), 1234);
+  array.reset();
+
+  EXPECT_EQ(array_stream->get_next(array_stream.get(), array.get()), 
NANOARROW_OK);
+  EXPECT_EQ(array->release, nullptr);
+}

Reply via email to