2 * Copyright 2013 Facebook, Inc.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #include "folly/String.h"
18 #include "folly/Format.h"
25 #include <glog/logging.h>
29 #if defined(__GNUG__) && __GNUG__ >= 4
31 # define FOLLY_DEMANGLE 1
35 // TODO(tudorb): Detect this with autoconf for the open-source version.
37 // __attribute__((weak)) doesn't work, because cplus_demangle_v3_callback
38 // is exported by an object file in libiberty.a, and the ELF spec says
39 // "The link editor does not extract archive members to resolve undefined weak
40 // symbols" (but, interestingly enough, will resolve undefined weak symbols
41 // with definitions from archive members that were extracted in order to
42 // resolve an undefined global (strong) symbol)
45 # define FOLLY_DEFINED_DMGL 1
46 # define DMGL_NO_OPTS 0 /* For readability... */
47 # define DMGL_PARAMS (1 << 0) /* Include function args */
48 # define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */
49 # define DMGL_JAVA (1 << 2) /* Demangle as Java rather than C++. */
50 # define DMGL_VERBOSE (1 << 3) /* Include implementation details. */
51 # define DMGL_TYPES (1 << 4) /* Also try to demangle type encodings. */
52 # define DMGL_RET_POSTFIX (1 << 5) /* Print function return types (when
53 present) after function signature */
56 extern "C" int cplus_demangle_v3_callback(
58 int options, // We use DMGL_PARAMS | DMGL_TYPES, aka 0x11
59 void (*callback)(const char*, size_t, void*),
68 inline void stringPrintfImpl(std::string& output, const char* format,
70 // Tru to the space at the end of output for our output buffer.
71 // Find out write point then inflate its size temporarily to its
72 // capacity; we will later shrink it to the size needed to represent
73 // the formatted string. If this buffer isn't large enough, we do a
74 // resize and try again.
76 const auto write_point = output.size();
77 auto remaining = output.capacity() - write_point;
78 output.resize(output.capacity());
81 va_copy(args_copy, args);
82 int bytes_used = vsnprintf(&output[write_point], remaining, format,
86 throw std::runtime_error(
87 to<std::string>("Invalid format string; snprintf returned negative "
88 "with format string: ", format));
89 } else if (bytes_used < remaining) {
90 // There was enough room, just shrink and return.
91 output.resize(write_point + bytes_used);
93 output.resize(write_point + bytes_used + 1);
94 remaining = bytes_used + 1;
96 va_copy(args_copy, args);
97 bytes_used = vsnprintf(&output[write_point], remaining, format,
100 if (bytes_used + 1 != remaining) {
101 throw std::runtime_error(
102 to<std::string>("vsnprint retry did not manage to work "
103 "with format string: ", format));
105 output.resize(write_point + bytes_used);
111 std::string stringPrintf(const char* format, ...) {
112 // snprintf will tell us how large the output buffer should be, but
113 // we then have to call it a second time, which is costly. By
114 // guestimating the final size, we avoid the double snprintf in many
115 // cases, resulting in a performance win. We use this constructor
116 // of std::string to avoid a double allocation, though it does pad
117 // the resulting string with nul bytes. Our guestimation is twice
118 // the format string size, or 32 bytes, whichever is larger. This
119 // is a hueristic that doesn't affect correctness but attempts to be
120 // reasonably fast for the most common cases.
121 std::string ret(std::max(32UL, strlen(format) * 2), '\0');
125 va_start(ap, format);
126 stringPrintfImpl(ret, format, ap);
131 // Basic declarations; allow for parameters of strings and string
132 // pieces to be specified.
133 std::string& stringAppendf(std::string* output, const char* format, ...) {
135 va_start(ap, format);
136 stringPrintfImpl(*output, format, ap);
141 void stringPrintf(std::string* output, const char* format, ...) {
144 va_start(ap, format);
145 stringPrintfImpl(*output, format, ap);
151 struct PrettySuffix {
156 const PrettySuffix kPrettyTimeSuffixes[] = {
166 const PrettySuffix kPrettyBytesMetricSuffixes[] = {
175 const PrettySuffix kPrettyBytesBinarySuffixes[] = {
176 { "TB", int64_t(1) << 40 },
177 { "GB", int64_t(1) << 30 },
178 { "MB", int64_t(1) << 20 },
179 { "kB", int64_t(1) << 10 },
184 const PrettySuffix kPrettyBytesBinaryIECSuffixes[] = {
185 { "TiB", int64_t(1) << 40 },
186 { "GiB", int64_t(1) << 30 },
187 { "MiB", int64_t(1) << 20 },
188 { "KiB", int64_t(1) << 10 },
193 const PrettySuffix kPrettyUnitsMetricSuffixes[] = {
202 const PrettySuffix kPrettyUnitsBinarySuffixes[] = {
203 { "T", int64_t(1) << 40 },
204 { "G", int64_t(1) << 30 },
205 { "M", int64_t(1) << 20 },
206 { "k", int64_t(1) << 10 },
211 const PrettySuffix kPrettyUnitsBinaryIECSuffixes[] = {
212 { "Ti", int64_t(1) << 40 },
213 { "Gi", int64_t(1) << 30 },
214 { "Mi", int64_t(1) << 20 },
215 { "Ki", int64_t(1) << 10 },
220 const PrettySuffix* const kPrettySuffixes[PRETTY_NUM_TYPES] = {
222 kPrettyBytesMetricSuffixes,
223 kPrettyBytesBinarySuffixes,
224 kPrettyBytesBinaryIECSuffixes,
225 kPrettyUnitsMetricSuffixes,
226 kPrettyUnitsBinarySuffixes,
227 kPrettyUnitsBinaryIECSuffixes,
232 std::string prettyPrint(double val, PrettyType type, bool addSpace) {
235 // pick the suffixes to use
237 assert(type < PRETTY_NUM_TYPES);
238 const PrettySuffix* suffixes = kPrettySuffixes[type];
240 // find the first suffix we're bigger than -- then use it
241 double abs_val = fabs(val);
242 for (int i = 0; suffixes[i].suffix; ++i) {
243 if (abs_val >= suffixes[i].val) {
244 snprintf(buf, sizeof buf, "%.4g%s%s",
245 (suffixes[i].val ? (val / suffixes[i].val)
247 (addSpace ? " " : ""),
249 return std::string(buf);
253 // no suffix, we've got a tiny value -- just print it in sci-notation
254 snprintf(buf, sizeof buf, "%.4g", val);
255 return std::string(buf);
258 std::string hexDump(const void* ptr, size_t size) {
259 std::ostringstream os;
260 hexDump(ptr, size, std::ostream_iterator<StringPiece>(os, "\n"));
264 fbstring errnoStr(int err) {
265 int savedErrno = errno;
267 // Ensure that we reset errno upon exit.
268 auto guard(makeGuard([&] { errno = savedErrno; }));
275 // https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man3/strerror_r.3.html
276 // http://www.kernel.org/doc/man-pages/online/pages/man3/strerror.3.html
277 #if defined(__APPLE__) || defined(__FreeBSD__) || \
278 ((_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && !_GNU_SOURCE)
279 // Using XSI-compatible strerror_r
280 int r = strerror_r(err, buf, sizeof(buf));
282 // OSX/FreeBSD use EINVAL and Linux uses -1 so just check for non-zero
284 result = to<fbstring>(
285 "Unknown error ", err,
286 " (strerror_r failed with error ", errno, ")");
291 // Using GNU strerror_r
292 result.assign(strerror_r(err, buf, sizeof(buf)));
300 // glibc doesn't have strlcpy
301 size_t my_strlcpy(char* dest, const char* src, size_t size) {
302 size_t len = strlen(src);
304 size_t n = std::min(len, size - 1); // always null terminate!
305 memcpy(dest, src, n);
313 #ifdef FOLLY_DEMANGLE
315 fbstring demangle(const char* name) {
318 // malloc() memory for the demangled type name
319 char* demangled = abi::__cxa_demangle(name, nullptr, &len, &status);
323 // len is the length of the buffer (including NUL terminator and maybe
325 return fbstring(demangled, strlen(demangled), len, AcquireMallocatedString());
336 void demangleCallback(const char* str, size_t size, void* p) {
337 DemangleBuf* buf = static_cast<DemangleBuf*>(p);
338 size_t n = std::min(buf->remaining, size);
339 memcpy(buf->dest, str, n);
347 size_t demangle(const char* name, char* out, size_t outSize) {
350 dbuf.remaining = outSize ? outSize - 1 : 0; // leave room for null term
353 // Unlike most library functions, this returns 1 on success and 0 on failure
354 int status = cplus_demangle_v3_callback(
356 DMGL_PARAMS | DMGL_ANSI | DMGL_TYPES,
359 if (status == 0) { // failed, return original
360 return my_strlcpy(out, name, outSize);
370 fbstring demangle(const char* name) {
374 size_t demangle(const char* name, char* out, size_t outSize) {
375 return my_strlcpy(out, name, outSize);
379 #undef FOLLY_DEMANGLE
383 size_t hexDumpLine(const void* ptr, size_t offset, size_t size,
388 // (1+2)*16: hex bytes, each preceded by a space
389 // 1: space separating the two halves
396 const uint8_t* p = reinterpret_cast<const uint8_t*>(ptr) + offset;
397 size_t n = std::min(size - offset, size_t(16));
398 format("{:08x} ", offset).appendTo(line);
400 for (size_t i = 0; i < n; i++) {
404 format(" {:02x}", p[i]).appendTo(line);
407 // 3 spaces for each byte we're not printing, one separating the halves
409 line.append(3 * (16 - n) + (n <= 8), ' ');
412 for (size_t i = 0; i < n; i++) {
413 char c = (p[i] >= 32 && p[i] <= 126 ? static_cast<char>(p[i]) : '.');
416 line.append(16 - n, ' ');
418 DCHECK_EQ(line.size(), 78);
423 } // namespace detail
427 #ifdef FOLLY_DEFINED_DMGL
428 # undef FOLLY_DEFINED_DMGL
435 # undef DMGL_RET_POSTFIX