| 1631 | // of its children. |
| 1632 | template <typename T, bool IsFlattening = false> |
| 1633 | class NestedSelector { |
| 1634 | public: |
| 1635 | using ArrowType = T; |
| 1636 | using Util = NestedSelectorUtil; |
| 1637 | |
| 1638 | explicit NestedSelector(const std::vector<std::shared_ptr<T>>& children) |
| 1639 | : parent_or_children_(&children) {} |
| 1640 | explicit NestedSelector(const T& parent) : parent_or_children_(&parent) {} |
| 1641 | explicit NestedSelector(std::shared_ptr<T> parent) |
| 1642 | : owned_parent_(std::move(parent)), parent_or_children_(owned_parent_.get()) {} |
| 1643 | template <typename Arg> |
| 1644 | NestedSelector(Arg&& arg, MemoryPool* pool) : NestedSelector(std::forward<Arg>(arg)) { |
| 1645 | if (pool) { |
| 1646 | pool_ = pool; |
| 1647 | } |
| 1648 | } |
| 1649 | |
| 1650 | // If the index is out of bounds, this returns an invalid selector rather than an |
| 1651 | // error. |
| 1652 | Result<NestedSelector> GetChild(int i) const { |
| 1653 | std::shared_ptr<T> child; |
| 1654 | if (auto parent = get_parent()) { |
| 1655 | const DataType* type = Util::GetType(*parent); |
| 1656 | // We avoid this check for schema fields since it's inconsequential (plus there are |
| 1657 | // tests elsewhere that rely on it not happening) |
| 1658 | if constexpr (!std::is_same_v<T, Field>) { |
| 1659 | if (ARROW_PREDICT_FALSE(type->id() != Type::STRUCT)) { |
| 1660 | return Util::NonStructError(); |
| 1661 | } |
| 1662 | } |
| 1663 | // Bounds-check the index *once* using the parent's type |
| 1664 | if (ARROW_PREDICT_TRUE(i >= 0 && i < type->num_fields())) { |
| 1665 | ARROW_ASSIGN_OR_RAISE(child, GetChild(*parent, i, pool_)); |
| 1666 | } |
| 1667 | } else if (auto children = get_children()) { |
| 1668 | if (ARROW_PREDICT_TRUE(i >= 0 && static_cast<size_t>(i) < children->size())) { |
| 1669 | child = (*children)[i]; |
| 1670 | } |
| 1671 | } |
| 1672 | return NestedSelector(std::move(child), pool_); |
| 1673 | } |
| 1674 | |
| 1675 | Result<std::shared_ptr<T>> Finish() const { |
| 1676 | DCHECK(get_parent() && owned_parent_); |
| 1677 | return owned_parent_; |
| 1678 | } |
| 1679 | |
| 1680 | template <typename OStream, typename U = T> |
| 1681 | std::enable_if_t<std::is_same_v<U, Field>> Summarize(OStream* os) const { |
| 1682 | const FieldVector* fields = get_children(); |
| 1683 | if (!fields && get_parent()) { |
| 1684 | fields = &get_parent()->type()->fields(); |
| 1685 | } |
| 1686 | *os << "fields: { "; |
| 1687 | if (fields) { |
| 1688 | for (const auto& field : *fields) { |
| 1689 | *os << field->ToString() << ", "; |
| 1690 | } |
no test coverage detected