Logo ROOT   6.19/01
Reference Guide
StringConv.hxx
Go to the documentation of this file.
1 // @(#)root/base
2 // Author: Philippe Canal 12/2015
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2015, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 #ifndef ROOT_StringConv
13 #define ROOT_StringConv
14 
15 
16 #include "ROOT/RStringView.hxx"
17 #include "Rtypes.h"
18 #include "RConfigure.h"
19 #include <cmath>
20 
21 namespace ROOT {
22 
23  // Adapted from http://stackoverflow.com/questions/3758606/
24  // how-to-convert-byte-size-into-human-readable-format-in-java
25  // and http://agentzlerich.blogspot.com/2011/01/converting-to-and-from-human-readable.html
26  // However those sources use the 'conventional' 'legacy' nomenclature,
27  // rather than the official Standard Units. See
28  // http://physics.nist.gov/cuu/Units/binary.html
29  // and http://www.dr-lex.be/info-stuff/bytecalc.html for example.
30 
31 ///////////////////////////////////////////////////////////////////////////////
32 /// Return the size expressed in 'human readable' format.
33 /// \param bytes the size in bytes to be converted
34 /// \param si whether to use the SI units or not.
35 /// \param coeff return the size expressed in the new unit.
36 /// \param units return a pointer to the string representation of the new unit
37 template <typename value_type>
38 void ToHumanReadableSize(value_type bytes,
39  Bool_t si,
40  Double_t *coeff,
41  const char **units)
42 {
43  // Static lookup table of byte-based SI units
44  static const char *const suffix[][2] =
45  { { "B", "B" },
46  { "KB", "KiB" },
47  { "MB", "MiB" },
48  { "GB", "GiB" },
49  { "TB", "TiB" },
50  { "EB", "EiB" },
51  { "ZB", "ZiB" },
52  { "YB", "YiB" } };
53  value_type unit = si ? 1000 : 1024;
54  int exp = 0;
55  if (bytes == unit) {
56  // On some 32bit platforms, the result of
57  // (int) (std::log(bytes) / std::log(unit)
58  // in the case of bytes==unit ends up surprisingly to be zero
59  // rather than one, so 'hard code' the result
60  exp = 1;
61  } else if (bytes > 0) {
62  exp = std::min( (int) (std::log(bytes) / std::log(unit)),
63  (int) (sizeof(suffix) / sizeof(suffix[0]) - 1));
64  }
65  *coeff = bytes / std::pow(unit, exp);
66  *units = suffix[exp][!si];
67 }
68 
70  kSuccess,
71  kParseFail,
72  kOverflow
73 };
74 
75 ///////////////////////////////////////////////////////////////////////////////
76 /// Convert strings like the following into byte counts
77 /// 5MB, 5 MB, 5M, 3.7GB, 123b, 456kB, 3.7GiB, 5MiB
78 /// with some amount of forgiveness baked into the parsing.
79 /// For this routine we use the official SI unit where the [i] is reserved
80 /// for the 'legacy' power of two units. 1KB = 1000 bytes, 1KiB = 1024 bytes.
81 /// \param str the string to be parsed
82 /// \param value will be updated with the result if and only if the parse is successful and does not overflow for the type of value.
83 /// \return return a EFromHumanReadableSize enum value indicating the success or failure of the parse.
84 ///
85 template <typename T>
86 EFromHumanReadableSize FromHumanReadableSize(std::string_view str, T &value)
87 {
88  try {
89  size_t cur, size = str.size();
90  // Parse leading numeric factor
91  const double coeff = stod(std::string(str.data(), str.size()), &cur);
92 
93  // Skip any intermediate white space
94  while (cur<size && isspace(str[cur])) ++cur;
95 
96  // Read off first character which should be an SI prefix
97  int exp = 0, unit = 1000;
98 
99  auto result = [coeff,&exp,&unit,&value]() {
100  double v = exp ? coeff * std::pow(unit, exp / 3) : coeff;
101  if (v < (double) std::numeric_limits<T>::max()) {
102  value = (T)v;
104  } else {
106  }
107  };
108  if (cur==size) return result();
109 
110  switch (toupper(str[cur])) {
111  case 'B': exp = 0; break;
112  case 'K': exp = 3; break;
113  case 'M': exp = 6; break;
114  case 'G': exp = 9; break;
115  case 'T': exp = 12; break;
116  case 'E': exp = 15; break;
117  case 'Z': exp = 18; break;
118  case 'Y': exp = 21; break;
119 
120  default: return EFromHumanReadableSize::kParseFail;
121  }
122  ++cur;
123 
124  // If an 'i' or 'I' is present use non-SI factor-of-1024 units
125  if (cur<size && toupper(str[cur]) == 'I') {
126  ++cur;
127  unit = 1024;
128  }
129 
130  if (cur==size) return result();
131 
132  // Next character must be one of B/empty/whitespace
133  switch (toupper(str[cur])) {
134  case 'B':
135  case ' ':
136  case '\t': ++cur; break;
137 
138  case '\0': return result();
139 
140  default: return EFromHumanReadableSize::kParseFail;
141  }
142 
143  // Skip any remaining white space
144  // while (cur<size && isspace(str[cur])) ++cur;
145 
146  // Do not:
147  // Parse error on anything but a null terminator
148  // if (cur<size) return -1;
149 
150  return result();
151  } catch (...) {
153  }
154 
155 }
156 
157 template <typename T>
159 {
160  return FromHumanReadableSize(std::string_view(str),value);
161 }
162 
163 } // namespace ROOT.
164 
165 #endif // ROOT_StringConv
Namespace for new ROOT classes and functions.
Definition: StringConv.hxx:21
double T(double x)
Definition: ChebyshevPol.h:34
bool Bool_t
Definition: RtypesCore.h:59
void ToHumanReadableSize(value_type bytes, Bool_t si, Double_t *coeff, const char **units)
Return the size expressed in &#39;human readable&#39; format.
Definition: StringConv.hxx:38
EFromHumanReadableSize FromHumanReadableSize(std::string_view str, T &value)
Convert strings like the following into byte counts 5MB, 5 MB, 5M, 3.7GB, 123b, 456kB, 3.7GiB, 5MiB with some amount of forgiveness baked into the parsing.
Definition: StringConv.hxx:86
EFromHumanReadableSize
Definition: StringConv.hxx:69
double pow(double, double)
double Double_t
Definition: RtypesCore.h:55
double exp(double)
double log(double)