OGS
Algorithm.h
Go to the documentation of this file.
1// SPDX-FileCopyrightText: Copyright (c) OpenGeoSys Community (opengeosys.org)
2// SPDX-License-Identifier: BSD-3-Clause
3
4#pragma once
5
6#include <algorithm>
7#include <cassert>
8#include <concepts>
9#include <optional>
10#include <range/v3/algorithm/find_if.hpp>
11#include <range/v3/range/concepts.hpp>
12#include <range/v3/range/conversion.hpp>
13#include <range/v3/view/concat.hpp>
14#include <range/v3/view/partial_sum.hpp>
15#include <range/v3/view/single.hpp>
16#include <string>
17#include <typeindex>
18#include <typeinfo>
19#include <utility>
20
21#include "CompilerWorkarounds.h"
22#include "Error.h"
23
24namespace BaseLib
25{
34template <typename T>
35std::vector<T> excludeObjectCopy(
36 std::vector<T> const& src_vec,
37 std::vector<std::size_t> const& exclude_positions)
38{
39 std::vector<T> dest_vec;
40 if (exclude_positions.empty())
41 {
42 dest_vec = src_vec;
43 return dest_vec;
44 }
45
46 assert(exclude_positions.back() < src_vec.size());
47
48 std::copy_n(src_vec.cbegin(), exclude_positions[0],
49 std::back_inserter(dest_vec));
50 for (std::size_t i = 1; i < exclude_positions.size(); ++i)
51 {
52 std::copy_n(src_vec.cbegin() + exclude_positions[i - 1] + 1,
53 exclude_positions[i] - (exclude_positions[i - 1] + 1),
54 std::back_inserter(dest_vec));
55 }
56 std::copy(src_vec.cbegin() + exclude_positions.back() + 1, src_vec.cend(),
57 std::back_inserter(dest_vec));
58
59 return dest_vec;
60}
61
62template <typename T>
63void excludeObjectCopy(std::vector<T> const& src_vec,
64 std::vector<std::size_t> const& exclude_positions,
65 std::vector<T>& dest_vec)
66{
67 dest_vec = excludeObjectCopy(src_vec, exclude_positions);
68}
69
73template <ranges::input_range Range>
74ranges::range_reference_t<Range> findElementOrError(
75 Range& range,
76 std::predicate<ranges::range_reference_t<Range>> auto&& predicate,
77 std::invocable auto error_callback)
78{
79 auto it =
80 ranges::find_if(range, std::forward<decltype(predicate)>(predicate));
81 if (it == ranges::end(range))
82 {
83 error_callback();
85 "Element not found in the input range. The user provided error "
86 "callback is meant not to return. That has not happened.");
87 }
88 return *it;
89}
90
96template <typename Map, typename Key, typename Value>
97void insertIfKeyUniqueElseError(Map& map, Key const& key, Value&& value,
98 std::string const& error_message)
99{
100 auto const inserted = map.emplace(key, std::forward<Value>(value));
101 if (!inserted.second)
102 { // insertion failed, i.e., key already exists
103 OGS_FATAL("{} Key `{}' already exists.", error_message, key);
104 }
105}
106
110template <typename Map, typename Key>
111OGS_NO_DANGLING typename Map::mapped_type& getOrError(
112 Map& map, Key const& key, std::string const& error_message)
113{
114 auto it = map.find(key);
115 if (it == map.end())
116 {
117 if constexpr (std::is_convertible<Key, std::string>::value)
118 {
119 OGS_FATAL("{:s} Key `{:s}' does not exist.", error_message, key);
120 }
121 else
122 {
123 OGS_FATAL("{:s} Key `{:s}' does not exist.", error_message,
124 std::to_string(key));
125 }
126 }
127
128 return it->second;
129}
130
131template <typename Map, typename Key>
132OGS_NO_DANGLING typename Map::mapped_type const& getOrError(
133 Map const& map, Key const& key, std::string const& error_message)
134{
135 auto it = map.find(key);
136 if (it == map.end())
137 {
138 if constexpr (std::is_convertible<Key, std::string>::value)
139 {
140 OGS_FATAL("{:s} Key `{:s}' does not exist.", error_message, key);
141 }
142 else
143 {
144 OGS_FATAL("{:s} Key `{:s}' does not exist.", error_message,
145 std::to_string(key));
146 }
147 }
148
149 return it->second;
150}
151
155template <typename Container, typename Predicate>
156OGS_NO_DANGLING typename Container::value_type const& getIfOrError(
157 Container const& container,
158 Predicate&& predicate,
159 std::string const& error_message)
160{
161 auto it = std::find_if(begin(container), end(container), predicate);
162 if (it == end(container))
163 {
164 OGS_FATAL("Could not find element matching the predicate: {:s}",
165 error_message);
166 }
167 return *it;
168}
169
172template <typename T>
173void makeVectorUnique(std::vector<T>& v)
174{
175 std::sort(v.begin(), v.end());
176 auto it = std::unique(v.begin(), v.end());
177 v.erase(it, v.end());
178}
179
182template <typename T, class Compare>
183void makeVectorUnique(std::vector<T>& v, Compare comp)
184{
185 std::sort(v.begin(), v.end(), comp);
186 auto it = std::unique(v.begin(), v.end());
187 v.erase(it, v.end());
188}
189
195template <typename ValueType, typename IndexType>
196void reorderVector(std::vector<ValueType>& v,
197 std::vector<IndexType> const& order)
198{
199 std::vector<ValueType> temp_v(v.size());
200 temp_v.swap(v);
201
202 for (std::size_t i = 0; i < order.size(); i++)
203 {
204 std::swap(v[i], temp_v[order[i]]);
205 }
206}
207
208template <typename Container>
209void uniquePushBack(Container& container,
210 typename Container::value_type const& element)
211{
212 if (std::find(container.begin(), container.end(), element) ==
213 container.end())
214 {
215 container.push_back(element);
216 }
217}
218
219template <typename Container>
220std::optional<typename Container::value_type> findFirstNotEqualElement(
221 Container const& container, typename Container::value_type const& element)
222{
223 auto const it =
224 std::find_if_not(container.begin(), container.end(),
225 [&element](typename Container::value_type const& e)
226 { return e == element; });
227 return it == container.end() ? std::nullopt : std::make_optional(*it);
228}
229
235template <typename Container>
236std::size_t findIndex(Container const& container,
237 typename Container::value_type const& element)
238{
239 auto const it = std::find(container.begin(), container.end(), element);
240 if (it == container.end())
241 {
242 return std::numeric_limits<std::size_t>::max();
243 }
244 return std::distance(container.begin(), it);
245}
246
248template <typename T>
249void cleanupVectorElements(std::vector<T*>& items)
250{
251 for (auto item : items)
252 {
253 delete item;
254 }
255 items.clear();
256}
257
265template <typename T1, typename... Args>
266void cleanupVectorElements(std::vector<T1*>& dependent_items, Args&&... args)
267{
268 cleanupVectorElements(dependent_items);
269 cleanupVectorElements(std::forward<Args>(args)...);
270}
271
274template <ranges::range R>
275 requires std::is_integral_v<ranges::range_value_t<R>>
276std::vector<ranges::range_value_t<R>> sizesToOffsets(R const& sizes)
277{
278 return ranges::views::concat(
279 ranges::views::single(ranges::range_value_t<R>{0}),
280 ranges::views::partial_sum(sizes)) |
281 ranges::to<std::vector<ranges::range_value_t<R>>>();
282}
283
285template <typename List>
286constexpr bool any_of(List const& values)
287{
288 // std::any_of is not constexpr enough in some STLs
289 for (auto& value : values)
290 {
291 if (static_cast<bool>(value))
292 {
293 return true;
294 }
295 }
296
297 return false;
298}
299
301template <typename List>
302constexpr bool all_of(List const& values)
303{
304 // std::all_of is not constexpr enough in some STLs
305 for (auto& value : values)
306 {
307 if (!static_cast<bool>(value))
308 {
309 return false;
310 }
311 }
312
313 return true;
314}
315
317template <typename List>
318constexpr bool none_of(List const& values)
319{
320 return !any_of(values);
321}
322
327template <class... Ts>
328struct Overloaded : Ts...
329{
330 using Ts::operator()...;
331};
332#if defined(__clang__)
333#if (__clang_major__ <= 16)
335template <class... Ts>
336Overloaded(Ts...) -> Overloaded<Ts...>;
337#endif
338#endif
339
340} // namespace BaseLib
#define OGS_NO_DANGLING
#define OGS_FATAL(...)
Definition Error.h:19
Wraps a pair of iterators for use as a range in range-based for-loops.
std::vector< T > excludeObjectCopy(std::vector< T > const &src_vec, std::vector< std::size_t > const &exclude_positions)
Definition Algorithm.h:35
std::size_t findIndex(Container const &container, typename Container::value_type const &element)
Definition Algorithm.h:236
void insertIfKeyUniqueElseError(Map &map, Key const &key, Value &&value, std::string const &error_message)
Definition Algorithm.h:97
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:74
constexpr bool none_of(List const &values)
Checks if none of the elements in the given list are true.
Definition Algorithm.h:318
void cleanupVectorElements(std::vector< T * > &items)
Definition Algorithm.h:249
void uniquePushBack(Container &container, typename Container::value_type const &element)
Definition Algorithm.h:209
constexpr bool all_of(List const &values)
Checks if all of the elements in the given list are true.
Definition Algorithm.h:302
OGS_NO_DANGLING Container::value_type const & getIfOrError(Container const &container, Predicate &&predicate, std::string const &error_message)
Definition Algorithm.h:156
std::vector< ranges::range_value_t< R > > sizesToOffsets(R const &sizes)
Definition Algorithm.h:276
void reorderVector(std::vector< ValueType > &v, std::vector< IndexType > const &order)
Definition Algorithm.h:196
OGS_NO_DANGLING Map::mapped_type & getOrError(Map &map, Key const &key, std::string const &error_message)
Definition Algorithm.h:111
void makeVectorUnique(std::vector< T > &v)
Definition Algorithm.h:173
std::optional< typename Container::value_type > findFirstNotEqualElement(Container const &container, typename Container::value_type const &element)
Definition Algorithm.h:220
constexpr bool any_of(List const &values)
Checks if any of the elements in the given list is true.
Definition Algorithm.h:286