kblib 0.2.3
General utilities library for modern C++
multi_span.h
Go to the documentation of this file.
1/* *****************************************************************************
2 * kblib is a general utility library for C++14 and C++17, intended to provide
3 * performant high-level abstractions and more expressive ways to do simple
4 * things.
5 *
6 * Copyright (c) 2021 killerbee
7 *
8 * This program is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <https://www.gnu.org/licenses/>.
20 * ****************************************************************************/
21
31#ifndef MULTI_SPAN_H
32#define MULTI_SPAN_H
33
34#include "tdecl.h"
35
36#if KBLIB_USE_CXX17
37
38# include <initializer_list>
39# include <optional>
40# include <ostream>
41# include <type_traits>
42# include <utility>
43
44# include <boost/iterator.hpp>
45# include <boost/iterator/iterator_facade.hpp>
46# include <gsl/gsl>
47
48namespace KBLIB_NS {
49
50template <typename T>
51class multi_span;
52
53namespace multi_impl {
54
55 template <typename T>
56 using subspan_t = std::pair<std::ptrdiff_t, gsl::span<T>>;
57
58 template <typename T>
60 : public boost::iterator_facade<mulspan_iterator<T>, T,
61 std::bidirectional_iterator_tag> {
62 public:
63 mulspan_iterator() = default;
65 : parent(&s) {
66 recalculate_cache();
67 }
68 mulspan_iterator(const multi_span<T>& s, std::ptrdiff_t i)
69 : parent(&s)
70 , index(i) {}
71
72 private:
73 mulspan_iterator(const multi_span<T>& s, std::ptrdiff_t i,
74 typename std::vector<subspan_t<T>>::const_iterator r,
75 typename gsl::span<T>::iterator p)
76 : parent(&s)
77 , index(i)
78 , pos_cache(cached_iterator{r, p}) {}
79
80 public:
81 template <typename U,
82 typename
83 = std::enable_if_t<std::is_convertible_v<U (*)[], T (*)[]>>>
85 template <typename U,
86 typename
87 = std::enable_if_t<std::is_convertible_v<U (*)[], T (*)[]>>>
89
90 private:
91 friend class boost::iterator_core_access;
92
93 auto recalculate_cache() const -> void {
94 if (! pos_cache) {
95 if (index == 0) {
96 pos_cache = {parent->spans.begin(),
97 parent->spans.front().second.begin()};
98 } else if (index == parent->size()) {
99 pos_cache
100 = {parent->spans.end(), parent->spans.back().second.begin()};
101 } else if (auto it = std::prev(parent->spans.end());
102 index >= it->first) {
103 pos_cache = {it, it->second.begin() + (index - it->first)};
104 } else {
105 // get the subspan before the first subspan starting after index
106 it = std::prev(std::upper_bound(
107 parent->spans.begin(), parent->spans.end(), index,
108 [](std::ptrdiff_t l, const subspan_t<T>& r) {
109 return l < r.first;
110 }));
111 // calculate delta into that subspan
112 pos_cache = {it, it->second.begin() + (index - it->first)};
113 }
114 }
115 }
116 auto dereference() const noexcept -> T& {
117 recalculate_cache();
118 assert(index != parent->size());
119 return *pos_cache.value().pos;
120 }
121 template <typename U,
122 typename = decltype(std::declval<T*>() == std::declval<U*>())>
123 auto equal(const mulspan_iterator<U>& o) const noexcept -> bool {
124 return
125 // if both *this and o have caches,
126 /*(pos_cache and o.pos_cache)
127 //compare them
128 ? pos_cache.value() == o.pos_cache.value()
129 //else, compare parent and index
130 :*/
131 std::tie(parent, index) == std::tie(o.parent, o.index);
132 }
133 auto increment() noexcept -> void {
134 ++index;
135 if (pos_cache) {
136 ++pos_cache.value().pos;
137 if (pos_cache.value().pos == pos_cache.value().subs->second.end()) {
138 ++pos_cache.value().subs;
139 pos_cache.value().pos = pos_cache.value().subs->second.begin();
140 }
141 }
142 }
143 auto decrement() noexcept -> void {
144 --index;
145 if (pos_cache) {
146 if (pos_cache.value().pos
147 == pos_cache.value().subs->second.begin()) {
148 --pos_cache.value().subs;
149 pos_cache.value().pos = pos_cache.value().subs->second.end();
150 } else {
151 --pos_cache.value().pos;
152 }
153 }
154 }
155 auto advance(std::ptrdiff_t delta) noexcept -> void {
156 index += delta;
157 pos_cache = std::nullopt;
158 }
159 // enabled if T* is comparable with U*
160 template <typename U,
161 typename = decltype(std::declval<T*>() == std::declval<U*>())>
162 auto distance_to(mulspan_iterator<U> o) const noexcept -> std::ptrdiff_t {
163 return index - o.index;
164 }
165
166 const multi_span<T>* parent{};
167 std::ptrdiff_t index{};
168 struct cached_iterator {
169 typename std::vector<multi_impl::subspan_t<T>>::const_iterator subs;
170 typename gsl::span<T>::iterator pos;
171 auto operator==(const cached_iterator& o) const noexcept -> bool {
172 return std::tie(subs, pos) == std::tie(o.subs, o.pos);
173 }
174 };
175 mutable std::optional<cached_iterator> pos_cache = std::nullopt;
176
177 friend class multi_span<T>;
178 };
179
180} // namespace multi_impl
181
182template <typename T>
184 public:
185 using element_type = T;
186 using value_type = std::remove_cv<T>;
187 using index_type = std::ptrdiff_t;
188 using difference_type = std::ptrdiff_t;
189 using pointer = T*;
190 using reference = T&;
193 using reverse_iterator = std::reverse_iterator<iterator>;
194 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
195
196 multi_span() noexcept
197 : spans{{0, {}}} {}
198 template <typename U,
199 typename
200 = std::enable_if_t<std::is_convertible_v<U (*)[], T (*)[]>>>
201 multi_span(gsl::span<U> o) noexcept
202 : spans{{0, o}, {o.size(), {}}} {}
203 template <typename U,
204 typename
205 = std::enable_if_t<std::is_convertible_v<U (*)[], T (*)[]>>>
206 multi_span(std::initializer_list<gsl::span<U>> i_spans) noexcept {
207 index_type c
208 = std::accumulate(i_spans.begin(), i_spans.end(), index_type{0},
209 [this](int c, gsl::span<U> s) {
210 spans.push_back({c, s});
211 return c + s.size();
212 });
213 spans.push_back({c, {}});
214 }
215 template <typename Iterator,
216 typename = std::enable_if_t<std::is_convertible_v<
217 decltype(*std::declval<Iterator>()), gsl::span<T>>>>
218 multi_span(Iterator begin, Iterator end) noexcept {
219 index_type c = std::accumulate(begin, end, index_type{0},
220 [this](int c, gsl::span<T> s) {
221 spans.push_back({c, s});
222 return c + s.size();
223 });
224 spans.push_back({c, {}});
225 }
226
227 template <typename U,
228 typename
229 = std::enable_if_t<std::is_convertible_v<U (*)[], T (*)[]>>>
231
232 multi_span(const multi_span&) = default;
233 multi_span(multi_span&&) noexcept = default;
234
235 auto operator=(const multi_span&) -> multi_span& = default;
236 auto operator=(multi_span&&) noexcept -> multi_span& = default;
237
238 ~multi_span() = default;
239
240 KBLIB_NODISCARD auto begin() noexcept -> iterator { return {*this}; }
241 KBLIB_NODISCARD auto begin() const noexcept -> const_iterator {
242 return {*this};
243 }
244 KBLIB_NODISCARD auto cbegin() const noexcept -> const_iterator {
245 return {*this};
246 }
247
248 KBLIB_NODISCARD auto end() noexcept -> iterator {
249 return {*this, size(), spans.end(), spans.back().second.begin()};
250 }
251 KBLIB_NODISCARD auto end() const noexcept -> const_iterator {
252 return {*this, size(), spans.end(), spans.back().second.begin()};
253 }
254 KBLIB_NODISCARD auto cend() const noexcept -> const_iterator {
255 return {*this, size(), spans.end(), spans.back().second.begin()};
256 }
257
259 return iterator{*this, size(), spans.end(), spans.back().second.begin()};
260 }
262 return iterator{*this, size(), spans.end(), spans.back().second.begin()};
263 }
265 return iterator{*this, size(), spans.end(), spans.back().second.begin()};
266 }
267
269 return iterator{*this};
270 }
271 KBLIB_NODISCARD auto rend() const noexcept -> const_reverse_iterator {
272 return iterator{*this};
273 }
275 return iterator{*this};
276 }
277
279 return *iterator{*this, i};
280 }
281
282 // see invariant on spans
283 KBLIB_NODISCARD auto size() const noexcept -> index_type {
284 return spans.back().first;
285 }
286 KBLIB_NODISCARD auto empty() const noexcept -> bool {
287 return spans.back().first == 0;
288 }
289
290 auto diag(std::ostream& os) const noexcept -> void {
291 os << "Diagnostics: " << spans.size() << '\n';
292 for (auto& s : spans) {
293 os << &s << '\t' << s.first << ':' << s.second.size() << '\t';
294 os << s.second.data() << ',' << s.second.data() + s.second.size()
295 << '\n';
296 }
297 }
298
299 // multi_span<T> first(index_type count) const
300 // {
301
302 // }
303 // multi_span<T> last(index_type count) const
304 // {
305
306 // }
307 // multi_span<T> subspan(index_type offset, index_type count = -1) const
308 // {
309 // if (count == -1) {
310 // count = size() - offset;
311 // }
312
313 // }
314 private:
315 template <typename U>
317 // invariant: holds one extra value, {size, {}}
318 std::vector<multi_impl::subspan_t<T>> spans;
319};
320
321} // namespace KBLIB_NS
322
323#endif
324
325#endif // MULTI_SPAN_H
mulspan_iterator(mulspan_iterator< U > &&)
mulspan_iterator(const mulspan_iterator< U > &)
mulspan_iterator(const multi_span< T > &s, std::ptrdiff_t i)
Definition: multi_span.h:68
mulspan_iterator(const multi_span< T > &s)
Definition: multi_span.h:64
auto cend() const noexcept -> const_iterator
Definition: multi_span.h:254
auto rbegin() noexcept -> reverse_iterator
Definition: multi_span.h:258
auto crbegin() const noexcept -> const_reverse_iterator
Definition: multi_span.h:264
auto end() noexcept -> iterator
Definition: multi_span.h:248
auto begin() const noexcept -> const_iterator
Definition: multi_span.h:241
multi_span(Iterator begin, Iterator end) noexcept
Definition: multi_span.h:218
multi_span(const multi_span &)=default
multi_span(gsl::span< U > o) noexcept
Definition: multi_span.h:201
auto crend() const noexcept -> const_reverse_iterator
Definition: multi_span.h:274
multi_span(std::initializer_list< gsl::span< U > > i_spans) noexcept
Definition: multi_span.h:206
std::reverse_iterator< iterator > reverse_iterator
Definition: multi_span.h:193
multi_span(multi_span &&) noexcept=default
auto diag(std::ostream &os) const noexcept -> void
Definition: multi_span.h:290
multi_span(const multi_span< U > &)
auto cbegin() const noexcept -> const_iterator
Definition: multi_span.h:244
auto rend() noexcept -> reverse_iterator
Definition: multi_span.h:268
std::reverse_iterator< const_iterator > const_reverse_iterator
Definition: multi_span.h:194
std::ptrdiff_t difference_type
Definition: multi_span.h:188
reference operator[](index_type i) const
Definition: multi_span.h:278
auto end() const noexcept -> const_iterator
Definition: multi_span.h:251
std::remove_cv< T > value_type
Definition: multi_span.h:186
auto size() const noexcept -> index_type
Definition: multi_span.h:283
auto rend() const noexcept -> const_reverse_iterator
Definition: multi_span.h:271
multi_span() noexcept
Definition: multi_span.h:196
auto rbegin() const noexcept -> const_reverse_iterator
Definition: multi_span.h:261
auto empty() const noexcept -> bool
Definition: multi_span.h:286
std::ptrdiff_t index_type
Definition: multi_span.h:187
constexpr auto size(const C &c) -> decltype(c.size())
Definition: fakestd.h:366
std::pair< std::ptrdiff_t, gsl::span< T > > subspan_t
Definition: multi_span.h:56
typename std::enable_if< B, T >::type enable_if_t
Definition: fakestd.h:54
constexpr auto accumulate(InputIt first, InputIt last, T init) -> T
A constexpr version of std::accumulate.
Definition: algorithm.h:162
constexpr auto equal(InputIt1 first1, InputIt1 last1, InputIt2 first2) -> bool
Definition: fakestd.h:960
Provides macros and basic templates used by the rest of kblib.
#define KBLIB_NS
Definition: tdecl.h:113
#define KBLIB_NODISCARD
This internal macro is used to provide a fallback for [[nodiscard]] in C++14.
Definition: tdecl.h:129