Rivet API documentation

Rivet 4.1.3
Utils.hh
1// -*- C++ -*-
2#ifndef RIVET_Utils_HH
3#define RIVET_Utils_HH
4
5#include "Rivet/Tools/Exceptions.hh"
6#include "Rivet/Tools/PrettyPrint.hh"
7#include "Rivet/Tools/RivetSTL.hh"
8#include "Rivet/Tools/TypeTraits.hh"
9#include <cctype>
10#include <cerrno>
11#include <cfloat>
12#include <climits>
13#include <cmath>
14#include <functional>
15#include <limits>
16#include <numeric>
17#include <ostream>
18#include <sstream>
19#include <stdexcept>
20
22
23
25#ifndef DEPRECATED
26 #if __GNUC__ && __cplusplus && RIVET_NO_DEPRECATION_WARNINGS == 0
27 #define DEPRECATED(x) __attribute__((deprecated(x)))
28 #else
29 #define DEPRECATED(x)
30 #endif
31#endif
32
33
34namespace Rivet {
35
36
38 static constexpr double DBL_NAN = std::numeric_limits<double>::quiet_NaN();
39
40
46 template <typename T>
47 inline T& maybe(const T& x, std::function<bool(const T&)> fn, const T& fallback) {
48 return fn(x) ? x : fallback;
49 }
50
51
54
56 struct bad_lexical_cast : public std::runtime_error {
57 bad_lexical_cast(const std::string& what)
58 : std::runtime_error(what) { }
59 };
60
62 template <typename T, typename U>
63 T lexical_cast(const U& in) {
64 try {
65 std::stringstream ss;
66 ss << in;
67 T out;
68 ss >> out;
69 return out;
70 }
71 catch (const std::exception& e) {
72 throw bad_lexical_cast(e.what());
73 }
74 }
75
79 template <typename T>
80 inline string to_str(const T& x) {
81 return lexical_cast<string>(x);
82 }
83
85 inline string& ireplace_first(string& str, const string& patt, const string& repl) {
86 if (!contains(str, patt)) return str; //< contains from RivetSTL
87 str.replace(str.find(patt), patt.size(), repl);
88 return str;
89 }
90
94 template <typename T>
95 inline string toString(T&& x) {
96 return to_str(std::forward<T>(x));
97 }
98
100 template <typename T>
101 inline string toStr(T&& x) {
102 return to_str(std::forward<T>(x));
103 }
104
105
107 inline string replace_first(string str, const string& patt, const string& repl) {
108 return ireplace_first(str, patt, repl);
109 }
110
116 inline string& ireplace_all(string& str, const string& patt, const string& repl) {
117 if (!contains(str, patt)) return str; //< contains from RivetSTL
118 while (true) {
119 string::size_type it = str.find(patt);
120 if (it == string::npos) break;
121 str.replace(it, patt.size(), repl);
122 }
123 return str;
124 }
125
131 inline string replace_all(string str, const string& patt, const string& repl) {
132 return ireplace_all(str, patt, repl);
133 }
134
135
137 inline int nocase_cmp(const string& s1, const string& s2) {
138 string::const_iterator it1 = s1.begin();
139 string::const_iterator it2 = s2.begin();
140 while ((it1 != s1.end()) && (it2 != s2.end())) {
141 if (::toupper(*it1) != ::toupper(*it2)) { // < Letters differ?
142 // Return -1 to indicate smaller than, 1 otherwise
143 return (::toupper(*it1) < ::toupper(*it2)) ? -1 : 1;
144 }
145 // Proceed to the next character in each string
146 ++it1;
147 ++it2;
148 }
149 size_t size1 = s1.size(), size2 = s2.size(); // Cache lengths
150 // Return -1,0 or 1 according to strings' lengths
151 if (size1 == size2) return 0;
152 return (size1 < size2) ? -1 : 1;
153 }
154
155
157 inline bool nocase_equals(const string& s1, const string& s2) {
158 return nocase_cmp(s1, s2) == 0;
159 }
160
161
163 inline string toLower(const string& s) {
164 string out = s;
165 std::transform(out.begin(), out.end(), out.begin(), (int (*)(int))std::tolower);
166 return out;
167 }
168
169
171 inline string toUpper(const string& s) {
172 string out = s;
173 std::transform(out.begin(), out.end(), out.begin(), (int (*)(int))std::toupper);
174 return out;
175 }
176
177
179 inline bool startsWith(const string& s, const string& start) {
180 if (s.length() < start.length()) return false;
181 return s.substr(0, start.length()) == start;
182 }
183
184
186 inline bool endsWith(const string& s, const string& end) {
187 if (s.length() < end.length()) return false;
188 return s.substr(s.length() - end.length()) == end;
189 }
190
191
192 // Terminating version of strjoin, for empty fargs list
193 inline string strcat() {
194 return "";
195 }
197 template <typename T, typename... Ts>
198 inline string strcat(T value, Ts... fargs) {
199 const string strthis = lexical_cast<string>(value);
200 const string strnext = strcat(fargs...);
201 return strnext.empty() ? strthis : strthis + strnext;
202 }
203
204
206 template <typename T>
207 inline string join(const vector<T>& v, const string& sep = " ") {
208 string rtn;
209 for (size_t i = 0; i < v.size(); ++i) {
210 if (i != 0) rtn += sep;
211 rtn += to_str(v[i]);
212 }
213 return rtn;
214 }
215
217 template <>
218 inline string join(const vector<string>& v, const string& sep) {
219 string rtn;
220 for (size_t i = 0; i < v.size(); ++i) {
221 if (i != 0) rtn += sep;
222 rtn += v[i];
223 }
224 return rtn;
225 }
226
228 template <typename T>
229 inline string join(const set<T>& s, const string& sep = " ") {
230 string rtn;
231 for (const T& x : s) {
232 if (rtn.size() > 0) rtn += sep;
233 rtn += to_str(x);
234 }
235 return rtn;
236 }
237
239 template <>
240 inline string join(const set<string>& s, const string& sep) {
241 string rtn;
242 for (const string& x : s) {
243 if (rtn.size() > 0) rtn += sep;
244 rtn += x;
245 }
246 return rtn;
247 }
248
250 inline vector<string> split(const string& s, const string& sep) {
251 vector<string> dirs;
252 string tmp = s;
253 while (true) {
254 const size_t delim_pos = tmp.find(sep);
255 if (delim_pos == string::npos) break;
256 const string dir = tmp.substr(0, delim_pos);
257 if (dir.length()) dirs.push_back(dir); // Don't insert "empties"
258 tmp.replace(0, delim_pos + 1, "");
259 }
260 if (tmp.length()) dirs.push_back(tmp); // Don't forget the trailing component!
261 return dirs;
262 }
263
265 inline string lpad(const string& s, size_t width, const string& padchar = " ") {
266 if (s.size() >= width) return s;
267 return string(width - s.size(), padchar[0]) + s;
268 }
269
271 inline string rpad(const string& s, size_t width, const string& padchar = " ") {
272 if (s.size() >= width) return s;
273 return s + string(width - s.size(), padchar[0]);
274 }
275
277
278
281
285 inline vector<string> pathsplit(const string& path) {
286 return split(path, ":");
287 }
288
293 inline string pathjoin(const vector<string>& paths) {
294 return join(paths, ":");
295 }
296
298 inline string operator/(const string& a, const string& b) {
299 // Ensure that a doesn't end with a slash, and b doesn't start with one, to avoid "//"
300 const string anorm = (a.find("/") != string::npos) ? a.substr(0, a.find_last_not_of("/") + 1) : a;
301 const string bnorm = (b.find("/") != string::npos) ? b.substr(b.find_first_not_of("/")) : b;
302 return anorm + "/" + bnorm;
303 }
304
306 inline string basename(const string& p) {
307 if (!contains(p, "/")) return p;
308 return p.substr(p.rfind("/") + 1);
309 }
310
312 inline string dirname(const string& p) {
313 if (!contains(p, "/")) return "";
314 return p.substr(0, p.rfind("/"));
315 }
316
318 inline string file_stem(const string& f) {
319 if (!contains(f, ".")) return f;
320 return f.substr(0, f.rfind("."));
321 }
322
324 inline string file_extn(const string& f) {
325 if (!contains(f, ".")) return "";
326 return f.substr(f.rfind(".") + 1);
327 }
328
330
331
334
336 template <typename CONTAINER, typename = std::enable_if_t<is_citerable_v<std::decay_t<CONTAINER>>>>
337 inline unsigned int count(const CONTAINER& c) {
338 // return std::count_if(std::begin(c), std::end(c), [](const typename CONTAINER::value_type& x){return bool(x);});
339 unsigned int rtn = 0;
340 for (const auto& x : c) {
341 if (bool(x)) rtn += 1;
342 }
343 return rtn;
344 }
345
346 // /// Return number of elements in the container @a c for which @c f(x) is true.
347 // template <typename CONTAINER>
348 // inline unsigned int count(const CONTAINER& c, const std::function<bool(typename CONTAINER::value_type)>& f) {
349 // return std::count_if(std::begin(c), std::end(c), f);
350 // }
351
353 template <typename CONTAINER,
354 typename FN,
355 //typename FN = bool(const typename std::decay_t<CONTAINER>::value_type&, const std::decay_t<T>&),
356 typename = std::enable_if_t<is_citerable_v<std::decay_t<CONTAINER>>>>
357 inline unsigned int count(const CONTAINER& c, const FN& f) {
358 return std::count_if(std::begin(c), std::end(c), f);
359 }
360
361
363 template <typename CONTAINER, typename = std::enable_if_t<is_citerable_v<std::decay_t<CONTAINER>>>>
364 inline bool any(const CONTAINER& c) {
365 // return std::any_of(std::begin(c), std::end(c), [](const auto& x){return bool(x);});
366 for (const auto& x : c) {
367 if (bool(x)) return true;
368 }
369 return false;
370 }
371
372 // /// Return true if f(x) is true for any x in container c, otherwise false.
373 // template <typename CONTAINER>
374 // inline bool any(const CONTAINER& c, const std::function<bool(typename CONTAINER::value_type)>& f) {
375 // return std::any_of(std::begin(c), std::end(c), f);
376 // }
377
379 template <
380 typename CONTAINER,
381 typename FN,
382 //typename FN = double(const typename std::decay_t<CONTAINER>::value_type&, const std::decay_t<T>&),
383 typename = std::enable_if_t<is_citerable_v<std::decay_t<CONTAINER>>>>
384 inline bool any(const CONTAINER& c, const FN& f) {
385 return std::any_of(std::begin(c), std::end(c), f);
386 }
387
388
390 template <typename CONTAINER, typename = std::enable_if_t<is_citerable_v<std::decay_t<CONTAINER>>>>
391 inline bool all(const CONTAINER& c) {
392 // return std::all_of(std::begin(c), std::end(c), [](const auto& x){return bool(x);});
393 for (const auto& x : c) {
394 if (!bool(x)) return false;
395 }
396 return true;
397 }
398
399 // /// Return true if @a f(x) is true for all @c x in container @a c, otherwise false.
400 // template <typename CONTAINER>
401 // inline bool all(const CONTAINER& c, const std::function<bool(typename CONTAINER::value_type)>& f) {
402 // return std::all_of(std::begin(c), std::end(c), f);
403 // }
404
406 template <
407 typename CONTAINER,
408 typename FN,
409 //typename FN = double(const typename std::decay_t<CONTAINER>::value_type&, const std::decay_t<T>&),
410 typename = std::enable_if_t<is_citerable_v<std::decay_t<CONTAINER>>>>
411 inline bool all(const CONTAINER& c, const FN& f) {
412 return std::all_of(std::begin(c), std::end(c), f);
413 }
414
415
417 template <typename CONTAINER, typename = std::enable_if_t<is_citerable_v<std::decay_t<CONTAINER>>>>
418 inline bool none(const CONTAINER& c) {
419 // return std::none_of(std::begin(c), std::end(c), [](){});
420 for (const auto& x : c) {
421 if (bool(x)) return false;
422 }
423 return true;
424 }
425
426 // /// Return true if @a f(x) is false for all @c x in container @a c, otherwise false.
427 // template <typename C>
428 // inline bool none(const C& c, const std::function<bool(typename C::value_type)>& f) {
429 // return std::none_of(std::begin(c), std::end(c), f);
430 // }
431
433 template <
434 typename CONTAINER,
435 typename FN,
436 //typename FN = double(const typename std::decay_t<CONTAINER>::value_type&, const std::decay_t<T>&),
437 typename = std::enable_if_t<is_citerable_v<std::decay_t<CONTAINER>>>>
438 inline bool none(const CONTAINER& c, const FN& f) {
439 return std::none_of(std::begin(c), std::end(c), f);
440 }
441
442
443 // /// A single-container-arg version of std::transform, aka @c map
444 // template <typename CONTAINER1, typename CONTAINER2>
445 // inline const CONTAINER2& transform(const CONTAINER1& in, CONTAINER2& out,
446 // const std::function<typename CONTAINER2::value_type(typename CONTAINER1::value_type)>& f) {
447 // out.clear(); out.resize(in.size());
448 // std::transform(in.begin(), in.end(), out.begin(), f);
449 // return out;
450 // }
451
453 template <typename CONTAINER1,
454 typename CONTAINER2,
455 typename FN = typename std::decay_t<CONTAINER2>::value_type(
456 const typename std::decay_t<CONTAINER1>::value_type::ParticleBase&),
457 typename = std::enable_if_t<is_citerable_v<std::decay_t<CONTAINER1>>
458 && is_citerable_v<std::decay_t<CONTAINER2>>>>
459 inline const CONTAINER2& transform(const CONTAINER1& in, CONTAINER2& out, FN&& f) {
460 out.clear();
461 out.resize(in.size());
462 std::transform(in.begin(), in.end(), out.begin(), std::forward<FN>(f));
463 return out;
464 }
465
469 template <typename CONTAINER1,
470 typename RTN,
471 typename = std::enable_if_t<is_citerable_v<std::decay_t<CONTAINER1>>>>
472 inline std::vector<RTN> transform(
473 const CONTAINER1& in,
474 const std::function<RTN(typename CONTAINER1::value_type::ParticleBase)>& f) {
475 std::vector<RTN> out;
476 transform(in, out, f);
477 return out;
478 }
479
480 // /// A single-container-arg version of std::accumulate, aka @c reduce
481 // template <typename CONTAINER1, typename T>
482 // inline T accumulate(const CONTAINER1& in, const T& init, const std::function<T(typename CONTAINER1::value_type)>& f) {
483 // const T rtn = std::accumulate(in.begin(), in.end(), init, f);
484 // return rtn;
485 // }
486
488 template <typename CONTAINER1,
489 typename T,
490 typename FN,
491 typename = std::enable_if_t<is_citerable_v<std::decay_t<CONTAINER1>>>>
492 inline T accumulate(const CONTAINER1& in, const T& init, const FN& f) {
493 const T rtn = std::accumulate(in.begin(), in.end(), init, f);
494 return rtn;
495 }
496
497
501 template <typename CONTAINER, typename = std::enable_if_t<is_citerable_v<std::decay_t<CONTAINER>>>>
502 inline typename CONTAINER::value_type sum(const CONTAINER& c) {
503 typename CONTAINER::value_type rtn; //< default construct return type
504 for (const auto& x : c) rtn += x;
505 return rtn;
506 }
507
511 template <typename CONTAINER,
512 typename T,
513 typename = std::enable_if_t<is_citerable_v<std::decay_t<CONTAINER>>>>
514 inline T sum(const CONTAINER& c, const T& start) {
515 T rtn = start;
516 for (const auto& x : c) {
517 rtn += x;
518 }
519 return rtn;
520 }
521
523 template <typename CONTAINER,
524 typename T,
525 typename FN = T(const typename std::decay_t<CONTAINER>::value_type::ParticleBase&),
526 typename = std::enable_if_t<is_citerable_v<std::decay_t<CONTAINER>>>>
527 inline T sum(const CONTAINER& c, FN&& fn, const T& start = T()) {
528 auto f = std::function(std::forward<FN>(fn));
529 T rtn = start;
530 for (const auto& x : c) {
531 rtn += fn(x);
532 }
533 return rtn;
534 }
535
536
540 template <typename CONTAINER,
541 typename T,
542 typename = std::enable_if_t<is_citerable_v<std::decay_t<CONTAINER>>>>
543 inline T& isum(const CONTAINER& c, T& out) {
544 for (const auto& x : c) {
545 out += x;
546 }
547 return out;
548 }
549
553 template <
554 typename CONTAINER,
555 typename FN,
556 typename T,
557 //typename FN = double(const typename std::decay_t<CONTAINER>::value_type&, const std::decay_t<T>&),
558 typename = std::enable_if_t<is_citerable_v<std::decay_t<CONTAINER>>>>
559 inline T& isum(const CONTAINER& c, const FN& f, T& out) {
560 for (const auto& x : c) {
561 out += f(x);
562 }
563 return out;
564 }
565
566
570 template <typename CONTAINER,
571 typename FN,
572 typename = std::enable_if_t<is_citerable_v<std::decay_t<CONTAINER>>>>
573 inline CONTAINER& idiscard(CONTAINER& c, const FN& f) {
574 const auto newend = std::remove_if(std::begin(c), std::end(c), f);
575 c.erase(newend, c.end());
576 return c;
577 }
578
580 template <typename CONTAINER, typename = std::enable_if_t<is_citerable_v<std::decay_t<CONTAINER>>>>
581 inline CONTAINER& idiscard(CONTAINER& c, const typename CONTAINER::value_type& y) {
582 return idiscard(c, [&](typename CONTAINER::value_type& x) { return x == y; });
583 }
584
586 template <typename CONTAINER, typename = std::enable_if_t<is_citerable_v<std::decay_t<CONTAINER>>>>
587 inline CONTAINER& idiscard_if_any(CONTAINER& c, const CONTAINER& ys) {
588 return idiscard(c, [&](typename CONTAINER::value_type& x) { return contains(ys, x); });
589 }
590
591
595 template <typename CONTAINER,
596 typename FN,
597 typename = std::enable_if_t<is_citerable_v<std::decay_t<CONTAINER>>>>
598 inline CONTAINER discard(const CONTAINER& c, const FN& f) {
599 CONTAINER rtn = c;
600 return idiscard(rtn, f);
601 }
602
604 template <typename CONTAINER, typename = std::enable_if_t<is_citerable_v<std::decay_t<CONTAINER>>>>
605 inline CONTAINER discard(const CONTAINER& c, const typename CONTAINER::value_type& y) {
606 return discard(c, [&](typename CONTAINER::value_type& x) { return x == y; });
607 }
608
610 template <typename CONTAINER, typename = std::enable_if_t<is_citerable_v<std::decay_t<CONTAINER>>>>
611 inline CONTAINER discard_if_any(const CONTAINER& c, const CONTAINER& ys) {
612 return discard(c, [&](typename CONTAINER::value_type& x) { return contains(ys, x); });
613 }
614
615
621 template <typename CONTAINER,
622 typename FN,
623 //typename FN = bool(const typename std::decay_t<CONTAINER>::value_type&, const std::decay_t<T>&),
624 typename = std::enable_if_t<is_citerable_v<std::decay_t<CONTAINER>>>>
625 inline CONTAINER& discard(const CONTAINER& c, const FN& f, CONTAINER& out) {
626 out = discard(c, f);
627 return out;
628 }
629
631 template <typename CONTAINER, typename = std::enable_if_t<is_citerable_v<std::decay_t<CONTAINER>>>>
632 inline CONTAINER& discard(const CONTAINER& c, const typename CONTAINER::value_type& y, CONTAINER& out) {
633 return discard(c, [&](typename CONTAINER::value_type& x) { return x == y; }, out);
634 }
635
637 template <typename CONTAINER, typename = std::enable_if_t<is_citerable_v<std::decay_t<CONTAINER>>>>
638 inline CONTAINER& discard_if_any(const CONTAINER& c, const CONTAINER& ys, CONTAINER& out) {
639 return discard(c, [&](typename CONTAINER::value_type& x) { return contains(ys, x); }, out);
640 }
641
642
646 template <typename CONTAINER,
647 typename FN,
648 typename = std::enable_if_t<is_citerable_v<std::decay_t<CONTAINER>>>>
649 inline CONTAINER& iselect(CONTAINER& c, const FN& f) {
650 auto invf = [&](const typename CONTAINER::value_type& x) {
651 return !f(x);
652 };
653 return idiscard(c, invf); //< yes, intentional!
654 }
655
656 // No single equality-comparison version for select, since that would be silly!
657
659 template <typename CONTAINER, typename = std::enable_if_t<is_citerable_v<std::decay_t<CONTAINER>>>>
660 inline CONTAINER& iselect_if_any(CONTAINER& c, const CONTAINER& ys) {
661 return iselect(c, [&](typename CONTAINER::value_type& x) { return contains(ys, x); });
662 }
663
664
668 template <typename CONTAINER,
669 typename FN,
670 typename = std::enable_if_t<is_citerable_v<std::decay_t<CONTAINER>>>>
671 inline CONTAINER select(const CONTAINER& c, const FN& f) {
672 CONTAINER rtn = c;
673 return iselect(
674 rtn,
675 f);
676 }
677
678 // No single equality-comparison version for select, since that would be silly!
679
681 template <typename CONTAINER, typename = std::enable_if_t<is_citerable_v<std::decay_t<CONTAINER>>>>
682 inline CONTAINER select_if_any(const CONTAINER& c, const CONTAINER& ys) {
683 return select(c, [&](typename CONTAINER::value_type& x) { return contains(ys, x); });
684 }
685
686
692 template <typename CONTAINER,
693 typename FN,
694 typename = std::enable_if_t<is_citerable_v<std::decay_t<CONTAINER>>>>
695 inline CONTAINER& select(const CONTAINER& c, const FN& f, CONTAINER& out) {
696 out = select(c, f);
697 return out;
698 }
699
700 // No single equality-comparison version for select, since that would be silly!
701
703 template <typename CONTAINER, typename = std::enable_if_t<is_citerable_v<std::decay_t<CONTAINER>>>>
704 inline CONTAINER& select_if_any(const CONTAINER& c, const CONTAINER& ys, CONTAINER& out) {
705 return select(c, [&](typename CONTAINER::value_type& x) { return contains(ys, x); }, out);
706 }
707
708
713 template <typename CONTAINER, typename = std::enable_if_t<is_citerable_v<std::decay_t<CONTAINER>>>>
714 inline CONTAINER slice(const CONTAINER& c, int i, int j) {
715 CONTAINER rtn;
716 const size_t off1 = (i >= 0) ? i : c.size() + i;
717 const size_t off2 = (j >= 0) ? j : c.size() + j;
718 if (off1 > c.size() || off2 > c.size()) throw RangeError("Attempting to slice beyond requested offsets");
719 if (off2 < off1) throw RangeError("Requested offsets in invalid order");
720 rtn.resize(off2 - off1);
721 std::copy(c.begin() + off1, c.begin() + off2, rtn.begin());
722 return rtn;
723 }
724
728 template <typename CONTAINER, typename = std::enable_if_t<is_citerable_v<std::decay_t<CONTAINER>>>>
729 inline CONTAINER slice(const CONTAINER& c, int i) {
730 return slice(c, i, c.size());
731 }
732
736 template <typename CONTAINER, typename = std::enable_if_t<is_citerable_v<std::decay_t<CONTAINER>>>>
737 inline CONTAINER head(const CONTAINER& c, int n) {
738 // if (n > c.size()) throw RangeError("Requested head longer than container");
739 if (n < 0) n = std::max(0, (int)c.size() + n);
740 n = std::min(n, (int)c.size());
741 return slice(c, 0, n);
742 }
743
747 template <typename CONTAINER, typename = std::enable_if_t<is_citerable_v<std::decay_t<CONTAINER>>>>
748 inline CONTAINER tail(const CONTAINER& c, int n) {
749 // if (n > c.size()) throw RangeError("Requested tail longer than container");
750 if (n < 0) n = std::max(0, (int)c.size() + n);
751 n = std::min(n, (int)c.size());
752 return slice(c, c.size() - n);
753 }
754
755
756 using std::max;
757 using std::min;
758
760 inline double min(const vector<double>& in, double errval = DBL_NAN) {
761 const auto e = std::min_element(in.begin(), in.end());
762 return e != in.end() ? *e : errval;
763 }
764
766 inline double max(const vector<double>& in, double errval = DBL_NAN) {
767 const auto e = std::max_element(in.begin(), in.end());
768 return e != in.end() ? *e : errval;
769 }
770
772 inline pair<double, double> minmax(const vector<double>& in, double errval = DBL_NAN) {
773 const auto e = std::minmax_element(in.begin(), in.end());
774 const double rtnmin = e.first != in.end() ? *e.first : errval;
775 const double rtnmax = e.second != in.end() ? *e.first : errval;
776 return std::make_pair(rtnmin, rtnmax);
777 }
778
779
781 inline int min(const vector<int>& in, int errval = -1) {
782 const auto e = std::min_element(in.begin(), in.end());
783 return e != in.end() ? *e : errval;
784 }
785
787 inline int max(const vector<int>& in, int errval = -1) {
788 const auto e = std::max_element(in.begin(), in.end());
789 return e != in.end() ? *e : errval;
790 }
791
793 inline pair<int, int> minmax(const vector<int>& in, int errval = -1) {
794 const auto e = std::minmax_element(in.begin(), in.end());
795 const double rtnmin = e.first != in.end() ? *e.first : errval;
796 const double rtnmax = e.second != in.end() ? *e.first : errval;
797 return std::make_pair(rtnmin, rtnmax);
798 }
799
801
802
805
811 template <typename CONTAINER,
812 typename FN = double(const typename std::decay_t<CONTAINER>::value_type::ParticleBase&),
813 typename = isCIterable<CONTAINER>>
814 inline int closestMatchIndex(const CONTAINER& c,
815 FN&& fn,
816 double target,
817 double minval = -DBL_MAX,
818 double maxval = DBL_MAX) {
819 auto f = std::function(std::forward<FN>(fn));
820 int ibest = -1;
821 double best = DBL_NAN;
822 for (size_t i = 0; i < c.size(); ++i) {
823 const double val = f(c[i]);
824 if (isnan(val)) continue;
825 if (val < minval || val > maxval) continue;
826 if (isnan(best) || fabs(val - target) < fabs(best - target)) {
827 best = val;
828 ibest = i;
829 }
830 }
831 return ibest;
832 }
833
842 template <typename CONTAINER1,
843 typename CONTAINER2,
844 typename FN = double(const typename std::decay_t<CONTAINER1>::value_type::ParticleBase&,
845 const typename std::decay_t<CONTAINER2>::value_type::ParticleBase&),
846 typename = isCIterable<CONTAINER1, CONTAINER2>>
847 inline pair<int, int> closestMatchIndices(const CONTAINER1& c1,
848 const CONTAINER2& c2,
849 FN&& fn,
850 double target,
851 double minval = -DBL_MAX,
852 double maxval = DBL_MAX) {
853 auto f = std::function(std::forward<FN>(fn));
854 pair<int, int> ijbest{-1, -1};
855 double best = DBL_NAN;
856 for (size_t i = 0; i < c1.size(); ++i) {
857 for (size_t j = 0; j < c2.size(); ++j) {
858 const double val = f(c1[i], c2[j]);
859 if (isnan(val)) continue;
860 if (val < minval || val > maxval) continue;
861 if (isnan(best) || fabs(val - target) < fabs(best - target)) {
862 best = val;
863 ijbest = {i, j};
864 }
865 }
866 }
867 return ijbest;
868 }
869
878 template <typename CONTAINER,
879 typename T,
880 typename FN = double(const typename std::decay_t<CONTAINER>::value_type::ParticleBase&,
881 const std::decay_t<T>&),
882 typename = isCIterable<CONTAINER>>
883 inline int closestMatchIndex(const CONTAINER& c,
884 const T& x,
885 FN&& fn,
886 double target,
887 double minval = -DBL_MAX,
888 double maxval = DBL_MAX) {
889 pair<int, int> ijbest = closestMatchIndices(c, vector<T>{x}, std::forward<FN>(fn), target, minval,
890 maxval);
891 return ijbest.first;
892 }
893
902 template <typename CONTAINER, typename T, typename FN, typename = isCIterable<CONTAINER>>
903 inline int closestMatchIndex(const T& x,
904 const CONTAINER& c,
905 FN&& fn,
906 double target,
907 double minval = -DBL_MAX,
908 double maxval = DBL_MAX) {
909 return closestMatchIndex(c, x, std::forward<FN>(fn), target, minval, maxval);
910 }
911
913
914
920 template <typename T>
921 T getEnvParam(const std::string name, const T& fallback) {
922 char* env = getenv(name.c_str());
923 return env ? lexical_cast<T>(env) : fallback;
924 }
925
926
930 template <class T>
931 vector<T> slice(const vector<T>& v, int startidx, int endidx) {
932
933 if (startidx < 0 || endidx <= startidx || endidx >= v.size())
934 throw RangeError("Requested start or end indices incompatible with given vector");
935
936 auto start = v.begin() + startidx;
937 auto end = v.begin() + endidx;
938
939 vector<T> output(endidx - startidx);
940
941 copy(start, end, output.begin());
942
943 return output;
944 }
945
946
947}
948
949#endif
int closestMatchIndex(const CONTAINER &c, FN &&fn, double target, double minval=-DBL_MAX, double maxval=DBL_MAX)
Return the index from a vector which best matches fn(c[i]) to the target value.
Definition Utils.hh:814
pair< int, int > closestMatchIndices(const CONTAINER1 &c1, const CONTAINER2 &c2, FN &&fn, double target, double minval=-DBL_MAX, double maxval=DBL_MAX)
Return the indices from two vectors which best match fn(c1[i], c2[j]) to the target value.
Definition Utils.hh:847
CONTAINER head(const CONTAINER &c, int n)
Head slice of the n first container elements.
Definition Utils.hh:737
bool any(const CONTAINER &c)
Return true if x is true for any x in container c, otherwise false.
Definition Utils.hh:364
CONTAINER discard_if_any(const CONTAINER &c, const CONTAINER &ys)
Version with several element-equality comparisons in place of a function.
Definition Utils.hh:611
CONTAINER slice(const CONTAINER &c, int i, int j)
Slice of the container elements cf. Python's [i:j] syntax.
Definition Utils.hh:714
T accumulate(const CONTAINER1 &in, const T &init, const FN &f)
A single-container-arg version of std::accumulate, aka reduce.
Definition Utils.hh:492
CONTAINER & idiscard_if_any(CONTAINER &c, const CONTAINER &ys)
Version with several element-equality comparisons in place of a function.
Definition Utils.hh:587
pair< double, double > minmax(const vector< double > &in, double errval=DBL_NAN)
Find the minimum and maximum values in the vector.
Definition Utils.hh:772
bool none(const CONTAINER &c)
Return true if x is false for all x in container c, otherwise false.
Definition Utils.hh:418
CONTAINER tail(const CONTAINER &c, int n)
Tail slice of the n last container elements.
Definition Utils.hh:748
bool all(const CONTAINER &c)
Return true if x is true for all x in container c, otherwise false.
Definition Utils.hh:391
unsigned int count(const CONTAINER &c)
Return number of true elements in the container c .
Definition Utils.hh:337
T & isum(const CONTAINER &c, T &out)
Definition Utils.hh:543
CONTAINER & iselect_if_any(CONTAINER &c, const CONTAINER &ys)
Version with several element-equality comparisons in place of a function.
Definition Utils.hh:660
CONTAINER select_if_any(const CONTAINER &c, const CONTAINER &ys)
Version with several element-equality comparisons in place of a function.
Definition Utils.hh:682
Jets & idiscard(Jets &jets, const Cut &c)
Filter a jet collection in-place to the subset that fails the supplied Cut.
Jets select(const Jets &jets, const Cut &c)
Filter a jet collection in-place to the subset that passes the supplied Cut.
Definition JetUtils.hh:183
Jets & iselect(Jets &jets, const Cut &c)
Filter a jet collection in-place to the subset that passes the supplied Cut.
Jets discard(const Jets &jets, const Cut &c)
Filter a jet collection in-place to the subset that fails the supplied Cut.
Definition JetUtils.hh:201
double p(const ParticleBase &p)
Unbound function access to p.
Definition ParticleBaseUtils.hh:819
string dirname(const string &p)
Get the dirname (i.e. path to the penultimate directory) from a path p.
Definition Utils.hh:312
string file_extn(const string &f)
Get the file extension from a filename f.
Definition Utils.hh:324
string pathjoin(const vector< string > &paths)
Join several filesystem paths together with the standard ':' delimiter.
Definition Utils.hh:293
vector< string > pathsplit(const string &path)
Split a path string with colon delimiters.
Definition Utils.hh:285
string basename(const string &p)
Get the basename (i.e. terminal file name) from a path p.
Definition Utils.hh:306
string file_stem(const string &f)
Get the stem (i.e. part without a file extension) from a filename f.
Definition Utils.hh:318
bool endsWith(const string &s, const string &end)
Check whether a string end is found at the end of s.
Definition Utils.hh:186
bool nocase_equals(const string &s1, const string &s2)
Case-insensitive string equality function.
Definition Utils.hh:157
string toStr(T &&x)
Perfect-forwarding alias for to_str() with a more Rivet-user-facing name.
Definition Utils.hh:101
bool startsWith(const string &s, const string &start)
Check whether a string start is found at the start of s.
Definition Utils.hh:179
string & ireplace_all(string &str, const string &patt, const string &repl)
Replace all instances of patt with repl in-place.
Definition Utils.hh:116
string toUpper(const string &s)
Convert a string to upper-case.
Definition Utils.hh:171
string rpad(const string &s, size_t width, const string &padchar=" ")
Right-pad the given string s to width width.
Definition Utils.hh:271
string to_str(const T &x)
Convert any object to a string.
Definition Utils.hh:80
string lpad(const string &s, size_t width, const string &padchar=" ")
Left-pad the given string s to width width.
Definition Utils.hh:265
string toLower(const string &s)
Convert a string to lower-case.
Definition Utils.hh:163
string replace_all(string str, const string &patt, const string &repl)
Replace all instances of patt with repl.
Definition Utils.hh:131
T lexical_cast(const U &in)
Convert between any types via stringstream.
Definition Utils.hh:63
vector< string > split(const string &s, const string &sep)
Split a string on a specified separator string.
Definition Utils.hh:250
string join(const vector< T > &v, const string &sep=" ")
Make a string containing the string representations of each item in v, separated by sep.
Definition Utils.hh:207
string & ireplace_first(string &str, const string &patt, const string &repl)
Replace the first instance of patt with repl in-place.
Definition Utils.hh:85
string replace_first(string str, const string &patt, const string &repl)
Replace the first instance of patt with repl.
Definition Utils.hh:107
int nocase_cmp(const string &s1, const string &s2)
Case-insensitive string comparison function.
Definition Utils.hh:137
T getEnvParam(const std::string name, const T &fallback)
Get a parameter from a named environment variable, with automatic type conversion.
Definition Utils.hh:921
Definition LHCbCommon.hh:9
std::enable_if_t< std::is_arithmetic_v< N1 > &&std::is_arithmetic_v< N2 >, signed_if_mixed_t< N1, N2 > > max(N1 a, N2 b)
Get the maximum of two numbers.
Definition MathUtils.hh:124
T sum(const DressedLeptons &c, FN &&fn, const T &start=T())
Generic sum function, adding fn(x) for all x in container c, starting with start.
Definition DressedLepton.hh:66
static constexpr double DBL_NAN
Convenient const for getting the double NaN value.
Definition Utils.hh:38
std::enable_if_t< std::is_arithmetic_v< N1 > &&std::is_arithmetic_v< N2 >, signed_if_mixed_t< N1, N2 > > min(N1 a, N2 b)
Get the minimum of two numbers.
Definition MathUtils.hh:113
bool contains(const std::string &s, const std::string &sub)
Does s contain sub as a substring?
Definition RivetSTL.hh:213
T & maybe(const T &x, std::function< bool(const T &)> fn, const T &fallback)
Wrapper for avoiding repetition/recalculation when computing and maybe using a value.
Definition Utils.hh:47
std::string toString(const AnalysisInfo &ai)
String representation.
Error for e.g. use of invalid bin ranges.
Definition Exceptions.hh:23
Exception class for throwing from lexical_cast when a parse goes wrong.
Definition Utils.hh:56