sparrow 1.0.0
Loading...
Searching...
No Matches
builder_utils.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 mplied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15
16#pragma once
17
18#include <array>
19#include <ranges>
20#include <string>
21#include <tuple>
22#include <type_traits>
23#include <utility>
24#include <vector>
25
26#include <sparrow/array.hpp>
28
29namespace sparrow
30{
31
32 namespace detail
33 {
34 template <class T>
36 {
37 public:
38
40 using value_type = T;
41
42 // default constructor
43 constexpr express_layout_desire() = default;
44
45 // variadic perfect forwarding constructor
46 template <class... Args>
47 express_layout_desire(Args&&... args)
48 : m_value(std::forward<Args>(args)...)
49 {
50 }
51
52 [[nodiscard]] constexpr const T& get() const noexcept
53 {
54 return m_value;
55 }
56
57 [[nodiscard]] constexpr T& get() noexcept
58 {
59 return m_value;
60 }
61
62 private:
63
64 T m_value = T{};
65 };
66 }
67
68 // express the desire to use a dictionary encoding layout for
69 // whatever is inside. Note that what is inside **is not yet**
70 // encoded. This is done once the complete data which is to be
71 // dict encoded is known
72 template <class T, class KEY_TYPE = std::uint64_t>
74 {
75 using base_type = detail::express_layout_desire<T>;
76
77 public:
78
79 using base_type::base_type;
80 using key_type = KEY_TYPE;
81 };
82
83 // express the desire to use a run-length encoding layout for
84 // whatever is inside. Note that what is inside **is not yet**
85 // encoded. This is done once the complete data which is to be
86 // dict encoded is known
87 template <class T, class LENGTH_TYPE = std::uint64_t>
89 {
90 using base_type = detail::express_layout_desire<T>;
91
92 public:
93
94 using base_type::base_type;
95 using length_type = LENGTH_TYPE;
96 };
97
98 namespace detail
99 {
100 // might be changed later to also allowm for std::optional
101 template <class T>
103
105 {
106 };
107
109 {
110 };
111
115
116 template <class T>
118
119 template <class T>
121
122 template <class T>
124
125 template <class T>
127
128 template <class T>
129 using decayed_range_value_t = std::decay_t<std::ranges::range_value_t<T>>;
130
131 template <class F, std::size_t... Is>
132 void for_each_index_impl(F&& f, std::index_sequence<Is...>)
133 {
134 // Apply f to each index individually
135 (f(std::integral_constant<std::size_t, Is>{}), ...);
136 }
137
138 template <std::size_t SIZE, class F>
139 void for_each_index(F&& f)
140 {
141 for_each_index_impl(std::forward<F>(f), std::make_index_sequence<SIZE>());
142 }
143
144 template <class F, std::size_t... Is>
145 bool exitable_for_each_index_impl(F&& f, std::index_sequence<Is...>)
146 {
147 return (f(std::integral_constant<std::size_t, Is>{}) && ...);
148 }
149
150 template <std::size_t SIZE, class F>
152 {
153 return exitable_for_each_index_impl(std::forward<F>(f), std::make_index_sequence<SIZE>());
154 }
155
156 template <class T, std::size_t N>
157 concept has_tuple_element = requires(T t) {
158 typename std::tuple_element_t<N, std::remove_const_t<T>>;
159 { get<N>(t) } -> std::convertible_to<const std::tuple_element_t<N, T>&>;
160 };
161
162 template <typename T, std::size_t... N>
163 constexpr bool check_tuple_elements(std::index_sequence<N...>)
164 {
165 return (has_tuple_element<T, N> && ...);
166 }
167
168 template <typename T>
169 constexpr bool is_tuple_like()
170 {
171 return check_tuple_elements<T>(std::make_index_sequence<std::tuple_size_v<T>>());
172 }
173
174 template <typename T>
175 concept variant_like =
176 // Must not be a reference
177 !std::is_reference_v<T> &&
178
179 // Must have an index() member function returning a size_t
180 requires(const T& v) {
181 { v.index() } -> std::convertible_to<std::size_t>;
182 } &&
183
184 // Must work with std::visit
185 requires(T v) {
186 std::visit([](auto&&) {}, v); // Use a generic lambda to test visitation
187 } &&
188
189 // Must allow std::get with an index
190 requires(T v) {
191 { std::get<0>(v) }; // Access by index
192 } &&
193
194 // Must allow std::get with a type
195 requires(T v) {
196 { std::get<typename std::variant_alternative<0, T>::type>(v) }; // Access by type
197 };
198
199 template <typename T>
200 concept tuple_like = !std::is_reference_v<T> && requires(T t) {
201 typename std::tuple_size<T>::type;
202 requires std::derived_from<std::tuple_size<T>, std::integral_constant<std::size_t, std::tuple_size_v<T>>>;
203 } && is_tuple_like<T>();
204
205 template <typename Tuple, size_t... Is>
206 [[nodiscard]] constexpr bool all_elements_same_impl(std::index_sequence<Is...>)
207 {
208 return sizeof...(Is) == 0
209 || ((std::is_same_v<std::tuple_element_t<0, Tuple>, std::tuple_element_t<Is, Tuple>>) && ...);
210 }
211
212 template <typename T>
215 std::make_index_sequence<std::tuple_size_v<T>>{}
216 );
217
218 template <class T>
220 {
221 using type = T;
222 };
223
224 template <is_nullable_like T>
226 {
227 using type = typename T::value_type;
228 };
229
230 // shorthand for maybe_nullable_value_type<T>::type
231 template <class T>
233
234 template <class T>
236 {
237 using type = T;
238 };
239
240 template <is_express_layout_desire T>
242 {
243 using type = typename T::value_type;
244 };
245 // shorthand for maybe_express_layout_desire_value_type<T>::type
246 template <class T>
248
249
250 template <class T>
251 using layout_flag_t = std::conditional_t<
254 std::conditional_t<is_run_end_encode<mnv_t<T>>, enforce_run_end_encoded_layout, dont_enforce_layout>>;
255
256 template <class T>
258
259 // shorhand for look_trough_t<std::ranges::range_value_t<T>>
260 template <class T>
262
263 // helper to get inner value type of smth like a vector of vector of T
264 // we also translate any nullable to the inner type
265 template <class T>
267
268 // a save way to return .size from
269 // a possibly nullable object or "express layout desire object"
270 template <class T>
271 [[nodiscard]] constexpr std::size_t get_size_save(T&& t)
272 {
273 using decayed = std::decay_t<T>;
274 if constexpr (is_nullable_like<decayed>)
275 {
276 if (t.has_value())
277 {
278 return get_size_save(t.get());
279 }
280 else
281 {
282 return 0;
283 }
284 }
285 else if constexpr (is_express_layout_desire<decayed>)
286 {
287 return get_size_save(t.get());
288 }
289 else
290 {
291 return static_cast<std::size_t>(t.size());
292 }
293 }
294
295 template <class T>
296 [[nodiscard]] constexpr decltype(auto) ensure_value(T&& t)
297 {
298 using decayed = std::decay_t<T>;
300 {
301 return ensure_value(std::forward<T>(t).get());
302 }
303 else
304 {
305 return std::forward<T>(t);
306 }
307 }
308
309 template <std::ranges::range T>
310 requires(is_nullable_like<std::ranges::range_value_t<T>>)
311 [[nodiscard]] constexpr std::vector<std::size_t> where_null(T&& t)
312 {
313 std::vector<std::size_t> result;
314 for (std::size_t i = 0; i < t.size(); ++i)
315 {
316 if (!t[i].has_value())
317 {
318 result.push_back(i);
319 }
320 }
321 return result;
322 }
323
324 template <class T>
325 requires(
326 is_express_layout_desire<std::ranges::range_value_t<T>>
327 && is_nullable_like<typename std::ranges::range_value_t<T>::value_type>
328 )
329 [[nodiscard]] constexpr std::vector<std::size_t> where_null(T&& t)
330 {
331 std::vector<std::size_t> result;
332 for (std::size_t i = 0; i < t.size(); ++i)
333 {
334 if (!(t[i].get().has_value()))
335 {
336 result.push_back(i);
337 }
338 }
339 return result;
340 }
341
342 template <class T>
343 [[nodiscard]] constexpr std::array<std::size_t, 0> where_null(T&&) noexcept
344 {
345 return {};
346 }
347
348 template <class T>
349 requires(is_plain_value_type<std::ranges::range_value_t<T>>)
350 [[nodiscard]] constexpr decltype(auto) ensure_value_range(T&& t) noexcept
351 {
352 return std::forward<T>(t);
353 }
354
355 template <class T>
356 requires(!is_plain_value_type<std::ranges::range_value_t<T>>)
357 [[nodiscard]] constexpr decltype(auto) ensure_value_range(T&& t)
358 {
359 return t
360 | std::views::transform(
361 [](auto&& v)
362 {
363 return ensure_value(std::forward<decltype(v)>(v));
364 }
365 );
366 }
367 } // namespace detail
368} // namespace sparrow
constexpr const T & get() const noexcept
constexpr express_layout_desire()=default
express_layout_desire< T > self_type
bool exitable_for_each_index_impl(F &&f, std::index_sequence< Is... >)
std::conditional_t< is_dict_encode< mnv_t< T > >, enforce_dict_encoded_layout, std::conditional_t< is_run_end_encode< mnv_t< T > >, enforce_run_end_encoded_layout, dont_enforce_layout > > layout_flag_t
typename maybe_nullable_value_type< T >::type mnv_t
constexpr decltype(auto) ensure_value_range(T &&t) noexcept
look_trough_t< std::ranges::range_value_t< T > > ensured_range_value_t
meldv_t< mnv_t< meldv_t< T > > > look_trough_t
ensured_range_value_t< ensured_range_value_t< T > > nested_ensured_range_inner_value_t
constexpr bool check_tuple_elements(std::index_sequence< N... >)
constexpr std::size_t get_size_save(T &&t)
constexpr bool is_tuple_like()
std::decay_t< std::ranges::range_value_t< T > > decayed_range_value_t
constexpr bool all_elements_same_impl(std::index_sequence< Is... >)
constexpr std::vector< std::size_t > where_null(T &&t)
constexpr decltype(auto) ensure_value(T &&t)
typename maybe_express_layout_desire_value_type< T >::type meldv_t
bool exitable_for_each_index(F &&f)
void for_each_index(F &&f)
void for_each_index_impl(F &&f, std::index_sequence< Is... >)
constexpr bool is_type_instance_of_v
Variable template for convenient access to is_type_instance_of.
Definition mp_utils.hpp:102
constexpr bool is_nullable_v
Definition nullable.hpp:62