iceberg-cpp
Loading...
Searching...
No Matches
arrow_c_data_util_internal.h
1/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20#pragma once
21
22#include <cerrno>
23#include <concepts>
24#include <cstdint>
25#include <cstring>
26#include <memory>
27#include <optional>
28#include <span>
29#include <string>
30#include <utility>
31#include <vector>
32
34#include "iceberg/iceberg_export.h"
35#include "iceberg/result.h"
36#include "iceberg/type_fwd.h"
37
38namespace iceberg {
39
43class ICEBERG_EXPORT ProjectionContext {
44 public:
45 using ProjectBatchState = std::shared_ptr<void>;
46
47 using ProjectBatchFunction = auto (*)(ArrowArray* input_batch,
48 std::span<const int32_t> row_indices,
49 ProjectionContext& projection)
50 -> Result<ArrowArray>;
51
56 static void RegisterProjectBatchFunction(ProjectBatchFunction project_batch_function);
57
59 static bool HasProjectBatchFunction();
60
62 static auto ResolveProjectBatchFunction() -> ProjectBatchFunction;
63
75 static Result<ProjectionContext> Make(const Schema& input_schema,
76 const Schema& output_schema,
77 ProjectBatchFunction project_batch_function);
78
80 ProjectionContext& operator=(ProjectionContext&&) noexcept;
82
83 ProjectionContext(const ProjectionContext&) = delete;
84 ProjectionContext& operator=(const ProjectionContext&) = delete;
85
86 const Schema& input_schema() const;
87
88 const Schema& output_schema() const;
89
90 const ArrowSchema& input_arrow_schema() const;
91
92 const ArrowSchema& output_arrow_schema() const;
93
94 std::span<const int32_t> selected_field_indices() const;
95
96 ProjectBatchFunction project_batch_function() const;
97
98 ProjectBatchState& project_batch_state();
99
100 private:
101 ProjectionContext() = default;
102
103 // Raw schema pointers are borrowed from caller-owned schemas. FileScanTaskReader
104 // keeps those schema objects alive in the same stream source that owns this context.
105 const Schema* input_schema_ = nullptr;
106 const Schema* output_schema_ = nullptr;
107 std::vector<int32_t> selected_field_indices_;
108 ArrowSchema input_arrow_schema_{};
109 ArrowSchema output_arrow_schema_{};
110 ProjectBatchFunction project_batch_function_ = nullptr;
111 ProjectBatchState project_batch_state_;
112};
113
115template <typename Source>
116concept ArrowArrayStreamProvider = requires(Source& source) {
117 { source.Close() } -> std::same_as<Status>;
118 { source.Next() } -> std::same_as<Result<std::optional<ArrowArray>>>;
119 { source.Schema() } -> std::same_as<Result<ArrowSchema>>;
120};
121
122namespace detail {
123
124template <ArrowArrayStreamProvider Source>
125struct ArrowArrayStreamPrivateData {
126 std::unique_ptr<Source> source;
127 std::string last_error;
128
129 explicit ArrowArrayStreamPrivateData(std::unique_ptr<Source> src)
130 : source(std::move(src)) {}
131
132 ~ArrowArrayStreamPrivateData() {
133 if (source != nullptr) {
134 std::ignore = source->Close();
135 }
136 }
137};
138
139template <ArrowArrayStreamProvider Source>
140int GetSchema(struct ArrowArrayStream* stream, struct ArrowSchema* out) {
141 if (stream == nullptr || stream->private_data == nullptr) {
142 return EINVAL;
143 }
144
145 auto* private_data =
146 static_cast<ArrowArrayStreamPrivateData<Source>*>(stream->private_data);
147 auto schema_result = private_data->source->Schema();
148 if (!schema_result.has_value()) {
149 private_data->last_error = schema_result.error().message;
150 std::memset(out, 0, sizeof(ArrowSchema));
151 return EIO;
152 }
153
154 *out = std::move(schema_result.value());
155 return 0;
156}
157
158template <ArrowArrayStreamProvider Source>
159int GetNext(struct ArrowArrayStream* stream, struct ArrowArray* out) {
160 if (stream == nullptr || stream->private_data == nullptr) {
161 return EINVAL;
162 }
163
164 auto* private_data =
165 static_cast<ArrowArrayStreamPrivateData<Source>*>(stream->private_data);
166 auto next_result = private_data->source->Next();
167 if (!next_result.has_value()) {
168 private_data->last_error = next_result.error().message;
169 std::memset(out, 0, sizeof(ArrowArray));
170 return EIO;
171 }
172
173 auto& optional_array = next_result.value();
174 if (optional_array.has_value()) {
175 *out = std::move(optional_array.value());
176 } else {
177 std::memset(out, 0, sizeof(ArrowArray));
178 }
179
180 return 0;
181}
182
183template <ArrowArrayStreamProvider Source>
184const char* GetLastError(struct ArrowArrayStream* stream) {
185 if (stream == nullptr || stream->private_data == nullptr) {
186 return nullptr;
187 }
188
189 auto* private_data =
190 static_cast<ArrowArrayStreamPrivateData<Source>*>(stream->private_data);
191 return private_data->last_error.empty() ? nullptr : private_data->last_error.c_str();
192}
193
194template <ArrowArrayStreamProvider Source>
195void Release(struct ArrowArrayStream* stream) {
196 if (stream == nullptr || stream->private_data == nullptr) {
197 return;
198 }
199
200 delete static_cast<ArrowArrayStreamPrivateData<Source>*>(stream->private_data);
201 stream->private_data = nullptr;
202 stream->release = nullptr;
203}
204
205} // namespace detail
206
208template <ArrowArrayStreamProvider Source>
209Result<ArrowArrayStream> MakeArrowArrayStream(std::unique_ptr<Source> source) {
210 if (source == nullptr) {
211 return InvalidArgument("Cannot make ArrowArrayStream from null source");
212 }
213
214 auto private_data =
215 std::make_unique<detail::ArrowArrayStreamPrivateData<Source>>(std::move(source));
216 ArrowArrayStream stream{.get_schema = detail::GetSchema<Source>,
217 .get_next = detail::GetNext<Source>,
218 .get_last_error = detail::GetLastError<Source>,
219 .release = detail::Release<Source>,
220 .private_data = private_data.release()};
221 return stream;
222}
223
225ICEBERG_EXPORT Result<ArrowArrayStream> MakeArrowArrayStream(
226 std::unique_ptr<Reader> reader);
227
241ICEBERG_EXPORT Result<ArrowArray> ProjectBatch(ArrowArray* input_batch,
242 std::span<const int32_t> row_indices,
243 ProjectionContext& projection);
244
245} // namespace iceberg
Cached state for ProjectBatch over one input/output schema pair.
Definition arrow_c_data_util_internal.h:43
A schema for a Table.
Definition schema.h:51
Concept for sources that can be wrapped as ArrowArrayStreams.
Definition arrow_c_data_util_internal.h:116
STL namespace.
Definition arrow_c_data.h:79
Definition arrow_c_data.h:57
Definition arrow_c_data.h:41