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();