Logo ROOT   6.12/07
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 "RStringView.h"
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>
87 {
88  try {
89  size_t size = str.size();
90  size_t cur;
91  // Parse leading numeric factor
92  const double coeff = stod(std::string(str.data(), str.size()), &cur);
93 
94  // Skip any intermediate white space
95  while (cur<size && isspace(str[cur])) ++cur;
96 
97  // Read off first character which should be an SI prefix
98  int exp = 0;
99  int unit = 1000;
100 
101  auto result = [coeff,&exp,&unit,&value]() {
102  double v = exp ? coeff * std::pow(unit, exp / 3) : coeff;
103  if (v < std::numeric_limits<T>::max()) {
104  value = (T)v;
106  } else {
108  }
109  };
110  if (cur==size) return result();
111 
112  switch (toupper(str[cur])) {
113  case 'B': exp = 0; break;
114  case 'K': exp = 3; break;
115  case 'M': exp = 6; break;
116  case 'G': exp = 9; break;
117  case 'T': exp = 12; break;
118  case 'E': exp = 15; break;
119  case 'Z': exp = 18; break;
120  case 'Y': exp = 21; break;
121 
122  default: return EFromHumanReadableSize::kParseFail;
123  }
124  ++cur;
125 
126  // If an 'i' or 'I' is present use non-SI factor-of-1024 units
127  if (cur<size && toupper(str[cur]) == 'I') {
128  ++cur;
129  unit = 1024;
130  }
131 
132  if (cur==size) return result();
133 
134  // Next character must be one of B/empty/whitespace
135  switch (toupper(str[cur])) {
136  case 'B':
137  case ' ':
138  case '\t': ++cur; break;
139 
140  case '\0': return result();
141 
142  default: return EFromHumanReadableSize::kParseFail;
143  }
144 
145  // Skip any remaining white space
146  // while (cur<size && isspace(str[cur])) ++cur;
147 
148  // Do not:
149  // Parse error on anything but a null terminator
150  // if (cur<size) return -1;
151 
152  return result();
153  } catch (...) {
155  }
156 
157 }
158 
159 template <typename T>
161 {
162  return FromHumanReadableSize(std::string_view(str),value);
163 }
164 
165 } // namespace ROOT.
166 
167 #endif // ROOT_StringConv
basic_string_view< char > string_view
Definition: RStringView.h:35
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)
SVector< double, 2 > v
Definition: Dict.h:5
double Double_t
Definition: RtypesCore.h:55
double exp(double)
double log(double)