Simple-Utility v2.3.1
Loading...
Searching...
No Matches
Algorithm.hpp
Go to the documentation of this file.
1// Copyright Dominic Koepke 2019 - 2023.
2// Distributed under the Boost Software License, Version 1.0.
3// (See accompanying file LICENSE_1_0.txt or copy at
4// https://www.boost.org/LICENSE_1_0.txt)
5
6#ifndef SL_UTILITY_TUPLE_ALGORITHM_HPP
7#define SL_UTILITY_TUPLE_ALGORITHM_HPP
8
9#pragma once
10
11#include <algorithm>
12#include <functional>
13#include <type_traits>
14
16
17namespace sl::tuple
18{
41 template <class Tuple, class Transform>
43 [[nodiscard]]
44 constexpr auto transform_elements(Tuple&& tuple, Transform transform)
45 {
46 return std::apply(
47 [&]<class... Elements>(Elements&&... elements) -> std::tuple<std::invoke_result_t<Transform, Elements>...>
48 {
49 return {std::invoke(transform, std::forward<Elements>(elements))...};
50 },
51 std::forward<Tuple>(tuple));
52 }
53
57}
58
59namespace sl::tuple::detail
60{
61 template <class Tuple>
62 requires concepts::tuple<std::remove_cvref_t<Tuple>>
63 [[nodiscard]]
64 constexpr auto envelop_elements(Tuple&& tuple)
65 {
66 return transform_elements(
67 std::forward<Tuple>(tuple),
68 []<class Element>(Element&& el) { return std::make_tuple(std::forward<Element>(el)); });
69 }
70}
71
72namespace sl::tuple
73{
83 template <class Tuple>
84 requires concepts::tuple<std::remove_cvref_t<Tuple>>
86 {
87 using type = decltype(detail::envelop_elements(std::declval<Tuple>()));
88 };
89
93 template <class Tuple>
96
108 template <class Tuple>
110 [[nodiscard]]
112 Tuple&& tuple
113 ) noexcept(std::is_nothrow_constructible_v<std::remove_cvref_t<Tuple>, Tuple>)
114 {
115 return detail::envelop_elements(std::forward<Tuple>(tuple));
116 }
117
119}
120
121namespace sl::tuple::detail
122{
123 template <class... Tuples>
124 [[nodiscard]]
125 constexpr auto zip(Tuples&&... tuples)
126 {
127 return [&]<std::size_t... indices>([[maybe_unused]] std::index_sequence<indices...>)
128 {
129 return std::make_tuple(
130 [&]<std::size_t index>()
131 {
132 return std::make_tuple(std::get<index>(std::forward<Tuples>(tuples))...);
133 }.template operator()<indices>()...
134 );
135 }(std::make_index_sequence<std::min({std::tuple_size_v<Tuples>...})>{});
136 }
137}
138
139namespace sl::tuple
140{
150 template <class... Tuples>
151 requires (2 <= sizeof...(Tuples))
152 && (concepts::tuple<std::remove_cvref_t<Tuples>> && ...)
154 {
155 using type = decltype(detail::zip(std::declval<Tuples>()...));
156 };
157
161 template <class... Tuples>
162 requires (2 <= sizeof...(Tuples))
164 using zip_result_t = typename zip_result<Tuples...>::type;
165
191 template <class First, class Second, class... Others>
195 [[nodiscard]]
196 constexpr zip_result_t<First, Second, Others...> zip(First&& first, Second&& second, Others&&... others)
197 {
198 return detail::zip(
199 std::forward<First>(first),
200 std::forward<Second>(second),
201 std::forward<Others>(others)...);
202 }
203
205}
206
207namespace sl::tuple::detail
208{
209 // idea taken from: https://stackoverflow.com/questions/70404549/cartesian-product-of-stdtuple/70405807#70405807
210 [[nodiscard]]
211 constexpr auto cartesian_product(const concepts::tuple auto& first)
212 {
213 return envelop_elements(first);
214 }
215
216 [[nodiscard]]
217 constexpr auto cartesian_product(const concepts::tuple auto& first, const concepts::tuple auto&... others)
218 {
219 auto trailers = cartesian_product(others...);
220 return std::apply(
221 [&](auto&... firstElements)
222 {
223 return std::tuple_cat(
224 [&](auto& currentFirst)
225 {
226 return std::apply(
227 [&](auto&... trailerElements)
228 {
229 return std::make_tuple(std::tuple_cat(std::make_tuple(currentFirst), trailerElements)...);
230 },
231 trailers
232 );
233 }(firstElements)...
234 );
235 },
236 first
237 );
238 }
239}
240
241namespace sl::tuple
242{
252 template <class... Tuples>
253 requires (2 <= sizeof...(Tuples))
254 && (concepts::tuple<std::remove_cvref_t<Tuples>> && ...)
256 {
257 using type = decltype(detail::cartesian_product(std::declval<Tuples>()...));
258 };
259
263 template <class... Tuples>
264 requires (2 <= sizeof...(Tuples))
266 using cartesian_product_result_t = typename cartesian_product_result<Tuples...>::type;
267
288 template <concepts::tuple First, concepts::tuple Second, concepts::tuple... Others>
289 [[nodiscard]]
290 constexpr cartesian_product_result_t<First, Second, Others...> cartesian_product(
291 const First& first,
292 const Second& second,
293 const Others&... others
294 ) noexcept(std::is_nothrow_copy_constructible_v<First>
295 && std::is_nothrow_copy_constructible_v<Second>
296 && (std::is_nothrow_copy_constructible_v<Others> && ...))
297 {
298 return detail::cartesian_product(first, second, others...);
299 }
300
302}
303
304#endif
Determines whether a type can be used as a tuple-like.
Definition: General.hpp:105
constexpr cartesian_product_result_t< First, Second, Others... > cartesian_product(const First &first, const Second &second, const Others &... others) noexcept(std::is_nothrow_copy_constructible_v< First > &&std::is_nothrow_copy_constructible_v< Second > &&(std::is_nothrow_copy_constructible_v< Others > &&...))
Creates the cartesian product of the given tuples.
Definition: Algorithm.hpp:290
typename cartesian_product_result< Tuples... >::type cartesian_product_result_t
Alias type determining the result of a cartesian_product call.
Definition: Algorithm.hpp:266
constexpr envelop_elements_result_t< Tuple > envelop_elements(Tuple &&tuple) noexcept(std::is_nothrow_constructible_v< std::remove_cvref_t< Tuple >, Tuple >)
Envelops all elements of the given tuple into their own std::tuple and creates a tuple of tuples.
Definition: Algorithm.hpp:111
typename envelop_elements_result< Tuple >::type envelop_elements_result_t
Alias type determining the result of a tuple_envelop_elements call.
Definition: Algorithm.hpp:95
constexpr auto transform_elements(Tuple &&tuple, Transform transform)
Applies the transform on each element of the given source tuple and returns the results as a new tupl...
Definition: Algorithm.hpp:44
typename zip_result< Tuples... >::type zip_result_t
Alias type determining the result of a zip call.
Definition: Algorithm.hpp:164
constexpr zip_result_t< First, Second, Others... > zip(First &&first, Second &&second, Others &&... others)
Zips elements of all provided source tuples and creates a tuple of tuples.
Definition: Algorithm.hpp:196
cartesian_product_as< common_container< Lists... >::template type, Lists... > cartesian_product
Alternative algorithm yielding the result as the type member alias and determining the result contain...
Definition: TypeList.hpp:1475
Definition: Algorithm.hpp:18
Trait type determining the result of a cartesian_product call.
Definition: Algorithm.hpp:256
decltype(detail::cartesian_product(std::declval< Tuples >()...)) type
Definition: Algorithm.hpp:257
Trait type determining the result of a tuple_envelop_elements call.
Definition: Algorithm.hpp:86
decltype(detail::envelop_elements(std::declval< Tuple >())) type
Definition: Algorithm.hpp:87
Trait type determining the result of a zip call.
Definition: Algorithm.hpp:154
decltype(detail::zip(std::declval< Tuples >()...)) type
Definition: Algorithm.hpp:155