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