sparrow 2.5.0
C++20 idiomatic APIs for the Apache Arrow Columnar Format
Loading...
Searching...
No Matches
struct_array.hpp
Go to the documentation of this file.
1// Copyright 2024 Man Group Operations Limited
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or mplied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#pragma once
16
17#include <ranges>
18#include <string_view>
19#include <version>
20
22
23#if defined(__cpp_lib_format)
25#endif
26
27#include "sparrow/array_api.hpp"
39
40namespace sparrow
41{
42 class struct_array;
43
44 namespace detail
45 {
46 template <>
48 {
49 [[nodiscard]] static constexpr sparrow::data_type get()
50 {
52 }
53 };
54 }
55
56 template <>
68
74 template <class T>
75 constexpr bool is_struc_array_v = std::same_as<T, struct_array>;
76
125 class struct_array final : public mutable_array_bitmap_base<struct_array>
126 {
127 public:
128
132 using value_iterator = typename inner_types::value_iterator;
133 using const_value_iterator = typename inner_types::const_value_iterator;
135
138
140
144
148 using iterator = typename base_type::iterator;
149 using const_iterator = typename base_type::const_iterator;
150
151 using base_type::insert;
152 using base_type::push_back;
153 using base_type::resize;
154
168
184 template <class... Args>
186 explicit struct_array(Args&&... args)
187 : struct_array(create_proxy(std::forward<Args>(args)...))
188 {
189 }
190
202
215
218
227 [[nodiscard]] SPARROW_API size_type children_count() const;
228
239 [[nodiscard]] SPARROW_API const array_wrapper* raw_child(std::size_t i) const;
240
251 [[nodiscard]] SPARROW_API array_wrapper* raw_child(std::size_t i);
252
258 [[nodiscard]] auto names() const
259 {
260 return get_arrow_proxy().children()
261 | std::views::transform(
262 [](const auto& child)
263 {
264 return child.name();
265 }
266 );
267 }
268
276 template <layout_or_array A>
277 void add_child(A&& child);
278
293 template <std::ranges::input_range R>
295 void add_children(R&& children);
296
307 template <layout_or_array A>
308 void set_child(A&& child, size_t index);
309
319 SPARROW_API void pop_children(size_t n);
320
321 protected:
322
344 template <
345 std::ranges::input_range CHILDREN_RANGE,
347 input_metadata_container METADATA_RANGE = std::vector<metadata_pair>>
348 requires std::same_as<std::ranges::range_value_t<CHILDREN_RANGE>, array>
349 [[nodiscard]] static auto create_proxy(
350 CHILDREN_RANGE&& children,
351 VB&& bitmaps,
352 std::optional<std::string_view> name = std::nullopt,
353 std::optional<METADATA_RANGE> metadata = std::nullopt
354 ) -> arrow_proxy;
355
373 template <std::ranges::input_range CHILDREN_RANGE, input_metadata_container METADATA_RANGE = std::vector<metadata_pair>>
374 requires std::same_as<std::ranges::range_value_t<CHILDREN_RANGE>, array>
375 [[nodiscard]] static auto create_proxy(
376 CHILDREN_RANGE&& children,
377 bool nullable = true,
378 std::optional<std::string_view> name = std::nullopt,
379 std::optional<METADATA_RANGE> metadata = std::nullopt
380 ) -> arrow_proxy;
381
401 template <std::ranges::input_range CHILDREN_RANGE, input_metadata_container METADATA_RANGE = std::vector<metadata_pair>>
402 requires std::same_as<std::ranges::range_value_t<CHILDREN_RANGE>, array>
403 [[nodiscard]] static auto create_proxy_impl(
404 CHILDREN_RANGE&& children,
405 std::optional<validity_bitmap>&& bitmap,
406 std::optional<std::string_view> name = std::nullopt,
407 std::optional<METADATA_RANGE> metadata = std::nullopt
408 ) -> arrow_proxy;
409
410 using children_type = std::vector<cloning_ptr<array_wrapper>>;
411
420
429
438
447
449
450 template <std::input_iterator InputIt>
451 requires std::convertible_to<typename std::iterator_traits<InputIt>::value_type, struct_value>
452 constexpr value_iterator insert_values(const_value_iterator pos, InputIt first, InputIt last);
453
456
458
469
480
490
491 private:
492
504 template <class TRANSFORM>
505 void rebuild_children(size_type new_length, TRANSFORM&& transform)
506 {
507 std::vector<array> new_children;
508 new_children.reserve(children_count());
509 for (std::size_t child_index = 0; child_index < children_count(); ++child_index)
510 {
511 auto new_values = snapshot_array(make_array_view(*m_children[child_index]));
512 transform(new_values, child_index);
513 array child = make_array_view(*m_children[child_index]);
514 array new_child = array_empty_like(child);
515 append_values(new_child, new_values);
516 new_children.push_back(std::move(new_child));
517 }
518 get_arrow_proxy().set_length(new_length);
519 for (std::size_t child_index = 0; child_index < new_children.size(); ++child_index)
520 {
521 set_child(std::move(new_children[child_index]), child_index);
522 }
523 }
524
525 // data members
526 children_type m_children;
527
528 // friend classes
529 friend class array_crtp_base<self_type>;
530 friend class mutable_array_base<self_type>;
531
532 // needs access to this->value(i)
535 };
536
537 template <std::ranges::input_range CHILDREN_RANGE, validity_bitmap_input VB, input_metadata_container METADATA_RANGE>
538 requires std::same_as<std::ranges::range_value_t<CHILDREN_RANGE>, array>
540 CHILDREN_RANGE&& children,
541 VB&& validity_input,
542 std::optional<std::string_view> name,
543 std::optional<METADATA_RANGE> metadata
544 ) -> arrow_proxy
545 {
546 const auto size = children.empty() ? 0 : children[0].size();
547 validity_bitmap vbitmap = ensure_validity_bitmap(size, std::forward<VB>(validity_input));
548 return create_proxy_impl(
549 std::forward<CHILDREN_RANGE>(children),
550 std::move(vbitmap),
551 std::move(name),
552 std::move(metadata)
553 );
554 }
555
556 template <std::input_iterator InputIt>
557 requires std::convertible_to<typename std::iterator_traits<InputIt>::value_type, struct_value>
558 constexpr auto struct_array::insert_values(const_value_iterator pos, InputIt first, InputIt last)
560 {
561 const auto index = static_cast<size_type>(std::distance(value_cbegin(), pos));
562 size_type count = 0;
563 for (auto it = first; it != last; ++it, ++count)
564 {
565 insert_value(std::next(value_cbegin(), static_cast<std::ptrdiff_t>(index + count)), *it, 1);
566 }
567 return std::next(value_begin(), static_cast<std::ptrdiff_t>(index));
568 }
569
570 template <std::ranges::input_range CHILDREN_RANGE, input_metadata_container METADATA_RANGE>
571 requires std::same_as<std::ranges::range_value_t<CHILDREN_RANGE>, array>
573 CHILDREN_RANGE&& children,
574 bool nullable,
575 std::optional<std::string_view> name,
576 std::optional<METADATA_RANGE> metadata
577 ) -> arrow_proxy
578 {
579 const size_t size = children.empty() ? 0 : children[0].size();
580 return create_proxy_impl(
581 std::forward<CHILDREN_RANGE>(children),
583 ? std::make_optional<validity_bitmap>(nullptr, size, validity_bitmap::storage_type::allocator_type{})
584 : std::nullopt,
585 std::move(name),
586 std::move(metadata)
587 );
588 }
589
590 template <std::ranges::input_range CHILDREN_RANGE, input_metadata_container METADATA_RANGE>
591 requires std::same_as<std::ranges::range_value_t<CHILDREN_RANGE>, array>
593 CHILDREN_RANGE&& children,
594 std::optional<validity_bitmap>&& bitmap,
595 std::optional<std::string_view> name,
596 std::optional<METADATA_RANGE> metadata
597 ) -> arrow_proxy
598 {
599 const auto n_children = children.size();
600 ArrowSchema** child_schemas = new ArrowSchema*[n_children];
601 ArrowArray** child_arrays = new ArrowArray*[n_children];
602
603 const auto size = children.empty() ? 0 : children[0].size();
604
605 for (std::size_t i = 0; i < n_children; ++i)
606 {
607 auto& child = children[i];
608 SPARROW_ASSERT_TRUE(child.size() == size);
609 auto [flat_arr, flat_schema] = extract_arrow_structures(std::move(child));
610 child_arrays[i] = new ArrowArray(std::move(flat_arr));
611 child_schemas[i] = new ArrowSchema(std::move(flat_schema));
612 }
613
614 const bool bitmap_has_value = bitmap.has_value();
615 const auto null_count = bitmap_has_value ? bitmap->null_count() : 0;
616 const auto flags = bitmap_has_value
617 ? std::make_optional<std::unordered_set<sparrow::ArrowFlag>>({ArrowFlag::NULLABLE})
618 : std::nullopt;
619
621 std::string("+s"), // format
622 std::move(name), // name
623 std::move(metadata), // metadata
624 flags, // flags,
625 child_schemas, // children
626 repeat_view<bool>(true, n_children), // children_ownership
627 nullptr, // dictionary
628 true // dictionary ownership
629 );
630
631 buffer<uint8_t> bitmap_buffer = bitmap_has_value
632 ? std::move(*bitmap).extract_storage()
634
635 std::vector<buffer<std::uint8_t>> arr_buffs;
636 arr_buffs.reserve(1);
637 arr_buffs.emplace_back(std::move(bitmap_buffer));
638
640 static_cast<std::int64_t>(size), // length
641 static_cast<std::int64_t>(null_count), // null_count
642 0, // offset
643 std::move(arr_buffs),
644 child_arrays, // children
645 repeat_view<bool>(true, n_children), // children_ownership
646 nullptr, // dictionary
647 true // dictionary ownership
648 );
649 return arrow_proxy{std::move(arr), std::move(schema)};
650 }
651
652 template <layout_or_array A>
654 {
655 SPARROW_ASSERT_TRUE(child.size() == size());
656 auto [array, schema] = extract_arrow_structures(std::forward<A>(child));
657 get_arrow_proxy().add_child(std::move(array), std::move(schema));
658 m_children.emplace_back(array_factory(get_arrow_proxy().children().back().view()));
659 }
660
661 template <std::ranges::input_range R>
663 void struct_array::add_children(R&& children)
664 {
665 for (const auto& child : children)
666 {
667 SPARROW_ASSERT_TRUE(child.size() == size());
668 }
669 m_children.reserve(m_children.size() + children.size());
670 for (auto&& child : children)
671 {
672 add_child(std::forward<decltype(child)>(child));
673 }
674 }
675
676 template <layout_or_array A>
677 void struct_array::set_child(A&& child, size_t index)
678 {
679 SPARROW_ASSERT_TRUE(child.size() == size());
680 auto [array, schema] = extract_arrow_structures(std::forward<A>(child));
681 get_arrow_proxy().set_child(index, std::move(array), std::move(schema));
682 m_children[index] = array_factory(get_arrow_proxy().children()[index].view());
683 }
684}
685
686#if defined(__cpp_lib_format)
687
688
689template <>
690struct std::formatter<sparrow::struct_array>
691{
692 constexpr auto parse(std::format_parse_context& ctx)
693 {
694 return ctx.begin();
695 }
696
697 SPARROW_API auto format(const sparrow::struct_array& struct_array, std::format_context& ctx) const
698 -> decltype(ctx.out());
699};
700
701namespace sparrow
702{
703 SPARROW_API std::ostream& operator<<(std::ostream& os, const struct_array& value);
704}
705
706#endif
void struct_array()
typename base_type::const_bitmap_range const_bitmap_range
typename base_type::iterator_tag iterator_tag
typename base_type::bitmap_const_reference bitmap_const_reference
typename base_type::bitmap_type bitmap_type
Base class for array type erasure.
Dynamically typed array encapsulating an Arrow layout.
Definition array_api.hpp:50
SPARROW_API size_type size() const
Object that owns a piece of contiguous memory.
Definition buffer.hpp:142
xsimd::aligned_allocator< T > default_allocator
Definition buffer.hpp:155
constexpr void reserve(size_type new_cap)
Definition buffer.hpp:824
Base class definining common interface for arrays with a bitmap.
A view that repeats a value a given number of times.
SPARROW_API value_iterator erase_values(const_value_iterator pos, size_type count)
SPARROW_API inner_reference value(size_type i)
Gets mutable reference to struct at specified index.
array_inner_types< self_type > inner_types
SPARROW_API children_type make_children()
Creates the children array wrappers.
void add_child(A &&child)
Adds a child array to the struct.
static auto create_proxy_impl(CHILDREN_RANGE &&children, std::optional< validity_bitmap > &&bitmap, std::optional< std::string_view > name=std::nullopt, std::optional< METADATA_RANGE > metadata=std::nullopt) -> arrow_proxy
Implementation helper for creating Arrow proxy from components.
typename base_type::iterator iterator
SPARROW_API const_value_iterator value_cbegin() const
Gets const iterator to beginning of value range.
typename base_type::const_iterator const_iterator
SPARROW_API struct_array(const struct_array &rhs)
Copy constructor.
SPARROW_API struct_array(arrow_proxy proxy)
Constructs struct array from Arrow proxy.
SPARROW_API value_iterator insert_value(const_value_iterator pos, const struct_value &value, size_type count)
SPARROW_API value_iterator value_end()
Gets iterator to end of value range.
mutable_array_bitmap_base< self_type > base_type
SPARROW_API void resize_values(size_type new_length, const struct_value &value)
SPARROW_API void pop_children(size_t n)
Removes the last n children from the struct.
auto names() const
Gets the names of all child arrays.
void set_child(A &&child, size_t index)
Sets a child array at the specified index.
SPARROW_API inner_const_reference value(size_type i) const
Gets const reference to struct at specified index.
constexpr value_iterator insert_values(const_value_iterator pos, InputIt first, InputIt last)
SPARROW_API array_wrapper * raw_child(std::size_t i)
Gets mutable pointer to child array at specified index.
void add_children(R &&children)
Adds multiple children to the struct array.
SPARROW_API const array_wrapper * raw_child(std::size_t i) const
Gets const pointer to child array at specified index.
nullable< inner_value_type > value_type
nullable< inner_const_reference, bitmap_const_reference > const_reference
SPARROW_API value_iterator value_begin()
Gets iterator to beginning of value range.
struct_value inner_reference
struct_array(Args &&... args)
Generic constructor for creating struct array from various inputs.
typename base_type::size_type size_type
typename inner_types::value_iterator value_iterator
base_type::iterator_tag iterator_tag
struct_value inner_value_type
std::vector< cloning_ptr< array_wrapper > > children_type
typename base_type::bitmap_type bitmap_type
struct_array(struct_array &&)=default
struct_array & operator=(struct_array &&)=default
static auto create_proxy(CHILDREN_RANGE &&children, VB &&bitmaps, std::optional< std::string_view > name=std::nullopt, std::optional< METADATA_RANGE > metadata=std::nullopt) -> arrow_proxy
Creates Arrow proxy from children arrays with explicit validity bitmap.
struct_value inner_const_reference
SPARROW_API size_type children_count() const
Gets the number of child arrays (fields).
base_type::const_bitmap_range const_bitmap_range
SPARROW_API const_value_iterator value_cend() const
Gets const iterator to end of value range.
SPARROW_API struct_array & operator=(const struct_array &rhs)
Copy assignment operator.
typename base_type::bitmap_const_reference bitmap_const_reference
typename inner_types::const_value_iterator const_value_iterator
Concept for input containers that can provide metadata pairs.
Definition metadata.hpp:332
Concept defining valid input types for validity bitmap creation.
#define SPARROW_API
Definition config.hpp:38
#define SPARROW_ASSERT_TRUE(expr__)
constexpr bool excludes_copy_and_move_ctor_v
Convenience variable template for excludes_copy_and_move_ctor.
array_bitmap_base_impl< D, true > mutable_array_bitmap_base
Convenient alias for arrays with mutable validity bitmaps.
ArrowSchema make_arrow_schema(F format, N name, std::optional< M > metadata, std::optional< std::unordered_set< ArrowFlag > > flags, ArrowSchema **children, const CHILDREN_OWNERSHIP &children_ownership, ArrowSchema *dictionary, bool dictionary_ownership)
Creates an ArrowSchema owned by a unique_ptr and holding the provided data.
SPARROW_API void append_values(array &destination, const std::vector< array_traits::value_type > &values)
SPARROW_API array array_empty_like(const array &source)
constexpr bool is_struc_array_v
Type trait to check if a type is a struct_array.
std::pair< ArrowArray, ArrowSchema > extract_arrow_structures(A &&a)
Extracts the internal ArrowArray and ArrowSchema structures from the given array or typed layout.
Definition array.hpp:110
ArrowArray make_arrow_array(int64_t length, int64_t null_count, int64_t offset, B buffers, ArrowArray **children, const CHILDREN_OWNERSHIP &children_ownership, ArrowArray *dictionary, bool dictionary_ownership)
Creates an ArrowArray.
dynamic_bitset< std::uint8_t > validity_bitmap
Type alias for a validity bitmap using 8-bit storage blocks.
std::ostream & operator<<(std::ostream &os, const nullval_t &)
SPARROW_API cloning_ptr< array_wrapper > array_factory(arrow_proxy proxy)
validity_bitmap ensure_validity_bitmap(std::size_t size, R &&validity_input)
Ensures a validity bitmap of the specified size from various input types.
SPARROW_API array make_array_view(const array_wrapper &source)
data_type
Runtime identifier of arrow data types, usually associated with raw bytes with the associated value.
SPARROW_API std::vector< array_traits::value_type > snapshot_array(const array &source)
functor_index_iterator< detail::layout_value_functor< array_type, inner_value_type > > value_iterator
functor_index_iterator< detail::layout_value_functor< const array_type, inner_value_type > > const_value_iterator
std::random_access_iterator_tag iterator_tag
Base class for array_inner_types specializations.
Traits class that must be specialized by array implementations.
Metafunction for retrieving the data_type of a typed array.