-
Notifications
You must be signed in to change notification settings - Fork 21
Many small fixes on ArrowStream #616
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
1095b1f
2991f24
5759797
a80f7c6
239dcba
ff345bb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -101,7 +101,9 @@ namespace sparrow | |||||
| arrow_array_stream_proxy(const arrow_array_stream_proxy&) = delete; | ||||||
| arrow_array_stream_proxy& operator=(const arrow_array_stream_proxy&) = delete; | ||||||
|
|
||||||
| SPARROW_API | ||||||
| arrow_array_stream_proxy(arrow_array_stream_proxy&& other) noexcept; | ||||||
| SPARROW_API | ||||||
| arrow_array_stream_proxy& operator=(arrow_array_stream_proxy&& other) noexcept; | ||||||
|
|
||||||
| /** | ||||||
|
|
@@ -111,6 +113,12 @@ namespace sparrow | |||||
| * released. This ensures proper cleanup of all Arrow C interface objects. | ||||||
| */ | ||||||
| SPARROW_API ~arrow_array_stream_proxy(); | ||||||
|
|
||||||
| /** | ||||||
| * Check whether the proxy has ownership of its internal `ArrowArrayStream`. | ||||||
| */ | ||||||
| SPARROW_API bool owns_stream() const; | ||||||
|
|
||||||
| /** | ||||||
| * @brief Export the stream pointer. | ||||||
| * | ||||||
|
|
@@ -143,7 +151,7 @@ namespace sparrow | |||||
| requires layout<std::ranges::range_value_t<R>> | ||||||
| void push(R&& arrays) | ||||||
| { | ||||||
| arrow_array_stream_private_data& private_data = *get_private_data(); | ||||||
| arrow_array_stream_private_data& private_data = get_private_data(); | ||||||
|
|
||||||
| // Check if we need to create schema from first array | ||||||
| if (private_data.schema() == nullptr) | ||||||
|
|
@@ -234,18 +242,11 @@ namespace sparrow | |||||
| */ | ||||||
| void throw_if_immutable() const; | ||||||
|
|
||||||
| /** | ||||||
| * @brief Gets the private data (const version). | ||||||
| * | ||||||
| * @return Const pointer to the stream's private data. | ||||||
| */ | ||||||
| [[nodiscard]] SPARROW_API const arrow_array_stream_private_data* get_private_data() const; | ||||||
|
|
||||||
| /** | ||||||
| * @brief Gets the private data (mutable version). | ||||||
| * | ||||||
| * @return Mutable pointer to the stream's private data. | ||||||
|
||||||
| * @return Mutable pointer to the stream's private data. | |
| * @return Mutable reference to the stream's private data. |
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -74,24 +74,127 @@ namespace sparrow | |||||||||||||
|
|
||||||||||||||
| TEST_SUITE("arrow_array_stream_proxy") | ||||||||||||||
| { | ||||||||||||||
| TEST_CASE("constructor - default") | ||||||||||||||
| TEST_CASE("constructor") | ||||||||||||||
| { | ||||||||||||||
| arrow_array_stream_proxy proxy; | ||||||||||||||
| ArrowArrayStream* aas = proxy.export_stream(); | ||||||||||||||
| REQUIRE_NE(aas, nullptr); | ||||||||||||||
| aas->release(aas); | ||||||||||||||
| delete aas; | ||||||||||||||
| SUBCASE("default") | ||||||||||||||
| { | ||||||||||||||
| arrow_array_stream_proxy proxy; | ||||||||||||||
| ArrowArrayStream* aas = proxy.export_stream(); | ||||||||||||||
| REQUIRE_NE(aas, nullptr); | ||||||||||||||
| aas->release(aas); | ||||||||||||||
| delete aas; | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| SUBCASE("pointer") | ||||||||||||||
| { | ||||||||||||||
| ArrowArrayStream* stream = new ArrowArrayStream; | ||||||||||||||
| fill_arrow_array_stream(*stream); | ||||||||||||||
| arrow_array_stream_proxy proxy(stream); | ||||||||||||||
| ArrowArrayStream* aas = proxy.export_stream(); | ||||||||||||||
| REQUIRE_NE(aas, nullptr); | ||||||||||||||
| aas->release(aas); | ||||||||||||||
| delete aas; | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| SUBCASE("move") | ||||||||||||||
| { | ||||||||||||||
| ArrowArrayStream stream{}; | ||||||||||||||
| fill_arrow_array_stream(stream); | ||||||||||||||
| arrow_array_stream_proxy proxy(std::move(stream)); | ||||||||||||||
| REQUIRE_EQ(stream.private_data, nullptr); | ||||||||||||||
| REQUIRE_EQ(stream.release, nullptr); | ||||||||||||||
| ArrowArrayStream* aas = proxy.export_stream(); | ||||||||||||||
| REQUIRE_NE(aas, nullptr); | ||||||||||||||
| aas->release(aas); | ||||||||||||||
| delete aas; | ||||||||||||||
| } | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| TEST_CASE("constructor - from existing stream") | ||||||||||||||
| TEST_CASE("move semantics") | ||||||||||||||
| { | ||||||||||||||
| ArrowArrayStream* stream = new ArrowArrayStream; | ||||||||||||||
| fill_arrow_array_stream(*stream); | ||||||||||||||
| arrow_array_stream_proxy proxy(stream); | ||||||||||||||
| ArrowArrayStream* aas = proxy.export_stream(); | ||||||||||||||
| REQUIRE_NE(aas, nullptr); | ||||||||||||||
| aas->release(aas); | ||||||||||||||
| delete aas; | ||||||||||||||
| SUBCASE("move constructor") | ||||||||||||||
| { | ||||||||||||||
| { | ||||||||||||||
| ArrowArrayStream stream{}; | ||||||||||||||
| fill_arrow_array_stream(stream); | ||||||||||||||
| arrow_array_stream_proxy src(std::move(stream)); | ||||||||||||||
| arrow_array_stream_proxy dst(std::move(src)); | ||||||||||||||
|
|
||||||||||||||
| auto* src_str = src.export_stream(); | ||||||||||||||
| auto* dst_str = dst.export_stream(); | ||||||||||||||
| REQUIRE_EQ(src_str->release, nullptr); | ||||||||||||||
| REQUIRE_NE(dst_str->release, nullptr); | ||||||||||||||
| delete src_str; | ||||||||||||||
| delete dst_str; | ||||||||||||||
| } | ||||||||||||||
|
Comment on lines
+117
to
+129
|
||||||||||||||
|
|
||||||||||||||
| { | ||||||||||||||
| ArrowArrayStream stream{}; | ||||||||||||||
| fill_arrow_array_stream(stream); | ||||||||||||||
| arrow_array_stream_proxy src(&stream); | ||||||||||||||
| arrow_array_stream_proxy dst(std::move(src)); | ||||||||||||||
|
|
||||||||||||||
| auto* src_str = src.export_stream(); | ||||||||||||||
| auto* dst_str = dst.export_stream(); | ||||||||||||||
| REQUIRE_EQ(src_str, nullptr); | ||||||||||||||
| REQUIRE_NE(dst_str, nullptr); | ||||||||||||||
| } | ||||||||||||||
|
Comment on lines
+131
to
+141
|
||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| SUBCASE("move assignment") | ||||||||||||||
| { | ||||||||||||||
| { | ||||||||||||||
| auto test_array = make_test_primitive_array<int32_t>(10); | ||||||||||||||
| ArrowArrayStream stream; | ||||||||||||||
| fill_arrow_array_stream(stream); | ||||||||||||||
| arrow_array_stream_proxy src(std::move(stream)); | ||||||||||||||
| src.push(std::move(test_array)); | ||||||||||||||
|
|
||||||||||||||
| ArrowArrayStream stream2; | ||||||||||||||
| fill_arrow_array_stream(stream2); | ||||||||||||||
| arrow_array_stream_proxy dst(std::move(stream2)); | ||||||||||||||
| dst = std::move(src); | ||||||||||||||
|
|
||||||||||||||
| auto* src_str = src.export_stream(); | ||||||||||||||
| REQUIRE_EQ(src_str->release, nullptr); | ||||||||||||||
| auto dst_arr = dst.pop(); | ||||||||||||||
| REQUIRE(dst_arr.has_value()); | ||||||||||||||
| delete src_str; | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
|
Comment on lines
+147
to
+164
|
||||||||||||||
| { | ||||||||||||||
| auto test_array = make_test_primitive_array<int32_t>(10); | ||||||||||||||
| ArrowArrayStream stream; | ||||||||||||||
| fill_arrow_array_stream(stream); | ||||||||||||||
| arrow_array_stream_proxy src(&stream); | ||||||||||||||
| src.push(std::move(test_array)); | ||||||||||||||
|
|
||||||||||||||
| ArrowArrayStream stream2; | ||||||||||||||
| fill_arrow_array_stream(stream2); | ||||||||||||||
| arrow_array_stream_proxy dst(&stream2); | ||||||||||||||
| dst = std::move(src); | ||||||||||||||
|
|
||||||||||||||
| auto* src_str = src.export_stream(); | ||||||||||||||
| REQUIRE_EQ(src_str, nullptr); | ||||||||||||||
| auto dst_arr = dst.pop(); | ||||||||||||||
| REQUIRE(dst_arr.has_value()); | ||||||||||||||
| } | ||||||||||||||
| } | ||||||||||||||
|
Comment on lines
+166
to
+182
|
||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| TEST_CASE("owns_stream") | ||||||||||||||
| { | ||||||||||||||
| { | ||||||||||||||
| arrow_array_stream_proxy proxy{}; | ||||||||||||||
| REQUIRE(proxy.owns_stream()); | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| { | ||||||||||||||
| ArrowArrayStream stream{}; | ||||||||||||||
| fill_arrow_array_stream(stream); | ||||||||||||||
| arrow_array_stream_proxy proxy(&stream); | ||||||||||||||
| REQUIRE(!proxy.owns_stream()); | ||||||||||||||
|
||||||||||||||
| REQUIRE(!proxy.owns_stream()); | |
| REQUIRE(!proxy.owns_stream()); | |
| if (stream.release != nullptr) | |
| { | |
| stream.release(&stream); | |
| } |
Copilot
AI
Nov 27, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test case has a memory leak. The stack-allocated stream is filled with fill_arrow_array_stream(stream) which allocates private_data. After being passed to src by pointer and then moved to dst, the original stream goes out of scope without calling its release function to free the private_data.
You should add cleanup code before the closing brace:
if (stream.release != nullptr)
{
stream.release(&stream);
}| CHECK_THROWS_AS(src.pop(), std::runtime_error); | |
| CHECK_THROWS_AS(src.pop(), std::runtime_error); | |
| if (stream.release != nullptr) | |
| { | |
| stream.release(&stream); | |
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The
move_array_streamfunctions lack documentation. These functions appear to implement move semantics forArrowArrayStream(a C struct without native move constructor). Consider adding documentation that explains:Example: