Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 : Copyright (c) 2011-2023 The plumed team
3 : (see the PEOPLE file at the root of the distribution for a list of names)
4 :
5 : See http://www.plumed.org for more information.
6 :
7 : This file is part of plumed, version 2.
8 :
9 : plumed is free software: you can redistribute it and/or modify
10 : it under the terms of the GNU Lesser General Public License as published by
11 : the Free Software Foundation, either version 3 of the License, or
12 : (at your option) any later version.
13 :
14 : plumed is distributed in the hope that it will be useful,
15 : but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : GNU Lesser General Public License for more details.
18 :
19 : You should have received a copy of the GNU Lesser General Public License
20 : along with plumed. If not, see <http://www.gnu.org/licenses/>.
21 : +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
22 : #ifndef __PLUMED_tools_Tools_h
23 : #define __PLUMED_tools_Tools_h
24 :
25 : #include "AtomNumber.h"
26 : #include "Vector.h"
27 : #include "Tensor.h"
28 : #include "small_vector/small_vector.h"
29 : #include <string_view>
30 : #include <vector>
31 : #include <string>
32 : #include <cctype>
33 : #include <cstdio>
34 : #include <cmath>
35 : #include <limits>
36 : #include <algorithm>
37 : #include <sstream>
38 : #include <memory>
39 : #include <cstddef>
40 : #include <queue>
41 : #include <mutex>
42 : #include <filesystem>
43 : #include <utility>
44 : #include <unordered_map>
45 : #include <map>
46 : #include <condition_variable>
47 : #include <type_traits>
48 :
49 : namespace PLMD {
50 :
51 : class IFile;
52 :
53 : /// \ingroup TOOLBOX
54 : /// Very small non-zero number
55 : constexpr double epsilon(std::numeric_limits<double>::epsilon());
56 :
57 : /// \ingroup TOOLBOX
58 : /// Boltzman constant in kj/K
59 : constexpr double kBoltzmann(0.0083144621);
60 :
61 : /// \ingroup TOOLBOX
62 : /// PI
63 : constexpr double pi(3.141592653589793238462643383279502884197169399375105820974944592307);
64 : /// \ingroup TOOLBOX
65 : /// PI / 2
66 : constexpr double halfpi=PLMD::pi*0.5;
67 : /// \ingroup TOOLBOX
68 : /// PI * 2
69 : constexpr double twopi=PLMD::pi*2.0;
70 :
71 : constexpr double dp2cutoff(6.25);
72 :
73 : constexpr double dp2cutoffA=1.00193418799744762399; // 1.0/(1-std::exp(-dp2cutoff));
74 : constexpr double dp2cutoffB=-.00193418799744762399; // -std::exp(-dp2cutoff)/(1-std::exp(-dp2cutoff));
75 :
76 6593 : inline static bool dp2cutoffNoStretch() {
77 6593 : static const auto* res=std::getenv("PLUMED_DP2CUTOFF_NOSTRETCH");
78 6593 : return res;
79 : }
80 :
81 : /// \ingroup TOOLBOX
82 : /// Empty class which just contains several (static) tools
83 : class Tools {
84 : /// class to convert a string to a generic type T
85 : template<class T>
86 : static bool convertToAny(const std::string & str,T &t);
87 : /// class to convert a string to a real type T.
88 : /// T should be either float, double, or long double
89 : template<class T>
90 : static bool convertToReal(const std::string & str,T &t);
91 : /// class to convert a string to a int type T
92 : template<class T>
93 : static bool convertToInt(const std::string & str,T &t);
94 : /// @brief the recursive part of the template fastpow implementation
95 : template <int exp, typename T=double, std::enable_if_t< (exp >=0), bool> = true>
96 : static constexpr inline T fastpow_rec(T base, T result);
97 : public:
98 : static constexpr std::string_view replicaToken="@replicas:";
99 : /// Split the line in words using separators.
100 : /// It also take into account parenthesis. Outer parenthesis found are removed from
101 : /// output, and the text between them is considered as a single word. Only the
102 : /// outer parenthesis are processed, to allow nesting them.
103 : /// parlevel, if not NULL, is increased or decreased according to the number of opened/closed parenthesis
104 : static std::vector<std::string> getWords(std::string_view line,
105 : const char* sep=NULL,
106 : int* parlevel=NULL,
107 : const char* parenthesis="{",
108 : bool delete_parenthesis=true);
109 : /// Faster version
110 : /// This version does not parse parenthesis and operates on a preallocated small_vector of string_view's
111 : static void getWordsSimple(gch::small_vector<std::string_view> & words,
112 : std::string_view line);
113 : static void getWordsSimple(gch::small_vector<std::string_view> & words,
114 : std::string_view line,
115 : std::string_view sep);
116 : /// Get a line from the file pointer ifile
117 : static bool getline(FILE*,std::string & line);
118 : /// Get a parsed line from the file pointer ifile
119 : /// This function already takes care of joining continued lines and splitting the
120 : /// resulting line into an array of words
121 : static bool getParsedLine(IFile&ifile,std::vector<std::string> & line, const bool trimcomments=true);
122 : /// compare two string in a case insensitive manner
123 : static bool caseInSensStringCompare(std::string_view str1, std::string_view str2);
124 : /// Convert a string to a double, reading it
125 : static bool convertNoexcept(const std::string & str,double & t);
126 : /// Convert a string to a long double, reading it
127 : static bool convertNoexcept(const std::string & str,long double & t);
128 : /// Convert a string to a float, reading it
129 : static bool convertNoexcept(const std::string & str,float & t);
130 : /// Convert a string to a int, reading it
131 : static bool convertNoexcept(const std::string & str,int & t);
132 : /// Convert a string to a long int, reading it
133 : static bool convertNoexcept(const std::string & str,long int & t);
134 : /// Convert a string to a long long int, reading it
135 : static bool convertNoexcept(const std::string & str,long long int & t);
136 : /// Convert a string to an unsigned int, reading it
137 : static bool convertNoexcept(const std::string & str,unsigned & t);
138 : /// Convert a string to a long unsigned int, reading it
139 : static bool convertNoexcept(const std::string & str,long unsigned & t);
140 : /// Convert a string to a long long unsigned int, reading it
141 : static bool convertNoexcept(const std::string & str,long long unsigned & t);
142 : /// Convert a string to a atom number, reading it
143 : static bool convertNoexcept(const std::string & str,AtomNumber & t);
144 : /// Convert a string to a string (i.e. copy)
145 : static bool convertNoexcept(const std::string & str,std::string & t);
146 : /// Convert anything into a string
147 : template<typename T>
148 : static bool convertNoexcept(T i,std::string & str);
149 : /// Convert anything into anything, throwing an exception in case there is an error
150 : /// Remove trailing blanks
151 : static void trim(std::string & s);
152 : /// Remove leading blanks
153 : static void ltrim(std::string & s);
154 : /// Remove trailing comments
155 : static void trimComments(std::string & s);
156 : /// Apply pbc for a unitary cell
157 : template <typename T>
158 : static double pbc(T);
159 : /// Retrieve a key from a vector of options.
160 : /// It finds a key starting with "key=" or equal to "key" and copy the
161 : /// part after the = on s. E.g.:
162 : /// line.push_back("aa=xx");
163 : /// getKey(line,"aa",s);
164 : /// will set s="xx"
165 : static bool getKey(std::vector<std::string>& line,
166 : const std::string & key,
167 : std::string & s,
168 : int rep=-1);
169 : static std::string_view unravelReplicas(std::string_view argument,
170 : int rep=-1);
171 : template <typename T,typename U>
172 25154699 : static void convert(const T & t,U & u) {
173 25156207 : plumed_assert(convertNoexcept(t,u)) <<"Error converting "<<t;
174 25154698 : }
175 : /// Find a keyword on the input line, eventually deleting it, and saving its value to val
176 : template <typename T>
177 : static bool parse(std::vector<std::string>&line,
178 : const std::string&key,
179 : T&val,
180 : int rep=-1);
181 : /// Parse the argument and eventually unrave the variant for the current replica
182 : template <typename T>
183 : static bool parse(std::string_view argument, T&val);
184 : /// Find a keyword on the input line, eventually deleting it, and saving its value to a vector
185 : template <class T>
186 : static bool parseVector(std::vector<std::string>&line,const std::string&key,std::vector<T>&val,int rep=-1);
187 : template <class T>
188 : static bool parseVector(
189 : const std::string_view argument,
190 : std::vector<T>&val,
191 : int rep=-1) ;
192 : /// Find a keyword without arguments on the input line
193 : static bool parseFlag(std::vector<std::string>&line,const std::string&key,bool&val);
194 : /// Find a keyword on the input line, just reporting if it exists or not
195 : static bool findKeyword(const std::vector<std::string>&line,const std::string&key);
196 : /// Interpret atom ranges
197 : static void interpretRanges(std::vector<std::string>&);
198 : /// Remove duplicates from a vector of type T
199 : template <typename T>
200 : static void removeDuplicates(std::vector<T>& vec);
201 : /// interpret ":" syntax for labels
202 : static void interpretLabel(std::vector<std::string>&s);
203 : /// list files in a directory
204 : static std::vector<std::string> ls(const std::string&);
205 : /// removes leading and trailing blanks from a string
206 : static void stripLeadingAndTrailingBlanks( std::string& str );
207 : /// Extract the extensions from a file name.
208 : /// E.g.: extension("pippo.xyz")="xyz".
209 : /// It only returns extensions with a length between 1 and 4
210 : /// E.g.: extension("pippo.12345")="" whereas extenion("pippo.1234")="1234";
211 : /// It is also smart enough to detect "/", so that
212 : /// extension("pippo/.t")="" whereas extension("pippo/a.t")="t"
213 : static std::string extension(const std::string&);
214 : /// Fast int power
215 : template <typename T>
216 : static constexpr inline T fastpow(T base,int exp);
217 : /// Fast int power for power known at compile time
218 : template <int exp, typename T=double>
219 : static constexpr inline T fastpow(T base);
220 : /// Modified 0th-order Bessel function of the first kind
221 : static double bessel0(const double& val);
222 : /// Check if a string full starts with string start.
223 : /// Same as full.find(start)==0, but faster
224 : static bool startWith(std::string_view full, std::string_view start);
225 : /**
226 : Tool to create a vector of raw pointers from a vector of unique_pointers (const version).
227 : Returning a vector is fast in C++11. It can be used in order to feed a vector<unique_ptr<T>>
228 : to a function that takes a vector<T*>.
229 : \verbatim
230 : // some function that takes a vec
231 : void func(std::vector<Data*> & vec);
232 : std::vector<std::unique_ptr<Data>> vec;
233 : // func(vec); // does not compile
234 : func(Tools::unique2raw(vec)); // compiles
235 : \endverbatim
236 : Notice that the conversion is fast but takes
237 : some time to allocate the new vector and copy the pointers. In case the function
238 : acting on the vector<T*> is very fast and we do not want to add significant overhead,
239 : it might be convenient to store a separate set of raw pointers.
240 : \verbatim
241 : // some function that takes a vec
242 : void func(std::vector<Data*> & vec);
243 : std::vector<std::unique_ptr<Data>> vec;
244 :
245 : // conversion done only once:
246 : auto vec_ptr=Tools::unique2raw(vec);
247 :
248 : for(int i=0;i<1000;i++){
249 : func(vec_ptr);
250 : }
251 : \endverbatim
252 : */
253 : template <typename T>
254 : static std::vector<T*> unique2raw(const std::vector<std::unique_ptr<T>>&);
255 : /// Tool to create a vector of raw pointers from a vector of unique_pointers.
256 : /// See the non const version.
257 : template <typename T>
258 : static std::vector<const T*> unique2raw(const std::vector<std::unique_ptr<const T>>&);
259 : /// Tiny class that changes directory and comes back when going out of scope.
260 : /// In case system calls to change dir are not available it throws an exception.
261 : /// \warning By construction, changing directory breaks thread safety! Use with care.
262 : class DirectoryChanger {
263 : const std::filesystem::path originalpath;
264 : public:
265 : explicit DirectoryChanger(const char*path);
266 : ~DirectoryChanger();
267 : };
268 :
269 : template<class T, class... Args>
270 : static auto make_unique(Args&&... args) {
271 172439 : return std::make_unique<T>(std::forward<Args>(args)...);
272 : }
273 :
274 : template <typename T>
275 : static void set_to_zero(T*ptr, const unsigned n) {
276 29047 : const auto end=ptr+n;
277 1279471 : for(; ptr < end; ++ptr) {
278 1250424 : *ptr=T(0.0);
279 : }
280 : }
281 :
282 : template<typename T, unsigned n>
283 29047 : static void set_to_zero(std::vector<VectorTyped<T,n>> & vec) {
284 29047 : unsigned s=vec.size();
285 29047 : if(s==0) {
286 : return;
287 : }
288 29047 : set_to_zero(vec[0].data(),s*n);
289 : }
290 :
291 : template<typename T, unsigned n,unsigned m>
292 : static void set_to_zero(std::vector<TensorTyped<T,n,m>> & vec) {
293 : unsigned s=vec.size();
294 : if(s==0) {
295 : return;
296 : }
297 : set_to_zero(vec[0].data(),s*n*m);
298 : }
299 :
300 : static std::unique_ptr<std::lock_guard<std::mutex>> molfile_lock();
301 : /// Build a concatenated exception message.
302 : /// Should be called with an in-flight exception.
303 : static std::string concatenateExceptionMessages();
304 :
305 :
306 : /// Tiny class implementing faster std::string_view access to an unordered_map
307 : /// It exposes a limited number of methods of std::unordered_map. Others could be added.
308 : /// Importantly, when it is accessed via a std::string_view, the access does not
309 : /// require constructing a std::string and is thus faster.
310 : /// Deletion would be slower instead. It's not even implemented yet.
311 : template<class T>
312 809663 : class FastStringUnorderedMap {
313 : using container=std::unordered_map<std::string_view,T>;
314 : using keytype = std::unique_ptr<const char[]>;
315 : using keyholder = std::vector<keytype>;
316 : container map;
317 : keyholder keys;
318 : // see https://stackoverflow.com/questions/34596768/stdunordered-mapfind-using-a-type-different-than-the-key-type
319 687889 : static keytype conv(std::string_view const str) {
320 687889 : auto p=std::make_unique<char[]>(str.size()+1);
321 : std::memcpy(p.get(), str.data(), str.size());
322 : //the string_view might be a view of a longer string, so the last char might not be null
323 687889 : p[str.size()]='\0';
324 687889 : return p;
325 : }
326 :
327 : public:
328 :
329 : FastStringUnorderedMap() = default;
330 22131 : FastStringUnorderedMap(std::initializer_list<std::pair<const std::string_view,T>> init) {
331 688340 : for(const auto & c : init) {
332 666209 : (*this)[c.first]=c.second;
333 : }
334 22131 : }
335 :
336 5204814 : T& operator[]( const std::string_view & key ) {
337 : auto f=map.find(key);
338 5204814 : if(f!=map.end()) {
339 4516925 : return f->second;
340 : }
341 1375778 : keys.push_back(conv(key));
342 687889 : return map[keys.back().get()];
343 : }
344 :
345 : auto begin() noexcept {
346 : return map.begin();
347 : }
348 : auto end() noexcept {
349 : return map.end();
350 : }
351 : auto begin() const noexcept {
352 : return map.begin();
353 : }
354 : auto end() const noexcept {
355 : return map.end();
356 : }
357 : auto find(const std::string_view & key) {
358 : return map.find(key);
359 : }
360 : auto find(const std::string_view & key) const {
361 : return map.find(key);
362 : }
363 : };
364 :
365 : /// Utility to create named critical sections
366 : /// Key should be usable in a std::map
367 : template<class Key>
368 : class CriticalSectionWithKey {
369 : std::mutex mutex;
370 : std::condition_variable notify;
371 : std::map<Key, int> in_progress;
372 : public:
373 28 : void start(const Key & key) {
374 28 : std::unique_lock<std::mutex> lock(mutex);
375 140 : while (in_progress[key] > 0) {
376 : // Wait if this command is already in progress.
377 112 : notify.wait(lock);
378 : }
379 : // Mark this command as in progress.
380 28 : in_progress[key]++;
381 28 : }
382 28 : void stop(const Key & key) {
383 28 : std::unique_lock<std::mutex> lock(mutex);
384 : // Mark this command as completed.
385 28 : in_progress[key]--;
386 : // Notify other threads that may be waiting for this command to complete.
387 28 : notify.notify_all();
388 28 : }
389 : class Handler {
390 : CriticalSectionWithKey* section{nullptr};
391 : Key key;
392 28 : Handler(CriticalSectionWithKey* mysection,const Key& mykey):
393 28 : section(mysection),
394 28 : key(mykey) {
395 28 : section->start(key);
396 28 : }
397 : friend class CriticalSectionWithKey;
398 : public:
399 : /// Default constructor
400 : Handler() = default;
401 : /// Default copy constructor is deleted (not copyable)
402 : Handler(const Handler & handler) = delete;
403 : /// Default copy assignment is deleted (not copyable)
404 : Handler & operator=(const Handler & handler) = delete;
405 : /// Move constructor.
406 : Handler(Handler && handler) noexcept :
407 : section(handler.section),
408 : key(std::move(handler.key)) {
409 : handler.section=nullptr;
410 : };
411 : /// Move assignment.
412 : Handler & operator=(Handler && handler) noexcept {
413 : if(this!=&handler) {
414 : if(section) {
415 : section->stop(key);
416 : }
417 : section=handler.section;
418 : key=std::move(handler.key);
419 : }
420 : handler.section=nullptr;
421 : return *this;
422 : }
423 : /// Destructor
424 28 : ~Handler() {
425 28 : if(section) {
426 28 : section->stop(key);
427 : }
428 28 : }
429 : };
430 :
431 : Handler startStop(const Key & key) {
432 28 : return Handler(this,key);
433 : }
434 :
435 : };
436 : ///Correct the "escape sequences" from regexes to be compatible with the json format
437 : ///
438 : ///C++ wants a raw string (like `R"<<(content)<<"`) for the regexes
439 : ///and the python package json (and the json format itself actually)
440 : /// wants the various '\' to be escaped with and '\' because the interpreter tries
441 : /// to read anything that begins with '\' as an escape sequence (it does not know that it is an input for a regex)
442 : ///
443 : /// For example '\n' will not cause an error but it will be intepreted as and explicit newline, so we we want '\\n' in the json
444 : /// whereas '\.' will cause an erron when read by python
445 : static std::string convertRegexForJson (const std::string& command);
446 : };
447 :
448 : template <class T>
449 12597 : bool Tools::parse(std::vector<std::string>&line,
450 : const std::string&key,
451 : T&val,
452 : int rep) {
453 : std::string s;
454 25194 : if(!getKey(line,key+"=",s,rep)) {
455 : return false;
456 : }
457 8457 : if(s.length()>0 && !convertNoexcept(s,val)) {
458 : return false;
459 : }
460 : return true;
461 : }
462 :
463 : template <class T>
464 172723 : bool Tools::parse(std::string_view argument,
465 : T&val) {
466 : //NOTE: this expects the '@replica:' on the argument to be resolved by the caller
467 518169 : return argument.length()>0 && convertNoexcept(std::string(argument),val);
468 : }
469 :
470 : template <class T>
471 4647 : bool Tools::parseVector(std::vector<std::string>&line,const std::string&key,std::vector<T>&val,int rep) {
472 : std::string argument;
473 9294 : if(!getKey(line,key+"=",argument,rep)) {
474 : return false;
475 : }
476 639 : val.clear();
477 : //needs to get the parenteses
478 639 : std::vector<std::string> argWords=getWords(argument,"\t\n ,");
479 639 : val.reserve(argWords.size());
480 3421 : for(unsigned i=0; i<argWords.size(); ++i) {
481 : T v;
482 2782 : std::string s=argWords[i];
483 2782 : if(rep>=0 && startWith(s,replicaToken)) {
484 0 : s=s.substr(replicaToken.length(),s.length());
485 0 : std::vector<std::string> words=getWords(s,"\t\n ,");
486 0 : plumed_assert(rep<static_cast<int>(words.size()));
487 0 : s=words[rep];
488 0 : }
489 2782 : if(!convertNoexcept(s,v)) {
490 : return false;
491 : }
492 2782 : val.push_back(v);
493 : }
494 : return true;
495 639 : }
496 :
497 : template <class T>
498 520025 : bool Tools::parseVector(
499 : const std::string_view argument,
500 : std::vector<T>&val,
501 : int rep) {
502 : //NOTE: this expects the '@replica' on the argument of the whole vector to be resolved by the caller
503 212820 : val.clear();
504 : gch::small_vector<std::string_view> words;
505 520025 : getWordsSimple(words,argument,"\t\n ,");
506 520025 : val.reserve(words.size());
507 8869934 : for(unsigned i=0; i<words.size(); ++i) {
508 : T v;
509 16699818 : auto s=std::string(unravelReplicas(words[i],rep));
510 : // The erase/remove is there, because @ndx:{file tag} was not passing in some tests
511 8349909 : s.erase(std::remove_if(s.begin(),s.end(),
512 : [](unsigned char x) {
513 21865419 : switch (x) {
514 : case '{':
515 : case '}':
516 : return true;
517 : }
518 : return false;
519 : }),s.end());
520 8349909 : if(!convertNoexcept(s,v)) {
521 : return false;
522 : }
523 8349909 : val.push_back(v);
524 : }
525 : return true;
526 : }
527 : template<typename T>
528 15903 : void Tools::removeDuplicates(std::vector<T>& vec) {
529 15903 : std::sort(vec.begin(), vec.end());
530 15903 : vec.erase(std::unique(vec.begin(), vec.end()), vec.end());
531 15903 : }
532 :
533 : inline
534 4098 : bool Tools::parseFlag(std::vector<std::string>&line,const std::string&key,bool&val) {
535 16105 : for(auto p=line.begin(); p!=line.end(); ++p) {
536 12122 : if(key==*p) {
537 115 : val=true;
538 : line.erase(p);
539 : return true;
540 : }
541 : }
542 : return false;
543 : }
544 :
545 : /// beware: this brings any number into a pbc that ranges from -0.5 to 0.5
546 : template <typename T>
547 1966561608 : inline double Tools::pbc(T x) {
548 : #ifdef __PLUMED_PBC_WHILE
549 : while (x>0.5) {
550 : x-=1.0;
551 : }
552 : while (x<-0.5) {
553 : x+=1.0;
554 : }
555 : return x;
556 : #else
557 : if constexpr (std::is_same_v<T,float>) {
558 : // In single precision the offset used below costs accuracy: the spacing of floats
559 : // close to 100 is 7.6e-6, so the result would have an error up to 3.8e-6
560 : // whatever the value of x (e.g. in the scaled coordinates of a triclinic box
561 : // in the single precision GPU code). x-rint(x) is exact and branch-free.
562 : // At exact ties (x=+-0.5) the result can be +0.5 or -0.5 (both are valid images).
563 300000 : return x-std::rint(x);
564 : } else if constexpr (std::numeric_limits<int>::round_style == std::round_toward_zero) {
565 : constexpr T offset=100.0;
566 1966561608 : x+=offset;
567 1966561608 : if(x>=0) {
568 1966557030 : return x-int(x+0.5);
569 : } else {
570 4578 : return x-int(x-0.5);
571 : }
572 : } else if constexpr (std::numeric_limits<int>::round_style == std::round_to_nearest) {
573 : return x-int(x);
574 : } else {
575 : return x-floor(x+0.5);
576 : }
577 : #endif
578 : }
579 :
580 : template<typename T>
581 10425202 : bool Tools::convertNoexcept(T i,std::string & str) {
582 10425202 : std::ostringstream ostr;
583 1164397 : ostr<<i;
584 10425202 : str=ostr.str();
585 10425202 : return true;
586 10425202 : }
587 :
588 : template <typename T>
589 57598109 : constexpr inline T Tools::fastpow(T base, int exp) {
590 57598109 : if(exp<0) {
591 0 : exp=-exp;
592 0 : base=1.0/base;
593 : }
594 : double result = 1.0;
595 294642043 : while (exp) {
596 203443742 : if (exp & 1) {
597 143862573 : result *= base;
598 : }
599 203443742 : exp >>= 1;
600 203443742 : base *= base;
601 : }
602 :
603 57598109 : return result;
604 : }
605 :
606 : template <int exp, typename T, std::enable_if_t< (exp >=0), bool>>
607 : constexpr inline T Tools::fastpow_rec(T const base, T result) {
608 : if constexpr (exp == 0) {
609 : return result;
610 : }
611 : if constexpr (exp & 1) {
612 19591705 : result *= base;
613 : }
614 11594341 : return fastpow_rec<(exp>>1),T> (base*base, result);
615 : }
616 :
617 : template <int exp, typename T>
618 : constexpr inline T Tools::fastpow(T const base) {
619 : if constexpr (exp<0) {
620 : return fastpow_rec<-exp,T>(1.0/base,1.0);
621 : } else {
622 : return fastpow_rec<exp,T>(base, 1.0);
623 : }
624 : }
625 :
626 : template<typename T>
627 1308 : std::vector<T*> Tools::unique2raw(const std::vector<std::unique_ptr<T>> & x) {
628 1308 : std::vector<T*> v(x.size());
629 2683 : for(unsigned i=0; i<x.size(); i++) {
630 1375 : v[i]=x[i].get();
631 : }
632 1308 : return v;
633 : }
634 :
635 : template<typename T>
636 : std::vector<const T*> Tools::unique2raw(const std::vector<std::unique_ptr<const T>> & x) {
637 : std::vector<const T*> v(x.size());
638 : for(unsigned i=0; i<x.size(); i++) {
639 : v[i]=x[i].get();
640 : }
641 : return v;
642 : }
643 :
644 : }
645 :
646 : #endif
|