LHAPDF  6.5.4
Utils.h
1 // -*- C++ -*-
2 //
3 // This file is part of LHAPDF
4 // Copyright (C) 2012-2023 The LHAPDF collaboration (see AUTHORS for details)
5 //
6 #pragma once
7 #ifndef LHAPDF_Utils_H
8 #define LHAPDF_Utils_H
9 
10 // STL includes
11 #include <cassert>
12 #include <stdexcept>
13 #include <vector>
14 #include <map>
15 #include <string>
16 #include <algorithm>
17 #include <memory>
18 #include <iostream>
19 #include <iomanip>
20 #include <sstream>
21 #include <limits>
22 #include <cmath>
23 
24 
25 /// Namespace for all LHAPDF functions and classes
26 namespace LHAPDF {
27 
28 
29  // Allow implicit use of the std namespace within namespace LHAPDF
30  using namespace std;
31 
32 
33  /// @defgroup utils Internal utility functions
34  ///@{
35 
36  /// @name String handling utility functions
37  ///@{
38 
39  /// When lexical_cast goes bad
40  struct bad_lexical_cast : public std::runtime_error {
41  /// Constructor
42  bad_lexical_cast(const std::string& what) : std::runtime_error(what) {}
43  };
44 
45  /// @brief Convert between types via stringstream
46  template<typename T, typename U>
47  T lexical_cast(const U& in) {
48  try {
49  std::stringstream ss;
50  ss << in;
51  T out;
52  ss >> out;
53  return out;
54  } catch (const std::exception& e) {
55  throw bad_lexical_cast(e.what());
56  }
57  }
58 
59  /// Make a string representation of @a val
60  template <typename T>
61  inline std::string to_str(const T& val) {
62  return lexical_cast<string>(val);
63  }
64 
65  /// Make a string representation of a vector @a vec
66  template <typename T>
67  inline std::string to_str(const std::vector<T>& vec) {
68  string rtn = "[";
69  for (size_t i = 0; i < vec.size(); ++i) {
70  rtn += to_str(vec[i]);
71  if (i < vec.size()-1) rtn += ", ";
72  }
73  rtn += "]";
74  return rtn;
75  }
76 
77  /// Format an integer @a val as a zero-padded string of length @a nchars
78  inline std::string to_str_zeropad(int val, size_t nchars=4) {
79  stringstream ss;
80  ss << setfill('0') << setw(static_cast<int>(nchars)) << val;
81  return ss.str();
82  }
83 
84  /// Concatenate strings with separator strings between each element
85  inline std::string join(const std::vector<std::string>& svec, const std::string& sep) {
86  string rtn;
87  for (size_t i = 0; i < svec.size(); ++i) {
88  rtn += svec[i];
89  if (i < svec.size()-1) rtn += sep;
90  }
91  return rtn;
92  }
93 
94  /// Split a string by a given separator
95  inline std::vector<std::string> split(const std::string& s, const std::string& sep) {
96  vector<string> rtn;
97  string tmp = s; // non-const working copy, to be incrementally truncated
98  while (true) {
99  const size_t delim_pos = tmp.find(sep);
100  if (delim_pos == string::npos) break;
101  const string stmp = tmp.substr(0, delim_pos);
102  if (!stmp.empty()) rtn.push_back(stmp); // Don't insert "empties"
103  tmp.replace(0, delim_pos+1, ""); // Remove already-processed part
104  }
105  if (!tmp.empty()) rtn.push_back(tmp); // Don't forget the trailing component!
106  return rtn;
107  }
108 
109  /// Does a string @a s contain the @a sub substring?
110  inline bool contains(const std::string& s, const std::string& sub) {
111  return s.find(sub) != string::npos;
112  }
113 
114  /// Does a string @a s start with the @a sub substring?
115  inline bool startswith(const std::string& s, const std::string& sub) {
116  return s.find(sub) == 0;
117  }
118 
119  /// Does a string @a s end with the @a sub substring?
120  inline bool endswith(const std::string& s, const std::string& sub) {
121  return s.find(sub) == s.length()-sub.length();
122  }
123 
124  /// How many times does a string @a s contain the character @a c?
125  inline size_t countchar(const std::string& s, const char c) {
126  return std::count(s.begin(), s.end(), c);
127  }
128 
129  /// Strip leading and trailing spaces (not in-place)
130  inline std::string trim(const std::string& s) {
131  const size_t firstnonspacepos = s.find_first_not_of(" ");
132  const size_t lastnonspacepos = s.find_last_not_of(" ");
133  if (firstnonspacepos == std::string::npos) return "";
134  return s.substr(firstnonspacepos, lastnonspacepos-firstnonspacepos+1);
135  }
136 
137  /// Convert a string to lower-case (not in-place)
138  inline std::string to_lower(const std::string& s) {
139  string rtn = s;
140  transform(rtn.begin(), rtn.end(), rtn.begin(), static_cast<int(*)(int)>(tolower));
141  return rtn;
142  }
143 
144  /// Convert a string to upper-case (not in-place)
145  inline std::string to_upper(const std::string& s) {
146  string rtn = s;
147  transform(rtn.begin(), rtn.end(), rtn.begin(), static_cast<int(*)(int)>(toupper));
148  return rtn;
149  }
150 
151  ///@}
152 
153 
154  /// @name Filesystem utils
155  ///@{
156 
157  /// Check if a path @a p (either file or dir) exists
158  bool path_exists(const std::string& p,int mode=0);
159 
160  /// Check if a file @a p exists
161  bool file_exists(const std::string& p,int mode=0);
162 
163  /// Check if a dir @a p exists
164  bool dir_exists(const std::string& p,int mode=0);
165 
166  /// Operator for joining strings @a a and @a b with filesystem separators
167  inline std::string operator / (const std::string& a, const std::string& b) {
168  // Ensure that a doesn't end with a slash, and b doesn't start with one, to avoid "//"
169  const string anorm = (a.find("/") != std::string::npos) ? a.substr(0, a.find_last_not_of("/")+1) : a;
170  const string bnorm = (b.find("/") != std::string::npos) ? b.substr(b.find_first_not_of("/")) : b;
171  return anorm + "/" + bnorm;
172  }
173 
174  /// Get the basename (i.e. terminal file name) from a path @a p
175  inline std::string basename(const std::string& p) {
176  if (!contains(p, "/")) return p;
177  return p.substr(p.rfind("/")+1);
178  }
179 
180  /// Get the dirname (i.e. path to the penultimate directory) from a path @a p
181  inline std::string dirname(const std::string& p) {
182  if (!contains(p, "/")) return "";
183  return p.substr(0, p.rfind("/"));
184  }
185 
186  /// Get the stem (i.e. part without a file extension) from a filename @a f
187  inline std::string file_stem(const std::string& f) {
188  if (!contains(f, ".")) return f;
189  return f.substr(0, f.rfind("."));
190  }
191 
192  /// Get the file extension from a filename @a f
193  inline std::string file_extn(const std::string& f) {
194  if (!contains(f, ".")) return "";
195  return f.substr(f.rfind(".")+1);
196  }
197 
198  /// @todo Add an abspath(p) function
199 
200  ///@}
201 
202 
203  /// @name Math functions
204  ///@{
205 
206  /// Convenience function for squaring (of any type)
207  template <typename N>
208  inline N sqr(const N& x) { return x*x; }
209 
210  /// Get the sign of a number
211  template <typename N>
212  inline int sgn(N val) { return (N(0) < val) - (val < N(0)); }
213 
214  /// Check if a number is in a range (closed-open)
215  inline int in_range(double x, double low, double high) { return x >= low && x < high; }
216 
217  /// Check if a number is in a range (closed-closed)
218  inline int in_closed_range(double x, double low, double high) { return x >= low && x <= high; }
219 
220  /// Check if a number is in a range (open-open)
221  inline int in_open_range(double x, double low, double high) { return x > low && x < high; }
222 
223  /// @todo Add iszero() & equals(,) functions?
224 
225  /// Quantiles of the standard normal probability distribution function
226  double norm_quantile(double p);
227 
228  /// Quantiles of the chi-squared probability distribution function
229  double chisquared_quantile(double p, double ndf);
230 
231  ///@}
232 
233 
234  /// @name Container utils
235  ///@{
236 
237  /// Does the vector<T> @a container contain @a item?
238  template <typename T>
239  inline bool contains(const std::vector<T>& container, const T& item) {
240  return find(container.begin(), container.end(), item) != container.end();
241  }
242 
243  // /// Does the set<T> @a container contain @a item?
244  // template <typename T>
245  // inline bool contains(const std::set<T>& container, const T& item) {
246  // return container.find(item) != container.end();
247  // }
248 
249  /// Does the map<K,T> @a container have a key K @a key?
250  template <typename K, typename T>
251  inline bool has_key(const std::map<K,T>& container, const K& key) {
252  return container.find(key) != container.end();
253  }
254 
255  // /// @name Implementation of generic begin/end container identification by traits
256  // /// taken from http://stackoverflow.com/a/9407420/91808 . Needs C++11 (or maybe just C++0x).
257  // //@{
258 
259  // #include <type_traits>
260 
261  // template<typename T>
262  // struct has_const_iterator {
263  // private:
264  // typedef char yes;
265  // typedef struct { char array[2]; } no;
266  // template<typename C> static yes test(typename C::const_iterator*);
267  // template<typename C> static no test(...);
268  // public:
269  // static const bool value = sizeof(test<T>(0)) == sizeof(yes);
270  // typedef T type;
271  // };
272 
273  // template <typename T>
274  // struct has_begin_end {
275  // template<typename C> static char (&f(typename std::enable_if<
276  // std::is_same<decltype(static_cast<typename C::const_iterator (C::*)() const>(&C::begin)),
277  // typename C::const_iterator(C::*)() const>::value, void>::type*))[1];
278 
279  // template<typename C> static char (&f(...))[2];
280 
281  // template<typename C> static char (&g(typename std::enable_if<
282  // std::is_same<decltype(static_cast<typename C::const_iterator (C::*)() const>(&C::end)),
283  // typename C::const_iterator(C::*)() const>::value, void>::type*))[1];
284 
285  // template<typename C> static char (&g(...))[2];
286 
287  // static bool const beg_value = sizeof(f<T>(0)) == 1;
288  // static bool const end_value = sizeof(g<T>(0)) == 1;
289  // };
290 
291  // template<typename T>
292  // struct is_container
293  // : std::integral_constant<bool, has_const_iterator<T>::value &&
294  // has_begin_end<T>::beg_value && has_begin_end<T>::end_value>
295  // { };
296 
297  ///@}
298 
299 
300 }
301 #endif