version 0.4.1
algorithms.hh
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2021-2024 The Ikarus Developers mueller@ibb.uni-stuttgart.de
2// SPDX-License-Identifier: LGPL-3.0-or-later
3
10#pragma once
11
12// This file contains stl-like algorithms
13#include <iosfwd>
14#include <ranges>
15
17namespace Ikarus::utils {
18
28void makeUniqueAndSort(std::ranges::random_access_range auto& r) {
29 sort(r.begin(), r.end());
30 r.erase(std::unique(r.begin(), r.end()), r.end());
31}
32
43template <typename T>
44auto appendUnique(std::ranges::random_access_range auto& r, T&& v) {
45 static_assert(std::is_same_v<typename decltype(begin(r))::value_type, std::remove_reference_t<decltype(v)>>);
46 const auto it = find(begin(r), end(r), v);
47 size_t index = std::distance(begin(r), it);
48 if (it == end(r))
49 r.push_back(std::forward<T>(v));
50
51 return index;
52}
53
63template <class C>
64void printContent(C&& c, std::ostream& os = std::cout) {
65 std::ranges::for_each(c, [&os](auto&& var) { os << var << '\n'; });
66}
67
76template <class C>
78 auto transformValueToPointer = [](auto&& obj) { return &obj; };
79 return (std::ranges::subrange(cont.begin(), cont.end()) | std::views::transform(transformValueToPointer));
80}
81
91template <class C>
93 auto transformValueToPointer = [](auto&& obj) -> auto& { return *obj; };
94 return (std::ranges::subrange(cont.begin(), cont.end()) | std::views::transform(transformValueToPointer));
95}
96
97#ifndef DOXYGEN
98// Forward declare functions
99template <typename... Types>
100auto makeNestedTupleFlat(std::tuple<Types...> tup);
101#endif
102
103namespace Impl {
104 template <class Tuple, std::size_t... I>
105 constexpr auto makeTupleSubsetImpl(Tuple&& t, std::index_sequence<I...>) {
106 return std::make_tuple(std::get<I>(std::forward<Tuple>(t))...);
107 }
108
109 template <class Tuple, std::size_t... I>
110 constexpr auto makeTupleFromTupleIndicesImpl(Tuple&& t, std::index_sequence<I...>) {
111 return std::make_tuple(std::get<I>(std::forward<Tuple>(t))...);
112 }
113
114 template <typename T, typename... Ts>
115 struct uniqueImpl : std::type_identity<T>
116 {
117 };
118
119 template <typename... Ts, typename U, typename... Us>
120 struct uniqueImpl<std::tuple<Ts...>, U, Us...>
121 : std::conditional_t<(std::is_same_v<U, Ts> || ...), uniqueImpl<std::tuple<Ts...>, Us...>,
122 uniqueImpl<std::tuple<Ts..., U>, Us...>>
123 {
124 };
125
126 template <typename... Ts>
127 using unique_tupleImpl = typename uniqueImpl<std::tuple<>, Ts...>::type;
128
129 template <typename T, typename... Types>
130 auto makeNestedTupleFlatImpl() {
131 constexpr bool isTuple = traits::isSpecialization<std::tuple, T>::value;
132 if constexpr (sizeof...(Types) > 0) {
133 if constexpr (isTuple)
134 return std::tuple_cat(makeNestedTupleFlat(T()), makeNestedTupleFlatImpl<Types...>());
135 else
136 return std::tuple_cat(std::make_tuple(T()), makeNestedTupleFlatImpl<Types...>());
137 } else {
138 if constexpr (isTuple)
139 return makeNestedTupleFlat(T());
140 else
141 return std::make_tuple(T());
142 }
143 }
144
145 template <typename T, typename... Types>
146 auto makeNestedTupleFlatAndStoreReferencesImpl(const std::tuple<T, Types...>& tup) {
147 constexpr bool isTuple = traits::isSpecialization<std::tuple, std::remove_cvref_t<T>>::value;
148 if constexpr (sizeof...(Types) > 0) {
149 if constexpr (isTuple)
150 return std::tuple_cat(
151 makeNestedTupleFlatAndStoreReferencesImpl(std::get<0>(tup)),
152 std::apply(
153 [](const T&, const Types&... args) {
154 return makeNestedTupleFlatAndStoreReferencesImpl(std::make_tuple(std::cref(args)...));
155 },
156 tup));
157 else
158 return std::tuple_cat(
159 std::make_tuple(std::cref(std::get<0>(tup))),
160 std::apply(
161 [](const T&, const Types&... args) {
162 return makeNestedTupleFlatAndStoreReferencesImpl(std::make_tuple(std::cref(args)...));
163 },
164 tup));
165 } else {
166 if constexpr (isTuple)
167 return makeNestedTupleFlatAndStoreReferencesImpl(std::get<0>(tup));
168 else
169 return std::make_tuple(std::cref(std::get<0>(tup)));
170 }
171 }
172
173 template <typename T, typename... Types>
174 auto makeNestedTupleFlatAndStoreReferencesNonConstImpl(const std::tuple<T, Types...>& tupconst) {
175 auto& tup = const_cast<std::tuple<T, Types...>&>(tupconst);
176 constexpr bool isTuple = traits::isSpecialization<std::tuple, std::remove_cvref_t<T>>::value;
177 if constexpr (sizeof...(Types) > 0) {
178 if constexpr (isTuple)
179 return std::tuple_cat(
180 makeNestedTupleFlatAndStoreReferencesNonConstImpl(std::get<0>(tup)),
181 std::apply(
182 [](T&, Types&... args) {
183 return makeNestedTupleFlatAndStoreReferencesNonConstImpl(std::make_tuple(std::ref(args)...));
184 },
185 tup));
186 else
187 return std::tuple_cat(
188 std::make_tuple(std::ref(std::get<0>(tup))),
189 std::apply(
190 [](T&, Types&... args) {
191 return makeNestedTupleFlatAndStoreReferencesNonConstImpl(std::make_tuple(std::ref(args)...));
192 },
193 tup));
194 } else {
195 if constexpr (isTuple)
196 return makeNestedTupleFlatAndStoreReferencesNonConstImpl(std::get<0>(tup));
197 else
198 return std::make_tuple(std::ref(std::get<0>(tup)));
199 }
200 }
201
202} // namespace Impl
203
219template <typename Tuple, typename Predicate>
220constexpr size_t find_if(Tuple&& tuple, Predicate pred) {
221 size_t index = std::tuple_size<std::remove_reference_t<Tuple>>::value;
222 size_t currentIndex = 0;
223 bool found = false;
224
225 Dune::Hybrid::forEach(tuple, [&](auto&& value) {
226 if (!found && pred(value)) {
227 index = currentIndex;
228 found = true;
229 }
230 ++currentIndex;
231 });
232 return index;
233}
234
247template <typename Tuple, typename Predicate>
248bool none_of(Tuple&& tuple, Predicate pred) {
249 return find_if(tuple, pred) == std::tuple_size<std::decay_t<Tuple>>::value;
250}
251
264template <typename Tuple, typename Predicate>
265bool any_of(Tuple&& tuple, Predicate pred) {
266 return !none_of(tuple, pred);
267}
268
283template <typename Tuple, typename Predicate>
284auto filter(Tuple&& tuple, Predicate pred) {
285 return std::apply(
286 [&pred](auto... ts) {
287 return std::tuple_cat(std::conditional_t<pred(ts), std::tuple<decltype(ts)>, std::tuple<>>{}...);
288 },
289 tuple);
290}
291
303template <typename... Types>
304constexpr auto unique([[maybe_unused]] std::tuple<Types...>&& tuple) {
305 return Impl::unique_tupleImpl<Types...>();
306}
307
321template <typename Tuple, typename Predicate>
322constexpr size_t count_if(Tuple&& tuple, Predicate pred) {
323 size_t counter = 0;
324 Dune::Hybrid::forEach(tuple, [&](auto&& value) {
325 if (pred(value))
326 ++counter;
327 });
328 return counter;
329}
330
343template <template <auto...> class Type, typename Tuple>
344constexpr int findTypeSpecialization() {
345 return find_if(std::remove_cvref_t<Tuple>(),
346 []<typename T>(T&&) { return traits::isSpecializationNonTypes<Type, std::remove_cvref_t<T>>::value; });
347}
348
361template <template <auto...> class Type, typename Tuple>
362auto getSpecialization(Tuple&& tuple) {
363 constexpr int index = findTypeSpecialization<Type, Tuple>();
364 static_assert(index < std::tuple_size_v<std::remove_cvref_t<Tuple>>,
365 "The found index has to be smaller than the tuple size");
366 return std::get<index>(tuple);
367}
368
382template <template <auto...> class Type, typename Tuple>
383constexpr bool hasTypeSpecialization() {
384 return (find_if(std::remove_cvref_t<Tuple>(), []<typename T>(T&&) {
385 return traits::isSpecializationNonTypes<Type, std::remove_cvref_t<T>>::value;
386 }) < std::tuple_size_v<std::remove_cvref_t<Tuple>>);
387}
388
400template <template <auto...> class Type, typename Tuple>
401constexpr bool countTypeSpecialization() {
402 return count_if(
403 Tuple(), []<typename T>(T&&) { return traits::isSpecializationNonTypes<Type, std::remove_cvref_t<T>>::value; });
404}
405
417template <template <auto...> class Type, typename Tuple>
418static constexpr bool countTypeSpecialization_v = countTypeSpecialization<Type, Tuple>();
419
432template <int N, class Tuple>
433constexpr auto makeTupleSubset(Tuple&& t) {
434 static_assert(N < std::tuple_size_v<std::remove_reference_t<Tuple>>,
435 "The requested size needs to be smaller than the size of the tuple.");
436
437 return Impl::makeTupleSubsetImpl(std::forward<Tuple>(t), std::make_index_sequence<N>{});
438}
439
453template <class Tuple, std::size_t... I>
454constexpr auto makeTupleFromTupleIndices(Tuple&& t) {
455 return Impl::makeTupleFromTupleIndicesImpl(std::forward<Tuple>(t), std::index_sequence<I...>{});
456}
457
465template <typename... Types>
466auto makeNestedTupleFlat(std::tuple<Types...>) {
467 return decltype(Impl::makeNestedTupleFlatImpl<Types...>())();
468}
469
479template <typename Tuple>
481 if constexpr (std::tuple_size_v<std::remove_cvref_t<Tuple>> == 0)
482 return tup;
483 else if constexpr (!std::is_const_v<std::remove_reference_t<Tuple>>)
484 return Impl::makeNestedTupleFlatAndStoreReferencesNonConstImpl(std::forward<Tuple>(tup));
485 else
486 return Impl::makeNestedTupleFlatAndStoreReferencesImpl(std::forward<Tuple>(tup));
487}
488
496template <typename T>
497requires traits::Pointer<T>
499 if constexpr (!std::is_same_v<T, std::nullptr_t>)
500 return *v;
501 else
502 return std::nullopt;
503}
504
505} // namespace Ikarus::utils
Contains stl-like type traits.
auto getSpecialization(Tuple &&tuple)
Gets the specialization of the given template type from the tuple.
Definition: algorithms.hh:362
auto appendUnique(std::ranges::random_access_range auto &r, T &&v)
Appends a value to the range if it is not already present.
Definition: algorithms.hh:44
constexpr auto unique(std::tuple< Types... > &&tuple)
Creates a tuple with unique types from the given tuple.
Definition: algorithms.hh:304
void printContent(C &&c, std::ostream &os=std::cout)
Prints the contents of a container to the specified output stream.
Definition: algorithms.hh:64
constexpr auto makeTupleSubset(Tuple &&t)
Creates a subset tuple with the first N elements from the given tuple.
Definition: algorithms.hh:433
bool none_of(Tuple &&tuple, Predicate pred)
Checks if none of the elements in the tuple satisfy a given predicate.
Definition: algorithms.hh:248
constexpr int findTypeSpecialization()
Finds the index of the first element in the tuple that is a specialization of the given template type...
Definition: algorithms.hh:344
static constexpr bool countTypeSpecialization_v
Variable template for counting the occurrences of a specialization of a template type in a tuple.
Definition: algorithms.hh:418
void makeUniqueAndSort(std::ranges::random_access_range auto &r)
Sorts and removes duplicate elements from a random access range.*.
Definition: algorithms.hh:28
auto transformValueRangeToPointerRange(C &cont)
Transforms a value range to a pointer range.
Definition: algorithms.hh:77
auto transformPointerRangeToReferenceRange(C &cont)
Transforms a pointer range to a reference range.
Definition: algorithms.hh:92
bool any_of(Tuple &&tuple, Predicate pred)
Checks if any of the elements in the tuple satisfy a given predicate.
Definition: algorithms.hh:265
auto filter(Tuple &&tuple, Predicate pred)
Filters the elements of a tuple based on a given predicate.
Definition: algorithms.hh:284
constexpr bool countTypeSpecialization()
Counts the occurrences of a specialization of a template type in a tuple.
Definition: algorithms.hh:401
constexpr size_t count_if(Tuple &&tuple, Predicate pred)
Counts the number of elements in the tuple satisfying the given predicate.
Definition: algorithms.hh:322
constexpr bool hasTypeSpecialization()
Checks if a tuple has a specialization of a template type.
Definition: algorithms.hh:383
constexpr auto makeTupleFromTupleIndices(Tuple &&t)
Creates a new tuple using indices from the original tuple.
Definition: algorithms.hh:454
constexpr size_t find_if(Tuple &&tuple, Predicate pred)
Finds the index of the first element in the tuple satisfying a predicate.
Definition: algorithms.hh:220
Definition: algorithms.hh:17
auto makeNestedTupleFlatAndStoreReferences(Tuple &&tup)
Creates a flattened nested tuple and stores references.
Definition: algorithms.hh:480
auto makeNestedTupleFlat(std::tuple< Types... >)
Creates a flattened nested tuple.
Definition: algorithms.hh:466
auto & returnReferenceOrNulloptIfObjectIsNullPtr(T v)
Returns a reference or std::nullopt if the object is a nullptr.
Definition: algorithms.hh:498
Concept to check if a type is a pointer or nullptr_t.
Definition: traits.hh:23