Logo ROOT   6.18/05
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
21namespace 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
37template <typename value_type>
38void 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
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///
85template <typename T>
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
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
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
157template <typename T>
159{
160 return FromHumanReadableSize(std::string_view(str),value);
161}
162
163} // namespace ROOT.
164
165#endif // ROOT_StringConv
SVector< double, 2 > v
Definition: Dict.h:5
bool Bool_t
Definition: RtypesCore.h:59
double Double_t
Definition: RtypesCore.h:55
double pow(double, double)
double exp(double)
double log(double)
@ kOverflow
Definition: TSystem.h:82
basic_string_view< char > string_view
double T(double x)
Definition: ChebyshevPol.h:34
Namespace for new ROOT classes and functions.
Definition: StringConv.hxx:21
void ToHumanReadableSize(value_type bytes, Bool_t si, Double_t *coeff, const char **units)
Return the size expressed in 'human readable' 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,...
Definition: StringConv.hxx:86
EFromHumanReadableSize
Definition: StringConv.hxx:69