File indexing completed on 2025-04-19 09:06:55
0001
0002 #ifndef RIVET_Utils_HH
0003 #define RIVET_Utils_HH
0004
0005 #include "Rivet/Tools/RivetSTL.hh"
0006 #include "Rivet/Tools/TypeTraits.hh"
0007 #include "Rivet/Tools/PrettyPrint.hh"
0008 #include "Rivet/Tools/Exceptions.hh"
0009 #include <ostream>
0010 #include <cctype>
0011 #include <cerrno>
0012 #include <stdexcept>
0013 #include <numeric>
0014 #include <limits>
0015 #include <climits>
0016 #include <cfloat>
0017 #include <cmath>
0018 #include <sstream>
0019 #include <functional>
0020
0021
0022
0023
0024
0025 #ifndef DEPRECATED
0026 #if __GNUC__ && __cplusplus && RIVET_NO_DEPRECATION_WARNINGS == 0
0027 #define DEPRECATED(x) __attribute__((deprecated(x)))
0028 #else
0029 #define DEPRECATED(x)
0030 #endif
0031 #endif
0032
0033
0034 namespace Rivet {
0035
0036
0037
0038 static constexpr double DBL_NAN = std::numeric_limits<double>::quiet_NaN();
0039
0040
0041
0042
0043
0044
0045 struct bad_lexical_cast : public std::runtime_error {
0046 bad_lexical_cast(const std::string& what) : std::runtime_error(what) {}
0047 };
0048
0049
0050 template<typename T, typename U>
0051 T lexical_cast(const U& in) {
0052 try {
0053 std::stringstream ss;
0054 ss << in;
0055 T out;
0056 ss >> out;
0057 return out;
0058 } catch (const std::exception& e) {
0059 throw bad_lexical_cast(e.what());
0060 }
0061 }
0062
0063
0064
0065
0066 template <typename T>
0067 inline string to_str(const T& x) {
0068 return lexical_cast<string>(x);
0069 }
0070
0071
0072
0073
0074 template <typename T>
0075 inline string toString(const T& x) {
0076 return lexical_cast<string>(x);
0077 }
0078
0079
0080 inline string& replace_first(string& str, const string& patt, const string& repl) {
0081 if (!contains(str, patt)) return str;
0082 str.replace(str.find(patt), patt.size(), repl);
0083 return str;
0084 }
0085
0086
0087
0088
0089
0090
0091 inline string& replace_all(string& str, const string& patt, const string& repl) {
0092 if (!contains(str, patt)) return str;
0093 while (true) {
0094 string::size_type it = str.find(patt);
0095 if (it == string::npos) break;
0096 str.replace(it, patt.size(), repl);
0097 }
0098 return str;
0099 }
0100
0101
0102
0103 inline int nocase_cmp(const string& s1, const string& s2) {
0104 string::const_iterator it1 = s1.begin();
0105 string::const_iterator it2 = s2.begin();
0106 while ( (it1 != s1.end()) && (it2 != s2.end()) ) {
0107 if(::toupper(*it1) != ::toupper(*it2)) {
0108
0109 return (::toupper(*it1) < ::toupper(*it2)) ? -1 : 1;
0110 }
0111
0112 ++it1;
0113 ++it2;
0114 }
0115 size_t size1 = s1.size(), size2 = s2.size();
0116
0117 if (size1 == size2) return 0;
0118 return (size1 < size2) ? -1 : 1;
0119 }
0120
0121
0122
0123 inline bool nocase_equals(const string& s1, const string& s2) {
0124 return nocase_cmp(s1, s2) == 0;
0125 }
0126
0127
0128
0129 inline string toLower(const string& s) {
0130 string out = s;
0131 std::transform(out.begin(), out.end(), out.begin(), (int(*)(int)) std::tolower);
0132 return out;
0133 }
0134
0135
0136
0137 inline string toUpper(const string& s) {
0138 string out = s;
0139 std::transform(out.begin(), out.end(), out.begin(), (int(*)(int)) std::toupper);
0140 return out;
0141 }
0142
0143
0144
0145 inline bool startsWith(const string& s, const string& start) {
0146 if (s.length() < start.length()) return false;
0147 return s.substr(0, start.length()) == start;
0148 }
0149
0150
0151
0152 inline bool endsWith(const string& s, const string& end) {
0153 if (s.length() < end.length()) return false;
0154 return s.substr(s.length() - end.length()) == end;
0155 }
0156
0157
0158
0159 inline string strcat() { return ""; }
0160
0161 template<typename T, typename... Ts>
0162 inline string strcat(T value, Ts... fargs) {
0163 const string strthis = lexical_cast<string>(value);
0164 const string strnext = strcat(fargs...);
0165 return strnext.empty() ? strthis : strthis + strnext;
0166 }
0167
0168
0169
0170 template <typename T>
0171 inline string join(const vector<T>& v, const string& sep=" ") {
0172 string rtn;
0173 for (size_t i = 0; i < v.size(); ++i) {
0174 if (i != 0) rtn += sep;
0175 rtn += to_str(v[i]);
0176 }
0177 return rtn;
0178 }
0179
0180
0181 template <>
0182 inline string join(const vector<string>& v, const string& sep) {
0183 string rtn;
0184 for (size_t i = 0; i < v.size(); ++i) {
0185 if (i != 0) rtn += sep;
0186 rtn += v[i];
0187 }
0188 return rtn;
0189 }
0190
0191
0192 template <typename T>
0193 inline string join(const set<T>& s, const string& sep=" ") {
0194 string rtn;
0195 for (const T& x : s) {
0196 if (rtn.size() > 0) rtn += sep;
0197 rtn += to_str(x);
0198 }
0199 return rtn;
0200 }
0201
0202
0203 template <>
0204 inline string join(const set<string>& s, const string& sep) {
0205 string rtn;
0206 for (const string & x : s) {
0207 if (rtn.size() > 0) rtn += sep;
0208 rtn += x;
0209 }
0210 return rtn;
0211 }
0212
0213
0214 inline vector<string> split(const string& s, const string& sep) {
0215 vector<string> dirs;
0216 string tmp = s;
0217 while (true) {
0218 const size_t delim_pos = tmp.find(sep);
0219 if (delim_pos == string::npos) break;
0220 const string dir = tmp.substr(0, delim_pos);
0221 if (dir.length()) dirs.push_back(dir);
0222 tmp.replace(0, delim_pos+1, "");
0223 }
0224 if (tmp.length()) dirs.push_back(tmp);
0225 return dirs;
0226 }
0227
0228
0229 inline string lpad(const string& s, size_t width, const string& padchar=" ") {
0230 if (s.size() >= width) return s;
0231 return string(width - s.size(), padchar[0]) + s;
0232 }
0233
0234
0235 inline string rpad(const string& s, size_t width, const string& padchar=" ") {
0236 if (s.size() >= width) return s;
0237 return s + string(width - s.size(), padchar[0]);
0238 }
0239
0240
0241
0242
0243
0244
0245
0246
0247
0248
0249
0250 inline vector<string> pathsplit(const string& path) {
0251 return split(path, ":");
0252 }
0253
0254
0255
0256
0257
0258 inline string pathjoin(const vector<string>& paths) {
0259 return join(paths, ":");
0260 }
0261
0262
0263 inline string operator / (const string& a, const string& b) {
0264
0265 const string anorm = (a.find("/") != string::npos) ? a.substr(0, a.find_last_not_of("/")+1) : a;
0266 const string bnorm = (b.find("/") != string::npos) ? b.substr(b.find_first_not_of("/")) : b;
0267 return anorm + "/" + bnorm;
0268 }
0269
0270
0271 inline string basename(const string& p) {
0272 if (!contains(p, "/")) return p;
0273 return p.substr(p.rfind("/")+1);
0274 }
0275
0276
0277 inline string dirname(const string& p) {
0278 if (!contains(p, "/")) return "";
0279 return p.substr(0, p.rfind("/"));
0280 }
0281
0282
0283 inline string file_stem(const string& f) {
0284 if (!contains(f, ".")) return f;
0285 return f.substr(0, f.rfind("."));
0286 }
0287
0288
0289 inline string file_extn(const string& f) {
0290 if (!contains(f, ".")) return "";
0291 return f.substr(f.rfind(".")+1);
0292 }
0293
0294
0295
0296
0297
0298
0299
0300
0301
0302 template <typename CONTAINER,
0303 typename = std::enable_if_t< is_citerable_v<std::decay_t<CONTAINER>> >>
0304 inline unsigned int count(const CONTAINER& c) {
0305
0306 unsigned int rtn = 0;
0307 for (const auto& x : c) if (bool(x)) rtn += 1;
0308 return rtn;
0309 }
0310
0311
0312
0313
0314
0315
0316
0317
0318 template <typename CONTAINER, typename FN,
0319
0320 typename = std::enable_if_t< is_citerable_v<std::decay_t<CONTAINER>> >>
0321 inline unsigned int count(const CONTAINER& c, const FN& f) {
0322 return std::count_if(std::begin(c), std::end(c), f);
0323 }
0324
0325
0326
0327
0328 template <typename CONTAINER,
0329 typename = std::enable_if_t< is_citerable_v<std::decay_t<CONTAINER>> >>
0330 inline bool any(const CONTAINER& c) {
0331
0332 for (const auto& x : c) if (bool(x)) return true;
0333 return false;
0334 }
0335
0336
0337
0338
0339
0340
0341
0342
0343 template <typename CONTAINER, typename FN,
0344
0345 typename = std::enable_if_t< is_citerable_v<std::decay_t<CONTAINER>> >>
0346 inline bool any(const CONTAINER& c, const FN& f) {
0347 return std::any_of(std::begin(c), std::end(c), f);
0348 }
0349
0350
0351
0352
0353 template <typename CONTAINER,
0354 typename = std::enable_if_t< is_citerable_v<std::decay_t<CONTAINER>> >>
0355 inline bool all(const CONTAINER& c) {
0356
0357 for (const auto& x : c) if (!bool(x)) return false;
0358 return true;
0359 }
0360
0361
0362
0363
0364
0365
0366
0367
0368 template <typename CONTAINER, typename FN,
0369
0370 typename = std::enable_if_t< is_citerable_v<std::decay_t<CONTAINER>> >>
0371 inline bool all(const CONTAINER& c, const FN& f) {
0372 return std::all_of(std::begin(c), std::end(c), f);
0373 }
0374
0375
0376
0377 template <typename CONTAINER,
0378 typename = std::enable_if_t< is_citerable_v<std::decay_t<CONTAINER>> >>
0379 inline bool none(const CONTAINER& c) {
0380
0381 for (const auto& x : c) if (bool(x)) return false;
0382 return true;
0383 }
0384
0385
0386
0387
0388
0389
0390
0391
0392 template <typename CONTAINER, typename FN,
0393
0394 typename = std::enable_if_t< is_citerable_v<std::decay_t<CONTAINER>> >>
0395 inline bool none(const CONTAINER& c, const FN& f) {
0396 return std::none_of(std::begin(c), std::end(c), f);
0397 }
0398
0399
0400
0401
0402
0403
0404
0405
0406
0407
0408
0409
0410
0411
0412 template <typename CONTAINER1, typename CONTAINER2,
0413 typename FN = typename std::decay_t<CONTAINER2>::value_type(
0414 const typename std::decay_t<CONTAINER1>::value_type::ParticleBase&),
0415 typename = std::enable_if_t< is_citerable_v<std::decay_t<CONTAINER1>> &&
0416 is_citerable_v<std::decay_t<CONTAINER2>> >>
0417 inline const CONTAINER2& transform(const CONTAINER1& in, CONTAINER2& out, FN&& f) {
0418 out.clear(); out.resize(in.size());
0419 std::transform(in.begin(), in.end(), out.begin(), std::forward<FN>(f));
0420 return out;
0421 }
0422
0423
0424
0425 template <typename CONTAINER1, typename RTN,
0426 typename = std::enable_if_t< is_citerable_v<std::decay_t<CONTAINER1>> >>
0427 inline std::vector<RTN> transform(const CONTAINER1& in,
0428 const std::function<RTN(typename CONTAINER1::value_type::ParticleBase)>& f) {
0429 std::vector<RTN> out;
0430 transform(in, out, f);
0431 return out;
0432 }
0433
0434
0435
0436
0437
0438
0439
0440
0441
0442 template <typename CONTAINER1, typename T, typename FN,
0443 typename = std::enable_if_t< is_citerable_v<std::decay_t<CONTAINER1>> >>
0444 inline T accumulate(const CONTAINER1& in, const T& init, const FN& f) {
0445 const T rtn = std::accumulate(in.begin(), in.end(), init, f);
0446 return rtn;
0447 }
0448
0449
0450
0451
0452
0453 template <typename CONTAINER,
0454 typename = std::enable_if_t< is_citerable_v<std::decay_t<CONTAINER>> >>
0455 inline typename CONTAINER::value_type sum(const CONTAINER& c) {
0456 typename CONTAINER::value_type rtn;
0457 for (const auto& x : c) rtn += x;
0458 return rtn;
0459 }
0460
0461
0462
0463
0464 template <typename CONTAINER, typename T,
0465 typename = std::enable_if_t< is_citerable_v<std::decay_t<CONTAINER>> >>
0466 inline T sum(const CONTAINER& c, const T& start) {
0467 T rtn = start;
0468 for (const auto& x : c) rtn += x;
0469 return rtn;
0470 }
0471
0472
0473 template <typename CONTAINER, typename T,
0474 typename FN = T(const typename std::decay_t<CONTAINER>::value_type&),
0475 typename = std::enable_if_t< is_citerable_v<std::decay_t<CONTAINER>> >>
0476 inline T sum(CONTAINER&& c, FN&& fn, const T& start=T()) {
0477 auto f = std::function(std::forward<FN>(fn));
0478 T rtn = start;
0479 for (const auto& x : c) rtn += fn(x);
0480 return rtn;
0481 }
0482
0483
0484
0485
0486
0487 template <typename CONTAINER, typename T,
0488 typename = std::enable_if_t< is_citerable_v<std::decay_t<CONTAINER>> >>
0489 inline T& isum(const CONTAINER& c, T& out) {
0490 for (const auto& x : c) out += x;
0491 return out;
0492 }
0493
0494
0495
0496
0497 template <typename CONTAINER, typename FN, typename T,
0498
0499 typename = std::enable_if_t< is_citerable_v<std::decay_t<CONTAINER>> >>
0500 inline T& isum(const CONTAINER& c, const FN& f, T& out) {
0501 for (const auto& x : c) out += f(x);
0502 return out;
0503 }
0504
0505
0506
0507
0508
0509
0510 template <typename CONTAINER, typename FN,
0511 typename = std::enable_if_t< is_citerable_v<std::decay_t<CONTAINER>> >>
0512 inline CONTAINER& idiscard(CONTAINER& c, const FN& f) {
0513 const auto newend = std::remove_if(std::begin(c), std::end(c), f);
0514 c.erase(newend, c.end());
0515 return c;
0516 }
0517
0518
0519 template <typename CONTAINER,
0520 typename = std::enable_if_t< is_citerable_v<std::decay_t<CONTAINER>> >>
0521 inline CONTAINER& idiscard(CONTAINER& c, const typename CONTAINER::value_type& y) {
0522 return idiscard(c, [&](typename CONTAINER::value_type& x){ return x == y; });
0523 }
0524
0525
0526 template <typename CONTAINER,
0527 typename = std::enable_if_t< is_citerable_v<std::decay_t<CONTAINER>> >>
0528 inline CONTAINER& idiscard_if_any(CONTAINER& c, const CONTAINER& ys) {
0529 return idiscard(c, [&](typename CONTAINER::value_type& x){ return contains(ys, x); });
0530 }
0531
0532
0533
0534
0535
0536 template <typename CONTAINER, typename FN,
0537 typename = std::enable_if_t< is_citerable_v<std::decay_t<CONTAINER>> >>
0538 inline CONTAINER discard(const CONTAINER& c, const FN& f) {
0539 CONTAINER rtn = c;
0540 return idiscard(rtn, f);
0541 }
0542
0543
0544 template <typename CONTAINER,
0545 typename = std::enable_if_t< is_citerable_v<std::decay_t<CONTAINER>> >>
0546 inline CONTAINER discard(const CONTAINER& c, const typename CONTAINER::value_type& y) {
0547 return discard(c, [&](typename CONTAINER::value_type& x){ return x == y; });
0548 }
0549
0550
0551 template <typename CONTAINER,
0552 typename = std::enable_if_t< is_citerable_v<std::decay_t<CONTAINER>> >>
0553 inline CONTAINER discard_if_any(const CONTAINER& c, const CONTAINER& ys) {
0554 return discard(c, [&](typename CONTAINER::value_type& x){ return contains(ys, x); });
0555 }
0556
0557
0558
0559
0560
0561
0562
0563 template <typename CONTAINER, typename FN,
0564
0565 typename = std::enable_if_t< is_citerable_v<std::decay_t<CONTAINER>> >>
0566 inline CONTAINER& discard(const CONTAINER& c, const FN& f, CONTAINER& out) {
0567 out = discard(c, f);
0568 return out;
0569 }
0570
0571
0572 template <typename CONTAINER,
0573 typename = std::enable_if_t< is_citerable_v<std::decay_t<CONTAINER>> >>
0574 inline CONTAINER& discard(const CONTAINER& c, const typename CONTAINER::value_type& y, CONTAINER& out) {
0575 return discard(c, [&](typename CONTAINER::value_type& x){ return x == y; }, out);
0576 }
0577
0578
0579 template <typename CONTAINER,
0580 typename = std::enable_if_t< is_citerable_v<std::decay_t<CONTAINER>> >>
0581 inline CONTAINER& discard_if_any(const CONTAINER& c, const CONTAINER& ys, CONTAINER& out) {
0582 return discard(c, [&](typename CONTAINER::value_type& x){ return contains(ys, x); }, out);
0583 }
0584
0585
0586
0587
0588
0589
0590 template <typename CONTAINER, typename FN,
0591 typename = std::enable_if_t< is_citerable_v<std::decay_t<CONTAINER>> >>
0592 inline CONTAINER& iselect(CONTAINER& c, const FN& f) {
0593 auto invf = [&](const typename CONTAINER::value_type& x){ return !f(x); };
0594 return idiscard(c, invf);
0595 }
0596
0597
0598
0599
0600 template <typename CONTAINER,
0601 typename = std::enable_if_t< is_citerable_v<std::decay_t<CONTAINER>> >>
0602 inline CONTAINER& iselect_if_any(CONTAINER& c, const CONTAINER& ys) {
0603 return iselect(c, [&](typename CONTAINER::value_type& x){ return contains(ys, x); });
0604 }
0605
0606
0607
0608
0609
0610 template <typename CONTAINER, typename FN,
0611 typename = std::enable_if_t< is_citerable_v<std::decay_t<CONTAINER>> >>
0612 inline CONTAINER select(const CONTAINER& c, const FN& f) {
0613 CONTAINER rtn = c;
0614 return iselect(rtn, f);
0615 }
0616
0617
0618
0619
0620 template <typename CONTAINER,
0621 typename = std::enable_if_t< is_citerable_v<std::decay_t<CONTAINER>> >>
0622 inline CONTAINER select_if_any(const CONTAINER& c, const CONTAINER& ys) {
0623 return select(c, [&](typename CONTAINER::value_type& x){ return contains(ys, x); });
0624 }
0625
0626
0627
0628
0629
0630
0631
0632 template <typename CONTAINER, typename FN,
0633 typename = std::enable_if_t< is_citerable_v<std::decay_t<CONTAINER>> >>
0634 inline CONTAINER& select(const CONTAINER& c, const FN& f, CONTAINER& out) {
0635 out = select(c, f);
0636 return out;
0637 }
0638
0639
0640
0641
0642 template <typename CONTAINER,
0643 typename = std::enable_if_t< is_citerable_v<std::decay_t<CONTAINER>> >>
0644 inline CONTAINER& select_if_any(const CONTAINER& c, const CONTAINER& ys, CONTAINER& out) {
0645 return select(c, [&](typename CONTAINER::value_type& x){ return contains(ys, x); }, out);
0646 }
0647
0648
0649
0650
0651
0652
0653
0654 template <typename CONTAINER,
0655 typename = std::enable_if_t< is_citerable_v<std::decay_t<CONTAINER>> >>
0656 inline CONTAINER slice(const CONTAINER& c, int i, int j) {
0657 CONTAINER rtn;
0658 const size_t off1 = (i >= 0) ? i : c.size() + i;
0659 const size_t off2 = (j >= 0) ? j : c.size() + j;
0660 if (off1 > c.size() || off2 > c.size()) throw RangeError("Attempting to slice beyond requested offsets");
0661 if (off2 < off1) throw RangeError("Requested offsets in invalid order");
0662 rtn.resize(off2 - off1);
0663 std::copy(c.begin()+off1, c.begin()+off2, rtn.begin());
0664 return rtn;
0665 }
0666
0667
0668
0669
0670 template <typename CONTAINER,
0671 typename = std::enable_if_t< is_citerable_v<std::decay_t<CONTAINER>> >>
0672 inline CONTAINER slice(const CONTAINER& c, int i) {
0673 return slice(c, i, c.size());
0674 }
0675
0676
0677
0678
0679 template <typename CONTAINER,
0680 typename = std::enable_if_t< is_citerable_v<std::decay_t<CONTAINER>> >>
0681 inline CONTAINER head(const CONTAINER& c, int n) {
0682
0683 if (n < 0) n = std::max(0, (int)c.size()+n);
0684 n = std::min(n, (int)c.size());
0685 return slice(c, 0, n);
0686 }
0687
0688
0689
0690
0691 template <typename CONTAINER,
0692 typename = std::enable_if_t< is_citerable_v<std::decay_t<CONTAINER>> >>
0693 inline CONTAINER tail(const CONTAINER& c, int n) {
0694
0695 if (n < 0) n = std::max(0, (int)c.size()+n);
0696 n = std::min(n, (int)c.size());
0697 return slice(c, c.size()-n);
0698 }
0699
0700
0701 using std::min;
0702 using std::max;
0703
0704
0705 inline double min(const vector<double>& in, double errval=DBL_NAN) {
0706 const auto e = std::min_element(in.begin(), in.end());
0707 return e != in.end() ? *e : errval;
0708 }
0709
0710
0711 inline double max(const vector<double>& in, double errval=DBL_NAN) {
0712 const auto e = std::max_element(in.begin(), in.end());
0713 return e != in.end() ? *e : errval;
0714 }
0715
0716
0717 inline pair<double,double> minmax(const vector<double>& in, double errval=DBL_NAN) {
0718 const auto e = std::minmax_element(in.begin(), in.end());
0719 const double rtnmin = e.first != in.end() ? *e.first : errval;
0720 const double rtnmax = e.second != in.end() ? *e.first : errval;
0721 return std::make_pair(rtnmin, rtnmax);
0722 }
0723
0724
0725
0726 inline int min(const vector<int>& in, int errval=-1) {
0727 const auto e = std::min_element(in.begin(), in.end());
0728 return e != in.end() ? *e : errval;
0729 }
0730
0731
0732 inline int max(const vector<int>& in, int errval=-1) {
0733 const auto e = std::max_element(in.begin(), in.end());
0734 return e != in.end() ? *e : errval;
0735 }
0736
0737
0738 inline pair<int,int> minmax(const vector<int>& in, int errval=-1) {
0739 const auto e = std::minmax_element(in.begin(), in.end());
0740 const double rtnmin = e.first != in.end() ? *e.first : errval;
0741 const double rtnmax = e.second != in.end() ? *e.first : errval;
0742 return std::make_pair(rtnmin, rtnmax);
0743 }
0744
0745
0746
0747
0748
0749
0750
0751
0752
0753
0754
0755
0756 template <typename CONTAINER,
0757 typename FN = double(const typename std::decay_t<CONTAINER>::value_type&),
0758 typename = isCIterable<CONTAINER>>
0759 inline int closestMatchIndex(CONTAINER&& c, FN&& fn,
0760 double target, double minval=-DBL_MAX, double maxval=DBL_MAX) {
0761 auto f = std::function(std::forward<FN>(fn));
0762 int ibest = -1;
0763 double best = DBL_NAN;
0764 for (size_t i = 0; i < c.size(); ++i) {
0765 const double val = f(c[i]);
0766 if (isnan(val)) continue;
0767 if (val < minval || val > maxval) continue;
0768 if (isnan(best) || fabs(val-target) < fabs(best-target)) {
0769 best = val;
0770 ibest = i;
0771 }
0772 }
0773 return ibest;
0774 }
0775
0776
0777
0778
0779
0780
0781
0782
0783
0784 template <typename CONTAINER1, typename CONTAINER2,
0785 typename FN = double(const typename std::decay_t<CONTAINER1>::value_type&,
0786 const typename std::decay_t<CONTAINER2>::value_type&),
0787 typename = isCIterable<CONTAINER1, CONTAINER2>>
0788 inline pair<int,int> closestMatchIndices(CONTAINER1&& c1, CONTAINER2&& c2, FN&& fn,
0789 double target, double minval=-DBL_MAX, double maxval=DBL_MAX) {
0790 auto f = std::function(std::forward<FN>(fn));
0791 pair<int,int> ijbest{-1,-1};
0792 double best = DBL_NAN;
0793 for (size_t i = 0; i < c1.size(); ++i) {
0794 for (size_t j = 0; j < c2.size(); ++j) {
0795 const double val = f(c1[i], c2[j]);
0796 if (isnan(val)) continue;
0797 if (val < minval || val > maxval) continue;
0798 if (isnan(best) || fabs(val-target) < fabs(best-target)) {
0799 best = val;
0800 ijbest = {i,j};
0801 }
0802 }
0803 }
0804 return ijbest;
0805 }
0806
0807
0808
0809
0810
0811
0812
0813
0814
0815 template <typename CONTAINER, typename T,
0816 typename FN = double(const typename std::decay_t<CONTAINER>::value_type&, const std::decay_t<T>&),
0817 typename = isCIterable<CONTAINER>>
0818 inline int closestMatchIndex(CONTAINER&& c, const T& x, FN&& fn,
0819 double target, double minval=-DBL_MAX, double maxval=DBL_MAX) {
0820 pair<int,int> ijbest = closestMatchIndices(std::forward<CONTAINER>(c), vector<T>{x}, std::forward<FN>(fn), target, minval, maxval);
0821 return ijbest.first;
0822 }
0823
0824
0825
0826
0827
0828
0829
0830
0831
0832 template <typename CONTAINER, typename T, typename FN, typename = isCIterable<CONTAINER>>
0833 inline int closestMatchIndex(T&& x, CONTAINER&& c, FN&& fn,
0834 double target, double minval=-DBL_MAX, double maxval=DBL_MAX) {
0835 return closestMatchIndex(std::forward<CONTAINER>(c), std::forward<T>(x), std::forward<FN>(fn), target, minval, maxval);
0836 }
0837
0838
0839
0840
0841
0842
0843
0844
0845
0846 template <typename T>
0847 T getEnvParam(const std::string name, const T& fallback) {
0848 char* env = getenv(name.c_str());
0849 return env ? lexical_cast<T>(env) : fallback;
0850 }
0851
0852
0853
0854
0855
0856
0857 template<class T>
0858 vector<T> slice(const vector<T>& v, int startidx, int endidx) {
0859
0860 if (startidx < 0 || endidx <= startidx || endidx >= v.size())
0861 throw RangeError("Requested start or end indices incompatible with given vector");
0862
0863 auto start = v.begin() + startidx;
0864 auto end = v.begin() + endidx;
0865
0866 vector<T> output(endidx - startidx);
0867
0868 copy(start, end, output.begin());
0869
0870 return output;
0871 }
0872
0873
0874 }
0875
0876 #endif