OGS
Algorithm.h
Go to the documentation of this file.
1
11#pragma once
12
13#include <algorithm>
14#include <cassert>
15#include <concepts>
16#include <optional>
17#include <range/v3/algorithm/find_if.hpp>
18#include <range/v3/range/concepts.hpp>
19#include <range/v3/range/conversion.hpp>
20#include <range/v3/view/concat.hpp>
21#include <range/v3/view/partial_sum.hpp>
22#include <range/v3/view/single.hpp>
23#include <string>
24#include <typeindex>
25#include <typeinfo>
26#include <utility>
27
28#include "CompilerWorkarounds.h"
29#include "Error.h"
30
31namespace BaseLib
32{
41template <typename T>
42std::vector<T> excludeObjectCopy(
43 std::vector<T> const& src_vec,
44 std::vector<std::size_t> const& exclude_positions)
45{
46 std::vector<T> dest_vec;
47 if (exclude_positions.empty())
48 {
49 dest_vec = src_vec;
50 return dest_vec;
51 }
52
53 assert(exclude_positions.back() < src_vec.size());
54
55 std::copy_n(src_vec.cbegin(), exclude_positions[0],
56 std::back_inserter(dest_vec));
57 for (std::size_t i = 1; i < exclude_positions.size(); ++i)
58 {
59 std::copy_n(src_vec.cbegin() + exclude_positions[i - 1] + 1,
60 exclude_positions[i] - (exclude_positions[i - 1] + 1),
61 std::back_inserter(dest_vec));
62 }
63 std::copy(src_vec.cbegin() + exclude_positions.back() + 1, src_vec.cend(),
64 std::back_inserter(dest_vec));
65
66 return dest_vec;
67}
68
69template <typename T>
70void excludeObjectCopy(std::vector<T> const& src_vec,
71 std::vector<std::size_t> const& exclude_positions,
72 std::vector<T>& dest_vec)
73{
74 dest_vec = excludeObjectCopy(src_vec, exclude_positions);
75}
76
80template <ranges::input_range Range>
81ranges::range_reference_t<Range> findElementOrError(
82 Range& range,
83 std::predicate<ranges::range_reference_t<Range>> auto&& predicate,
84 std::invocable auto error_callback)
85{
86 auto it =
87 ranges::find_if(range, std::forward<decltype(predicate)>(predicate));
88 if (it == ranges::end(range))
89 {
90 error_callback();
92 "Element not found in the input range. The user provided error "
93 "callback is meant not to return. That has not happened.");
94 }
95 return *it;
96}
97
103template <typename Map, typename Key, typename Value>
104void insertIfKeyUniqueElseError(Map& map, Key const& key, Value&& value,
105 std::string const& error_message)
106{
107 auto const inserted = map.emplace(key, std::forward<Value>(value));
108 if (!inserted.second)
109 { // insertion failed, i.e., key already exists
110 OGS_FATAL("{} Key `{}' already exists.", error_message, key);
111 }
112}
113
117template <typename Map, typename Key>
118OGS_NO_DANGLING typename Map::mapped_type& getOrError(
119 Map& map, Key const& key, std::string const& error_message)
120{
121 auto it = map.find(key);
122 if (it == map.end())
123 {
124 if constexpr (std::is_convertible<Key, std::string>::value)
125 {
126 OGS_FATAL("{:s} Key `{:s}' does not exist.", error_message, key);
127 }
128 else
129 {
130 OGS_FATAL("{:s} Key `{:s}' does not exist.", error_message,
131 std::to_string(key));
132 }
133 }
134
135 return it->second;
136}
138template <typename Map, typename Key>
139OGS_NO_DANGLING typename Map::mapped_type const& getOrError(
140 Map const& map, Key const& key, std::string const& error_message)
141{
142 auto it = map.find(key);
143 if (it == map.end())
144 {
145 if constexpr (std::is_convertible<Key, std::string>::value)
146 {
147 OGS_FATAL("{:s} Key `{:s}' does not exist.", error_message, key);
148 }
149 else
150 {
151 OGS_FATAL("{:s} Key `{:s}' does not exist.", error_message,
152 std::to_string(key));
153 }
154 }
155
156 return it->second;
157}
158
162template <typename Container, typename Predicate>
163OGS_NO_DANGLING typename Container::value_type const& getIfOrError(
164 Container const& container,
165 Predicate&& predicate,
166 std::string const& error_message)
167{
168 auto it = std::find_if(begin(container), end(container), predicate);
169 if (it == end(container))
170 {
171 OGS_FATAL("Could not find element matching the predicate: {:s}",
172 error_message);
173 }
174 return *it;
175}
176
179template <typename T>
180void makeVectorUnique(std::vector<T>& v)
181{
182 std::sort(v.begin(), v.end());
183 auto it = std::unique(v.begin(), v.end());
184 v.erase(it, v.end());
185}
186
189template <typename T, class Compare>
190void makeVectorUnique(std::vector<T>& v, Compare comp)
191{
192 std::sort(v.begin(), v.end(), comp);
193 auto it = std::unique(v.begin(), v.end());
194 v.erase(it, v.end());
195}
196
202template <typename ValueType, typename IndexType>
203void reorderVector(std::vector<ValueType>& v,
204 std::vector<IndexType> const& order)
205{
206 std::vector<ValueType> temp_v(v.size());
207 temp_v.swap(v);
208
209 for (std::size_t i = 0; i < order.size(); i++)
210 {
211 std::swap(v[i], temp_v[order[i]]);
212 }
213}
214
215template <typename Container>
216void uniquePushBack(Container& container,
217 typename Container::value_type const& element)
218{
219 if (std::find(container.begin(), container.end(), element) ==
220 container.end())
221 {
222 container.push_back(element);
223 }
224}
225
226template <typename Container>
227std::optional<typename Container::value_type> findFirstNotEqualElement(
228 Container const& container, typename Container::value_type const& element)
229{
230 auto const it =
231 std::find_if_not(container.begin(), container.end(),
232 [&element](typename Container::value_type const& e)
233 { return e == element; });
234 return it == container.end() ? std::nullopt : std::make_optional(*it);
235}
236
242template <typename Container>
243std::size_t findIndex(Container const& container,
244 typename Container::value_type const& element)
245{
246 auto const it = std::find(container.begin(), container.end(), element);
247 if (it == container.end())
248 {
249 return std::numeric_limits<std::size_t>::max();
250 }
251 return std::distance(container.begin(), it);
252}
253
255template <typename T>
256void cleanupVectorElements(std::vector<T*>& items)
257{
258 for (auto item : items)
259 {
260 delete item;
261 }
262 items.clear();
263}
264
272template <typename T1, typename... Args>
273void cleanupVectorElements(std::vector<T1*>& dependent_items, Args&&... args)
274{
275 cleanupVectorElements(dependent_items);
276 cleanupVectorElements(std::forward<Args>(args)...);
277}
278
281template <ranges::range R>
282 requires std::is_integral_v<ranges::range_value_t<R>>
283std::vector<ranges::range_value_t<R>> sizesToOffsets(R const& sizes)
284{
285 return ranges::views::concat(
286 ranges::views::single(ranges::range_value_t<R>{0}),
287 ranges::views::partial_sum(sizes)) |
288 ranges::to<std::vector<ranges::range_value_t<R>>>();
289}
290
292template <typename List>
293constexpr bool any_of(List const& values)
294{
295 // std::any_of is not constexpr enough in some STLs
296 for (auto& value : values)
297 {
298 if (static_cast<bool>(value))
299 {
300 return true;
301 }
302 }
303
304 return false;
305}
306
308template <typename List>
309constexpr bool all_of(List const& values)
310{
311 // std::all_of is not constexpr enough in some STLs
312 for (auto& value : values)
313 {
314 if (!static_cast<bool>(value))
315 {
316 return false;
317 }
318 }
319
320 return true;
321}
322
324template <typename List>
325constexpr bool none_of(List const& values)
326{
327 return !any_of(values);
328}
329
334template <class... Ts>
335struct Overloaded : Ts...
336{
337 using Ts::operator()...;
338};
339#if defined(__clang__)
340#if (__clang_major__ <= 16)
342template <class... Ts>
343Overloaded(Ts...) -> Overloaded<Ts...>;
344#endif
345#endif
346
347} // namespace BaseLib
#define OGS_NO_DANGLING
#define OGS_FATAL(...)
Definition Error.h:26
Wraps a pair of iterators for use as a range in range-based for-loops.
Definition ConfigTree.h:48
std::vector< T > excludeObjectCopy(std::vector< T > const &src_vec, std::vector< std::size_t > const &exclude_positions)
Definition Algorithm.h:42
std::size_t findIndex(Container const &container, typename Container::value_type const &element)
Definition Algorithm.h:243
void insertIfKeyUniqueElseError(Map &map, Key const &key, Value &&value, std::string const &error_message)
Definition Algorithm.h:104
ranges::range_reference_t< Range > findElementOrError(Range &range, std::predicate< ranges::range_reference_t< Range > > auto &&predicate, std::invocable auto error_callback)
Definition Algorithm.h:81
constexpr bool none_of(List const &values)
Checks if none of the elements in the given list are true.
Definition Algorithm.h:325
void cleanupVectorElements(std::vector< T * > &items)
Definition Algorithm.h:256
void uniquePushBack(Container &container, typename Container::value_type const &element)
Definition Algorithm.h:216
constexpr bool all_of(List const &values)
Checks if all of the elements in the given list are true.
Definition Algorithm.h:309
OGS_NO_DANGLING Container::value_type const & getIfOrError(Container const &container, Predicate &&predicate, std::string const &error_message)
Definition Algorithm.h:163
std::vector< ranges::range_value_t< R > > sizesToOffsets(R const &sizes)
Definition Algorithm.h:283
void reorderVector(std::vector< ValueType > &v, std::vector< IndexType > const &order)
Definition Algorithm.h:203
OGS_NO_DANGLING Map::mapped_type & getOrError(Map &map, Key const &key, std::string const &error_message)
Definition Algorithm.h:118
void makeVectorUnique(std::vector< T > &v)
Definition Algorithm.h:180
std::optional< typename Container::value_type > findFirstNotEqualElement(Container const &container, typename Container::value_type const &element)
Definition Algorithm.h:227
constexpr bool any_of(List const &values)
Checks if any of the elements in the given list is true.
Definition Algorithm.h:293