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>
27 #if FOLLY_HAVE_CPLUS_DEMANGLE_V3_CALLBACK
32 // TODO(tudorb): Detect this with autoconf for the open-source version.
34 // __attribute__((weak)) doesn't work, because cplus_demangle_v3_callback
35 // is exported by an object file in libiberty.a, and the ELF spec says
36 // "The link editor does not extract archive members to resolve undefined weak
37 // symbols" (but, interestingly enough, will resolve undefined weak symbols
38 // with definitions from archive members that were extracted in order to
39 // resolve an undefined global (strong) symbol)
42 # define FOLLY_DEFINED_DMGL 1
43 # define DMGL_NO_OPTS 0 /* For readability... */
44 # define DMGL_PARAMS (1 << 0) /* Include function args */
45 # define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */
46 # define DMGL_JAVA (1 << 2) /* Demangle as Java rather than C++. */
47 # define DMGL_VERBOSE (1 << 3) /* Include implementation details. */
48 # define DMGL_TYPES (1 << 4) /* Also try to demangle type encodings. */
49 # define DMGL_RET_POSTFIX (1 << 5) /* Print function return types (when
50 present) after function signature */
53 extern "C" int cplus_demangle_v3_callback(
55 int options, // We use DMGL_PARAMS | DMGL_TYPES, aka 0x11
56 void (*callback)(const char*, size_t, void*),
65 inline void stringPrintfImpl(std::string& output, const char* format,
67 // Tru to the space at the end of output for our output buffer.
68 // Find out write point then inflate its size temporarily to its
69 // capacity; we will later shrink it to the size needed to represent
70 // the formatted string. If this buffer isn't large enough, we do a
71 // resize and try again.
73 const auto write_point = output.size();
74 auto remaining = output.capacity() - write_point;
75 output.resize(output.capacity());
78 va_copy(args_copy, args);
79 int bytes_used = vsnprintf(&output[write_point], remaining, format,
83 throw std::runtime_error(
84 to<std::string>("Invalid format string; snprintf returned negative "
85 "with format string: ", format));
86 } else if (bytes_used < remaining) {
87 // There was enough room, just shrink and return.
88 output.resize(write_point + bytes_used);
90 output.resize(write_point + bytes_used + 1);
91 remaining = bytes_used + 1;
93 va_copy(args_copy, args);
94 bytes_used = vsnprintf(&output[write_point], remaining, format,
97 if (bytes_used + 1 != remaining) {
98 throw std::runtime_error(
99 to<std::string>("vsnprint retry did not manage to work "
100 "with format string: ", format));
102 output.resize(write_point + bytes_used);
108 std::string stringPrintf(const char* format, ...) {
109 // snprintf will tell us how large the output buffer should be, but
110 // we then have to call it a second time, which is costly. By
111 // guestimating the final size, we avoid the double snprintf in many
112 // cases, resulting in a performance win. We use this constructor
113 // of std::string to avoid a double allocation, though it does pad
114 // the resulting string with nul bytes. Our guestimation is twice
115 // the format string size, or 32 bytes, whichever is larger. This
116 // is a hueristic that doesn't affect correctness but attempts to be
117 // reasonably fast for the most common cases.
118 std::string ret(std::max(32UL, strlen(format) * 2), '\0');
122 va_start(ap, format);
123 stringPrintfImpl(ret, format, ap);
128 // Basic declarations; allow for parameters of strings and string
129 // pieces to be specified.
130 std::string& stringAppendf(std::string* output, const char* format, ...) {
132 va_start(ap, format);
133 stringPrintfImpl(*output, format, ap);
138 void stringPrintf(std::string* output, const char* format, ...) {
141 va_start(ap, format);
142 stringPrintfImpl(*output, format, ap);
148 struct PrettySuffix {
153 const PrettySuffix kPrettyTimeSuffixes[] = {
163 const PrettySuffix kPrettyBytesMetricSuffixes[] = {
172 const PrettySuffix kPrettyBytesBinarySuffixes[] = {
173 { "TB", int64_t(1) << 40 },
174 { "GB", int64_t(1) << 30 },
175 { "MB", int64_t(1) << 20 },
176 { "kB", int64_t(1) << 10 },
181 const PrettySuffix kPrettyBytesBinaryIECSuffixes[] = {
182 { "TiB", int64_t(1) << 40 },
183 { "GiB", int64_t(1) << 30 },
184 { "MiB", int64_t(1) << 20 },
185 { "KiB", int64_t(1) << 10 },
190 const PrettySuffix kPrettyUnitsMetricSuffixes[] = {
199 const PrettySuffix kPrettyUnitsBinarySuffixes[] = {
200 { "T", int64_t(1) << 40 },
201 { "G", int64_t(1) << 30 },
202 { "M", int64_t(1) << 20 },
203 { "k", int64_t(1) << 10 },
208 const PrettySuffix kPrettyUnitsBinaryIECSuffixes[] = {
209 { "Ti", int64_t(1) << 40 },
210 { "Gi", int64_t(1) << 30 },
211 { "Mi", int64_t(1) << 20 },
212 { "Ki", int64_t(1) << 10 },
217 const PrettySuffix* const kPrettySuffixes[PRETTY_NUM_TYPES] = {
219 kPrettyBytesMetricSuffixes,
220 kPrettyBytesBinarySuffixes,
221 kPrettyBytesBinaryIECSuffixes,
222 kPrettyUnitsMetricSuffixes,
223 kPrettyUnitsBinarySuffixes,
224 kPrettyUnitsBinaryIECSuffixes,
229 std::string prettyPrint(double val, PrettyType type, bool addSpace) {
232 // pick the suffixes to use
234 assert(type < PRETTY_NUM_TYPES);
235 const PrettySuffix* suffixes = kPrettySuffixes[type];
237 // find the first suffix we're bigger than -- then use it
238 double abs_val = fabs(val);
239 for (int i = 0; suffixes[i].suffix; ++i) {
240 if (abs_val >= suffixes[i].val) {
241 snprintf(buf, sizeof buf, "%.4g%s%s",
242 (suffixes[i].val ? (val / suffixes[i].val)
244 (addSpace ? " " : ""),
246 return std::string(buf);
250 // no suffix, we've got a tiny value -- just print it in sci-notation
251 snprintf(buf, sizeof buf, "%.4g", val);
252 return std::string(buf);
255 std::string hexDump(const void* ptr, size_t size) {
256 std::ostringstream os;
257 hexDump(ptr, size, std::ostream_iterator<StringPiece>(os, "\n"));
261 fbstring errnoStr(int err) {
262 int savedErrno = errno;
264 // Ensure that we reset errno upon exit.
265 auto guard(makeGuard([&] { errno = savedErrno; }));
272 // https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man3/strerror_r.3.html
273 // http://www.kernel.org/doc/man-pages/online/pages/man3/strerror.3.html
274 #if defined(__APPLE__) || defined(__FreeBSD__) || \
275 ((_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && !_GNU_SOURCE)
276 // Using XSI-compatible strerror_r
277 int r = strerror_r(err, buf, sizeof(buf));
279 // OSX/FreeBSD use EINVAL and Linux uses -1 so just check for non-zero
281 result = to<fbstring>(
282 "Unknown error ", err,
283 " (strerror_r failed with error ", errno, ")");
288 // Using GNU strerror_r
289 result.assign(strerror_r(err, buf, sizeof(buf)));
297 // glibc doesn't have strlcpy
298 size_t my_strlcpy(char* dest, const char* src, size_t size) {
299 size_t len = strlen(src);
301 size_t n = std::min(len, size - 1); // always null terminate!
302 memcpy(dest, src, n);
310 #if FOLLY_HAVE_CPLUS_DEMANGLE_V3_CALLBACK
312 fbstring demangle(const char* name) {
315 // malloc() memory for the demangled type name
316 char* demangled = abi::__cxa_demangle(name, nullptr, &len, &status);
320 // len is the length of the buffer (including NUL terminator and maybe
322 return fbstring(demangled, strlen(demangled), len, AcquireMallocatedString());
333 void demangleCallback(const char* str, size_t size, void* p) {
334 DemangleBuf* buf = static_cast<DemangleBuf*>(p);
335 size_t n = std::min(buf->remaining, size);
336 memcpy(buf->dest, str, n);
344 size_t demangle(const char* name, char* out, size_t outSize) {
347 dbuf.remaining = outSize ? outSize - 1 : 0; // leave room for null term
350 // Unlike most library functions, this returns 1 on success and 0 on failure
351 int status = cplus_demangle_v3_callback(
353 DMGL_PARAMS | DMGL_ANSI | DMGL_TYPES,
356 if (status == 0) { // failed, return original
357 return my_strlcpy(out, name, outSize);
367 fbstring demangle(const char* name) {
371 size_t demangle(const char* name, char* out, size_t outSize) {
372 return my_strlcpy(out, name, outSize);
379 size_t hexDumpLine(const void* ptr, size_t offset, size_t size,
384 // (1+2)*16: hex bytes, each preceded by a space
385 // 1: space separating the two halves
392 const uint8_t* p = reinterpret_cast<const uint8_t*>(ptr) + offset;
393 size_t n = std::min(size - offset, size_t(16));
394 format("{:08x} ", offset).appendTo(line);
396 for (size_t i = 0; i < n; i++) {
400 format(" {:02x}", p[i]).appendTo(line);
403 // 3 spaces for each byte we're not printing, one separating the halves
405 line.append(3 * (16 - n) + (n <= 8), ' ');
408 for (size_t i = 0; i < n; i++) {
409 char c = (p[i] >= 32 && p[i] <= 126 ? static_cast<char>(p[i]) : '.');
412 line.append(16 - n, ' ');
414 DCHECK_EQ(line.size(), 78);
419 } // namespace detail
423 #ifdef FOLLY_DEFINED_DMGL
424 # undef FOLLY_DEFINED_DMGL
431 # undef DMGL_RET_POSTFIX