stl_util.h Source File

CPP API: stl_util.h Source File
stl_util.h
Go to the documentation of this file.
1 /*
2 * Copyright (C) 2020-2026 MEmilio
3 *
4 * Authors: Daniel Abele
5 *
6 * Contact: Martin J. Kuehn <Martin.Kuehn@DLR.de>
7 *
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 */
20 #ifndef MIO_UTIL_STL_UTIL_H
21 #define MIO_UTIL_STL_UTIL_H
22 
23 #include <array>
24 #include <concepts>
25 #include <filesystem>
26 #include <numeric>
27 #include <vector>
28 #include <algorithm>
29 #include <utility>
30 #include <iterator>
31 #include <iostream>
32 #include <iomanip>
33 #include <cstring>
34 #include <cassert>
35 #include <memory>
36 
38 template <class T>
39 std::ostream& operator<<(std::ostream& out, const std::vector<T>& vec)
40 {
41  out << "{";
42  // use size - 1 and handle the last entry separately, for nicer separator usage
43  for (size_t i = 0; i < vec.size() - 1; i++) {
44  out << vec[i] << ", ";
45  }
46  if (!vec.empty()) {
47  out << vec.back();
48  }
49  out << "}";
50  return out;
51 }
52 
53 namespace mio
54 {
55 
65 inline std::ostream& set_ostream_format(std::ostream& out, size_t width, size_t precision, char fill = ' ')
66 {
67  // Note: ostream& operator<< returns a reference to itself
68  return out << std::setw(width) << std::fixed << std::setprecision(precision) << std::setfill(fill);
69 }
70 
81 template <typename T, typename Pred>
82 void insert_sorted_replace(std::vector<T>& vec, T const& item, Pred pred)
83 {
84  auto bounds = std::equal_range(begin(vec), end(vec), item, pred);
85  auto lb = bounds.first;
86  auto ub = bounds.second;
87  assert(ub - lb <= 1); //input vector contains at most one item that is equal to the new item
88  if (ub - lb == 1) {
89  *lb = item;
90  return;
91  }
92  else {
93  vec.insert(lb, item);
94  return;
95  }
96 }
97 
98 template <typename T>
99 void insert_sorted_replace(std::vector<T>& vec, T const& item)
100 {
101  return insert_sorted_replace(vec, item, std::less<T>());
102 }
103 
111 template <class Iterator, class Sentinel = Iterator>
112  requires std::input_or_output_iterator<Iterator> && std::input_or_output_iterator<Sentinel> &&
113  std::equality_comparable_with<Iterator, Sentinel>
114 class Range
115 {
116  // TODO: Make this a thin wrapper for std::ranges::subrange, once we have the ranges library (min libc++ version 16)
117 public:
118  // Type definitions for STL compatible containers.
119  using iterator = Iterator;
121  using reverse_iterator = std::reverse_iterator<iterator>;
122  using const_reverse_iterator = std::reverse_iterator<const_iterator>;
123  using value_type = typename std::iterator_traits<iterator>::value_type;
124  using reference = typename std::iterator_traits<iterator>::reference;
125 
127  Range(Iterator begin, Sentinel end)
128  : m_iterator(std::move(begin))
129  , m_sentinel(std::move(end))
130  {
131  }
133  template <class T>
134  Range(T&& range)
135  : m_iterator(std::forward<T>(range).begin())
136  , m_sentinel(std::forward<T>(range).end())
137  {
138  }
140  template <class I, class S>
141  Range(std::pair<I, S> iterator_pair)
142  : m_iterator(std::move(iterator_pair).first)
143  , m_sentinel(std::move(iterator_pair).second)
144  {
145  }
146 
148  Iterator begin() const
149  {
150  return m_iterator;
151  }
153  Sentinel end() const
154  {
155  return m_sentinel;
156  }
157 
159  reference front() const
160  requires std::forward_iterator<iterator>
161  {
162  return *(begin());
163  }
165  reference back() const
166  requires std::bidirectional_iterator<iterator>
167  {
168  return *(--end());
169  }
170 
172  size_t size() const
173  {
174  return static_cast<size_t>(std::distance(begin(), end()));
175  }
177  bool empty() const
178  {
179  return size() == 0;
180  }
181 
188  reference operator[](size_t index) const
189  {
190  assert(index < size());
191  auto it = begin();
192  std::advance(it, index);
193  return *it;
194  }
195 
197  decltype(auto) rbegin() const
198  requires std::bidirectional_iterator<iterator>
199  {
200  return std::make_reverse_iterator(end());
201  }
203  decltype(auto) rend() const
204  requires std::bidirectional_iterator<iterator>
205  {
206  return std::make_reverse_iterator(begin());
207  }
208 
209 private:
210  Iterator m_iterator;
211  Sentinel m_sentinel;
212 };
213 
215 template <class I, class S>
216 Range(std::pair<I, S> iterator_pair) -> Range<I, S>;
217 
219 template <class T>
220 Range(T&& range) -> Range<decltype(range.begin()), decltype(range.end())>;
221 
223 template <class T>
224 concept HasOstreamOperator = requires(std::ostream os, T t) { os << t; };
225 
238 template <class String, class... Strings>
239 std::string path_join(String&& base, Strings&&... app)
240 {
241  std::filesystem::path p(base);
242  ((p /= std::filesystem::path(app)), ...);
243  return p.string();
244 }
245 
254 template <class U, class T>
255 std::unique_ptr<U> dynamic_unique_ptr_cast(std::unique_ptr<T>&& base_ptr)
256 {
257  auto tmp_base_ptr = std::move(base_ptr);
258  U* tmp = dynamic_cast<U*>(tmp_base_ptr.get());
259  std::unique_ptr<U> derived_ptr;
260  if (tmp != nullptr) {
261  tmp_base_ptr.release();
262  derived_ptr.reset(tmp);
263  }
264  return derived_ptr;
265 }
266 
270 template <class Iter, class Pred>
271 bool contains(Iter b, Iter e, Pred p)
272 {
273  return find_if(b, e, p) != e;
274 }
275 
288 template <class T>
289 constexpr std::array<T, size_t(T::Count)> enum_members()
290 {
291  auto enum_members = std::array<T, size_t(T::Count)>{};
292  auto indices = std::array<std::underlying_type_t<T>, size_t(T::Count)>{};
293  std::iota(indices.begin(), indices.end(), std::underlying_type_t<T>(0));
294  std::transform(indices.begin(), indices.end(), enum_members.begin(), [](auto i) {
295  return T(i);
296  });
297  return enum_members;
298 }
299 
307 template <class T>
308 using VectorRange =
309  std::conditional_t<std::is_const_v<T>,
312 
313 } // namespace mio
314 
315 #endif // MIO_UTIL_STL_UTIL_H
A range of items defined by two iterators.
Definition: stl_util.h:115
std::reverse_iterator< iterator > reverse_iterator
Definition: stl_util.h:121
Range(Iterator begin, Sentinel end)
Directly construct a Range from two iterators.
Definition: stl_util.h:127
Iterator iterator
Definition: stl_util.h:119
Range(std::pair< I, S > iterator_pair)
Construct a Range from an std::pair of iterators.
Definition: stl_util.h:141
typename std::iterator_traits< iterator >::reference reference
Definition: stl_util.h:124
iterator const_iterator
Definition: stl_util.h:120
reference front() const requires std Sentinel m_sentinel
Get a reference to the first element in the range.
Definition: stl_util.h:159
Range(T &&range)
Construct a Range from another range.
Definition: stl_util.h:134
std::reverse_iterator< const_iterator > const_reverse_iterator
Definition: stl_util.h:122
Sentinel end() const
Get an iterator at the end of the range, pointing to one element after the last in the range.
Definition: stl_util.h:153
Iterator begin() const
Get an iterator to the start of the range, pointing at the first element of the range.
Definition: stl_util.h:148
typename std::iterator_traits< iterator >::value_type value_type
Definition: stl_util.h:123
int size(Comm comm)
Return the size of the given communicator.
Definition: miompi.cpp:75
A collection of classes to simplify handling of matrix shapes in meta programming.
Definition: models/abm/analyze_result.h:30
requires details::IsElementReference< M > RowMajorIterator< M, false > end(M &m)
create a non-const end iterator for the matrix m.
Definition: eigen_util.h:449
Range(std::pair< I, S > iterator_pair) -> Range< I, S >
Deduction guide to correctly deduce range type when constructed from a pair.
auto i
Definition: io.h:810
concept HasOstreamOperator
Concept to check if type T has an existing stream output operator "<<".
Definition: stl_util.h:224
std::unique_ptr< U > dynamic_unique_ptr_cast(std::unique_ptr< T > &&base_ptr)
converts a unique_ptr<T> to unique_ptr.
Definition: stl_util.h:255
std::conditional_t< std::is_const_v< T >, typename mio::Range< typename std::vector< std::remove_const_t< T > >::const_iterator >, typename mio::Range< typename std::vector< std::remove_const_t< T > >::iterator > > VectorRange
Defines generic Range type for IterPair of a vector.
Definition: stl_util.h:311
requires(!std::is_trivial_v< T >) void BinarySerializerObject
Definition: binary_serializer.h:333
std::ostream & set_ostream_format(std::ostream &out, size_t width, size_t precision, char fill=' ')
Adds manipulators for width, (fixed) precision and fill character to an ostream.
Definition: stl_util.h:65
constexpr std::array< T, size_t(T::Count)> enum_members()
Get an std::array that contains all members of an enum class.
Definition: stl_util.h:289
requires details::IsElementReference< M > RowMajorIterator< M, false > begin(M &m)
create a non-const iterator to first element of the matrix m.
Definition: eigen_util.h:421
std::string path_join(String &&base, Strings &&... app)
join one ore more strings with path separators.
Definition: stl_util.h:239
void insert_sorted_replace(std::vector< T > &vec, T const &item, Pred pred)
inserts element in a sorted vector, replacing items that are equal precondition: elements in the vect...
Definition: stl_util.h:82
bool contains(Iter b, Iter e, Pred p)
checks if there is an element in this range that matches a predicate
Definition: stl_util.h:271
Definition: io.h:95
std::ostream & operator<<(std::ostream &out, const std::vector< T > &vec)
Stream operator for writing std::vector to an std::ostream. Requires that T has a viable overload its...
Definition: stl_util.h:39