faunus
auxiliary.h
Go to the documentation of this file.
1 #pragma once
2 #include "average.h"
3 #include <nlohmann/json.hpp>
4 #include <ranges>
5 #include <functional>
6 #include <iterator>
7 #include <fstream>
8 #include <vector>
9 #include <string>
10 #include <sstream>
11 #include <concepts>
12 
20 namespace Faunus {
21 
30 template <std::integral TOut, std::floating_point TIn> inline TOut numeric_cast(const TIn number)
31 {
32  if (std::isfinite(number)) {
33  // The number is finite ...
34  if (number < std::nextafter(static_cast<TIn>(std::numeric_limits<TOut>::max()), 0) &&
35  number > std::nextafter(static_cast<TIn>(std::numeric_limits<TOut>::min()), 0)) {
36  // ... and fits into the integral type range.
37  // The nextafter function is used to mitigate possible rounding up or down.
38  return static_cast<TOut>(number >= 0 ? number + TIn(0.5)
39  : number - TIn(0.5)); // round before cast
40  }
41  }
42  // not-a-number, infinite, or outside the representable range
43  throw std::overflow_error("numeric cast overflow");
44 }
45 
54 template <std::forward_iterator Titer, typename Tfunction, typename T = double,
55  typename Taggregate_function>
56 T for_each_unique_pair(Titer begin, Titer end, Tfunction f,
57  Taggregate_function aggregator = std::plus<T>())
58 {
59  T x = T();
60  for (auto i = begin; i != end; ++i) {
61  for (auto j = i; ++j != end;) {
62  x = aggregator(x, f(*i, *j));
63  }
64  }
65  return x;
66 }
67 
69 template <std::ranges::range T> T erase_range(T target, const T& values)
70 {
71  target.erase(std::remove_if(target.begin(), target.end(),
72  [&](auto i) {
73  return std::find(values.begin(), values.end(), i) !=
74  values.end();
75  }),
76  target.end());
77  return target;
78 }
79 
88 template <class T> struct ordered_pair : public std::pair<T, T>
89 {
90  using base = std::pair<T, T>;
91  ordered_pair() = default;
92 
93  ordered_pair(const T& a, const T& b)
94  : base(std::minmax(a, b))
95  {
96  }
97 
98  bool contains(const T& value) const { return value == base::first || value == base::second; }
99 };
100 
118 template <std::floating_point T, std::integral Tint = int> Tint to_bin(T x, T dx = 1)
119 {
120  return (x < 0) ? Tint(x / dx - 0.5) : Tint(x / dx + 0.5);
121 }
122 
145 template <std::floating_point Tfloat = double> class Quantize
146 {
147  private:
148  Tfloat xmin, dx, x;
149 
150  public:
156  Quantize(Tfloat dx, Tfloat xmin = 0)
157  : xmin(xmin)
158  , dx(dx)
159  {
160  }
161 
163  Quantize& operator=(Tfloat val)
164  {
165  assert(val >= xmin);
166  if (val >= 0) {
167  x = int(val / dx + 0.5) * dx;
168  }
169  else {
170  x = int(val / dx - 0.5) * dx;
171  }
172  assert(x >= xmin);
173  return *this;
174  }
175 
176  Quantize& frombin(unsigned int i)
177  {
178  x = i * dx + xmin;
179  return *this;
180  }
181 
183  Quantize& operator()(Tfloat val)
184  {
185  *this = val;
186  return *this;
187  }
188 
190  template <typename T> operator T()
191  {
192  if (std::is_integral<T>::value) {
193  return T((x - xmin) / dx + 0.5);
194  }
195  return x;
196  }
197 };
198 
199 template <class T>
200 concept StringStreamable = requires(T a) {
201  { std::istringstream() >> a };
202  { std::ostringstream() << a };
203 };
204 
214 template <StringStreamable T> auto splitConvert(const std::string& words)
215 {
216  auto stream = std::istringstream(words);
217  return std::vector<T>(std::istream_iterator<T>(stream), std::istream_iterator<T>());
218 } // space separated string to vector of values
219 
225 template <std::ranges::range Range>
226 std::string joinToString(const Range& values)
227  requires StringStreamable<std::ranges::range_value_t<Range>>
228 {
229  std::ostringstream o;
230  if (!values.empty()) {
231  o << *values.begin();
232  std::for_each(std::next(values.begin()), values.end(), [&](auto& val) { o << " " << val; });
233  }
234  return o.str();
235 }
236 
237 template <typename T> struct BasePointerVector
238 {
239  using value_type = std::shared_ptr<T>;
240  std::vector<value_type> vec;
241 
242  auto begin() noexcept { return vec.begin(); }
243 
244  auto begin() const noexcept { return vec.begin(); }
245 
246  auto end() noexcept { return vec.end(); }
247 
248  auto end() const noexcept { return vec.end(); }
249 
250  auto empty() const noexcept { return vec.empty(); }
251 
252  auto size() const noexcept { return vec.size(); }
253 
254  auto& back() noexcept { return vec.back(); }
255 
256  auto& back() const noexcept { return vec.back(); }
257 
258  auto& front() noexcept { return vec.front(); }
259 
260  auto& front() const noexcept { return vec.front(); }
261 
262  auto& at(size_t n) { return vec.at(n); }
263 
264  auto& at(size_t n) const { return vec.at(n); }
265 
266  template <typename Tderived, class... Args,
267  class = std::enable_if_t<std::is_base_of<T, Tderived>::value>>
268  void emplace_back(Args&... args)
269  {
270  vec.push_back(std::make_shared<Tderived>(args...));
271  }
272 
273  template <typename Tderived, class... Args,
274  class = std::enable_if_t<std::is_base_of<T, Tderived>::value>>
275  void emplace_back(const Args&... args)
276  {
277  vec.push_back(std::make_shared<Tderived>(args...));
278  }
279 
280  // template <typename Tderived, class Arg, class = std::enable_if_t<std::is_base_of<T,
281  // Tderived>::value>> auto& push_back(std::shared_ptr<Arg> arg) {
282  // vec.push_back(arg);
283  // return vec.back(); // reference to element just added
284  // } //!< Append a pointer to a (derived) instance to the vector
285 
286  auto& push_back(value_type arg)
287  {
288  vec.push_back(arg);
289  return vec.back(); // reference to element just added
290  }
291 
292  template <typename Tderived, class = std::enable_if_t<std::is_base_of<T, Tderived>::value>>
294  {
295  vec.assign(d.vec.begin(), d.vec.end());
296  return *this;
297  }
298 
299  template <typename Tderived, class = std::enable_if_t<std::is_base_of<T, Tderived>::value>>
300  auto find() const
301  {
303  for (auto& base : vec) {
304  if (auto derived = std::dynamic_pointer_cast<Tderived>(base); derived) {
305  _v.push_back(derived);
306  }
307  }
308  return _v;
309  }
310 
311  template <typename Tderived, class = std::enable_if_t<std::is_base_of<T, Tderived>::value>>
312  std::shared_ptr<Tderived> findFirstOf() const
313  {
314  for (auto& base : vec) {
315  if (auto derived = std::dynamic_pointer_cast<Tderived>(base); derived) {
316  return derived;
317  }
318  }
319  return nullptr;
320  }
321 
322  template <typename U>
323  friend void to_json(nlohmann::json&,
324  const BasePointerVector<U>&);
325 };
326 
327 template <typename T> void to_json(nlohmann::json& j, const BasePointerVector<T>& b)
328 {
329  using namespace std::string_literals;
330  try {
331  for (auto& shared_ptr : b.vec) {
332  j.push_back(*shared_ptr);
333  }
334  }
335  catch (const std::exception& e) {
336  throw std::runtime_error("error converting to json: "s + e.what());
337  }
338 }
339 
340 template <typename T> void from_json(const nlohmann::json& j, BasePointerVector<T>& b)
341 {
342  using namespace std::string_literals;
343  try {
344  for (const auto& it : j) {
345  std::shared_ptr<T> ptr = it;
346  b.push_back(ptr);
347  }
348  }
349  catch (const std::exception& e) {
350  throw std::runtime_error("error converting from json: "s + e.what());
351  }
352 }
353 } // namespace Faunus
auto splitConvert(const std::string &words)
Convert space separated words into vector of type T.
Definition: auxiliary.h:214
void emplace_back(const Args &... args)
Create an (derived) instance and append a pointer to it to the vector.
Definition: auxiliary.h:275
Tint to_bin(T x, T dx=1)
Round a floating point to integer for use with histogram binning.
Definition: auxiliary.h:118
double T
floating point size
Definition: units.h:73
Quantize(Tfloat dx, Tfloat xmin=0)
Constructor.
Definition: auxiliary.h:156
T for_each_unique_pair(Titer begin, Titer end, Tfunction f, Taggregate_function aggregator=std::plus< T >())
Iterate over pairs in container, call a function on the elements, and sum results.
Definition: auxiliary.h:56
T erase_range(T target, const T &values)
Erase from target range all values found in values range.
Definition: auxiliary.h:69
std::string joinToString(const Range &values) requires StringStreamable< std
Convert range of values into space separated string.
Definition: auxiliary.h:226
auto & operator=(const BasePointerVector< Tderived > &d)
Allow assignment to a vector of ancestors.
Definition: auxiliary.h:293
Ordered pair where first<=second
Definition: auxiliary.h:88
Cell list class templates.
Definition: actions.cpp:11
void emplace_back(Args &... args)
Create an (derived) instance and append a pointer to it to the vector.
Definition: auxiliary.h:268
TOut numeric_cast(const TIn number)
Convert floating point number to integral number.
Definition: auxiliary.h:30
std::vector< value_type > vec
Vector of shared pointers to base class.
Definition: auxiliary.h:240
auto & push_back(value_type arg)
Append a pointer to a (derived) instance to the vector.
Definition: auxiliary.h:286
Helper class for storing vectors of base pointers.
Definition: auxiliary.h:237
Quantize & operator=(Tfloat val)
Assigment operator.
Definition: auxiliary.h:163
Round and bin numbers for use with tables and histograms.
Definition: auxiliary.h:145
Quantize & operator()(Tfloat val)
Assignment with function operator.
Definition: auxiliary.h:183
auto find() const
Pointer list to all matching type.
Definition: auxiliary.h:300