9#include <userver/utils/assert.hpp>
11#include <userver/storages/clickhouse/io/columns/column_wrapper.hpp>
13USERVER_NAMESPACE_BEGIN
22template <
typename ColumnType>
23class ColumnIterator
final {
25 using iterator_category = std::forward_iterator_tag;
26 using difference_type = std::ptrdiff_t;
27 using value_type =
typename ColumnType::cpp_type;
28 using reference = value_type&;
29 using pointer = value_type*;
31 ColumnIterator() =
default;
32 ColumnIterator(ColumnRef column);
34 static ColumnIterator End(ColumnRef column);
36 ColumnIterator operator++(
int);
37 ColumnIterator& operator++();
38 reference operator*()
const;
39 pointer operator->()
const;
41 bool operator==(
const ColumnIterator& other)
const;
42 bool operator!=(
const ColumnIterator& other)
const;
44 enum class IteratorPosition { kBegin, kEnd };
49 ColumnIterator(IteratorPosition iter_position, ColumnRef&& column);
51 class DataHolder
final {
53 DataHolder() =
default;
54 DataHolder(IteratorPosition iter_position, ColumnRef&& column);
56 DataHolder operator++(
int);
57 DataHolder& operator++();
58 value_type& UpdateValue();
59 bool operator==(
const DataHolder& other)
const;
61 value_type Get()
const;
69 std::optional<value_type> current_value_ = std::nullopt;
72 template <
typename T,
typename =
void>
73 struct IteratorDataHolder
final {
74 using type = DataHolder;
78 struct IteratorDataHolder<T, std::void_t<
typename T::iterator_data>> final {
79 using type =
typename T::iterator_data;
82 using data_holder =
typename IteratorDataHolder<ColumnType>::type;
84 mutable data_holder data_;
87template <
typename ColumnType>
88ColumnIterator<ColumnType>::ColumnIterator(ColumnRef column)
89 : ColumnIterator{IteratorPosition::kBegin, std::move(column)} {}
91template <
typename ColumnType>
92ColumnIterator<ColumnType> ColumnIterator<ColumnType>::End(ColumnRef column) {
93 return ColumnIterator{IteratorPosition::kEnd, std::move(column)};
96template <
typename ColumnType>
97ColumnIterator<ColumnType>::ColumnIterator(IteratorPosition iter_position,
99 : data_{data_holder{iter_position, std::move(column)}} {}
101template <
typename ColumnType>
102ColumnIterator<ColumnType> ColumnIterator<ColumnType>::operator++(
int) {
103 ColumnIterator<ColumnType> old{};
109template <
typename ColumnType>
110ColumnIterator<ColumnType>& ColumnIterator<ColumnType>::operator++() {
115template <
typename ColumnType>
116typename ColumnIterator<ColumnType>::reference
117ColumnIterator<ColumnType>::operator*()
const {
118 return data_.UpdateValue();
121template <
typename ColumnType>
122typename ColumnIterator<ColumnType>::pointer
123ColumnIterator<ColumnType>::operator->()
const {
124 return &data_.UpdateValue();
127template <
typename ColumnType>
128bool ColumnIterator<ColumnType>::operator==(
const ColumnIterator& other)
const {
129 return data_ == other.data_;
132template <
typename ColumnType>
133bool ColumnIterator<ColumnType>::operator!=(
134 const ColumnIterator<ColumnType>& other)
const {
135 return !((*
this) == other);
138template <
typename ColumnType>
139ColumnIterator<ColumnType>::DataHolder::DataHolder(
140 IteratorPosition iter_position, ColumnRef&& column)
141 : column_{std::move(column)} {
142 switch (iter_position) {
143 case IteratorPosition::kBegin: {
147 case IteratorPosition::kEnd: {
148 ind_ = GetColumnSize(column_);
154template <
typename ColumnType>
155typename ColumnIterator<ColumnType>::DataHolder
156ColumnIterator<ColumnType>::DataHolder::operator++(
int) {
158 old.column_ = column_;
160 old.current_value_ = std::move_if_noexcept(current_value_);
161 current_value_.reset();
166template <
typename ColumnType>
167typename ColumnIterator<ColumnType>::DataHolder&
168ColumnIterator<ColumnType>::DataHolder::operator++() {
170 current_value_.reset();
175template <
typename ColumnType>
176typename ColumnIterator<ColumnType>::value_type&
177ColumnIterator<ColumnType>::DataHolder::UpdateValue() {
178 UASSERT(ind_ < GetColumnSize(column_));
179 if (!current_value_.has_value()) {
180 current_value_.emplace(Get());
182 return *current_value_;
185template <
typename ColumnType>
186bool ColumnIterator<ColumnType>::DataHolder::operator==(
187 const DataHolder& other)
const {
188 return ind_ == other.ind_ && column_.get() == other.column_.get();