sandbox
Loading...
Searching...
No Matches
iterator.hpp
1#ifndef LIBSBX_UTILITY_ITERATOR_HPP_
2#define LIBSBX_UTILITY_ITERATOR_HPP_
3
4#include <concepts>
5#include <cstddef>
6#include <iterator>
7#include <ranges>
8#include <type_traits>
9#include <algorithm>
10
11#include <range/v3/all.hpp>
12
13namespace sbx::utility {
14
15template<typename Category, typename Type, typename Distance = std::ptrdiff_t, typename Pointer = Type*, typename Reference = Type&>
16struct iterator {
17 using iterator_category = Category;
18 using value_type = Type;
19 using difference_type = Distance;
20 using pointer = Pointer;
21 using reference = Reference;
22}; // struct iterator
23
24template<typename Type>
25concept iterable = requires(Type t) {
26 { std::begin(t) } -> std::same_as<typename Type::iterator>;
27 { std::end(t) } -> std::same_as<typename Type::iterator>;
28} || requires(Type t) {
29 { std::begin(t) } -> std::same_as<typename Type::const_iterator>;
30 { std::end(t) } -> std::same_as<typename Type::const_iterator>;
31} || std::is_array_v<Type>;
32
33template<template<typename> typename To, ranges::input_range Range, std::invocable<const ranges::range_value_t<Range>&> Fn>
34requires (ranges::output_range<To<std::invoke_result_t<Fn, const ranges::range_value_t<Range>&>>, std::invoke_result_t<Fn, const ranges::range_value_t<Range>&>>)
35auto map_to(Range&& range, Fn&& fn) -> To<std::invoke_result_t<Fn, const ranges::range_value_t<Range>&>> {
36 return std::forward<Range>(range) | ranges::views::transform(std::forward<Fn>(fn)) | ranges::to<To>();
37}
38
49template<std::movable Type>
50auto append(std::vector<Type>& destination, std::vector<Type>&& source) -> void {
51 destination.reserve(destination.size() + source.size());
52 std::move(std::make_move_iterator(source.begin()), std::make_move_iterator(source.end()), std::back_inserter(destination));
53 source.clear();
54}
55
64template<std::copyable Type>
65auto append(std::vector<Type>& destination, const std::vector<Type>& source) -> void {
66 destination.reserve(destination.size() + source.size());
67 std::copy(source.begin(), source.end(), std::back_inserter(destination));
68}
69
73template<typename Type>
74concept range_descriptor = requires(const Type& descriptor, const std::size_t size) {
75 { descriptor.is_valid(size) } -> std::same_as<bool>;
76 { descriptor.start(size) } -> std::same_as<std::size_t>;
77 { descriptor.end(size) } -> std::same_as<std::size_t>;
78}; // concept range_descriptor
79
84
85 std::size_t offset;
86 std::size_t count;
87
88 constexpr auto is_valid(const std::size_t size) const -> bool {
89 return offset <= size;
90 }
91
92 constexpr auto start([[maybe_unused]] const std::size_t size) const -> std::size_t {
93 return offset;
94 }
95
96 constexpr auto end(const std::size_t size) const -> std::size_t {
97 return std::min(offset + count, size);
98 }
99
100}; // struct offset_count
101
105struct start_end {
106
107 std::size_t begin_index;
108 std::size_t end_index;
109
110 constexpr auto is_valid(const std::size_t size) const -> bool {
111 return begin_index <= end_index && end_index <= size;
112 }
113
114 constexpr auto start([[maybe_unused]] const std::size_t size) const -> std::size_t {
115 return begin_index;
116 }
117
118 constexpr auto end(const std::size_t size) const -> std::size_t {
119 return end_index;
120 }
121
122}; // struct start_end
123
137template<std::movable Type, range_descriptor Range>
138auto subrange(std::vector<Type>&& vector, const Range& range) -> std::vector<Type> {
139 const auto size = vector.size();
140
141 if (!range.is_valid(size)) {
142 return {};
143 }
144
145 const auto start = range.start(size);
146 const auto end = range.end(size);
147
148 auto result = std::vector<Type>{};
149 result.reserve(end - start);
150
151 std::move(std::make_move_iterator(vector.begin() + start), std::make_move_iterator(vector.begin() + end), std::back_inserter(result));
152
153 vector.clear();
154
155 return result;
156}
157
169template<std::copyable Type, range_descriptor Range>
170auto subrange(const std::vector<Type>& vector, const Range& range) -> std::vector<Type> {
171 const auto size = vector.size();
172
173 if (!range.is_valid(size)) {
174 return {};
175 }
176
177 const auto start = range.start(size);
178 const auto end = range.end(size);
179
180 auto result = std::vector<Type>{};
181 result.reserve(end - start);
182
183 std::copy(vector.begin() + start, vector.begin() + end, std::back_inserter(result));
184
185 return result;
186}
187
188
189} // namespace sbx::utility
190
191#endif // LIBSBX_UTILITY_ITERATOR_HPP_
Concept for a range descriptor that calculates a start/end subrange from a given size.
Definition: iterator.hpp:74
Definition: iterator.hpp:16
Range specified by an offset and a count.
Definition: iterator.hpp:83
Range specified by an explicit start and end index.
Definition: iterator.hpp:105