1 #include "string_util.h"
10 #include "arraysize.h"
15 // kilo, Mega, Giga, Tera, Peta, Exa, Zetta, Yotta.
16 const char kBigSIUnits
[] = "kMGTPEZY";
17 // Kibi, Mebi, Gibi, Tebi, Pebi, Exbi, Zebi, Yobi.
18 const char kBigIECUnits
[] = "KMGTPEZY";
19 // milli, micro, nano, pico, femto, atto, zepto, yocto.
20 const char kSmallSIUnits
[] = "munpfazy";
22 // We require that all three arrays have the same size.
23 static_assert(arraysize(kBigSIUnits
) == arraysize(kBigIECUnits
),
24 "SI and IEC unit arrays must be the same size");
25 static_assert(arraysize(kSmallSIUnits
) == arraysize(kBigSIUnits
),
26 "Small SI and Big SI unit arrays must be the same size");
28 static const int64_t kUnitsSize
= arraysize(kBigSIUnits
);
30 void ToExponentAndMantissa(double val
, double thresh
, int precision
,
31 double one_k
, std::string
* mantissa
,
33 std::stringstream mantissa_stream
;
36 mantissa_stream
<< "-";
40 // Adjust threshold so that it never excludes things which can't be rendered
41 // in 'precision' digits.
42 const double adjusted_threshold
=
43 std::max(thresh
, 1.0 / std::pow(10.0, precision
));
44 const double big_threshold
= adjusted_threshold
* one_k
;
45 const double small_threshold
= adjusted_threshold
;
46 // Values in ]simple_threshold,small_threshold[ will be printed as-is
47 const double simple_threshold
= 0.01;
49 if (val
> big_threshold
) {
52 for (size_t i
= 0; i
< arraysize(kBigSIUnits
); ++i
) {
54 if (scaled
<= big_threshold
) {
55 mantissa_stream
<< scaled
;
57 *mantissa
= mantissa_stream
.str();
61 mantissa_stream
<< val
;
63 } else if (val
< small_threshold
) {
65 if (val
< simple_threshold
) {
67 for (size_t i
= 0; i
< arraysize(kSmallSIUnits
); ++i
) {
69 if (scaled
>= small_threshold
) {
70 mantissa_stream
<< scaled
;
71 *exponent
= -static_cast<int64_t>(i
+ 1);
72 *mantissa
= mantissa_stream
.str();
77 mantissa_stream
<< val
;
80 mantissa_stream
<< val
;
83 *mantissa
= mantissa_stream
.str();
86 std::string
ExponentToPrefix(int64_t exponent
, bool iec
) {
87 if (exponent
== 0) return "";
89 const int64_t index
= (exponent
> 0 ? exponent
- 1 : -exponent
- 1);
90 if (index
>= kUnitsSize
) return "";
93 (exponent
> 0 ? (iec
? kBigIECUnits
: kBigSIUnits
) : kSmallSIUnits
);
95 return array
[index
] + std::string("i");
97 return std::string(1, array
[index
]);
100 std::string
ToBinaryStringFullySpecified(double value
, double threshold
,
101 int precision
, double one_k
= 1024.0) {
102 std::string mantissa
;
104 ToExponentAndMantissa(value
, threshold
, precision
, one_k
, &mantissa
,
106 return mantissa
+ ExponentToPrefix(exponent
, false);
111 void AppendHumanReadable(int n
, std::string
* str
) {
112 std::stringstream ss
;
113 // Round down to the nearest SI prefix.
114 ss
<< ToBinaryStringFullySpecified(n
, 1.0, 0);
118 std::string
HumanReadableNumber(double n
, double one_k
) {
119 // 1.1 means that figures up to 1.1k should be shown with the next unit down;
120 // this softens edge effects.
121 // 1 means that we should show one decimal place of precision.
122 return ToBinaryStringFullySpecified(n
, 1.1, 1, one_k
);
125 std::string
StrFormatImp(const char* msg
, va_list args
) {
126 // we might need a second shot at this, so pre-emptivly make a copy
128 va_copy(args_cp
, args
);
130 // TODO(ericwf): use std::array for first attempt to avoid one memory
131 // allocation guess what the size might be
132 std::array
<char, 256> local_buff
;
133 std::size_t size
= local_buff
.size();
134 // 2015-10-08: vsnprintf is used instead of snd::vsnprintf due to a limitation
135 // in the android-ndk
136 auto ret
= vsnprintf(local_buff
.data(), size
, msg
, args_cp
);
140 // handle empty expansion
141 if (ret
== 0) return std::string
{};
142 if (static_cast<std::size_t>(ret
) < size
)
143 return std::string(local_buff
.data());
145 // we did not provide a long enough buffer on our first attempt.
146 // add 1 to size to account for null-byte in size cast to prevent overflow
147 size
= static_cast<std::size_t>(ret
) + 1;
148 auto buff_ptr
= std::unique_ptr
<char[]>(new char[size
]);
149 // 2015-10-08: vsnprintf is used instead of snd::vsnprintf due to a limitation
150 // in the android-ndk
151 ret
= vsnprintf(buff_ptr
.get(), size
, msg
, args
);
152 return std::string(buff_ptr
.get());
155 std::string
StrFormat(const char* format
, ...) {
157 va_start(args
, format
);
158 std::string tmp
= StrFormatImp(format
, args
);
163 void ReplaceAll(std::string
* str
, const std::string
& from
,
164 const std::string
& to
) {
165 std::size_t start
= 0;
166 while ((start
= str
->find(from
, start
)) != std::string::npos
) {
167 str
->replace(start
, from
.length(), to
);
168 start
+= to
.length();
172 } // end namespace benchmark