sparrow 2.3.1
C++20 idiomatic APIs for the Apache Arrow Columnar Format
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 <numeric>
19#include <ranges>
20#include <vector>
21
22#if defined(__cpp_lib_format)
23# include <format>
24
26#endif
27
30
31namespace sparrow
32{
33 template <std::ranges::input_range R>
34 requires(std::ranges::sized_range<R>)
35 [[nodiscard]] constexpr std::size_t range_size(R&& r)
36 {
37 return static_cast<std::size_t>(std::ranges::size(r));
38 }
39
40 template <std::ranges::input_range R>
41 requires(!std::ranges::sized_range<R>)
42 [[nodiscard]] constexpr std::size_t range_size(R&& r)
43 {
44 return static_cast<std::size_t>(std::ranges::distance(r));
45 }
46
47 template <std::ranges::range Range>
48 requires std::ranges::sized_range<std::ranges::range_value_t<Range>>
49 [[nodiscard]] constexpr bool all_same_size(const Range& range)
50 {
51 // Optimization for std::array and fixed-size sequence_view
52 if constexpr (
55 )
56 {
57 return true;
58 }
59 else
60 {
61 if (std::ranges::empty(range))
62 {
63 return true;
64 }
65
66 // GCC false-positive: dereferencing a transform_view iterator that yields a container
67 // value type (e.g. vector<byte>) is incorrectly flagged as a potential null dereference
68 // when the copy constructor is deeply inlined.
69#ifdef __GNUC__
70# pragma GCC diagnostic push
71# pragma GCC diagnostic ignored "-Wnull-dereference"
72#endif
73 const std::size_t first_size = range.front().size();
74 return std::ranges::all_of(
75 range,
76 [first_size](const auto& element)
77 {
78 return element.size() == first_size;
79 }
80 );
81#ifdef __GNUC__
82# pragma GCC diagnostic pop
83#endif
84 }
85 }
86
87 namespace ranges
88 {
89 template <typename InputRange, typename OutputIterator>
90 concept has_ranges_copy = requires(InputRange input, OutputIterator output) {
91 {
92 std::ranges::copy(input, output)
93 } -> std::same_as<std::ranges::copy_result<std::ranges::iterator_t<InputRange>, OutputIterator>>;
94 };
95
101 struct copy_fn
102 {
103 template <std::input_iterator I, std::sentinel_for<I> S, std::weakly_incrementable O>
104 requires std::indirectly_copyable<I, O>
105 constexpr std::ranges::copy_result<I, O> operator()(I first, S last, O result) const
106 {
107 for (; first != last; ++first, (void) ++result)
108 {
109#if defined(__GNUC__) && __GNUC__ < 12
110# pragma GCC diagnostic push
111# pragma GCC diagnostic ignored "-Wnull-dereference"
112#endif
113 *result = *first;
114#if defined(__GNUC__) && __GNUC__ < 12
115# pragma GCC diagnostic pop
116#endif
117 }
118 return {std::move(first), std::move(result)};
119 }
120
121 template <std::ranges::input_range R, std::weakly_incrementable O>
122 requires std::indirectly_copyable<std::ranges::iterator_t<R>, O>
123 constexpr std::ranges::copy_result<std::ranges::borrowed_iterator_t<R>, O>
124 operator()(R&& r, O result) const
125 {
126 return (*this)(std::ranges::begin(r), std::ranges::end(r), std::move(result));
127 }
128 };
129
130 template <std::ranges::input_range R, std::weakly_incrementable O>
131 requires std::indirectly_copyable<std::ranges::iterator_t<R>, O>
132 constexpr std::ranges::copy_result<std::ranges::borrowed_iterator_t<R>, O> copy(R&& r, O result)
133 {
134 if constexpr (has_ranges_copy<R, O>)
135 {
136 return std::ranges::copy(std::forward<R>(r), std::move(result));
137 }
138 else
139 {
140 return copy_fn{}(std::forward<R>(r), std::move(result));
141 }
142 }
143
144 template <std::ranges::input_range R, class T>
145 constexpr T accumulate(R&& r, T init)
146 {
147 return std::accumulate(r.begin(), r.end(), init);
148 }
149
150 template <std::ranges::input_range R, class T, std::copy_constructible Op>
151 constexpr T accumulate(R&& r, T init, Op op)
152 {
153 return std::accumulate(r.begin(), r.end(), init, op);
154 }
155 }
156};
157
158#if defined(__cpp_lib_format)
159
160template <typename T, std::size_t N>
161struct std::formatter<std::array<T, N>>
162{
163 constexpr auto parse(std::format_parse_context& ctx)
164 {
165 return m_spec.parse(ctx.begin(), ctx.end());
166 }
167
168 auto format(const std::array<T, N>& array, std::format_context& ctx) const
169 {
170 std::string core = m_spec.build_core(array);
171 std::string out_str = m_spec.apply_alignment(std::move(core));
172 return std::ranges::copy(out_str, ctx.out()).out;
173 }
174
175private:
176
177 sparrow::detail::sequence_format_spec m_spec;
178};
179
180template <typename T>
181struct std::formatter<std::vector<T>>
182{
183 constexpr auto parse(std::format_parse_context& ctx)
184 {
185 return m_spec.parse(ctx.begin(), ctx.end());
186 }
187
188 auto format(const std::vector<T>& vector, std::format_context& ctx) const
189 {
190 std::string core = m_spec.build_core(vector);
191 std::string out_str = m_spec.apply_alignment(std::move(core));
192 return std::ranges::copy(out_str, ctx.out()).out;
193 }
194
195private:
196
197 sparrow::detail::sequence_format_spec m_spec;
198};
199
200template <std::size_t T>
201struct std::formatter<std::bitset<T>>
202{
203 constexpr auto parse(std::format_parse_context& ctx)
204 {
205 return m_spec.parse(ctx.begin(), ctx.end());
206 }
207
208 auto format(const std::bitset<T>& vector, std::format_context& ctx) const
209 {
210 std::string core = m_spec.build_core(vector);
211 std::string out_str = m_spec.apply_alignment(std::move(core));
212 return std::ranges::copy(out_str, ctx.out()).out;
213 }
214
215private:
216
217 sparrow::detail::sequence_format_spec m_spec;
218};
219
220#endif
Concept for std::array types.
constexpr T accumulate(R &&r, T init)
Definition ranges.hpp:145
constexpr std::ranges::copy_result< std::ranges::borrowed_iterator_t< R >, O > copy(R &&r, O result)
Definition ranges.hpp:132
constexpr bool all_same_size(const Range &range)
Definition ranges.hpp:49
constexpr std::size_t range_size(R &&r)
Definition ranges.hpp:35
Extensions to the C++ standard library.
Copies the elements from the input range to the output iterator.
Definition ranges.hpp:102
constexpr std::ranges::copy_result< I, O > operator()(I first, S last, O result) const
Definition ranges.hpp:105
constexpr std::ranges::copy_result< std::ranges::borrowed_iterator_t< R >, O > operator()(R &&r, O result) const
Definition ranges.hpp:124