/* * 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 "converters.hpp" namespace red_arrow { namespace { class ValuesBuilder : private Converter, public arrow::ArrayVisitor { public: explicit ValuesBuilder(VALUE values) : Converter(), values_(values), row_offset_(0) { } void build(const arrow::Array& array, VALUE rb_array) { rb::protect([&] { check_status(array.Accept(this), "[array][values]"); return Qnil; }); } void build(const arrow::ChunkedArray& chunked_array, VALUE rb_chunked_array) { rb::protect([&] { for (const auto& array : chunked_array.chunks()) { check_status(array->Accept(this), "[chunked-array][values]"); row_offset_ += array->length(); } return Qnil; }); } #define VISIT(TYPE) \ arrow::Status Visit(const arrow::TYPE ## Array& array) override { \ convert(array); \ return arrow::Status::OK(); \ } VISIT(Null) VISIT(Boolean) VISIT(Int8) VISIT(Int16) VISIT(Int32) VISIT(Int64) VISIT(UInt8) VISIT(UInt16) VISIT(UInt32) VISIT(UInt64) // TODO // VISIT(HalfFloat) VISIT(Float) VISIT(Double) VISIT(Binary) VISIT(String) VISIT(FixedSizeBinary) VISIT(Date32) VISIT(Date64) VISIT(Time32) VISIT(Time64) VISIT(Timestamp) // TODO // VISIT(Interval) VISIT(List) VISIT(Struct) VISIT(SparseUnion) VISIT(DenseUnion) VISIT(Dictionary) VISIT(Decimal128) VISIT(Decimal256) // TODO // VISIT(Extension) #undef VISIT private: template void convert(const ArrayType& array) { const auto n = array.length(); if (array.null_count() > 0) { for (int64_t i = 0, ii = row_offset_; i < n; ++i, ++ii) { auto value = Qnil; if (!array.IsNull(i)) { value = convert_value(array, i); } rb_ary_store(values_, ii, value); } } else { for (int64_t i = 0, ii = row_offset_; i < n; ++i, ++ii) { rb_ary_store(values_, ii, convert_value(array, i)); } } } // Destination for converted values. VALUE values_; // The current row offset. int64_t row_offset_; }; } VALUE array_values(VALUE rb_array) { auto garrow_array = GARROW_ARRAY(RVAL2GOBJ(rb_array)); auto array = garrow_array_get_raw(garrow_array).get(); const auto n_rows = array->length(); auto values = rb_ary_new_capa(n_rows); try { ValuesBuilder builder(values); builder.build(*array, rb_array); } catch (rb::State& state) { state.jump(); } return values; } VALUE chunked_array_values(VALUE rb_chunked_array) { auto garrow_chunked_array = GARROW_CHUNKED_ARRAY(RVAL2GOBJ(rb_chunked_array)); auto chunked_array = garrow_chunked_array_get_raw(garrow_chunked_array).get(); const auto n_rows = chunked_array->length(); auto values = rb_ary_new_capa(n_rows); try { ValuesBuilder builder(values); builder.build(*chunked_array, rb_chunked_array); } catch (rb::State& state) { state.jump(); } return values; } }