userver: userver/storages/clickhouse/io/columns/column_iterator.hpp Source File
⚠️ This is the documentation for an old userver version. Click here to switch to the latest version.
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages Concepts
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