sandbox
Loading...
Searching...
No Matches
iterator.hpp
1// SPDX-License-Identifier: MIT
2#ifndef LIBSBX_UTILITY_ITERATOR_HPP_
3#define LIBSBX_UTILITY_ITERATOR_HPP_
4
5#include <concepts>
6#include <cstddef>
7#include <iterator>
8#include <ranges>
9#include <type_traits>
10#include <algorithm>
11
12#include <range/v3/all.hpp>
13
14namespace sbx::utility {
15
16template<typename Category, typename Type, typename Distance = std::ptrdiff_t, typename Pointer = Type*, typename Reference = Type&>
17struct iterator {
18 using iterator_category = Category;
19 using value_type = Type;
20 using difference_type = Distance;
21 using pointer = Pointer;
22 using reference = Reference;
23}; // struct iterator
24
25template<typename Type>
26concept iterable = requires(Type t) {
27 { std::begin(t) } -> std::same_as<typename Type::iterator>;
28 { std::end(t) } -> std::same_as<typename Type::iterator>;
29} || requires(Type t) {
30 { std::begin(t) } -> std::same_as<typename Type::const_iterator>;
31 { std::end(t) } -> std::same_as<typename Type::const_iterator>;
32} || std::is_array_v<Type>;
33
34template<template<typename> typename To, ranges::input_range Range, std::invocable<const ranges::range_value_t<Range>&> Fn>
35requires (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>&>>)
36auto map_to(Range&& range, Fn&& fn) -> To<std::invoke_result_t<Fn, const ranges::range_value_t<Range>&>> {
37 return std::forward<Range>(range) | ranges::views::transform(std::forward<Fn>(fn)) | ranges::to<To>();
38}
39
40template<typename Range>
41concept move_appendable = std::movable<typename Range::value_type> && requires(Range& destination, Range& source, std::size_t n) {
42 source.size();
43 source.clear();
44 destination.size();
45 destination.reserve(n);
46 destination.insert(destination.end(), std::make_move_iterator(source.begin()), std::make_move_iterator(source.end()));
47}; // concept move_appendable
48
59template<move_appendable Range>
60auto append(Range& destination, Range&& source) -> void {
61 destination.reserve(destination.size() + source.size());
62 std::move(std::make_move_iterator(source.begin()), std::make_move_iterator(source.end()), std::back_inserter(destination));
63 source.clear();
64}
65
66template<typename Range>
67concept copy_appendable = std::copyable<typename Range::value_type> && requires(Range& destination, const Range& source, std::size_t n) {
68 source.size();
69 destination.size();
70 destination.reserve(n);
71 destination.insert(destination.end(), source.begin(), source.end());
72}; // concept copy_appendable
73
82template<copy_appendable Range>
83auto append(Range& destination, const Range& source) -> void {
84 destination.reserve(destination.size() + source.size());
85 std::copy(source.begin(), source.end(), std::back_inserter(destination));
86}
87
91template<typename Type>
92concept range_descriptor = requires(const Type& descriptor, const std::size_t size) {
93 { descriptor.is_valid(size) } -> std::same_as<bool>;
94 { descriptor.start(size) } -> std::same_as<std::size_t>;
95 { descriptor.end(size) } -> std::same_as<std::size_t>;
96}; // concept range_descriptor
97
102
103 std::size_t offset;
104 std::size_t count;
105
106 constexpr auto is_valid(const std::size_t size) const -> bool {
107 return offset <= size;
108 }
109
110 constexpr auto start([[maybe_unused]] const std::size_t size) const -> std::size_t {
111 return offset;
112 }
113
114 constexpr auto end(const std::size_t size) const -> std::size_t {
115 return std::min(offset + count, size);
116 }
117
118}; // struct offset_count
119
123struct start_end {
124
125 std::size_t begin_index;
126 std::size_t end_index;
127
128 constexpr auto is_valid(const std::size_t size) const -> bool {
129 return begin_index <= end_index && end_index <= size;
130 }
131
132 constexpr auto start([[maybe_unused]] const std::size_t size) const -> std::size_t {
133 return begin_index;
134 }
135
136 constexpr auto end([[maybe_unused]] const std::size_t size) const -> std::size_t {
137 return end_index;
138 }
139
140}; // struct start_end
141
155template<std::movable Type, range_descriptor Range>
156auto subrange(std::vector<Type>&& vector, const Range& range) -> std::vector<Type> {
157 const auto size = vector.size();
158
159 if (!range.is_valid(size)) {
160 return {};
161 }
162
163 const auto start = range.start(size);
164 const auto end = range.end(size);
165
166 auto result = std::vector<Type>{};
167 result.reserve(end - start);
168
169 std::move(std::make_move_iterator(vector.begin() + start), std::make_move_iterator(vector.begin() + end), std::back_inserter(result));
170
171 vector.clear();
172
173 return result;
174}
175
187template<std::copyable Type, range_descriptor Range>
188auto subrange(const std::vector<Type>& vector, const Range& range) -> std::vector<Type> {
189 const auto size = vector.size();
190
191 if (!range.is_valid(size)) {
192 return {};
193 }
194
195 const auto start = range.start(size);
196 const auto end = range.end(size);
197
198 auto result = std::vector<Type>{};
199 result.reserve(end - start);
200
201 std::copy(vector.begin() + start, vector.begin() + end, std::back_inserter(result));
202
203 return result;
204}
205
206template<std::copyable Type>
207auto make_vector(const std::size_t size, const Type& value = Type{}) -> std::vector<Type> {
208 auto result = std::vector<Type>{};
209
210 result.resize(size, value);
211
212 return result;
213}
214
215template<typename Type>
216auto make_reserved_vector(const std::size_t size) -> std::vector<Type> {
217 auto result = std::vector<Type>{};
218
219 result.reserve(size);
220
221 return result;
222}
223
224} // namespace sbx::utility
225
226#endif // LIBSBX_UTILITY_ITERATOR_HPP_
Concept for a range descriptor that calculates a start/end subrange from a given size.
Definition: iterator.hpp:92
Definition: iterator.hpp:17
Range specified by an offset and a count.
Definition: iterator.hpp:101
Range specified by an explicit start and end index.
Definition: iterator.hpp:123