1 //
2 //  Copyright (C) 2020 Gareth Jones, Glysade LLC
3 //
4 //   @@ All Rights Reserved @@
5 //  This file is part of the RDKit.
6 //  The contents are covered by the terms of the BSD license
7 //  which is included in the file license.txt, found at the root
8 //  of the RDKit source tree.
9 
10 
11 #ifndef UTIL_H_
12 #define UTIL_H_
13 
14 #include <cmath>
15 #include <limits>
16 #include <cstdio>
17 #include <ctime>
18 #include <string>
19 #include <iostream>
20 #include <iterator>
21 #include <fstream>
22 #include <sstream>
23 #include <vector>
24 #include <memory>
25 #include <map>
26 #include <algorithm>
27 #include <boost/optional.hpp>
28 #include "export.h"
29 
30 /*
31  * Utility methods
32  */
33 namespace GarethUtil {
34 
35     using namespace std;
36 
37 /*
38  * Return current time as string
39  */
40     string currentTime();
41 
42 /**
43  *
44  * @param str
45  * @param prefix
46  * @return true id str starts with prefix
47  */
48     GA_EXPORT bool startsWith(string str, string prefix);
49 
50 /**
51  *
52  * @return current user name
53  */
54     GA_EXPORT string getUserName();
55 
56 /**
57  * Template function to convert a string to a type.  Can optionally process a substring
58  *
59  * @param str
60  * @param ok optional boolean reference to indicate success or failure
61  * @param start optional start position
62  * @param end optional end position
63  * @return
64  */
65     template<typename T>
66     T convertString(const string &str, bool *const ok =
67     nullptr, size_t start = 0, size_t noChars = 0) {
68         if (ok != nullptr)
69             *ok = false;
70         T rtn;
71         if (str.empty())
72             return rtn;
73         if (start >= str.length())
74             return rtn;
75         if (noChars == 0)
76             noChars = str.length() - start;
77         string field = str.substr(start, noChars);
78         stringstream ss(field);
79         ss >> rtn;
80         if (!ss.fail()) {
81             if (ok != nullptr)
82                 *ok = true;
83         }
84         return rtn;
85     }
86 
87 /**
88  * Template function to write all elements of a vector to a string
89  *
90  * @param vec
91  * @param seperator
92  * @return
93  */
94     template<typename T>
95     string collectionToString(const T &vec,
96                               const string &seperator = ", ") {
97         stringstream ss;
98         std::copy(vec.begin(), vec.end(),
99                   ostream_iterator<typename T::value_type>(ss, seperator.c_str()));
100         // erase trailing separator
101         string rtn = ss.str();
102         if (!rtn.empty())
103             rtn.erase(rtn.length() - seperator.length(), seperator.length());
104         return rtn;
105     }
106 
107 /**
108  * Removes any trailing linefeed (\r) from a string
109  * @param line
110  * @return
111  */
112     GA_EXPORT string &removeTrailingLF(string &line);
113 
114 /**
115  * Determines if a key is present in a map
116  *
117  * @param key
118  * @param map
119  * @param value  optionally set the value for the key
120  * @return
121  */
122     template<typename K, typename V>
123     bool isKeyPresent(const K key, const map<K, V> &map,
124                       V *const value = nullptr) {
125         auto iter = map.find(key);
126         if (iter != map.end()) {
127             if (value != nullptr)
128                 *value = iter->second;
129             return true;
130         }
131         return false;
132     }
133 
134 /**
135  * Bs whitespace from beginning and end of string.  Original argument is modified and returned.
136  * @param str
137  * @return
138  */
139     GA_EXPORT string &trim(string &str);
140 
141 /**
142  * Converts string to upper case.  Original argument is modified and returned.
143  * @param str
144  * @return
145  */
146     GA_EXPORT string &toUpperCase(string &str);
147 
148 /**
149  * Converts string to lower case.  Original argument is modified and returned.
150  * @param str
151  * @return
152  */
153     GA_EXPORT string &toLowerCase(string &str);
154 
155 /**
156  * @param str1
157  * @param str2
158  * @return true if the two strings are equal
159  */
160     GA_EXPORT bool equals(const string &str1, const string &str2);
161 
162 /**
163  * @param str1
164  * @param str2
165  * @return true if the two strings are equal (case insensitive)
166  */
167     GA_EXPORT bool equalsIgnoreCase(const string &str1, const string &str2);
168 
169 /**
170  *
171  * @param str
172  * @param suffix
173  * @return true if str ends with suffix
174  */
175     GA_EXPORT bool endsWith(const string &str, const string &suffix);
176 
177 /**
178  *
179  * @param vector
180  * @param value
181  * @return true if vector contains value
182  */
183     template<typename T>
contains(std::vector<T> vector,T value)184     bool contains(std::vector<T> vector, T value) {
185         return std::find(vector.begin(), vector.end(), value) != vector.end();
186     }
187 
188 /**
189  * Determines if two double numbers are equal within multiples of machine precision
190  *
191  * @param d1
192  * @param d2
193  * @param ulp machine precision (units in the last place)
194  * @return
195  */
196     GA_EXPORT bool equals(const double d1, const double d2, const int ulp);
197 
198 /**
199  * Returns true if the two numbers are within epsilon of each other
200  *
201  * @param d1
202  * @param d2
203  * @param epsilon
204  * @return
205  */
206     GA_EXPORT bool equals(const double d1, const double d2, const double epsilon);
207 
208 /**
209  * Determines if two double numbers are within one unit of the last place.
210  *
211  * @param d1
212  * @param d2
213  * @return
214  */
215     GA_EXPORT bool equals(const double d1, const double d2);
216 
217 /**
218  * Finds the first occurrence of an matching item in a list
219  *
220  * @param values
221  * @param matcher
222  * @return
223  */
224     template<typename T>
findFirstInList(const std::vector<T> & values,const function<bool (T)> & matcher)225     boost::optional<T> findFirstInList(const std::vector<T> &values,
226                                        const function<bool(T)> &matcher) {
227         auto iter = std::find_if(values.cbegin(), values.cend(), matcher);
228         if (iter != values.cend()) {
229             return *iter;
230         }
231         return boost::none;
232     }
233 
234 /**
235  * Finds the first occurrence of an matching item in a list of unique pointers
236  *
237  * @param values
238  * @param matcher
239  * @return
240  */
241     template<typename T>
findFirstInUniquePtrList(const std::vector<unique_ptr<T>> & values,const function<bool (const unique_ptr<T> &)> & matcher)242     boost::optional<T *> findFirstInUniquePtrList(
243             const std::vector<unique_ptr<T>> &values,
244             const function<bool(const unique_ptr<T> &)> &matcher) {
245         auto iter = std::find_if(values.cbegin(), values.cend(), matcher);
246         if (iter != values.cend()) {
247             return iter->get();
248         }
249         return boost::none;
250     }
251 
252 /**
253  * Removes all items from a list that DON'T match the filter.  Alters and returns the original list.
254  *
255  * @param values
256  * @param filter
257  * @return
258  */
259     template<typename T>
filterList(std::vector<T> & values,const function<bool (T &)> & filter)260     std::vector<T> &filterList(std::vector<T> &values,
261                                const function<bool(T &)> &filter) {
262         auto iter = remove_if(values.begin(), values.end(), not1(filter));
263         values.erase(iter, values.end());
264         return values;
265     }
266 
267 /**
268  * Creates a new vector of items in the input vector that match the filter
269  * @param values
270  * @param filter
271  * @return
272  */
273     template<typename T>
filterListToNewList(const std::vector<T> & values,const function<bool (const T &)> & filter)274     std::vector<T> filterListToNewList(const std::vector<T> &values,
275                                        const function<bool(const T &)> &filter) {
276         std::vector<T> newValues;
277         newValues.reserve(values.size());
278         copy_if(values.begin(), values.end(), back_inserter(newValues), filter);
279         return newValues;
280     }
281 
282 /**
283  * Creates a new vector of items in the input vector that match the filter.
284  * This method is specialized for an input list of unique pointers.
285  * A list of raw pointers is returned.  It is assumed that the input list will
286  * outlast the filtered list.
287  *
288  * @param values
289  * @param filter
290  * @return
291  */
292     template<typename T>
filterUniquePtrListToRawPtrList(const std::vector<unique_ptr<T>> & values,const function<bool (T &)> & filter)293     std::vector<T *> filterUniquePtrListToRawPtrList(
294             const std::vector<unique_ptr<T>> &values,
295             const function<bool(T &)> &filter) {
296         std::vector<T *> newValues;
297         newValues.reserve(values.size());
298         for (const auto &value : values) {
299             if (filter(*value)) {
300                 newValues.push_back(value.get());
301             }
302         }
303         return newValues;
304     }
305 
306 /**
307  * Specialization of the above for filtering non-const unique_ptrs to const raw pointer filtered list
308  * @param values
309  * @param filter
310  * @return
311  */
312     template<typename T>
filterUniquePtrListToConstRawPtrList(const std::vector<unique_ptr<T>> & values,const function<bool (T &)> & filter)313     std::vector<const T *> filterUniquePtrListToConstRawPtrList(
314             const std::vector<unique_ptr<T>> &values,
315             const function<bool(T &)> &filter) {
316         std::vector<const T *> newValues;
317         newValues.reserve(values.size());
318         for (const auto &value : values) {
319             if (filter(*value)) {
320                 newValues.push_back(value.get());
321             }
322         }
323         return newValues;
324     }
325 
326 /**
327  * Creates a new list from an existing list by applying the mapping function.
328  *
329  * @param values
330  * @param map
331  * @return
332  */
333     template<typename T, typename V>
mapToNewList(const std::vector<T> & values,const function<V (const T &)> & map)334     std::vector<V> mapToNewList(const std::vector<T> &values,
335                                 const function<V(const T &)> &map) {
336         std::vector<V> mappedValues;
337         mappedValues.reserve(values.size());
338         std::transform(values.cbegin(), values.cend(), back_inserter(mappedValues),
339                        map);
340         return mappedValues;
341     }
342 
343 /**
344  * Creates a new list from an existing list by applying the mapping function.
345  *
346  * @param values
347  * @param map
348  * @return
349  */
350     template<typename T>
mapToNewList(const std::vector<T> & values,const function<T (const T &)> & map)351     std::vector<T> mapToNewList(const std::vector<T> &values,
352                                 const function<T(const T &)> &map) {
353         return mapToNewList<T, T>(values, map);
354     }
355 
356 /**
357  * Applies a function to every value in a list.
358  *
359  * @param values
360  * @param func
361  */
362     template<typename T>
forEach(const std::vector<T> & values,const function<void (T &)> & func)363     void forEach(const std::vector<T> &values, const function<void(T &)> &func) {
364         for (const auto &v : values) {
365             func(v);
366         }
367     }
368 
369 /**
370  * Reduces a vector to a single value of a different type using the accumulator function.
371  *
372  * @param startingValue
373  * @param accumulator function takes accumulating value as first argument and current list value as second.
374  * @return
375  */
376     template<typename T, typename R>
reduce(const std::vector<T> & values,const R & startingValue,const function<R (R &,const T &)> accumulator)377     R reduce(const std::vector<T> &values, const R &startingValue,
378              const function<R(R &, const T &)> accumulator) {
379         R currentValue = startingValue;
380         for (auto iter = values.cbegin(); iter != values.cend(); ++iter) {
381             currentValue = accumulator(currentValue, *iter);
382         }
383         return currentValue;
384     }
385 
386 /**
387  * Writes an object to a string using the stream << operator.
388  *
389  * @param obj
390  * @return
391  */
392     template<typename T>
printToString(T obj)393     string printToString(T obj) {
394         stringstream ss;
395         ss << obj;
396         return ss.str();
397     }
398 
399 /**
400  * Retrieve an environment variable value, or none if it is not set.
401  *
402  * @param name
403  * @return
404  */
405     GA_EXPORT boost::optional<string> getEnv(const string &name);
406 
407 }
408 
409 #endif /* UTIL_H_ */
410