userver: userver/storages/clickhouse/io/columns/column_iterator.hpp Source File
Loading...
Searching...
No Matches
column_iterator.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/storages/clickhouse/io/columns/column_iterator.hpp
4/// @brief @copybrief storages::clickhouse::io::columns::BaseIterator
5
6#include <iterator>
7#include <optional>
8
9#include <userver/utils/assert.hpp>
10
11#include <userver/storages/clickhouse/io/columns/column_wrapper.hpp>
12
13USERVER_NAMESPACE_BEGIN
14
15namespace storages::clickhouse::io {
16
17class IteratorsTester;
18
19namespace columns {
20
21/// @brief Forward-iterator for iterating over column of type ColumnType
22template <typename ColumnType>
23class ColumnIterator final {
24 public:
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*;
30
31 ColumnIterator() = default;
32 ColumnIterator(ColumnRef column);
33
34 static ColumnIterator End(ColumnRef column);
35
36 ColumnIterator operator++(int);
37 ColumnIterator& operator++();
38 reference operator*() const;
39 pointer operator->() const;
40
41 bool operator==(const ColumnIterator& other) const;
42 bool operator!=(const ColumnIterator& other) const;
43
44 enum class IteratorPosition { kBegin, kEnd };
45
46 friend class storages::clickhouse::io::IteratorsTester;
47
48 private:
49 ColumnIterator(IteratorPosition iter_position, ColumnRef&& column);
50
51 class DataHolder final {
52 public:
53 DataHolder() = default;
54 DataHolder(IteratorPosition iter_position, ColumnRef&& column);
55
56 DataHolder operator++(int);
57 DataHolder& operator++();
58 value_type& UpdateValue();
59 bool operator==(const DataHolder& other) const;
60
61 value_type Get() const;
62
63 friend class storages::clickhouse::io::IteratorsTester;
64
65 private:
66 ColumnRef column_;
67 size_t ind_{0};
68
69 std::optional<value_type> current_value_ = std::nullopt;
70 };
71
72 template <typename T, typename = void>
73 struct IteratorDataHolder final {
74 using type = DataHolder;
75 };
76
77 template <typename T>
78 struct IteratorDataHolder<T, std::void_t<typename T::iterator_data>> final {
79 using type = typename T::iterator_data;
80 };
81
82 using data_holder = typename IteratorDataHolder<ColumnType>::type;
83
84 mutable data_holder data_;
85};
86
87template <typename ColumnType>
88ColumnIterator<ColumnType>::ColumnIterator(ColumnRef column)
89 : ColumnIterator{IteratorPosition::kBegin, std::move(column)} {}
90
91template <typename ColumnType>
92ColumnIterator<ColumnType> ColumnIterator<ColumnType>::End(ColumnRef column) {
93 return ColumnIterator{IteratorPosition::kEnd, std::move(column)};
94}
95
96template <typename ColumnType>
97ColumnIterator<ColumnType>::ColumnIterator(IteratorPosition iter_position,
98 ColumnRef&& column)
99 : data_{data_holder{iter_position, std::move(column)}} {}
100
101template <typename ColumnType>
102ColumnIterator<ColumnType> ColumnIterator<ColumnType>::operator++(int) {
103 ColumnIterator<ColumnType> old{};
104 old.data_ = data_++;
105
106 return old;
107}
108
109template <typename ColumnType>
110ColumnIterator<ColumnType>& ColumnIterator<ColumnType>::operator++() {
111 ++data_;
112 return *this;
113}
114
115template <typename ColumnType>
116typename ColumnIterator<ColumnType>::reference
117ColumnIterator<ColumnType>::operator*() const {
118 return data_.UpdateValue();
119}
120
121template <typename ColumnType>
122typename ColumnIterator<ColumnType>::pointer
123ColumnIterator<ColumnType>::operator->() const {
124 return &data_.UpdateValue();
125}
126
127template <typename ColumnType>
128bool ColumnIterator<ColumnType>::operator==(const ColumnIterator& other) const {
129 return data_ == other.data_;
130}
131
132template <typename ColumnType>
133bool ColumnIterator<ColumnType>::operator!=(
134 const ColumnIterator<ColumnType>& other) const {
135 return !((*this) == other);
136}
137
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: {
144 ind_ = 0;
145 break;
146 }
147 case IteratorPosition::kEnd: {
148 ind_ = GetColumnSize(column_);
149 break;
150 }
151 }
152}
153
154template <typename ColumnType>
155typename ColumnIterator<ColumnType>::DataHolder
156ColumnIterator<ColumnType>::DataHolder::operator++(int) {
157 DataHolder old{};
158 old.column_ = column_;
159 old.ind_ = ind_++;
160 old.current_value_ = std::move_if_noexcept(current_value_);
161 current_value_.reset();
162
163 return old;
164}
165
166template <typename ColumnType>
167typename ColumnIterator<ColumnType>::DataHolder&
168ColumnIterator<ColumnType>::DataHolder::operator++() {
169 ++ind_;
170 current_value_.reset();
171
172 return *this;
173}
174
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());
181 }
182 return *current_value_;
183}
184
185template <typename ColumnType>
186bool ColumnIterator<ColumnType>::DataHolder::operator==(
187 const DataHolder& other) const {
188 return ind_ == other.ind_ && column_.get() == other.column_.get();
189}
190
191} // namespace columns
192
193} // namespace storages::clickhouse::io
194
195USERVER_NAMESPACE_END