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