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 <set>
17#include <string>
18#include <typeindex>
19#include <typeinfo>
20#include <utility>
21
22#include "CompilerWorkarounds.h"
23#include "Error.h"
24
25namespace BaseLib
26{
35template <typename T>
36std::vector<T> excludeObjectCopy(
37 std::vector<T> const& src_vec,
38 std::vector<std::size_t> const& exclude_positions)
39{
40 std::vector<T> dest_vec;
41 if (exclude_positions.empty())
42 {
43 dest_vec = src_vec;
44 return dest_vec;
45 }
46
47 assert(exclude_positions.back() < src_vec.size());
48
49 std::copy_n(src_vec.cbegin(), exclude_positions[0],
50 std::back_inserter(dest_vec));
51 for (std::size_t i = 1; i < exclude_positions.size(); ++i)
52 {
53 std::copy_n(src_vec.cbegin() + exclude_positions[i - 1] + 1,
54 exclude_positions[i] - (exclude_positions[i - 1] + 1),
55 std::back_inserter(dest_vec));
56 }
57 std::copy(src_vec.cbegin() + exclude_positions.back() + 1, src_vec.cend(),
58 std::back_inserter(dest_vec));
59
60 return dest_vec;
61}
62
63template <typename T>
64void excludeObjectCopy(std::vector<T> const& src_vec,
65 std::vector<std::size_t> const& exclude_positions,
66 std::vector<T>& dest_vec)
67{
68 dest_vec = excludeObjectCopy(src_vec, exclude_positions);
69}
70
74template <ranges::input_range Range>
75ranges::range_reference_t<Range> findElementOrError(
76 Range& range,
77 std::predicate<ranges::range_reference_t<Range>> auto&& predicate,
78 std::invocable auto error_callback)
79{
80 auto it =
81 ranges::find_if(range, std::forward<decltype(predicate)>(predicate));
82 if (it == ranges::end(range))
83 {
84 error_callback();
86 "Element not found in the input range. The user provided error "
87 "callback is meant not to return. That has not happened.");
88 }
89 return *it;
90}
91
97template <typename Map, typename Key, typename Value>
98void insertIfKeyUniqueElseError(Map& map, Key const& key, Value&& value,
99 std::string const& error_message)
100{
101 auto const inserted = map.emplace(key, std::forward<Value>(value));
102 if (!inserted.second)
103 { // insertion failed, i.e., key already exists
104 OGS_FATAL("{} Key `{}' already exists.", error_message, key);
105 }
106}
107
111template <typename Map, typename Key>
112OGS_NO_DANGLING typename Map::mapped_type& getOrError(
113 Map& map, Key const& key, std::string const& error_message)
114{
115 auto it = map.find(key);
116 if (it == map.end())
117 {
118 if constexpr (std::is_convertible<Key, std::string>::value)
119 {
120 OGS_FATAL("{:s} Key `{:s}' does not exist.", error_message, key);
121 }
122 else
123 {
124 OGS_FATAL("{:s} Key `{:s}' does not exist.", error_message,
125 std::to_string(key));
126 }
127 }
128
129 return it->second;
130}
131
132template <typename Map, typename Key>
133OGS_NO_DANGLING typename Map::mapped_type const& getOrError(
134 Map const& map, Key const& key, std::string const& error_message)
135{
136 auto it = map.find(key);
137 if (it == map.end())
138 {
139 if constexpr (std::is_convertible<Key, std::string>::value)
140 {
141 OGS_FATAL("{:s} Key `{:s}' does not exist.", error_message, key);
142 }
143 else
144 {
145 OGS_FATAL("{:s} Key `{:s}' does not exist.", error_message,
146 std::to_string(key));
147 }
148 }
149
150 return it->second;
151}
152
156template <typename Container, typename Predicate>
157OGS_NO_DANGLING typename Container::value_type const& getIfOrError(
158 Container const& container,
159 Predicate&& predicate,
160 std::string const& error_message)
161{
162 auto it = std::find_if(begin(container), end(container), predicate);
163 if (it == end(container))
164 {
165 OGS_FATAL("Could not find element matching the predicate: {:s}",
166 error_message);
167 }
168 return *it;
169}
170
175template <ranges::input_range Range>
176 requires std::totally_ordered<ranges::range_value_t<Range>> &&
177 std::copyable<ranges::range_value_t<Range>>
178std::vector<ranges::range_value_t<Range>> getDuplicates(Range&& range)
179{
180 using Element = ranges::range_value_t<Range>;
181
182 std::set<Element> seen;
183 std::set<Element> duplicates;
184 for (auto const& element : range)
185 {
186 if (!seen.insert(element).second)
187 {
188 duplicates.insert(element);
189 }
190 }
191
192 return {duplicates.begin(), duplicates.end()};
193}
194
197template <typename T>
198void makeVectorUnique(std::vector<T>& v)
199{
200 std::sort(v.begin(), v.end());
201 auto it = std::unique(v.begin(), v.end());
202 v.erase(it, v.end());
203}
204
207template <typename T, class Compare>
208void makeVectorUnique(std::vector<T>& v, Compare comp)
209{
210 std::sort(v.begin(), v.end(), comp);
211 auto it = std::unique(v.begin(), v.end());
212 v.erase(it, v.end());
213}
214
220template <typename ValueType, typename IndexType>
221void reorderVector(std::vector<ValueType>& v,
222 std::vector<IndexType> const& order)
223{
224 std::vector<ValueType> temp_v(v.size());
225 temp_v.swap(v);
226
227 for (std::size_t i = 0; i < order.size(); i++)
228 {
229 std::swap(v[i], temp_v[order[i]]);
230 }
231}
232
233template <typename Container>
234void uniquePushBack(Container& container,
235 typename Container::value_type const& element)
236{
237 if (std::find(container.begin(), container.end(), element) ==
238 container.end())
239 {
240 container.push_back(element);
241 }
242}
243
244template <typename Container>
245std::optional<typename Container::value_type> findFirstNotEqualElement(
246 Container const& container, typename Container::value_type const& element)
247{
248 auto const it =
249 std::find_if_not(container.begin(), container.end(),
250 [&element](typename Container::value_type const& e)
251 { return e == element; });
252 return it == container.end() ? std::nullopt : std::make_optional(*it);
253}
254
260template <typename Container>
261std::size_t findIndex(Container const& container,
262 typename Container::value_type const& element)
263{
264 auto const it = std::find(container.begin(), container.end(), element);
265 if (it == container.end())
266 {
267 return std::numeric_limits<std::size_t>::max();
268 }
269 return std::distance(container.begin(), it);
270}
271
273template <typename T>
274void cleanupVectorElements(std::vector<T*>& items)
275{
276 for (auto item : items)
277 {
278 delete item;
279 }
280 items.clear();
281}
282
290template <typename T1, typename... Args>
291void cleanupVectorElements(std::vector<T1*>& dependent_items, Args&&... args)
292{
293 cleanupVectorElements(dependent_items);
294 cleanupVectorElements(std::forward<Args>(args)...);
295}
296
299template <ranges::range R>
300 requires std::is_integral_v<ranges::range_value_t<R>>
301std::vector<ranges::range_value_t<R>> sizesToOffsets(R const& sizes)
302{
303 return ranges::views::concat(
304 ranges::views::single(ranges::range_value_t<R>{0}),
305 ranges::views::partial_sum(sizes)) |
306 ranges::to<std::vector<ranges::range_value_t<R>>>();
307}
308
310template <typename List>
311constexpr bool any_of(List const& values)
312{
313 // std::any_of is not constexpr enough in some STLs
314 for (auto& value : values)
315 {
316 if (static_cast<bool>(value))
317 {
318 return true;
319 }
320 }
321
322 return false;
323}
324
326template <typename List>
327constexpr bool all_of(List const& values)
328{
329 // std::all_of is not constexpr enough in some STLs
330 for (auto& value : values)
331 {
332 if (!static_cast<bool>(value))
333 {
334 return false;
335 }
336 }
337
338 return true;
339}
340
342template <typename List>
343constexpr bool none_of(List const& values)
344{
345 return !any_of(values);
346}
347
352template <class... Ts>
353struct Overloaded : Ts...
354{
355 using Ts::operator()...;
356};
357#if defined(__clang__)
358#if (__clang_major__ <= 16)
360template <class... Ts>
361Overloaded(Ts...) -> Overloaded<Ts...>;
362#endif
363#endif
364
365} // namespace BaseLib
#define OGS_NO_DANGLING
#define OGS_FATAL(...)
Definition Error.h:10
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:36
std::vector< ranges::range_value_t< Range > > getDuplicates(Range &&range)
Definition Algorithm.h:178
std::size_t findIndex(Container const &container, typename Container::value_type const &element)
Definition Algorithm.h:261
void insertIfKeyUniqueElseError(Map &map, Key const &key, Value &&value, std::string const &error_message)
Definition Algorithm.h:98
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:75
constexpr bool none_of(List const &values)
Checks if none of the elements in the given list are true.
Definition Algorithm.h:343
void cleanupVectorElements(std::vector< T * > &items)
Definition Algorithm.h:274
void uniquePushBack(Container &container, typename Container::value_type const &element)
Definition Algorithm.h:234
constexpr bool all_of(List const &values)
Checks if all of the elements in the given list are true.
Definition Algorithm.h:327
OGS_NO_DANGLING Container::value_type const & getIfOrError(Container const &container, Predicate &&predicate, std::string const &error_message)
Definition Algorithm.h:157
std::vector< ranges::range_value_t< R > > sizesToOffsets(R const &sizes)
Definition Algorithm.h:301
void reorderVector(std::vector< ValueType > &v, std::vector< IndexType > const &order)
Definition Algorithm.h:221
OGS_NO_DANGLING Map::mapped_type & getOrError(Map &map, Key const &key, std::string const &error_message)
Definition Algorithm.h:112
void makeVectorUnique(std::vector< T > &v)
Definition Algorithm.h:198
std::optional< typename Container::value_type > findFirstNotEqualElement(Container const &container, typename Container::value_type const &element)
Definition Algorithm.h:245
constexpr bool any_of(List const &values)
Checks if any of the elements in the given list is true.
Definition Algorithm.h:311