opynsim
Unofficial C++ Documentation
Loading...
Searching...
No Matches
algorithms.h
Go to the documentation of this file.
1#pragma once
2
5
6#include <algorithm>
7#include <concepts>
8#include <functional>
9#include <iterator>
10#include <memory>
11#include <optional>
12#include <ranges>
13#include <stdexcept>
14#include <type_traits>
15#include <utility>
16
17namespace osc
18{
19 // returns the greater of the given projected values
20 template<
21 class T,
22 class Proj = std::identity,
23 std::indirect_strict_weak_order<std::projected<const T*, Proj>> Comp = std::ranges::less
24 >
25 constexpr const T& max(const T& a, const T& b, Comp comp = {}, Proj proj = {})
26 {
27 return std::ranges::max(a, b, std::ref(comp), std::ref(proj));
28 }
29
30 // returns the smaller of the given projected elements
31 template<
32 class T,
33 class Proj = std::identity,
34 std::indirect_strict_weak_order<std::projected<const T*, Proj>> Comp = std::ranges::less
35 >
36 constexpr const T& min(const T& a, const T& b, Comp comp = {}, Proj proj = {})
37 {
38 return std::ranges::min(a, b, std::ref(comp), std::ref(proj));
39 }
40
41 // if `v` compares less than `lo`, returns `lo`; otherwise, if `hi` compares less than `v`, returns `hi`; otherwise, returns `v`
42 template<
43 class T,
44 class Proj = std::identity,
45 std::indirect_strict_weak_order<std::projected<const T*, Proj>> Comp = std::ranges::less
46 >
47 constexpr const T& clamp(const T& v, const T& lo, const T& hi, Comp comp = {}, Proj proj = {})
48 {
49 return std::ranges::clamp(v, lo, hi, std::ref(comp), std::ref(proj));
50 }
51
52 // returns the index of the largest element in the range
53 template<
54 std::ranges::random_access_range R,
55 class Proj = std::identity,
56 std::indirect_strict_weak_order<std::projected<std::ranges::iterator_t<R>, Proj>> Comp = std::ranges::less
57 >
58 constexpr typename std::ranges::range_size_t<R> max_element_index(R&& r, Comp comp = {}, Proj proj = {})
59 {
60 const auto first = std::ranges::begin(r);
61 return std::distance(first, std::ranges::max_element(first, std::ranges::end(r), std::ref(comp), std::ref(proj)));
62 }
63
64 // returns a reference to the element at specified position `pos`, with bounds checking
65 template<std::ranges::random_access_range R>
66 requires std::ranges::borrowed_range<R>
67 constexpr std::ranges::range_reference_t<R> at(R&& r, std::ranges::range_size_t<R> pos)
68 {
69 if (pos < std::ranges::size(r)) {
70 return std::forward<R>(r)[pos];
71 }
72 else {
73 throw std::out_of_range{"out of bounds index given to a container"};
74 }
75 }
76
77 // returns a copy of the element that has a projection that compares equivalent to `value`, or `std::nullopt` if not found
78 template<
79 std::ranges::input_range R,
80 typename T,
81 typename Proj = std::identity
82 >
83 requires
84 std::indirect_binary_predicate<std::ranges::equal_to, std::projected<std::ranges::iterator_t<R>, Proj>, const T*>
85 std::optional<std::ranges::range_value_t<R>> find_or_nullopt(R&& r, const T& value, Proj proj = {})
86 {
87 const auto it = std::ranges::find(r, value, std::ref(proj));
88 return it != std::ranges::end(r) ? std::optional<std::ranges::range_value_t<R>>{*it} : std::nullopt;
89 }
90
91 // returns a copy of the element with key equivalent to `key`, or `std::nullopt` if no such element exists in `container`
92 template<AssociativeContainer Lookup, AssociativeContainerKeyFor<Lookup> Key>
93 std::optional<typename Lookup::mapped_type> lookup_or_nullopt(const Lookup& lookup, const Key& key)
94 {
95 if (const auto it = lookup.find(key); it != lookup.end()) {
96 return it->second;
97 }
98 return std::nullopt;
99 }
100
101 // returns a pointer to the element with a projection that compares equal to `value`, or `nullptr` if no such element exists in `r`
102 template<
103 std::ranges::input_range R,
104 typename T,
105 typename Proj = std::identity
106 >
107 requires std::ranges::borrowed_range<R>
108 auto find_or_nullptr(R&& r, const T& value, Proj proj = {}) -> decltype(std::addressof(*std::ranges::begin(r)))
109 {
110 const auto it = std::ranges::find(r, value, std::move(proj));
111 return it != std::ranges::end(r) ? std::addressof(*it) : nullptr;
112 }
113
114 // returns a pointer to the element with key equivalent to `key`, or `nullptr` if no such element exists in `container`
115 template<AssociativeContainer T, AssociativeContainerKeyFor<T> Key>
116 auto* lookup_or_nullptr(const T& container, const Key& key)
117 {
118 using return_type = decltype(std::addressof(std::ranges::begin(container)->second));
119
120 if (auto it = container.find(key); it != container.end()) {
121 return std::addressof(it->second);
122 }
123 return static_cast<return_type>(nullptr);
124 }
125
126 // returns a mutable pointer to the element with key equivalent to `key`, or `nullptr` if no such element exists in `container`
127 template<AssociativeContainer T, AssociativeContainerKeyFor<T> Key>
128 auto* lookup_or_nullptr(T& container, const Key& key)
129 {
130 using return_type = decltype(std::addressof(std::ranges::begin(container)->second));
131
132 if (auto it = container.find(key); it != container.end()) {
133 return std::addressof(it->second);
134 }
135 return static_cast<return_type>(nullptr);
136 }
137
138 // returns `true` if both `lhs` and `rhs` can be successfully `dynamic_cast`ed to `Downcasted` and compare equal
139 template<typename Downcasted, typename T1, typename T2>
140 requires
141 std::equality_comparable<Downcasted> and
142 std::is_polymorphic_v<Downcasted> and
143 std::derived_from<Downcasted, T1> and
144 std::derived_from<Downcasted, T2>
145 constexpr bool is_eq_downcasted(const T1& lhs, const T2& rhs)
146 {
147 const auto* lhs_casted = dynamic_cast<const Downcasted*>(std::addressof(lhs));
148 const auto* rhs_casted = dynamic_cast<const Downcasted*>(std::addressof(rhs));
150 return *lhs_casted == *rhs_casted;
151 }
152 return false;
153 }
154
155 template<std::ranges::range R1, std::ranges::input_range R2>
156 requires
157 std::convertible_to<std::ranges::range_value_t<R2>, std::ranges::range_value_t<R1>> and
158 requires (R1& r1, std::ranges::iterator_t<R1> it, std::ranges::iterator_t<R2> first, std::ranges::sentinel_t<R2> last) { r1.insert(it, first, last); }
159 constexpr void append_range(R1& r1, R2&& r2)
160 {
161 r1.insert(std::ranges::end(r1), std::ranges::begin(r2), std::ranges::end(r2));
162 }
163}
Definition custom_decoration_generator.h:5
constexpr auto min(Angle< Rep1, Units1 > x, Angle< Rep2, Units2 > y) -> std::common_type_t< decltype(x), decltype(y)>
Definition angle.h:267
constexpr Angle< Rep, Units > clamp(const Angle< Rep, Units > &v, const AngleMin &min, const AngleMax &max)
Definition angle.h:303
constexpr void append_range(R1 &r1, R2 &&r2)
Definition algorithms.h:159
auto find_or_nullptr(R &&r, const T &value, Proj proj={}) -> decltype(std::addressof(*std::ranges::begin(r)))
Definition algorithms.h:108
std::optional< std::ranges::range_value_t< R > > find_or_nullopt(R &&r, const T &value, Proj proj={})
Definition algorithms.h:85
constexpr std::ranges::range_reference_t< R > at(R &&r, std::ranges::range_size_t< R > pos)
Definition algorithms.h:67
constexpr auto max(Angle< Rep1, Units1 > x, Angle< Rep2, Units2 > y) -> std::common_type_t< decltype(x), decltype(y)>
Definition angle.h:283
auto * lookup_or_nullptr(const T &container, const Key &key)
Definition algorithms.h:116
Key
Definition key.h:6
and std::is_polymorphic_v< Downcasted > and std::derived_from< Downcasted, T1 > and std::derived_from< Downcasted, T2 > constexpr bool is_eq_downcasted(const T1 &lhs, const T2 &rhs)
Definition algorithms.h:145
constexpr U to(T &&value)
Definition conversion.h:56
std::optional< typename Lookup::mapped_type > lookup_or_nullopt(const Lookup &lookup, const Key &key)
Definition algorithms.h:93
constexpr std::ranges::range_size_t< R > max_element_index(R &&r, Comp comp={}, Proj proj={})
Definition algorithms.h:58
and
Definition algorithms.h:158