Utility.hpp
Go to the documentation of this file.
1 
10 #if !defined(GEOGRAPHICLIB_UTILITY_HPP)
11 #define GEOGRAPHICLIB_UTILITY_HPP 1
12 
14 #include <iomanip>
15 #include <vector>
16 #include <sstream>
17 #include <cctype>
18 #include <ctime>
19 #include <cstring>
20 
21 #if defined(_MSC_VER)
22 // Squelch warnings about constant conditional expressions and unsafe gmtime
23 # pragma warning (push)
24 # pragma warning (disable: 4127 4996)
25 #endif
26 
27 namespace GeographicLib {
28 
36  private:
37  static bool gregorian(int y, int m, int d) {
38  // The original cut over to the Gregorian calendar in Pope Gregory XIII's
39  // time had 1582-10-04 followed by 1582-10-15. Here we implement the
40  // switch over used by the English-speaking world where 1752-09-02 was
41  // followed by 1752-09-14. We also assume that the year always begins
42  // with January 1, whereas in reality it often was reckoned to begin in
43  // March.
44  return 100 * (100 * y + m) + d >= 17520914; // or 15821004
45  }
46  static bool gregorian(int s) {
47  return s >= 639799; // 1752-09-14
48  }
49  public:
50 
60  static int day(int y, int m = 1, int d = 1) {
61  // Convert from date to sequential day and vice versa
62  //
63  // Here is some code to convert a date to sequential day and vice
64  // versa. The sequential day is numbered so that January 1, 1 AD is day 1
65  // (a Saturday). So this is offset from the "Julian" day which starts the
66  // numbering with 4713 BC.
67  //
68  // This is inspired by a talk by John Conway at the John von Neumann
69  // National Supercomputer Center when he described his Doomsday algorithm
70  // for figuring the day of the week. The code avoids explicitly doing ifs
71  // (except for the decision of whether to use the Julian or Gregorian
72  // calendar). Instead the equivalent result is achieved using integer
73  // arithmetic. I got this idea from the routine for the day of the week
74  // in MACLisp (I believe that that routine was written by Guy Steele).
75  //
76  // There are three issues to take care of
77  //
78  // 1. the rules for leap years,
79  // 2. the inconvenient placement of leap days at the end of February,
80  // 3. the irregular pattern of month lengths.
81  //
82  // We deal with these as follows:
83  //
84  // 1. Leap years are given by simple rules which are straightforward to
85  // accommodate.
86  //
87  // 2. We simplify the calculations by moving January and February to the
88  // previous year. Here we internally number the months March–December,
89  // January, February as 0–9, 10, 11.
90  //
91  // 3. The pattern of month lengths from March through January is regular
92  // with a 5-month period—31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 31. The
93  // 5-month period is 153 days long. Since February is now at the end of
94  // the year, we don't need to include its length in this part of the
95  // calculation.
96  bool greg = gregorian(y, m, d);
97  y += (m + 9) / 12 - 1; // Move Jan and Feb to previous year,
98  m = (m + 9) % 12; // making March month 0.
99  return
100  (1461 * y) / 4 // Julian years converted to days. Julian year is 365 +
101  // 1/4 = 1461/4 days.
102  // Gregorian leap year corrections. The 2 offset with respect to the
103  // Julian calendar synchronizes the vernal equinox with that at the
104  // time of the Council of Nicea (325 AD).
105  + (greg ? (y / 100) / 4 - (y / 100) + 2 : 0)
106  + (153 * m + 2) / 5 // The zero-based start of the m'th month
107  + d - 1 // The zero-based day
108  - 305; // The number of days between March 1 and December 31.
109  // This makes 0001-01-01 day 1
110  }
111 
123  static int day(int y, int m, int d, bool check) {
124  int s = day(y, m, d);
125  if (!check)
126  return s;
127  int y1, m1, d1;
128  date(s, y1, m1, d1);
129  if (!(s > 0 && y == y1 && m == m1 && d == d1))
130  throw GeographicErr("Invalid date " +
131  str(y) + "-" + str(m) + "-" + str(d)
132  + (s > 0 ? "; use " +
133  str(y1) + "-" + str(m1) + "-" + str(d1) :
134  " before 0001-01-01"));
135  return s;
136  }
137 
146  static void date(int s, int& y, int& m, int& d) {
147  int c = 0;
148  bool greg = gregorian(s);
149  s += 305; // s = 0 on March 1, 1BC
150  if (greg) {
151  s -= 2; // The 2 day Gregorian offset
152  // Determine century with the Gregorian rules for leap years. The
153  // Gregorian year is 365 + 1/4 - 1/100 + 1/400 = 146097/400 days.
154  c = (4 * s + 3) / 146097;
155  s -= (c * 146097) / 4; // s = 0 at beginning of century
156  }
157  y = (4 * s + 3) / 1461; // Determine the year using Julian rules.
158  s -= (1461 * y) / 4; // s = 0 at start of year, i.e., March 1
159  y += c * 100; // Assemble full year
160  m = (5 * s + 2) / 153; // Determine the month
161  s -= (153 * m + 2) / 5; // s = 0 at beginning of month
162  d = s + 1; // Determine day of month
163  y += (m + 2) / 12; // Move Jan and Feb back to original year
164  m = (m + 2) % 12 + 1; // Renumber the months so January = 1
165  }
166 
179  static void date(const std::string& s, int& y, int& m, int& d) {
180  if (s == "now") {
181  std::time_t t = std::time(0);
182  struct tm* now = gmtime(&t);
183  y = now->tm_year + 1900;
184  m = now->tm_mon + 1;
185  d = now->tm_mday;
186  return;
187  }
188  int y1, m1 = 1, d1 = 1;
189  const char* digits = "0123456789";
190  std::string::size_type p1 = s.find_first_not_of(digits);
191  if (p1 == std::string::npos)
192  y1 = val<int>(s);
193  else if (s[p1] != '-')
194  throw GeographicErr("Delimiter not hyphen in date " + s);
195  else if (p1 == 0)
196  throw GeographicErr("Empty year field in date " + s);
197  else {
198  y1 = val<int>(s.substr(0, p1));
199  if (++p1 == s.size())
200  throw GeographicErr("Empty month field in date " + s);
201  std::string::size_type p2 = s.find_first_not_of(digits, p1);
202  if (p2 == std::string::npos)
203  m1 = val<int>(s.substr(p1));
204  else if (s[p2] != '-')
205  throw GeographicErr("Delimiter not hyphen in date " + s);
206  else if (p2 == p1)
207  throw GeographicErr("Empty month field in date " + s);
208  else {
209  m1 = val<int>(s.substr(p1, p2 - p1));
210  if (++p2 == s.size())
211  throw GeographicErr("Empty day field in date " + s);
212  d1 = val<int>(s.substr(p2));
213  }
214  }
215  y = y1; m = m1; d = d1;
216  }
217 
227  static int dow(int y, int m, int d) { return dow(day(y, m, d)); }
228 
236  static int dow(int s) {
237  return (s + 5) % 7; // The 5 offset makes day 1 (0001-01-01) a Saturday.
238  }
239 
253  template<typename T> static T fractionalyear(const std::string& s) {
254  try {
255  return val<T>(s);
256  }
257  catch (const std::exception&) {}
258  int y, m, d;
259  date(s, y, m, d);
260  int t = day(y, m, d, true);
261  return T(y) + T(t - day(y)) / T(day(y + 1) - day(y));
262  }
263 
276  template<typename T> static std::string str(T x, int p = -1) {
277  std::ostringstream s;
278  if (p >= 0) s << std::fixed << std::setprecision(p);
279  s << x; return s.str();
280  }
281 
294  static std::string str(Math::real x, int p = -1) {
295  if (!Math::isfinite(x))
296  return x < 0 ? std::string("-inf") :
297  (x > 0 ? std::string("inf") : std::string("nan"));
298  std::ostringstream s;
299 #if GEOGRAPHICLIB_PRECISION == 4
300  // boost-quadmath treats precision == 0 as "use as many digits as
301  // necessary" (see https://svn.boost.org/trac/boost/ticket/10103), so...
302  using std::floor; using std::fmod;
303  if (p == 0) {
304  x += Math::real(0.5);
305  Math::real ix = floor(x);
306  // Implement the "round ties to even" rule
307  x = (ix == x && fmod(ix, Math::real(2)) == 1) ? ix - 1 : ix;
308  s << std::fixed << std::setprecision(1) << x;
309  std::string r(s.str());
310  // strip off trailing ".0"
311  return r.substr(0, (std::max)(int(r.size()) - 2, 0));
312  }
313 #endif
314  if (p >= 0) s << std::fixed << std::setprecision(p);
315  s << x; return s.str();
316  }
317 
324  static std::string trim(const std::string& s) {
325  unsigned
326  beg = 0,
327  end = unsigned(s.size());
328  while (beg < end && isspace(s[beg]))
329  ++beg;
330  while (beg < end && isspace(s[end - 1]))
331  --end;
332  return std::string(s, beg, end-beg);
333  }
334 
359  template<typename T> static T val(const std::string& s) {
360  // If T is bool, then the specialization val<bool>() defined below is
361  // used.
362  T x;
363  std::string errmsg, t(trim(s));
364  do { // Executed once (provides the ability to break)
365  std::istringstream is(t);
366  if (!(is >> x)) {
367  errmsg = "Cannot decode " + t;
368  break;
369  }
370  int pos = int(is.tellg()); // Returns -1 at end of string?
371  if (!(pos < 0 || pos == int(t.size()))) {
372  errmsg = "Extra text " + t.substr(pos) + " at end of " + t;
373  break;
374  }
375  return x;
376  } while (false);
377  x = std::numeric_limits<T>::is_integer ? 0 : nummatch<T>(t);
378  if (x == 0)
379  throw GeographicErr(errmsg);
380  return x;
381  }
385  template<typename T>
386  // GEOGRAPHICLIB_DEPRECATED("Use new Utility::val<T>(s)")
387  static T num(const std::string& s) {
388  return val<T>(s);
389  }
390 
402  template<typename T> static T nummatch(const std::string& s) {
403  if (s.length() < 3)
404  return 0;
405  std::string t(s);
406  for (std::string::iterator p = t.begin(); p != t.end(); ++p)
407  *p = char(std::toupper(*p));
408  for (size_t i = s.length(); i--;)
409  t[i] = char(std::toupper(s[i]));
410  int sign = t[0] == '-' ? -1 : 1;
411  std::string::size_type p0 = t[0] == '-' || t[0] == '+' ? 1 : 0;
412  std::string::size_type p1 = t.find_last_not_of('0');
413  if (p1 == std::string::npos || p1 + 1 < p0 + 3)
414  return 0;
415  // Strip off sign and trailing 0s
416  t = t.substr(p0, p1 + 1 - p0); // Length at least 3
417  if (t == "NAN" || t == "1.#QNAN" || t == "1.#SNAN" || t == "1.#IND" ||
418  t == "1.#R")
419  return Math::NaN<T>();
420  else if (t == "INF" || t == "1.#INF")
421  return sign * Math::infinity<T>();
422  return 0;
423  }
424 
439  template<typename T> static T fract(const std::string& s) {
440  std::string::size_type delim = s.find('/');
441  return
442  !(delim != std::string::npos && delim >= 1 && delim + 2 <= s.size()) ?
443  val<T>(s) :
444  // delim in [1, size() - 2]
445  val<T>(s.substr(0, delim)) / val<T>(s.substr(delim + 1));
446  }
447 
459  static int lookup(const std::string& s, char c) {
460  std::string::size_type r = s.find(char(toupper(c)));
461  return r == std::string::npos ? -1 : int(r);
462  }
463 
475  static int lookup(const char* s, char c) {
476  const char* p = std::strchr(s, toupper(c));
477  return p != NULL ? int(p - s) : -1;
478  }
479 
493  template<typename ExtT, typename IntT, bool bigendp>
494  static void readarray(std::istream& str, IntT array[], size_t num) {
495 #if GEOGRAPHICLIB_PRECISION < 4
496  if (sizeof(IntT) == sizeof(ExtT) &&
497  std::numeric_limits<IntT>::is_integer ==
498  std::numeric_limits<ExtT>::is_integer)
499  {
500  // Data is compatible (aside from the issue of endian-ness).
501  str.read(reinterpret_cast<char*>(array), num * sizeof(ExtT));
502  if (!str.good())
503  throw GeographicErr("Failure reading data");
504  if (bigendp != Math::bigendian) { // endian mismatch -> swap bytes
505  for (size_t i = num; i--;)
506  array[i] = Math::swab<IntT>(array[i]);
507  }
508  }
509  else
510 #endif
511  {
512  const int bufsize = 1024; // read this many values at a time
513  ExtT buffer[bufsize]; // temporary buffer
514  int k = int(num); // data values left to read
515  int i = 0; // index into output array
516  while (k) {
517  int n = (std::min)(k, bufsize);
518  str.read(reinterpret_cast<char*>(buffer), n * sizeof(ExtT));
519  if (!str.good())
520  throw GeographicErr("Failure reading data");
521  for (int j = 0; j < n; ++j)
522  // fix endian-ness and cast to IntT
523  array[i++] = IntT(bigendp == Math::bigendian ? buffer[j] :
524  Math::swab<ExtT>(buffer[j]));
525  k -= n;
526  }
527  }
528  return;
529  }
530 
544  template<typename ExtT, typename IntT, bool bigendp>
545  static void readarray(std::istream& str, std::vector<IntT>& array) {
546  if (array.size() > 0)
547  readarray<ExtT, IntT, bigendp>(str, &array[0], array.size());
548  }
549 
562  template<typename ExtT, typename IntT, bool bigendp>
563  static void writearray(std::ostream& str, const IntT array[], size_t num)
564  {
565 #if GEOGRAPHICLIB_PRECISION < 4
566  if (sizeof(IntT) == sizeof(ExtT) &&
567  std::numeric_limits<IntT>::is_integer ==
568  std::numeric_limits<ExtT>::is_integer &&
569  bigendp == Math::bigendian)
570  {
571  // Data is compatible (including endian-ness).
572  str.write(reinterpret_cast<const char*>(array), num * sizeof(ExtT));
573  if (!str.good())
574  throw GeographicErr("Failure writing data");
575  }
576  else
577 #endif
578  {
579  const int bufsize = 1024; // write this many values at a time
580  ExtT buffer[bufsize]; // temporary buffer
581  int k = int(num); // data values left to write
582  int i = 0; // index into output array
583  while (k) {
584  int n = (std::min)(k, bufsize);
585  for (int j = 0; j < n; ++j)
586  // cast to ExtT and fix endian-ness
587  buffer[j] = bigendp == Math::bigendian ? ExtT(array[i++]) :
588  Math::swab<ExtT>(ExtT(array[i++]));
589  str.write(reinterpret_cast<const char*>(buffer), n * sizeof(ExtT));
590  if (!str.good())
591  throw GeographicErr("Failure writing data");
592  k -= n;
593  }
594  }
595  return;
596  }
597 
609  template<typename ExtT, typename IntT, bool bigendp>
610  static void writearray(std::ostream& str, std::vector<IntT>& array) {
611  if (array.size() > 0)
612  writearray<ExtT, IntT, bigendp>(str, &array[0], array.size());
613  }
614 
630  static bool ParseLine(const std::string& line,
631  std::string& key, std::string& val);
632 
650  static int set_digits(int ndigits = 0);
651 
652  };
653 
657  template<> inline std::string Utility::val<std::string>(const std::string& s)
658  { return trim(s); }
659 
663  template<> inline bool Utility::val<bool>(const std::string& s) {
664  std::string t(trim(s));
665  if (t.empty()) return false;
666  bool x;
667  std::istringstream is(t);
668  if (is >> x) {
669  int pos = int(is.tellg()); // Returns -1 at end of string?
670  if (!(pos < 0 || pos == int(t.size())))
671  throw GeographicErr("Extra text " + t.substr(pos) +
672  " at end of " + t);
673  return x;
674  }
675  for (std::string::iterator p = t.begin(); p != t.end(); ++p)
676  *p = char(std::tolower(*p));
677  switch (t[0]) { // already checked that t isn't empty
678  case 'f':
679  if (t == "f" || t == "false") return false;
680  break;
681  case 'n':
682  if (t == "n" || t == "nil" || t == "no") return false;
683  break;
684  case 'o':
685  if (t == "off") return false;
686  else if (t == "on") return true;
687  break;
688  case 't':
689  if (t == "t" || t == "true") return true;
690  break;
691  case 'y':
692  if (t == "y" || t == "yes") return true;
693  break;
694  }
695  throw GeographicErr("Cannot decode " + t + " as a bool");
696  }
697 
698 } // namespace GeographicLib
699 
700 #if defined(_MSC_VER)
701 # pragma warning (pop)
702 #endif
703 
704 #endif // GEOGRAPHICLIB_UTILITY_HPP
const gtsam::Symbol key('X', 0)
Matrix3f m
static T fract(const std::string &s)
Definition: Utility.hpp:439
static int day(int y, int m, int d, bool check)
Definition: Utility.hpp:123
#define max(a, b)
Definition: datatypes.h:20
#define GEOGRAPHICLIB_EXPORT
Definition: Constants.hpp:91
static void readarray(std::istream &str, std::vector< IntT > &array)
Definition: Utility.hpp:545
Scalar * y
static void readarray(std::istream &str, IntT array[], size_t num)
Definition: Utility.hpp:494
Vector3f p1
Some utility routines for GeographicLib.
Definition: Utility.hpp:35
static void date(const std::string &s, int &y, int &m, int &d)
Definition: Utility.hpp:179
#define min(a, b)
Definition: datatypes.h:19
static bool isfinite(T x)
Definition: Math.hpp:806
Definition: numpy.h:680
static bool gregorian(int y, int m, int d)
Definition: Utility.hpp:37
int n
Scalar Scalar * c
Definition: benchVecAdd.cpp:17
static T fractionalyear(const std::string &s)
Definition: Utility.hpp:253
Vector3f p0
static std::string trim(const std::string &s)
Definition: Utility.hpp:324
static void writearray(std::ostream &str, std::vector< IntT > &array)
Definition: Utility.hpp:610
static int lookup(const char *s, char c)
Definition: Utility.hpp:475
static T nummatch(const std::string &s)
Definition: Utility.hpp:402
EIGEN_DEVICE_FUNC const FloorReturnType floor() const
static void writearray(std::ostream &str, const IntT array[], size_t num)
Definition: Utility.hpp:563
static std::string str(Math::real x, int p=-1)
Definition: Utility.hpp:294
static int dow(int s)
Definition: Utility.hpp:236
EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC bfloat16 fmod(const bfloat16 &a, const bfloat16 &b)
Definition: BFloat16.h:567
Matrix3d m1
Definition: IOFormat.cpp:2
Definition: pytypes.h:1403
static void date(int s, int &y, int &m, int &d)
Definition: Utility.hpp:146
EIGEN_DEVICE_FUNC const SignReturnType sign() const
Eigen::Triplet< double > T
Namespace for GeographicLib.
#define time
RealScalar s
static std::string str(T x, int p=-1)
Definition: Utility.hpp:276
#define NULL
Definition: ccolamd.c:609
static int dow(int y, int m, int d)
Definition: Utility.hpp:227
void check(bool b, bool ref)
Definition: fastmath.cpp:12
static const bool bigendian
Definition: Math.hpp:196
static T num(const std::string &s)
Definition: Utility.hpp:387
Exception handling for GeographicLib.
Definition: Constants.hpp:389
Header for GeographicLib::Constants class.
static EIGEN_DEPRECATED const end_t end
float * p
static int lookup(const std::string &s, char c)
Definition: Utility.hpp:459
static int day(int y, int m=1, int d=1)
Definition: Utility.hpp:60
static bool gregorian(int s)
Definition: Utility.hpp:46
static Point3 p2
set noclip points set clip one set noclip two set bar set border lt lw set xdata set ydata set zdata set x2data set y2data set boxwidth set dummy x
std::ptrdiff_t j
static T val(const std::string &s)
Definition: Utility.hpp:359
Point2 t(10, 10)


gtsam
Author(s):
autogenerated on Tue Jul 4 2023 02:40:43