sparrow 0.6.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 <type_traits>
20#include <vector>
21
22#if defined(__cpp_lib_format)
23# include <format>
24# include <ostream>
25#endif
26
28
29namespace sparrow
30{
31 template <std::ranges::input_range R>
32 requires(std::ranges::sized_range<R>)
33 [[nodiscard]] std::size_t range_size(R&& r)
34 {
35 return static_cast<std::size_t>(std::ranges::size(r));
36 }
37
38 template <std::ranges::input_range R>
39 requires(!std::ranges::sized_range<R>)
40 [[nodiscard]] std::size_t range_size(R&& r)
41 {
42 return static_cast<std::size_t>(std::ranges::distance(r));
43 }
44
45 template <std::ranges::range Range>
46 requires std::ranges::sized_range<std::ranges::range_value_t<Range>>
47 [[nodiscard]] constexpr bool all_same_size(const Range& range)
48 {
49 // Optimization for std::array and fixed-size std::span
52 {
53 return true;
54 }
55 else
56 {
57 if (std::ranges::empty(range))
58 {
59 return true;
60 }
61
62 const std::size_t first_size = range.front().size();
63 return std::ranges::all_of(
64 range,
65 [first_size](const auto& element)
66 {
67 return element.size() == first_size;
68 }
69 );
70 }
71 }
72
73 namespace ranges
74 {
75 template <typename InputRange, typename OutputIterator>
76 concept has_ranges_copy = requires(InputRange input, OutputIterator output) {
77 {
78 std::ranges::copy(input, output)
79 } -> std::same_as<std::ranges::copy_result<std::ranges::iterator_t<InputRange>, OutputIterator>>;
80 };
81
87 struct copy_fn
88 {
89 template <std::input_iterator I, std::sentinel_for<I> S, std::weakly_incrementable O>
90 requires std::indirectly_copyable<I, O>
91 constexpr std::ranges::copy_result<I, O> operator()(I first, S last, O result) const
92 {
93 for (; first != last; ++first, (void) ++result)
94 {
95#if defined(__GNUC__) && __GNUC__ < 12
96# pragma GCC diagnostic push
97# pragma GCC diagnostic ignored "-Wnull-dereference"
98#endif
99 *result = *first;
100#if defined(__GNUC__) && __GNUC__ < 12
101# pragma GCC diagnostic pop
102#endif
103 }
104 return {std::move(first), std::move(result)};
105 }
106
107 template <std::ranges::input_range R, std::weakly_incrementable O>
108 requires std::indirectly_copyable<std::ranges::iterator_t<R>, O>
109 constexpr std::ranges::copy_result<std::ranges::borrowed_iterator_t<R>, O>
110 operator()(R&& r, O result) const
111 {
112 return (*this)(std::ranges::begin(r), std::ranges::end(r), std::move(result));
113 }
114 };
115
116 template <std::ranges::input_range R, std::weakly_incrementable O>
117 requires std::indirectly_copyable<std::ranges::iterator_t<R>, O>
118 constexpr std::ranges::copy_result<std::ranges::borrowed_iterator_t<R>, O> copy(R&& r, O result)
119 {
120 if constexpr (has_ranges_copy<R, O>)
121 {
122 return std::ranges::copy(std::forward<R>(r), std::move(result));
123 }
124 else
125 {
126 return copy_fn{}(std::forward<R>(r), std::move(result));
127 }
128 }
129 }
130};
131
132#if defined(__cpp_lib_format) && !defined(__cpp_lib_format_ranges)
133
134template <typename T, std::size_t N>
135struct std::formatter<std::array<T, N>>
136{
137 constexpr auto parse(std::format_parse_context& ctx)
138 {
139 return ctx.begin(); // Simple implementation
140 }
141
142 auto format(const std::array<T, N>& array, std::format_context& ctx) const
143 {
144 auto out = ctx.out();
145 *out++ = '<';
146
147 bool first = true;
148 for (const auto& elem : array)
149 {
150 if (!first)
151 {
152 *out++ = ',';
153 *out++ = ' ';
154 }
155 out = std::format_to(out, "{}", elem);
156 first = false;
157 }
158
159 *out++ = '>';
160 return out;
161 }
162};
163
164template <typename T>
165struct std::formatter<std::vector<T>>
166{
167 constexpr auto parse(std::format_parse_context& ctx)
168 {
169 return ctx.begin(); // Simple implementation
170 }
171
172 auto format(const std::vector<T>& vector, std::format_context& ctx) const
173 {
174 auto out = ctx.out();
175 *out++ = '<';
176
177 bool first = true;
178 for (const auto& elem : vector)
179 {
180 if (!first)
181 {
182 *out++ = ',';
183 *out++ = ' ';
184 }
185 out = std::format_to(out, "{}", elem);
186 first = false;
187 }
188
189 *out++ = '>';
190 return out;
191 }
192};
193
194template <std::size_t T>
195struct std::formatter<std::bitset<T>>
196{
197 constexpr auto parse(std::format_parse_context& ctx)
198 {
199 return ctx.begin(); // Simple implementation
200 }
201
202 auto format(const std::bitset<T>& vector, std::format_context& ctx) const
203 {
204 auto out = ctx.out();
205 *out++ = '<';
206
207 bool first = true;
208 for (const auto& elem : vector)
209 {
210 if (!first)
211 {
212 *out++ = ',';
213 *out++ = ' ';
214 }
215 out = std::format_to(out, "{}", elem);
216 first = false;
217 }
218
219 *out++ = '>';
220 return out;
221 }
222};
223#endif
constexpr std::ranges::copy_result< std::ranges::borrowed_iterator_t< R >, O > copy(R &&r, O result)
Definition ranges.hpp:118
constexpr bool all_same_size(const Range &range)
Definition ranges.hpp:47
std::size_t range_size(R &&r)
Definition ranges.hpp:33
Copies the elements from the input range to the output iterator.
Definition ranges.hpp:88
constexpr std::ranges::copy_result< I, O > operator()(I first, S last, O result) const
Definition ranges.hpp:91
constexpr std::ranges::copy_result< std::ranges::borrowed_iterator_t< R >, O > operator()(R &&r, O result) const
Definition ranges.hpp:110