sparrow 0.9.0
Loading...
Searching...
No Matches
ranges.hpp
Go to the documentation of this file.
1// Copyright 2024 Man Group Operations Limited
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14#pragma once
15
16#include <algorithm>
17#include <bitset>
18#include <ranges>
19#include <vector>
20
21#if defined(__cpp_lib_format)
22# include <format>
23#endif
24
27
28namespace sparrow
29{
30 template <std::ranges::input_range R>
31 requires(std::ranges::sized_range<R>)
32 [[nodiscard]] constexpr std::size_t range_size(R&& r)
33 {
34 return static_cast<std::size_t>(std::ranges::size(r));
35 }
36
37 template <std::ranges::input_range R>
38 requires(!std::ranges::sized_range<R>)
39 [[nodiscard]] constexpr std::size_t range_size(R&& r)
40 {
41 return static_cast<std::size_t>(std::ranges::distance(r));
42 }
43
44 template <std::ranges::range Range>
45 requires std::ranges::sized_range<std::ranges::range_value_t<Range>>
46 [[nodiscard]] constexpr bool all_same_size(const Range& range)
47 {
48 // Optimization for std::array and fixed-size sequence_view
51 {
52 return true;
53 }
54 else
55 {
56 if (std::ranges::empty(range))
57 {
58 return true;
59 }
60
61 const std::size_t first_size = range.front().size();
62 return std::ranges::all_of(
63 range,
64 [first_size](const auto& element)
65 {
66 return element.size() == first_size;
67 }
68 );
69 }
70 }
71
72 namespace ranges
73 {
74 template <typename InputRange, typename OutputIterator>
75 concept has_ranges_copy = requires(InputRange input, OutputIterator output) {
76 {
77 std::ranges::copy(input, output)
78 } -> std::same_as<std::ranges::copy_result<std::ranges::iterator_t<InputRange>, OutputIterator>>;
79 };
80
86 struct copy_fn
87 {
88 template <std::input_iterator I, std::sentinel_for<I> S, std::weakly_incrementable O>
89 requires std::indirectly_copyable<I, O>
90 constexpr std::ranges::copy_result<I, O> operator()(I first, S last, O result) const
91 {
92 for (; first != last; ++first, (void) ++result)
93 {
94#if defined(__GNUC__) && __GNUC__ < 12
95# pragma GCC diagnostic push
96# pragma GCC diagnostic ignored "-Wnull-dereference"
97#endif
98 *result = *first;
99#if defined(__GNUC__) && __GNUC__ < 12
100# pragma GCC diagnostic pop
101#endif
102 }
103 return {std::move(first), std::move(result)};
104 }
105
106 template <std::ranges::input_range R, std::weakly_incrementable O>
107 requires std::indirectly_copyable<std::ranges::iterator_t<R>, O>
108 constexpr std::ranges::copy_result<std::ranges::borrowed_iterator_t<R>, O>
109 operator()(R&& r, O result) const
110 {
111 return (*this)(std::ranges::begin(r), std::ranges::end(r), std::move(result));
112 }
113 };
114
115 template <std::ranges::input_range R, std::weakly_incrementable O>
116 requires std::indirectly_copyable<std::ranges::iterator_t<R>, O>
117 constexpr std::ranges::copy_result<std::ranges::borrowed_iterator_t<R>, O> copy(R&& r, O result)
118 {
119 if constexpr (has_ranges_copy<R, O>)
120 {
121 return std::ranges::copy(std::forward<R>(r), std::move(result));
122 }
123 else
124 {
125 return copy_fn{}(std::forward<R>(r), std::move(result));
126 }
127 }
128 }
129};
130
131#if defined(__cpp_lib_format)
132
133template <typename T, std::size_t N>
134struct std::formatter<std::array<T, N>>
135{
136 constexpr auto parse(std::format_parse_context& ctx)
137 {
138 return ctx.begin(); // Simple implementation
139 }
140
141 auto format(const std::array<T, N>& array, std::format_context& ctx) const
142 {
143 auto out = ctx.out();
144 *out++ = '<';
145
146 bool first = true;
147 for (const auto& elem : array)
148 {
149 if (!first)
150 {
151 *out++ = ',';
152 *out++ = ' ';
153 }
154 out = std::format_to(out, "{}", elem);
155 first = false;
156 }
157
158 *out++ = '>';
159 return out;
160 }
161};
162
163template <typename T>
164struct std::formatter<std::vector<T>>
165{
166 constexpr auto parse(std::format_parse_context& ctx)
167 {
168 return ctx.begin(); // Simple implementation
169 }
170
171 auto format(const std::vector<T>& vector, std::format_context& ctx) const
172 {
173 auto out = ctx.out();
174 *out++ = '<';
175
176 bool first = true;
177 for (const auto& elem : vector)
178 {
179 if (!first)
180 {
181 *out++ = ',';
182 *out++ = ' ';
183 }
184 out = std::format_to(out, "{}", elem);
185 first = false;
186 }
187
188 *out++ = '>';
189 return out;
190 }
191};
192
193template <std::size_t T>
194struct std::formatter<std::bitset<T>>
195{
196 constexpr auto parse(std::format_parse_context& ctx)
197 {
198 return ctx.begin(); // Simple implementation
199 }
200
201 auto format(const std::bitset<T>& vector, std::format_context& ctx) const
202 {
203 auto out = ctx.out();
204 *out++ = '<';
205
206 bool first = true;
207 for (const auto& elem : vector)
208 {
209 if (!first)
210 {
211 *out++ = ',';
212 *out++ = ' ';
213 }
214 out = std::format_to(out, "{}", elem);
215 first = false;
216 }
217
218 *out++ = '>';
219 return out;
220 }
221};
222
223#endif
Concept for std::array types.
constexpr std::ranges::copy_result< std::ranges::borrowed_iterator_t< R >, O > copy(R &&r, O result)
Definition ranges.hpp:117
constexpr bool all_same_size(const Range &range)
Definition ranges.hpp:46
constexpr std::size_t range_size(R &&r)
Definition ranges.hpp:32
Copies the elements from the input range to the output iterator.
Definition ranges.hpp:87
constexpr std::ranges::copy_result< I, O > operator()(I first, S last, O result) const
Definition ranges.hpp:90
constexpr std::ranges::copy_result< std::ranges::borrowed_iterator_t< R >, O > operator()(R &&r, O result) const
Definition ranges.hpp:109