Logo ROOT   6.16/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
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 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
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
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
159template <typename T>
161{
162 return FromHumanReadableSize(std::string_view(str),value);
163}
164
165} // namespace ROOT.
166
167#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)
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
double stod(std::string_view str, size_t *pos)
Definition: RStringView.hxx:48
basic_string_view< char > string_view
Definition: RStringView.hxx:35