#ifndef RFL_PARSING_TABULAR_ARROWREADER_HPP_ #define RFL_PARSING_TABULAR_ARROWREADER_HPP_ #include #include #include #include #include #include #include "../../Processors.hpp" #include "../../Result.hpp" #include "../../Tuple.hpp" #include "../../apply.hpp" #include "../../get.hpp" #include "../../named_tuple_t.hpp" #include "../../to_view.hpp" #include "../../view_t.hpp" #include "../call_destructors_where_necessary.hpp" #include "make_chunked_array_iterators.hpp" namespace rfl::parsing::tabular { template class ArrowReader { static_assert(!Processors::add_tags_to_variants_, "rfl::AddTagsToVariants cannot be used for tabular data."); static_assert(!Processors::add_namespaced_tags_to_variants_, "rfl::AddNamespacedTagsToVariants cannot be used for tabular data."); static_assert(!Processors::all_required_, "rfl::NoOptionals cannot be used for tabular data."); static_assert(!Processors::default_if_missing_, "rfl::DefaultIfMissing cannot be used for tabular data."); static_assert(!Processors::no_extra_fields_, "rfl::NoExtraFields cannot be used for tabular data (neither " "can rfl::ExtraFields)."); static_assert(!Processors::no_field_names_, "rfl::NoFieldNames cannot be used for tabular data."); public: using ValueType = typename std::remove_cvref_t; static Result make(const std::shared_ptr& _table) { try { return ArrowReader(_table); } catch (const std::exception& e) { return error(std::string("Could not create ArrowReader: ") + e.what()); } } ~ArrowReader() = default; Result read() const noexcept { return make_chunked_array_iterators, _s>( table_) .and_then([&](auto chunked_array_iterators) -> Result { VecType result; while (!end(chunked_array_iterators)) { auto value = new_value(&chunked_array_iterators); if (!value) { return error(value.error().what()); } result.emplace_back(std::move(*value)); } return result; }); } private: ArrowReader(const std::shared_ptr& _table) : table_(Ref::make(_table).value()) {} bool end(const auto& _chunked_array_iterators) const { return apply( [](const auto&... _its) { return (false || ... || _its.end()); }, _chunked_array_iterators); } Result new_value(auto* _chunked_array_iterators) const noexcept { alignas(ValueType) unsigned char buf[sizeof(ValueType)]{}; auto ptr = internal::ptr_cast(&buf); auto view = to_view(*ptr); using ViewType = std::remove_cvref_t; try { const auto set_one = [&](std::integral_constant) { using FieldType = tuple_element_t<_i, typename ViewType::Fields>; using T = std::remove_cvref_t< std::remove_pointer_t>; auto res = *_chunked_array_iterators->template get<_i>(); if (!res) { destroy_value<_i>(&view); throw std::runtime_error( std::string("Field '") + typename FieldType::Name().str() + std::string("' could not be set: ") + res.error().what()); } ::new (view.template get<_i>()) T(std::move(*res)); ++_chunked_array_iterators->template get<_i>(); }; [&](std::integer_sequence) { (set_one(std::integral_constant{}), ...); }(std::make_integer_sequence()); } catch (const std::exception& e) { return error(e.what()); } return std::move(*ptr); } template void destroy_value(ViewType* _view) const { static_assert(_i < ViewType::size(), "_i out of bounds."); auto set = std::array(); for (size_t i = 0; i < _i; ++i) { set[i] = true; } for (size_t i = _i; i < ViewType::size(); ++i) { set[i] = false; } call_destructors_where_necessary(set, _view); } private: Ref table_; }; } // namespace rfl::parsing::tabular #endif