89373e10f5e0df4d97ee95319ce3494924c8219c
[folly.git] / folly / String.cpp
1 /*
2  * Copyright 2013 Facebook, Inc.
3  *
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
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 #include "folly/String.h"
18 #include "folly/Format.h"
19
20 #include <cerrno>
21 #include <cstdarg>
22 #include <cstring>
23 #include <stdexcept>
24 #include <iterator>
25 #include <glog/logging.h>
26
27 #if FOLLY_HAVE_CPLUS_DEMANGLE_V3_CALLBACK
28 # include <cxxabi.h>
29
30 // From libiberty
31 //
32 // TODO(tudorb): Detect this with autoconf for the open-source version.
33 //
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)
40
41 # ifndef DMGL_NO_OPTS
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 */
51 # endif
52
53 extern "C" int cplus_demangle_v3_callback(
54     const char* mangled,
55     int options,  // We use DMGL_PARAMS | DMGL_TYPES, aka 0x11
56     void (*callback)(const char*, size_t, void*),
57     void* arg);
58
59 #endif
60
61 namespace folly {
62
63 namespace {
64
65 inline void stringPrintfImpl(std::string& output, const char* format,
66                              va_list args) {
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.
72
73   const auto write_point = output.size();
74   auto remaining = output.capacity() - write_point;
75   output.resize(output.capacity());
76
77   va_list args_copy;
78   va_copy(args_copy, args);
79   int bytes_used = vsnprintf(&output[write_point], remaining, format,
80                              args_copy);
81   va_end(args_copy);
82   if (bytes_used < 0) {
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);
89   } else {
90     output.resize(write_point + bytes_used + 1);
91     remaining = bytes_used + 1;
92     va_list args_copy;
93     va_copy(args_copy, args);
94     bytes_used = vsnprintf(&output[write_point], remaining, format,
95                            args_copy);
96     va_end(args_copy);
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));
101     }
102     output.resize(write_point + bytes_used);
103   }
104 }
105
106 }  // anon namespace
107
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');
119   ret.resize(0);
120
121   va_list ap;
122   va_start(ap, format);
123   stringPrintfImpl(ret, format, ap);
124   va_end(ap);
125   return ret;
126 }
127
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, ...) {
131   va_list ap;
132   va_start(ap, format);
133   stringPrintfImpl(*output, format, ap);
134   va_end(ap);
135   return *output;
136 }
137
138 void stringPrintf(std::string* output, const char* format, ...) {
139   output->clear();
140   va_list ap;
141   va_start(ap, format);
142   stringPrintfImpl(*output, format, ap);
143   va_end(ap);
144 };
145
146 namespace {
147
148 struct PrettySuffix {
149   const char* suffix;
150   double val;
151 };
152
153 const PrettySuffix kPrettyTimeSuffixes[] = {
154   { "s ", 1e0L },
155   { "ms", 1e-3L },
156   { "us", 1e-6L },
157   { "ns", 1e-9L },
158   { "ps", 1e-12L },
159   { "s ", 0 },
160   { 0, 0 },
161 };
162
163 const PrettySuffix kPrettyBytesMetricSuffixes[] = {
164   { "TB", 1e12L },
165   { "GB", 1e9L },
166   { "MB", 1e6L },
167   { "kB", 1e3L },
168   { "B ", 0L },
169   { 0, 0 },
170 };
171
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 },
177   { "B ", 0L },
178   { 0, 0 },
179 };
180
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 },
186   { "B  ", 0L },
187   { 0, 0 },
188 };
189
190 const PrettySuffix kPrettyUnitsMetricSuffixes[] = {
191   { "tril", 1e12L },
192   { "bil",  1e9L },
193   { "M",    1e6L },
194   { "k",    1e3L },
195   { " ",      0  },
196   { 0, 0 },
197 };
198
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 },
204   { " ", 0 },
205   { 0, 0 },
206 };
207
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 },
213   { "  ", 0 },
214   { 0, 0 },
215 };
216
217 const PrettySuffix* const kPrettySuffixes[PRETTY_NUM_TYPES] = {
218   kPrettyTimeSuffixes,
219   kPrettyBytesMetricSuffixes,
220   kPrettyBytesBinarySuffixes,
221   kPrettyBytesBinaryIECSuffixes,
222   kPrettyUnitsMetricSuffixes,
223   kPrettyUnitsBinarySuffixes,
224   kPrettyUnitsBinaryIECSuffixes,
225 };
226
227 }  // namespace
228
229 std::string prettyPrint(double val, PrettyType type, bool addSpace) {
230   char buf[100];
231
232   // pick the suffixes to use
233   assert(type >= 0);
234   assert(type < PRETTY_NUM_TYPES);
235   const PrettySuffix* suffixes = kPrettySuffixes[type];
236
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)
243                                 : val),
244                (addSpace ? " " : ""),
245                suffixes[i].suffix);
246       return std::string(buf);
247     }
248   }
249
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);
253 }
254
255 std::string hexDump(const void* ptr, size_t size) {
256   std::ostringstream os;
257   hexDump(ptr, size, std::ostream_iterator<StringPiece>(os, "\n"));
258   return os.str();
259 }
260
261 fbstring errnoStr(int err) {
262   int savedErrno = errno;
263
264   // Ensure that we reset errno upon exit.
265   auto guard(makeGuard([&] { errno = savedErrno; }));
266
267   char buf[1024];
268   buf[0] = '\0';
269
270   fbstring result;
271
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));
278
279   // OSX/FreeBSD use EINVAL and Linux uses -1 so just check for non-zero
280   if (r != 0) {
281     result = to<fbstring>(
282       "Unknown error ", err,
283       " (strerror_r failed with error ", errno, ")");
284   } else {
285     result.assign(buf);
286   }
287 #else
288   // Using GNU strerror_r
289   result.assign(strerror_r(err, buf, sizeof(buf)));
290 #endif
291
292   return result;
293 }
294
295 namespace {
296
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);
300   if (size != 0) {
301     size_t n = std::min(len, size - 1);  // always null terminate!
302     memcpy(dest, src, n);
303     dest[n] = '\0';
304   }
305   return len;
306 }
307
308 }  // namespace
309
310 #if FOLLY_HAVE_CPLUS_DEMANGLE_V3_CALLBACK
311
312 fbstring demangle(const char* name) {
313   int status;
314   size_t len = 0;
315   // malloc() memory for the demangled type name
316   char* demangled = abi::__cxa_demangle(name, nullptr, &len, &status);
317   if (status != 0) {
318     return name;
319   }
320   // len is the length of the buffer (including NUL terminator and maybe
321   // other junk)
322   return fbstring(demangled, strlen(demangled), len, AcquireMallocatedString());
323 }
324
325 namespace {
326
327 struct DemangleBuf {
328   char* dest;
329   size_t remaining;
330   size_t total;
331 };
332
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);
337   buf->dest += n;
338   buf->remaining -= n;
339   buf->total += size;
340 }
341
342 }  // namespace
343
344 size_t demangle(const char* name, char* out, size_t outSize) {
345   DemangleBuf dbuf;
346   dbuf.dest = out;
347   dbuf.remaining = outSize ? outSize - 1 : 0;   // leave room for null term
348   dbuf.total = 0;
349
350   // Unlike most library functions, this returns 1 on success and 0 on failure
351   int status = cplus_demangle_v3_callback(
352       name,
353       DMGL_PARAMS | DMGL_ANSI | DMGL_TYPES,
354       demangleCallback,
355       &dbuf);
356   if (status == 0) {  // failed, return original
357     return my_strlcpy(out, name, outSize);
358   }
359   if (outSize != 0) {
360     *dbuf.dest = '\0';
361   }
362   return dbuf.total;
363 }
364
365 #else
366
367 fbstring demangle(const char* name) {
368   return name;
369 }
370
371 size_t demangle(const char* name, char* out, size_t outSize) {
372   return my_strlcpy(out, name, outSize);
373 }
374
375 #endif
376
377 namespace detail {
378
379 size_t hexDumpLine(const void* ptr, size_t offset, size_t size,
380                    std::string& line) {
381   // Line layout:
382   // 8: address
383   // 1: space
384   // (1+2)*16: hex bytes, each preceded by a space
385   // 1: space separating the two halves
386   // 3: "  |"
387   // 16: characters
388   // 1: "|"
389   // Total: 78
390   line.clear();
391   line.reserve(78);
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);
395
396   for (size_t i = 0; i < n; i++) {
397     if (i == 8) {
398       line.push_back(' ');
399     }
400     format(" {:02x}", p[i]).appendTo(line);
401   }
402
403   // 3 spaces for each byte we're not printing, one separating the halves
404   // if necessary
405   line.append(3 * (16 - n) + (n <= 8), ' ');
406   line.append("  |");
407
408   for (size_t i = 0; i < n; i++) {
409     char c = (p[i] >= 32 && p[i] <= 126 ? static_cast<char>(p[i]) : '.');
410     line.push_back(c);
411   }
412   line.append(16 - n, ' ');
413   line.push_back('|');
414   DCHECK_EQ(line.size(), 78);
415
416   return n;
417 }
418
419 } // namespace detail
420
421 }   // namespace folly
422
423 #ifdef FOLLY_DEFINED_DMGL
424 # undef FOLLY_DEFINED_DMGL
425 # undef DMGL_NO_OPTS
426 # undef DMGL_PARAMS
427 # undef DMGL_ANSI
428 # undef DMGL_JAVA
429 # undef DMGL_VERBOSE
430 # undef DMGL_TYPES
431 # undef DMGL_RET_POSTFIX
432 #endif
433