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#include <algorithm>
36#include <vector>
37
38#if KBLIB_USE_CXX17
39
40# include <tuple>
41# include <optional>
42# include <ostream>
43# include <type_traits>
44# include <utility>
45
46# include <boost/iterator.hpp>
47# include <boost/iterator/iterator_facade.hpp>
48# if __cpp_lib_span >= 202002L
49# include <span>
50# else
51# include <gsl/gsl>
52# endif
53
54namespace KBLIB_NS {
55# if __cpp_lib_span >= 202002L
56
57using std::span;
58# else
59using gsl::span;
60# endif
61
62template <typename T>
63class multi_span;
64
65namespace multi_impl {
66
67 template <typename T>
68 using subspan_t = std::pair<std::ptrdiff_t, span<T>>;
69
70 template <typename T>
72 : public boost::iterator_facade<mulspan_iterator<T>, T,
73 std::bidirectional_iterator_tag> {
74 public:
75 mulspan_iterator() = default;
77 : parent(&s) {
78 recalculate_cache();
79 }
80 mulspan_iterator(const multi_span<T>& s, std::ptrdiff_t i)
81 : parent(&s)
82 , index(i) {}
83
84 private:
85 mulspan_iterator(const multi_span<T>& s, std::ptrdiff_t i,
86 typename std::vector<subspan_t<T>>::const_iterator r,
87 typename span<T>::iterator p)
88 : parent(&s)
89 , index(i)
90 , pos_cache(cached_iterator{r, p}) {}
91
92 public:
93 template <typename U,
94 typename
95 = std::enable_if_t<std::is_convertible_v<U (*)[], T (*)[]>>>
97 template <typename U,
98 typename
99 = std::enable_if_t<std::is_convertible_v<U (*)[], T (*)[]>>>
101
102 private:
103 friend class boost::iterator_core_access;
104
105 auto recalculate_cache() const -> void {
106 if (! pos_cache) {
107 if (index == 0) {
108 pos_cache = {parent->spans.begin(),
109 parent->spans.front().second.begin()};
110 } else if (index == parent->size()) {
111 pos_cache
112 = {parent->spans.end(), parent->spans.back().second.begin()};
113 } else if (auto it = std::prev(parent->spans.end());
114 index >= it->first) {
115 pos_cache = {it, it->second.begin() + (index - it->first)};
116 } else {
117 // get the subspan before the first subspan starting after index
118 it = std::prev(std::upper_bound(
119 parent->spans.begin(), parent->spans.end(), index,
120 [](std::ptrdiff_t l, const subspan_t<T>& r) {
121 return l < r.first;
122 }));
123 // calculate delta into that subspan
124 pos_cache = {it, it->second.begin() + (index - it->first)};
125 }
126 }
127 }
128 auto dereference() const noexcept -> T& {
129 recalculate_cache();
130 assert(index != parent->size());
131 return *pos_cache.value().pos;
132 }
133 template <typename U,
134 typename = decltype(std::declval<T*>() == std::declval<U*>())>
135 auto equal(const mulspan_iterator<U>& o) const noexcept -> bool {
136 return
137 // if both *this and o have caches,
138 /*(pos_cache and o.pos_cache)
139 //compare them
140 ? pos_cache.value() == o.pos_cache.value()
141 //else, compare parent and index
142 :*/
143 std::tie(parent, index) == std::tie(o.parent, o.index);
144 }
145 auto increment() noexcept -> void {
146 ++index;
147 if (pos_cache) {
148 ++pos_cache.value().pos;
149 if (pos_cache.value().pos == pos_cache.value().subs->second.end()) {
150 ++pos_cache.value().subs;
151 pos_cache.value().pos = pos_cache.value().subs->second.begin();
152 }
153 }
154 }
155 auto decrement() noexcept -> void {
156 --index;
157 if (pos_cache) {
158 if (pos_cache.value().pos
159 == pos_cache.value().subs->second.begin()) {
160 --pos_cache.value().subs;
161 pos_cache.value().pos = pos_cache.value().subs->second.end();
162 } else {
163 --pos_cache.value().pos;
164 }
165 }
166 }
167 auto advance(std::ptrdiff_t delta) noexcept -> void {
168 index += delta;
169 pos_cache = std::nullopt;
170 }
171 // enabled if T* is comparable with U*
172 template <typename U,
173 typename = decltype(std::declval<T*>() == std::declval<U*>())>
174 auto distance_to(mulspan_iterator<U> o) const noexcept -> std::ptrdiff_t {
175 return index - o.index;
176 }
177
178 const multi_span<T>* parent{};
179 std::ptrdiff_t index{};
180 struct cached_iterator {
181 typename std::vector<multi_impl::subspan_t<T>>::const_iterator subs;
182 typename span<T>::iterator pos;
183 auto operator==(const cached_iterator& o) const noexcept -> bool {
184 return std::tie(subs, pos) == std::tie(o.subs, o.pos);
185 }
186 };
187 mutable std::optional<cached_iterator> pos_cache = std::nullopt;
188
189 friend class multi_span<T>;
190 };
191
192} // namespace multi_impl
193
194template <typename T>
196 public:
197 using element_type = T;
198 using value_type = std::remove_cv<T>;
199 using index_type = std::ptrdiff_t;
200 using difference_type = std::ptrdiff_t;
201 using pointer = T*;
202 using reference = T&;
205 using reverse_iterator = std::reverse_iterator<iterator>;
206 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
207
208 multi_span() noexcept
209 : spans{{0, {}}} {}
210 template <typename U,
211 typename
212 = std::enable_if_t<std::is_convertible_v<U (*)[], T (*)[]>>>
213 multi_span(span<U> o) noexcept
214 : spans{{0, o}, {o.size(), {}}} {}
215 template <typename U,
216 typename
217 = std::enable_if_t<std::is_convertible_v<U (*)[], T (*)[]>>>
218 multi_span(std::initializer_list<span<U>> i_spans) noexcept {
219 index_type c = std::accumulate(i_spans.begin(), i_spans.end(),
220 index_type{0}, [this](int c, span<U> s) {
221 spans.push_back({c, s});
222 return c + s.size();
223 });
224 spans.push_back({c, {}});
225 }
226 template <typename Iterator,
227 typename = std::enable_if_t<std::is_convertible_v<
228 decltype(*std::declval<Iterator>()), span<T>>>>
229 multi_span(Iterator begin, Iterator end) noexcept {
230 index_type c = std::accumulate(begin, end, index_type{0},
231 [this](int c, span<T> s) {
232 spans.push_back({c, s});
233 return c + s.size();
234 });
235 spans.push_back({c, {}});
236 }
237
238 template <typename U,
239 typename
240 = std::enable_if_t<std::is_convertible_v<U (*)[], T (*)[]>>>
242
243 multi_span(const multi_span&) = default;
244 multi_span(multi_span&&) noexcept = default;
245
246 auto operator=(const multi_span&) -> multi_span& = default;
247 auto operator=(multi_span&&) noexcept -> multi_span& = default;
248
249 ~multi_span() = default;
250
251 KBLIB_NODISCARD auto begin() noexcept -> iterator { return {*this}; }
252 KBLIB_NODISCARD auto begin() const noexcept -> const_iterator {
253 return {*this};
254 }
255 KBLIB_NODISCARD auto cbegin() const noexcept -> const_iterator {
256 return {*this};
257 }
258
259 KBLIB_NODISCARD auto end() noexcept -> iterator {
260 return {*this, size(), spans.end(), spans.back().second.begin()};
261 }
262 KBLIB_NODISCARD auto end() const noexcept -> const_iterator {
263 return {*this, size(), spans.end(), spans.back().second.begin()};
264 }
265 KBLIB_NODISCARD auto cend() const noexcept -> const_iterator {
266 return {*this, size(), spans.end(), spans.back().second.begin()};
267 }
268
270 return iterator{*this, size(), spans.end(), spans.back().second.begin()};
271 }
273 return iterator{*this, size(), spans.end(), spans.back().second.begin()};
274 }
276 return iterator{*this, size(), spans.end(), spans.back().second.begin()};
277 }
278
280 return iterator{*this};
281 }
282 KBLIB_NODISCARD auto rend() const noexcept -> const_reverse_iterator {
283 return iterator{*this};
284 }
286 return iterator{*this};
287 }
288
290 return *iterator{*this, i};
291 }
292
293 // see invariant on spans
294 KBLIB_NODISCARD auto size() const noexcept -> index_type {
295 return spans.back().first;
296 }
297 KBLIB_NODISCARD auto empty() const noexcept -> bool {
298 return spans.back().first == 0;
299 }
300
301 auto diag(std::ostream& os) const noexcept -> void {
302 os << "Diagnostics: " << spans.size() << '\n';
303 for (auto& s : spans) {
304 os << &s << '\t' << s.first << ':' << s.second.size() << '\t';
305 os << s.second.data() << ',' << s.second.data() + s.second.size()
306 << '\n';
307 }
308 }
309
310 // multi_span<T> first(index_type count) const
311 // {
312
313 // }
314 // multi_span<T> last(index_type count) const
315 // {
316
317 // }
318 // multi_span<T> subspan(index_type offset, index_type count = -1) const
319 // {
320 // if (count == -1) {
321 // count = size() - offset;
322 // }
323
324 // }
325 private:
326 template <typename U>
328 // invariant: holds one extra value, {size, {}}
329 std::vector<multi_impl::subspan_t<T>> spans;
330};
331
332} // namespace KBLIB_NS
333
334#endif
335
336#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:80
mulspan_iterator(const multi_span< T > &s)
Definition: multi_span.h:76
auto cend() const noexcept -> const_iterator
Definition: multi_span.h:265
auto rbegin() noexcept -> reverse_iterator
Definition: multi_span.h:269
auto crbegin() const noexcept -> const_reverse_iterator
Definition: multi_span.h:275
auto end() noexcept -> iterator
Definition: multi_span.h:259
auto begin() const noexcept -> const_iterator
Definition: multi_span.h:252
multi_span(Iterator begin, Iterator end) noexcept
Definition: multi_span.h:229
multi_span(const multi_span &)=default
auto crend() const noexcept -> const_reverse_iterator
Definition: multi_span.h:285
multi_span(span< U > o) noexcept
Definition: multi_span.h:213
std::reverse_iterator< iterator > reverse_iterator
Definition: multi_span.h:205
multi_span(multi_span &&) noexcept=default
auto diag(std::ostream &os) const noexcept -> void
Definition: multi_span.h:301
multi_span(std::initializer_list< span< U > > i_spans) noexcept
Definition: multi_span.h:218
multi_span(const multi_span< U > &)
auto cbegin() const noexcept -> const_iterator
Definition: multi_span.h:255
auto rend() noexcept -> reverse_iterator
Definition: multi_span.h:279
std::reverse_iterator< const_iterator > const_reverse_iterator
Definition: multi_span.h:206
std::ptrdiff_t difference_type
Definition: multi_span.h:200
reference operator[](index_type i) const
Definition: multi_span.h:289
auto end() const noexcept -> const_iterator
Definition: multi_span.h:262
std::remove_cv< T > value_type
Definition: multi_span.h:198
auto size() const noexcept -> index_type
Definition: multi_span.h:294
auto rend() const noexcept -> const_reverse_iterator
Definition: multi_span.h:282
multi_span() noexcept
Definition: multi_span.h:208
auto rbegin() const noexcept -> const_reverse_iterator
Definition: multi_span.h:272
auto empty() const noexcept -> bool
Definition: multi_span.h:297
std::ptrdiff_t index_type
Definition: multi_span.h:199
constexpr auto size(const C &c) -> decltype(c.size())
Definition: fakestd.h:373
std::pair< std::ptrdiff_t, span< T > > subspan_t
Definition: multi_span.h:68
typename std::enable_if< B, T >::type enable_if_t
Definition: fakestd.h:61
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:966
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