• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

DNKpp / Simple-Utility / 6834940031

11 Nov 2023 02:59PM UTC coverage: 86.806% (-12.9%) from 99.712%
6834940031

Pull #71

github

web-flow
Merge e4ab927d5 into e4166ac5d
Pull Request #71: graph namespace

284 of 285 new or added lines in 17 files covered. (99.65%)

83 existing lines in 10 files now uncovered.

625 of 720 relevant lines covered (86.81%)

153.03 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

88.57
/include/Simple-Utility/tuple/Algorithm.hpp
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

15
#include "Simple-Utility/tuple/General.hpp"
16

17
namespace sl::tuple
18
{
19
        /**
20
         * \defgroup GROUP_TUPLE_ALGORITHM algorithm
21
         * \ingroup GROUP_TUPLE
22
         */
23

24
        /**
25
         * \defgroup GROUP_TUPLE_ALGORITHM_TRANSFORM_ELEMENTS transform_elements
26
         * \ingroup GROUP_TUPLE_ALGORITHM
27
         * @{
28
         */
29

30
        /**
31
         * \brief Applies the transform on each element of the given source tuple and returns the results as a new tuple.
32
         * \tparam Tuple The tuple type.
33
         * \tparam Transform The transform type.
34
         * \param tuple The source tuple.
35
         * \param transform The transformation to be applied on each element.
36
         * \return A newly created tuple with the transformed elements of the source tuple.
37
         *
38
         * \details The elements will be stored as they are retrieved from the transformation, thus no automatically
39
         * conversion will be applied.
40
         */
41
        template <class Tuple, class Transform>
42
                requires concepts::tuple<std::remove_cvref_t<Tuple>>
43
        [[nodiscard]]
44
        constexpr auto transform_elements(Tuple&& tuple, Transform transform)
95✔
45
        {
46
                return std::apply(
2✔
47
                        [&]<class... Elements>(Elements&&... elements) -> std::tuple<std::invoke_result_t<Transform, Elements>...>
385✔
48
                        {
49
                                return {std::invoke(transform, std::forward<Elements>(elements))...};
88✔
50
                        },
51
                        std::forward<Tuple>(tuple));
190✔
52
        }
53

54
        /**
55
         * \}
56
         */
57
}
58

59
namespace 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)
8✔
65
        {
UNCOV
66
                return transform_elements(
×
67
                        std::forward<Tuple>(tuple),
68
                        []<class Element>(Element&& el) { return std::make_tuple(std::forward<Element>(el)); });
17✔
69
        }
70
}
71

72
namespace sl::tuple
73
{
74
        /**
75
         * \defgroup GROUP_TUPLE_ALGORITHM_ENVELOP_ELEMENTS envelop elements
76
         * \ingroup GROUP_TUPLE_ALGORITHM
77
         * @{
78
         */
79

80
        /**
81
         * \brief Trait type determining the result of a ``tuple_envelop_elements`` call.
82
         */
83
        template <class Tuple>
84
                requires concepts::tuple<std::remove_cvref_t<Tuple>>
85
        struct envelop_elements_result
86
        {
87
                using type = decltype(detail::envelop_elements(std::declval<Tuple>()));
88
        };
89

90
        /**
91
         * \brief Alias type determining the result of a ``tuple_envelop_elements`` call.
92
         */
93
        template <class Tuple>
94
                requires concepts::tuple<std::remove_cvref_t<Tuple>>
95
        using envelop_elements_result_t = typename envelop_elements_result<Tuple>::type;
96

97
        /**
98
         * \brief Envelops all elements of the given tuple into their own ``std::tuple`` and creates a tuple of tuples.
99
         * \tparam Tuple The tuple type.
100
         * \param tuple The tuple.
101
         * \return A new tuple which elements are tuples.
102
         *
103
         * \details Provided a tuple ``t0 = (e0, e1, ..., en)`` then the resulting tuple is built as follows:
104
         * \code{.unparsed}
105
         * (        (e0), (e1), ..., (en)        )
106
         * \endcode
107
         */
108
        template <class Tuple>
109
                requires concepts::tuple<std::remove_cvref_t<Tuple>>
110
        [[nodiscard]]
111
        constexpr envelop_elements_result_t<Tuple> envelop_elements(
4✔
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));
4✔
116
        }
117

118
        /** @} */
119
}
120

121
namespace sl::tuple::detail
122
{
123
        template <class... Tuples>
124
        [[nodiscard]]
125
        constexpr auto zip(Tuples&&... tuples)
2✔
126
        {
127
                return [&]<std::size_t... indices>([[maybe_unused]] std::index_sequence<indices...>)
3✔
128
                {
UNCOV
129
                        return std::make_tuple(
×
130
                                [&]<std::size_t index>()
6✔
131
                                {
132
                                        return std::make_tuple(std::get<index>(std::forward<Tuples>(tuples))...);
2✔
133
                                }.template operator()<indices>()...
134
                        );
1✔
135
                }(std::make_index_sequence<std::min({std::tuple_size_v<Tuples>...})>{});
4✔
136
        }
137
}
138

139
namespace sl::tuple
140
{
141
        /**
142
         * \defgroup GROUP_TUPLE_ALGORITHM_ZIP zip
143
         * \ingroup GROUP_TUPLE_ALGORITHM
144
         * @{
145
         */
146

147
        /**
148
         * \brief Trait type determining the result of a ``zip`` call.
149
         */
150
        template <class... Tuples>
151
                requires (2 <= sizeof...(Tuples))
152
                                && (concepts::tuple<std::remove_cvref_t<Tuples>> && ...)
153
        struct zip_result
154
        {
155
                using type = decltype(detail::zip(std::declval<Tuples>()...));
156
        };
157

158
        /**
159
         * \brief Alias type determining the result of a ``zip`` call.
160
         */
161
        template <class... Tuples>
162
                requires (2 <= sizeof...(Tuples))
163
                                && (concepts::tuple<std::remove_cvref_t<Tuples>> && ...)
164
        using zip_result_t = typename zip_result<Tuples...>::type;
165

166
        /**
167
         * \brief Zips elements of all provided source tuples and creates a tuple of tuples.
168
         * \tparam First The first tuple type.
169
         * \tparam Second The second tuple type.
170
         * \tparam Others Other tuple types.
171
         * \param first The first tuple.
172
         * \param second The second tuple.
173
         * \param others Other tuples.
174
         * \return A new tuple which elements are tuples.
175
         *
176
         * \details Combines all given tuples into one tuple with tuples as elements. All resulting tuple element have equal dimensions,
177
         * which is the amount of provide source tuples (= ``N```).
178
         * The minimal dimension of all given source tuple determines the amount of the resulting tuple elements (= ``M``).
179
         * The resulting tuple will then contain ``M`` tuple elements, each consisting of exactly ``N`` elements.
180
         * Provided the tuples ``t0 = (e0, e1, ..., em)`` and ``t1 = (f0, f1, ... fr)`` where ``m <= r``, then the zip tuple is built
181
         * as follows:
182
         * \code{.unparsed}
183
         * (        (e0, f0),
184
         *                (e1, f1),
185
         *                ...,
186
         *                (em, fm)        )
187
         * \endcode
188
         *
189
         * \note If any of the given tuples are empty, then the resulting tuple will contain no elements.
190
         */
191
        template <class First, class Second, class... Others>
192
                requires concepts::tuple<std::remove_cvref_t<First>>
193
                                && concepts::tuple<std::remove_cvref_t<Second>>
194
                                && (concepts::tuple<std::remove_cvref_t<Others>> && ...)
195
        [[nodiscard]]
196
        constexpr zip_result_t<First, Second, Others...> zip(First&& first, Second&& second, Others&&... others)
1✔
197
        {
198
                return detail::zip(
199
                        std::forward<First>(first),
200
                        std::forward<Second>(second),
201
                        std::forward<Others>(others)...);
1✔
202
        }
203

204
        /** @} */
205
}
206

207
namespace 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)
4✔
212
        {
213
                return envelop_elements(first);
4✔
214
        }
215

216
        [[nodiscard]]
217
        constexpr auto cartesian_product(const concepts::tuple auto& first, const concepts::tuple auto&... others)
6✔
218
        {
219
                auto trailers = cartesian_product(others...);
6✔
UNCOV
220
                return std::apply(
×
221
                        [&](auto&... firstElements)
7✔
222
                        {
UNCOV
223
                                return std::tuple_cat(
×
224
                                        [&](auto& currentFirst)
7✔
225
                                        {
226
                                                return std::apply(
227
                                                        [&](auto&... trailerElements)
31✔
228
                                                        {
229
                                                                return std::make_tuple(std::tuple_cat(std::make_tuple(currentFirst), trailerElements)...);
7✔
230
                                                        },
231
                                                        trailers
232
                                                );
14✔
233
                                        }(firstElements)...
234
                                );
3✔
235
                        },
236
                        first
237
                );
12✔
238
        }
6✔
239
}
240

241
namespace sl::tuple
242
{
243
        /**
244
         * \defgroup GROUP_TUPLE_ALGORITHM_CARTESIAN_PRODUCT cartesian product
245
         * \ingroup GROUP_TUPLE_ALGORITHM
246
         * @{
247
         */
248

249
        /**
250
         * \brief Trait type determining the result of a ``cartesian_product`` call.
251
         */
252
        template <class... Tuples>
253
                requires (2 <= sizeof...(Tuples))
254
                                && (concepts::tuple<std::remove_cvref_t<Tuples>> && ...)
255
        struct cartesian_product_result
256
        {
257
                using type = decltype(detail::cartesian_product(std::declval<Tuples>()...));
258
        };
259

260
        /**
261
         * \brief Alias type determining the result of a ``cartesian_product`` call.
262
         */
263
        template <class... Tuples>
264
                requires (2 <= sizeof...(Tuples))
265
                                && (concepts::tuple<std::remove_cvref_t<Tuples>> && ...)
266
        using cartesian_product_result_t = typename cartesian_product_result<Tuples...>::type;
267

268
        /**
269
         * \brief Creates the cartesian product of the given tuples.
270
         * \tparam First The first tuple type.
271
         * \tparam Second The second tuple type.
272
         * \tparam Others Other tuple types.
273
         * \param first The first tuple.
274
         * \param second The second tuple.
275
         * \param others Other tuples.
276
         * \return A new tuple which elements are tuples.
277
         *
278
         * \details A cartesian product is built by combining all element of one tuple with all elements of another tuple
279
         * (potentially recursive). Provided the tuples ``t0 = (e0, e1, ..., en)`` and ``t1 = (f0, f1, ... fm)`` the cartesian
280
         * the product is built as follows:
281
         * \code{.unparsed}
282
         * (        (e0, f0), (e0, f1), ..., (e0, fm),
283
         *                (e1, f0), (e1, f1), ..., (e1, fm),
284
         *                ...,
285
         *                (en, f0), (en, f1), ..., (en, fm)        )
286
         * \endcode
287
         */
288
        template <concepts::tuple First, concepts::tuple Second, concepts::tuple... Others>
289
        [[nodiscard]]
290
        constexpr cartesian_product_result_t<First, Second, Others...> cartesian_product(
2✔
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...);
2✔
299
        }
300

301
        /** @} */
302
}
303

304
#endif
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc