MADARA  3.4.1
Utility.inl
Go to the documentation of this file.
1 #ifndef _MADARA_UTILITY_INL_
2 #define _MADARA_UTILITY_INL_
3 
4 #include <fstream>
5 #include <stdio.h>
6 #include "Utility.h"
7 #include "SimTime.h"
8 
9 #include "boost/crc.hpp"
11 
12 #include <sys/stat.h>
13 #include <errno.h>
14 #ifdef _WIN32
15 #include "madara/Boost.h"
16 #include "boost/asio.hpp"
17 #include <direct.h>
18 #else
19 #include <pthread.h>
20 #endif
21 
22 namespace madara
23 {
24 namespace utility
25 {
26 inline bool set_thread_priority(int priority)
27 {
28  bool result = false;
29 
30 #ifdef _WIN32
31 
32  if (SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS))
33  {
34  // in Windows, normalize for highest priority
35  if (priority > THREAD_PRIORITY_HIGHEST)
36  priority = THREAD_PRIORITY_HIGHEST;
37 
38  if (SetThreadPriority(GetCurrentThread(), priority))
39  {
40  result = true;
41  }
42  }
43 
44 #else
45  // assume POSIX
46  sched_param sch;
47  int policy;
48  pthread_getschedparam(pthread_self(), &policy, &sch);
49  sch.sched_priority = priority;
50  if (0 == pthread_setschedparam(pthread_self(), SCHED_FIFO, &sch))
51  {
52  result = true;
53  }
54 #endif
55 
56  return result;
57 }
58 
61  const std::string& input, const std::string& prefix)
62 {
63  return input.substr(prefix.size());
64 }
65 
67 inline std::string& upper(std::string& input)
68 {
69  for (std::string::iterator cur = input.begin(); cur != input.end(); ++cur)
70  *cur = toupper(*cur);
71 
72  return input;
73 }
74 
77 {
78  for (std::string::iterator cur = input.begin(); cur != input.end(); ++cur)
79  {
80  // change periods to _
81  if (*cur == '.')
82  *cur = '_';
83  }
84 
85  return input;
86 }
87 
89 inline std::string& lower(std::string& input)
90 {
91  for (std::string::iterator cur = input.begin(); cur != input.end(); ++cur)
92  *cur = tolower(*cur);
93 
94  return input;
95 }
96 
97 inline bool endian_is_little()
98 {
99  static const auto detect_little_endian = []() {
100  uint16_t tester = 1;
101  char copy[2];
102  static_assert(sizeof(uint16_t) == sizeof(copy), "uint16_t isn't 2 bytes!");
103  memcpy(copy, (char*)&tester, sizeof(copy));
104  return copy[0] != 1;
105  };
106 
107  static const bool ret = detect_little_endian();
108  return ret;
109 }
110 
111 inline std::vector <std::string> string_to_vector (const std::string & input,
112  const std::string delimiter, bool strip_whitespace)
113 {
114  // split by the delimiter
115  std::vector <std::string> splitters, tokens, pivot_list;
116  splitters.push_back (delimiter);
117 
118  tokenizer (input, splitters, tokens, pivot_list);
119 
120  if (strip_whitespace)
121  {
122  for (size_t i = 0; i < tokens.size (); ++i)
123  {
124  strip_extra_white_space (tokens[i]);
125  }
126  }
127 
128  return tokens;
129 }
130 
134 inline uint64_t endian_swap(uint64_t value)
135 {
136  // if host is little endian, then we have work to do
137  if (endian_is_little())
138  {
139  value = ((value << 8) & 0xFF00FF00FF00FF00ULL) |
140  ((value >> 8) & 0x00FF00FF00FF00FFULL);
141  value = ((value << 16) & 0xFFFF0000FFFF0000ULL) |
142  ((value >> 16) & 0x0000FFFF0000FFFFULL);
143  return (value << 32) | (value >> 32);
144  }
145 
146  return value;
147 }
148 
153 inline int64_t endian_swap(int64_t value)
154 {
155  // if host is little endian, then we have work to do
156  if (endian_is_little())
157  {
158  value = ((value << 8) & 0xFF00FF00FF00FF00ULL) |
159  ((value >> 8) & 0x00FF00FF00FF00FFULL);
160  value = ((value << 16) & 0xFFFF0000FFFF0000ULL) |
161  ((value >> 16) & 0x0000FFFF0000FFFFULL);
162  return (value << 32) | ((value >> 32) & 0xFFFFFFFFULL);
163  }
164 
165  return value;
166 }
167 
171 inline uint32_t endian_swap(uint32_t value)
172 {
173  // if host is little endian, then we have work to do
174  if (endian_is_little())
175  {
176  value = ((value << 8) & 0xFF00FF00) | ((value >> 8) & 0xFF00FF);
177  return (value << 16) | (value >> 16);
178  }
179 
180  return value;
181 }
182 
187 inline int32_t endian_swap(int32_t value)
188 {
189  // if host is little endian, then we have work to do
190  if (endian_is_little())
191  {
192  value = ((value << 8) & 0xFF00FF00) | ((value >> 8) & 0xFF00FF);
193  return (value << 16) | ((value >> 16) & 0xFFFF);
194  }
195 
196  return value;
197 }
198 
203 inline uint16_t endian_swap(uint16_t value)
204 {
205  // if host is little endian, then we have work to do
206  if (endian_is_little())
207  {
208  return ((value << 8) & 0xFFFF) | (value >> 8);
209  }
210 
211  return value;
212 }
213 
218 inline int16_t endian_swap(int16_t value)
219 {
220  // if host is little endian, then we have work to do
221  if (endian_is_little())
222  {
223  return ((value << 8) & 0xFFFF) | (value >> 8);
224  }
225 
226  return value;
227 }
228 
232 inline double endian_swap(double orig)
233 {
234  // if host is little endian, then we have work to do
235  if (endian_is_little())
236  {
237  uint64_t value;
238  memcpy(&value, &orig, sizeof(value));
239 
240  value = endian_swap(value);
241 
242  double result;
243  memcpy(&result, &value, sizeof(result));
244  return result;
245  }
246 
247  return orig;
248 }
249 
250 static const uint64_t milli_per = 1000;
251 static const uint64_t micro_per = milli_per * 1000;
252 static const uint64_t nano_per = micro_per * 1000;
253 
254 static const uint64_t simtime_min_sleep = 100 * (nano_per / milli_per);
255 
257 {
258 #ifndef MADARA_FEATURE_SIMTIME
259  return Clock::now();
260 #else
261  return TimeValue(std::chrono::nanoseconds(SimTime::time()));
262 #endif
263 }
264 
265 inline int64_t get_time(void)
266 {
267  auto current_time = get_time_value();
268  auto epoch = current_time.time_since_epoch();
269  return std::chrono::duration_cast<Duration>(epoch).count();
270 }
271 
272 inline TimeValue add_seconds(const TimeValue& start, double seconds)
273 {
274  return start + seconds_to_duration(seconds);
275 }
276 
277 inline Duration seconds_to_duration(double seconds)
278 {
279  return std::chrono::duration_cast<Duration>(
280  seconds_to_seconds_duration(seconds));
281 }
282 
284 {
285  return std::chrono::duration<double>(seconds);
286 }
287 
288 inline TimeValue seconds_to_time(double seconds)
289 {
290  return TimeValue(seconds_to_duration(seconds));
291 }
292 
293 
294 inline int64_t seconds_to_nanoseconds(double seconds)
295 {
296  return seconds_to_duration (seconds).count ();
297 }
298 
299 inline bool approx_equal(double value1, double value2, double epsilon)
300 {
301  return std::abs(value1 - value2) < epsilon;
302 }
303 
304 inline bool file_exists(const std::string& filename)
305 {
306  if (FILE* file = fopen(filename.c_str(), "r"))
307  {
308  fclose(file);
309  return true;
310  }
311  else
312  {
313  return false;
314  }
315 }
316 
317 inline bool is_directory(const std::string& path)
318 {
319 #if defined(_WIN32)
320  struct _stat info;
321  if (_stat(path.c_str(), &info) != 0)
322  {
323  return false;
324  }
325  return (info.st_mode & _S_IFDIR) != 0;
326 #else
327  struct stat info;
328  if (stat(path.c_str(), &info) != 0)
329  {
330  return false;
331  }
332  return (info.st_mode & S_IFDIR) != 0;
333 #endif
334 }
335 
336 inline bool recursive_mkdir(const std::string& path)
337 {
338  if (is_directory(path))
339  {
340  return true;
341  }
342 
343 #ifdef _WIN32
344  int result = _mkdir(path.c_str());
345 #else
346  mode_t mode = 0755;
347  int result = mkdir(path.c_str(), mode);
348 #endif
349 
350  if (result == 0)
351  {
352  return true;
353  }
354 
355  switch (errno)
356  {
357  case ENOENT:
358 
359  if (recursive_mkdir(utility::extract_path(path).c_str()))
360  {
361 #ifdef _WIN32
362  return 0 == _mkdir(path.c_str());
363 #else
364  return 0 == mkdir(path.c_str(), mode);
365 #endif
366  }
367  return false;
368 
369  default:
370  return false;
371  }
372 }
373 
375 {
376  std::size_t last = name.find_last_of("/\\");
377 
378  if (last != std::string::npos)
379  return name.substr(0, last);
380 
381  return {};
382 }
383 
385 {
386  std::size_t last = name.find_last_of("/\\");
387 
388  if (last == std::string::npos)
389  return name.substr(0);
390 
391  // return the substring from start to the end of the filename
392  return name.substr(last + 1);
393 }
394 
395 inline unsigned int file_size(const std::string& filename)
396 {
397  unsigned int size = 0;
398  if (FILE* file = fopen(filename.c_str(), "r"))
399  {
400  fseek(file, 0L, SEEK_END);
401  size = ftell(file);
402  fclose(file);
403  }
404 
405  return size;
406 }
407 
408 inline size_t file_size(std::ifstream& input)
409 {
410  // save the current stream position
411  std::streampos current = input.tellg();
412 
413  // seek to the end and
414  input.seekg(0, std::ios::end);
415  std::size_t size = input.tellg();
416 
417  // revert input stream to its original position
418  input.seekg(current, std::ios::beg);
419 
420  return size;
421 }
422 
423 inline uint32_t file_crc(const std::string& filename, size_t max_block)
424 {
425  boost::crc_32_type crc;
426 
427  // open the file and establish a block to read the file into
428  std::ifstream input(filename, std::ios::in | std::ios::binary);
429  std::vector<char> block(max_block);
430 
431  // process the file by block rather than reading in full
432  while (input)
433  {
434  input.read(block.data(), max_block);
435  std::size_t bytes_read = input.gcount();
436  if (bytes_read > 0)
437  {
438  crc.process_bytes(block.data(), bytes_read);
439  }
440  }
441 
442  return crc.checksum();
443 }
444 
445 inline bool filename_has_redirect(const std::string& filename)
446 {
447  // if filename has special characters, return false
448  if (filename.find("../") != std::string::npos)
449  {
450  return true;
451  }
452  else if (filename.find("//") != std::string::npos)
453  {
454  return true;
455  }
456  else if (filename.find("~") != std::string::npos)
457  {
458  return true;
459  }
460  else
461  {
462  return false;
463  }
464 }
465 
466 inline bool file_from_fragments(const std::string& filename, uint32_t crc,
467  bool delete_incomplete, bool delete_fragments)
468 {
469  std::string str_crc = std::to_string((unsigned long)crc);
470  std::string frag_suffix = "." + str_crc + ".frag";
471  std::string frag_file = filename + ".0" + frag_suffix;
472 
473  std::ofstream output(filename, std::ios::out | std::ios::binary);
474 
475  // if we could open the file, try to read each frag into the file
476  if (output)
477  {
478  // for each file that exists
479  for (int i = 0; file_exists(frag_file);
480  ++i, frag_file = filename + "." + std::to_string(i) + frag_suffix)
481  {
482  // read the file
483  void* buffer;
484  size_t size = 0;
485  utility::read_file(frag_file, buffer, size);
486 
487  // if anything was read, write the fragment to the file
488  if (size > 0)
489  {
490  output.write((char*)buffer, size);
491  delete[](char*) buffer;
492  } // end if size is greater than 0
493  } // end iteration over file fragments
494  output.close();
495 
496  uint32_t new_crc = utility::file_crc(filename);
497 
498  // if crc indicates file is complete
499  if (new_crc == crc)
500  {
501  if (delete_fragments)
502  {
503  frag_file = filename + ".0" + frag_suffix;
504 
505  // for each file that exists
506  for (int i = 0; file_exists(frag_file);
507  ++i, frag_file = filename + "." + std::to_string(i) + frag_suffix)
508  {
509  remove(frag_file.c_str());
510  }
511  }
512 
513  return true;
514  }
515  else
516  {
517  // crc doesn't check out
518  if (delete_incomplete)
519  {
520  remove(filename.c_str());
521  }
522  } // end if crc indicates incomplete file
523  }
524 
525  return false;
526 }
527 
528 inline size_t get_file_progress(const std::string& filename, uint32_t crc,
529  size_t expected_size, size_t fragment_size)
530 {
531  std::string str_crc = std::to_string((unsigned long)crc);
532  std::string frag_suffix = "." + str_crc + ".frag";
533  std::string frag_file = filename + ".0" + frag_suffix;
534 
535  std::ofstream output(filename, std::ios::out | std::ios::binary);
536 
537  size_t num_fragments = expected_size / fragment_size;
538  size_t actual_size = 0;
539 
540  if (expected_size % fragment_size > 0)
541  {
542  ++num_fragments;
543  }
544 
545  // if we could open the file, try to read each frag into the file
546  if (output)
547  {
548  // for each file that exists
549  for (int i = 0; i < (int)num_fragments;
550  ++i, frag_file = filename + "." + std::to_string(i) + frag_suffix)
551  {
552  // read the file
553  void* buffer;
554  size_t size = 0;
555  utility::read_file(frag_file, buffer, size);
556 
557  actual_size += size;
558 
559  // if anything was read, write the fragment to the file
560  if (size > 0)
561  {
562  output.write((char*)buffer, size);
563  delete[](char*) buffer;
564  } // end if size is greater than 0
565  } // end iteration over file fragments
566  output.close();
567  } // if file could be opened
568 
569  return actual_size;
570 }
571 
572 inline std::vector<int64_t> get_file_missing_fragments(
573  const std::string& filename, uint32_t crc, size_t expected_size,
574  int max_fragments, size_t fragment_size)
575 {
576  std::vector<int64_t> result;
577  std::string str_crc = std::to_string((unsigned long)crc);
578  std::string frag_suffix = "." + str_crc + ".frag";
579  std::string frag_file = filename + ".0" + frag_suffix;
580 
581  std::ofstream output(filename, std::ios::out | std::ios::binary);
582 
583  size_t num_fragments = expected_size / fragment_size;
584  //size_t actual_size = 0;
585 
586  if (expected_size % fragment_size > 0)
587  {
588  ++num_fragments;
589  }
590 
592  "utility::get_file_missing_fragments: looking at file %s\n",
593  filename.c_str());
594 
595  // if we could open the file, try to read each frag into the file
596  if (output)
597  {
598  // for each file that exists
599  for (int i = 0; i < (int)num_fragments;
600  ++i, frag_file = filename + "." + std::to_string(i) + frag_suffix)
601  {
602  // do we already have enough fragments?
603  if (max_fragments >= 0 && result.size() >= (size_t)max_fragments)
604  {
605  break;
606  }
607 
608  // read the file
609  void* buffer;
610  size_t size = 0;
611  utility::read_file(frag_file, buffer, size);
612 
613  //actual_size += size;
614 
616  "utility::get_file_missing_fragments: checking fragment %d\n", i);
617 
618  // if anything was read, write the fragment to the file
619  if (size > 0)
620  {
621  output.write((char*)buffer, size);
622  delete[](char*) buffer;
623  } // end if size is greater than 0
624  else
625  {
627  "utility::get_file_missing_fragments: missing fragment %d\n", i);
628 
629  result.push_back((int64_t)i);
630  }
631  } // end iteration over file fragments
632  output.close();
633  } // if file could be opened
634 
635  return result;
636 }
637 
638 inline bool begins_with(const std::string& input, const std::string& prefix)
639 {
640  bool result = false;
641 
642  if (prefix.length() <= input.length())
643  {
644  result = input.substr(0, prefix.length()) == prefix;
645  }
646 
647  return result;
648 }
649 
650 inline bool ends_with(const std::string& input, const std::string& match)
651 {
652  bool result = false;
653 
654  if (match.length() <= input.length())
655  {
656  result =
657  input.substr(input.size() - match.length(), match.length()) == match;
658  }
659 
660  return result;
661 }
662 
663 template<typename T>
664 T bitmask_add(T mask, T values)
665 {
666  return mask | values;
667 }
668 
672 template<typename T>
673 bool bitmask_check(T mask, T values)
674 {
675  return (mask & values) > 0;
676 }
677 
681 template<typename T>
682 T bitmask_remove(T mask, T values)
683 {
684  return mask & ~values;
685 }
686 
687 template<typename T>
688 bool less_compare(const T& left, const T& right)
689 {
690  return left < right;
691 }
692 
693 template<typename T>
694 bool greater_compare(const T& left, const T& right)
695 {
696  return right < left;
697 }
698 
699 template<typename T>
700 void sift_down(T* input, int start, int end,
701  bool (*comparator)(const T& left, const T& right))
702 {
703  int root = start;
704  for (int child = root * 2 + 1; child <= end; child = root * 2 + 1)
705  {
706  int swap = root;
707 
708  // check left child
709  if (comparator(input[child], input[swap]))
710  swap = child;
711 
712  // check right child
713  ++child;
714  if (child <= end && comparator(input[child], input[swap]))
715  swap = child;
716 
717  if (swap != root)
718  {
719  std::swap(input[root], input[swap]);
720  root = swap;
721  }
722  else
723  break;
724  }
725 }
726 
727 template<typename T>
728 void heapify(
729  T* input, int size, bool (*comparator)(const T& left, const T& right))
730 {
731  // start at lowest parent node and work our way back
732  for (int start = (size - 2) / 2; start >= 0; --start)
733  {
734  sift_down(input, start, size - 1, comparator);
735  }
736 }
737 
738 template<typename T>
740  T* input, int size, bool (*comparator)(const T& left, const T& right))
741 {
742  heapify(input, size, comparator);
743 
744  for (int end = size - 1; end > 0; --end)
745  {
746  std::swap(input[end], input[0]);
747  sift_down(input, 0, end - 1);
748  }
749 }
750 }
751 }
752 
753 #endif // _MADARA_UTILITY_INL_
#define madara_logger_ptr_log(loggering, level,...)
Fast version of the madara::logger::log method for Logger pointers.
Definition: Logger.h:41
constexpr string_t string
constexpr binary_t binary
T get(const KnowledgeRecord &kr)
Get the value of a KnowlegeRecord.
Definition: GetRecord.h:121
MADARA_EXPORT utility::Refcounter< logger::Logger > global_logger
MADARA_EXPORT void delete_fragments(FragmentMap &map)
Deletes fragments within a fragment map and clears the map.
Provides utility functions and classes for common tasks and needs.
Definition: IteratorImpl.h:15
uint64_t endian_swap(uint64_t value)
Converts a host format uint64_t into big endian.
Definition: Utility.inl:134
std::string & strip_extra_white_space(std::string &input)
Strip whitespace from front and end of string and also condense multiple whitespace into a single spa...
Definition: Utility.cpp:85
static const uint64_t nano_per
Definition: Utility.inl:252
MADARA_EXPORT bool set_thread_priority(int priority=20)
Sets the thread priority in a FIFO scheme.
Definition: Utility.inl:26
unsigned int file_size(const std::string &filename)
Returns the size of a file.
Definition: Utility.inl:395
bool greater_compare(const T &left, const T &right)
Returns true if right < left.
Definition: Utility.inl:694
static const uint64_t micro_per
Definition: Utility.inl:251
std::string & lower(std::string &input)
Converts the string to lower.
Definition: Utility.inl:89
T bitmask_add(T mask, T values)
Adds values to a bit mask.
Definition: Utility.inl:664
bool file_exists(const std::string &filename)
Checks if a file exists.
Definition: Utility.inl:304
static const uint64_t simtime_min_sleep
Definition: Utility.inl:254
std::chrono::time_point< Clock > TimeValue
time point
Definition: Utility.h:36
MADARA_EXPORT bool ends_with(const std::string &input, const std::string &ending)
Check if input contains a pattern at the end.
Definition: Utility.inl:650
std::chrono::nanoseconds Duration
default clock duration
Definition: Utility.h:30
T bitmask_remove(T mask, T values)
Removes values from a bit mask.
Definition: Utility.inl:682
void sift_down(T *input, int start, int end, bool(*comparator)(const T &left, const T &right)=greater_compare< T >)
Sifts elements down a heap according to a comparator.
Definition: Utility.inl:700
void tokenizer(const std::string &input, const ::std::vector< std::string > &splitters, ::std::vector< std::string > &tokens, ::std::vector< std::string > &pivots)
Split a string into tokens.
Definition: Utility.cpp:224
bool less_compare(const T &left, const T &right)
Returns true if left < right.
Definition: Utility.inl:688
uint32_t file_crc(const std::string &filename, size_t max_block=1000000)
Returns the crc of a file.
Definition: Utility.inl:423
MADARA_EXPORT bool file_from_fragments(const std::string &filename, uint32_t crc, bool delete_incomplete=true, bool delete_fragments=true)
Builds a file from fragments that have the format: filename.
Definition: Utility.inl:466
bool is_directory(const std::string &path)
Checks if a a path is a directory.
Definition: Utility.inl:317
void heapify(T *input, int size, bool(*comparator)(const T &left, const T &right)=greater_compare< T >)
Builds a heap out of an array of elements.
Definition: Utility.inl:728
TimeValue seconds_to_time(double seconds)
Returns seconds in double format as nanosecond since epoch.
Definition: Utility.inl:288
bool recursive_mkdir(const std::string &path)
Definition: Utility.inl:336
std::vector< std::string > string_to_vector(const std::string &input, const std::string delimiter="\n", bool strip_whitespace=true)
Splits a string into a vector of strings by delimiter.
Definition: Utility.inl:111
MADARA_EXPORT std::string extract_filename(const std::string &name)
Extracts the file name of an absolute or relative path.
Definition: Utility.inl:384
MADARA_EXPORT size_t get_file_progress(const std::string &filename, uint32_t crc, size_t expected_size, size_t fragment_size=60000)
Builds a file from fragments that have the format: filename.
Definition: Utility.inl:528
std::string & upper(std::string &input)
Converts the string to upper.
Definition: Utility.inl:67
bool bitmask_check(T mask, T values)
Returns true if mask contains values.
Definition: Utility.inl:673
std::string & dds_topicify(std::string &input)
Changes periods to underscores in compliance with OpenSplice needs.
Definition: Utility.inl:76
std::string strip_prefix(const std::string &input, const std::string &prefix)
Strips a prefix from an input string and returns the result.
Definition: Utility.inl:60
MADARA_EXPORT std::vector< int64_t > get_file_missing_fragments(const std::string &filename, uint32_t crc, size_t expected_size, int max_fragments=-1, size_t fragment_size=60000)
Attempts to builds a file from fragments that have the format: filename.
Definition: Utility.inl:572
SecondsDuration seconds_to_seconds_duration(double seconds)
Returns seconds in double format as seconds duration.
Definition: Utility.inl:283
bool endian_is_little()
Definition: Utility.inl:97
int64_t seconds_to_nanoseconds(double seconds)
Returns seconds in nanoseconds.
Definition: Utility.inl:294
int64_t get_time(void)
Returns a time of day in nanoseconds If simtime feature is enabled, this may be simulation time inste...
Definition: Utility.inl:265
bool approx_equal(double value1, double value2, double epsilon=0.0001)
Checks two doubles for approximate equality.
Definition: Utility.inl:299
std::chrono::duration< double > SecondsDuration
default clock duration
Definition: Utility.h:33
static const uint64_t milli_per
Definition: Utility.inl:250
MADARA_EXPORT std::string extract_path(const std::string &name)
Extracts the path of a filename.
Definition: Utility.inl:374
TimeValue get_time_value(void)
Returns a time of day as a chrono time value If simtime feature is enabled, this may be simulation ti...
Definition: Utility.inl:256
MADARA_EXPORT bool begins_with(const std::string &input, const std::string &prefix)
Check if input contains prefix at the beginning.
Definition: Utility.inl:638
void heap_sort(T *input, int size, bool(*comparator)(const T &left, const T &right)=greater_compare< T >)
Sorts an array with heap sort.
Definition: Utility.inl:739
int read_file(const std::string &filename, void *&buffer, size_t &size, bool add_zero_char)
Reads a file into a provided void pointer.
Definition: Utility.cpp:418
TimeValue add_seconds(const TimeValue &start, double seconds)
Returns an offset of a time by seconds in double format.
Definition: Utility.inl:272
MADARA_EXPORT bool filename_has_redirect(const std::string &filename)
Checks the filename for abnormal redirects such as "..".
Definition: Utility.inl:445
Duration seconds_to_duration(double seconds)
Returns seconds in double format as nanosecond duration.
Definition: Utility.inl:277
Copyright(c) 2020 Galois.