44b6a783369ddfbdc0060841ea89226f4e35404d
[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 #undef FOLLY_DEMANGLE
28
29 #if defined(__GNUG__) && __GNUG__ >= 4
30 # include <cxxabi.h>
31 # define FOLLY_DEMANGLE 1
32
33 // From libiberty
34 //
35 // TODO(tudorb): Detect this with autoconf for the open-source version.
36 //
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)
43 extern "C" int cplus_demangle_v3_callback(
44     const char* mangled,
45     int options,  // We use DMGL_PARAMS | DMGL_TYPES, aka 0x11
46     void (*callback)(const char*, size_t, void*),
47     void* arg);
48
49 #endif
50
51 namespace folly {
52
53 namespace {
54
55 inline void stringPrintfImpl(std::string& output, const char* format,
56                              va_list args) {
57   // Tru to the space at the end of output for our output buffer.
58   // Find out write point then inflate its size temporarily to its
59   // capacity; we will later shrink it to the size needed to represent
60   // the formatted string.  If this buffer isn't large enough, we do a
61   // resize and try again.
62
63   const auto write_point = output.size();
64   auto remaining = output.capacity() - write_point;
65   output.resize(output.capacity());
66
67   va_list args_copy;
68   va_copy(args_copy, args);
69   int bytes_used = vsnprintf(&output[write_point], remaining, format,
70                              args_copy);
71   va_end(args_copy);
72   if (bytes_used < 0) {
73     throw std::runtime_error(
74       to<std::string>("Invalid format string; snprintf returned negative "
75                       "with format string: ", format));
76   } else if (bytes_used < remaining) {
77     // There was enough room, just shrink and return.
78     output.resize(write_point + bytes_used);
79   } else {
80     output.resize(write_point + bytes_used + 1);
81     remaining = bytes_used + 1;
82     va_list args_copy;
83     va_copy(args_copy, args);
84     bytes_used = vsnprintf(&output[write_point], remaining, format,
85                            args_copy);
86     va_end(args_copy);
87     if (bytes_used + 1 != remaining) {
88       throw std::runtime_error(
89         to<std::string>("vsnprint retry did not manage to work "
90                         "with format string: ", format));
91     }
92     output.resize(write_point + bytes_used);
93   }
94 }
95
96 }  // anon namespace
97
98 std::string stringPrintf(const char* format, ...) {
99   // snprintf will tell us how large the output buffer should be, but
100   // we then have to call it a second time, which is costly.  By
101   // guestimating the final size, we avoid the double snprintf in many
102   // cases, resulting in a performance win.  We use this constructor
103   // of std::string to avoid a double allocation, though it does pad
104   // the resulting string with nul bytes.  Our guestimation is twice
105   // the format string size, or 32 bytes, whichever is larger.  This
106   // is a hueristic that doesn't affect correctness but attempts to be
107   // reasonably fast for the most common cases.
108   std::string ret(std::max(32UL, strlen(format) * 2), '\0');
109   ret.resize(0);
110
111   va_list ap;
112   va_start(ap, format);
113   stringPrintfImpl(ret, format, ap);
114   va_end(ap);
115   return ret;
116 }
117
118 // Basic declarations; allow for parameters of strings and string
119 // pieces to be specified.
120 std::string& stringAppendf(std::string* output, const char* format, ...) {
121   va_list ap;
122   va_start(ap, format);
123   stringPrintfImpl(*output, format, ap);
124   va_end(ap);
125   return *output;
126 }
127
128 void stringPrintf(std::string* output, const char* format, ...) {
129   output->clear();
130   va_list ap;
131   va_start(ap, format);
132   stringPrintfImpl(*output, format, ap);
133   va_end(ap);
134 };
135
136 namespace {
137
138 struct PrettySuffix {
139   const char* suffix;
140   double val;
141 };
142
143 const PrettySuffix kPrettyTimeSuffixes[] = {
144   { "s ", 1e0L },
145   { "ms", 1e-3L },
146   { "us", 1e-6L },
147   { "ns", 1e-9L },
148   { "ps", 1e-12L },
149   { "s ", 0 },
150   { 0, 0 },
151 };
152
153 const PrettySuffix kPrettyBytesMetricSuffixes[] = {
154   { "TB", 1e12L },
155   { "GB", 1e9L },
156   { "MB", 1e6L },
157   { "kB", 1e3L },
158   { "B ", 0L },
159   { 0, 0 },
160 };
161
162 const PrettySuffix kPrettyBytesBinarySuffixes[] = {
163   { "TB", int64_t(1) << 40 },
164   { "GB", int64_t(1) << 30 },
165   { "MB", int64_t(1) << 20 },
166   { "kB", int64_t(1) << 10 },
167   { "B ", 0L },
168   { 0, 0 },
169 };
170
171 const PrettySuffix kPrettyBytesBinaryIECSuffixes[] = {
172   { "TiB", int64_t(1) << 40 },
173   { "GiB", int64_t(1) << 30 },
174   { "MiB", int64_t(1) << 20 },
175   { "KiB", int64_t(1) << 10 },
176   { "B  ", 0L },
177   { 0, 0 },
178 };
179
180 const PrettySuffix kPrettyUnitsMetricSuffixes[] = {
181   { "tril", 1e12L },
182   { "bil",  1e9L },
183   { "M",    1e6L },
184   { "k",    1e3L },
185   { " ",      0  },
186   { 0, 0 },
187 };
188
189 const PrettySuffix kPrettyUnitsBinarySuffixes[] = {
190   { "T", int64_t(1) << 40 },
191   { "G", int64_t(1) << 30 },
192   { "M", int64_t(1) << 20 },
193   { "k", int64_t(1) << 10 },
194   { " ", 0 },
195   { 0, 0 },
196 };
197
198 const PrettySuffix kPrettyUnitsBinaryIECSuffixes[] = {
199   { "Ti", int64_t(1) << 40 },
200   { "Gi", int64_t(1) << 30 },
201   { "Mi", int64_t(1) << 20 },
202   { "Ki", int64_t(1) << 10 },
203   { "  ", 0 },
204   { 0, 0 },
205 };
206
207 const PrettySuffix* const kPrettySuffixes[PRETTY_NUM_TYPES] = {
208   kPrettyTimeSuffixes,
209   kPrettyBytesMetricSuffixes,
210   kPrettyBytesBinarySuffixes,
211   kPrettyBytesBinaryIECSuffixes,
212   kPrettyUnitsMetricSuffixes,
213   kPrettyUnitsBinarySuffixes,
214   kPrettyUnitsBinaryIECSuffixes,
215 };
216
217 }  // namespace
218
219 std::string prettyPrint(double val, PrettyType type, bool addSpace) {
220   char buf[100];
221
222   // pick the suffixes to use
223   assert(type >= 0);
224   assert(type < PRETTY_NUM_TYPES);
225   const PrettySuffix* suffixes = kPrettySuffixes[type];
226
227   // find the first suffix we're bigger than -- then use it
228   double abs_val = fabs(val);
229   for (int i = 0; suffixes[i].suffix; ++i) {
230     if (abs_val >= suffixes[i].val) {
231       snprintf(buf, sizeof buf, "%.4g%s%s",
232                (suffixes[i].val ? (val / suffixes[i].val)
233                                 : val),
234                (addSpace ? " " : ""),
235                suffixes[i].suffix);
236       return std::string(buf);
237     }
238   }
239
240   // no suffix, we've got a tiny value -- just print it in sci-notation
241   snprintf(buf, sizeof buf, "%.4g", val);
242   return std::string(buf);
243 }
244
245 std::string hexDump(const void* ptr, size_t size) {
246   std::ostringstream os;
247   hexDump(ptr, size, std::ostream_iterator<StringPiece>(os, "\n"));
248   return os.str();
249 }
250
251 fbstring errnoStr(int err) {
252   int savedErrno = errno;
253
254   // Ensure that we reset errno upon exit.
255   auto guard(makeGuard([&] { errno = savedErrno; }));
256
257   char buf[1024];
258   buf[0] = '\0';
259
260   fbstring result;
261
262   // https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man3/strerror_r.3.html
263   // http://www.kernel.org/doc/man-pages/online/pages/man3/strerror.3.html
264 #if defined(__APPLE__) || defined(__FreeBSD__) || \
265     ((_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && !_GNU_SOURCE)
266   // Using XSI-compatible strerror_r
267   int r = strerror_r(err, buf, sizeof(buf));
268
269   // OSX/FreeBSD use EINVAL and Linux uses -1 so just check for non-zero
270   if (r != 0) {
271     result = to<fbstring>(
272       "Unknown error ", err,
273       " (strerror_r failed with error ", errno, ")");
274   } else {
275     result.assign(buf);
276   }
277 #else
278   // Using GNU strerror_r
279   result.assign(strerror_r(err, buf, sizeof(buf)));
280 #endif
281
282   return result;
283 }
284
285 namespace {
286
287 // glibc doesn't have strlcpy
288 size_t my_strlcpy(char* dest, const char* src, size_t size) {
289   size_t len = strlen(src);
290   if (size != 0) {
291     size_t n = std::min(len, size - 1);  // always null terminate!
292     memcpy(dest, src, n);
293     dest[n] = '\0';
294   }
295   return len;
296 }
297
298 }  // namespace
299
300 #ifdef FOLLY_DEMANGLE
301
302 fbstring demangle(const char* name) {
303   int status;
304   size_t len = 0;
305   // malloc() memory for the demangled type name
306   char* demangled = abi::__cxa_demangle(name, nullptr, &len, &status);
307   if (status != 0) {
308     return name;
309   }
310   // len is the length of the buffer (including NUL terminator and maybe
311   // other junk)
312   return fbstring(demangled, strlen(demangled), len, AcquireMallocatedString());
313 }
314
315 namespace {
316
317 struct DemangleBuf {
318   char* dest;
319   size_t remaining;
320   size_t total;
321 };
322
323 void demangleCallback(const char* str, size_t size, void* p) {
324   DemangleBuf* buf = static_cast<DemangleBuf*>(p);
325   size_t n = std::min(buf->remaining, size);
326   memcpy(buf->dest, str, n);
327   buf->dest += n;
328   buf->remaining -= n;
329   buf->total += size;
330 }
331
332 }  // namespace
333
334 size_t demangle(const char* name, char* out, size_t outSize) {
335   DemangleBuf dbuf;
336   dbuf.dest = out;
337   dbuf.remaining = outSize ? outSize - 1 : 0;   // leave room for null term
338   dbuf.total = 0;
339
340   // Unlike most library functions, this returns 1 on success and 0 on failure
341   int status = cplus_demangle_v3_callback(
342       name,
343       0x11,  // DMGL_PARAMS | DMGL_TYPES
344       demangleCallback,
345       &dbuf);
346   if (status == 0) {  // failed, return original
347     return my_strlcpy(out, name, outSize);
348   }
349   if (outSize != 0) {
350     *dbuf.dest = '\0';
351   }
352   return dbuf.total;
353 }
354
355 #else
356
357 fbstring demangle(const char* name) {
358   return name;
359 }
360
361 size_t demangle(const char* name, char* out, size_t outSize) {
362   return my_strlcpy(out, name, outSize);
363 }
364
365 #endif
366 #undef FOLLY_DEMANGLE
367
368 namespace detail {
369
370 size_t hexDumpLine(const void* ptr, size_t offset, size_t size,
371                    std::string& line) {
372   // Line layout:
373   // 8: address
374   // 1: space
375   // (1+2)*16: hex bytes, each preceded by a space
376   // 1: space separating the two halves
377   // 3: "  |"
378   // 16: characters
379   // 1: "|"
380   // Total: 78
381   line.clear();
382   line.reserve(78);
383   const uint8_t* p = reinterpret_cast<const uint8_t*>(ptr) + offset;
384   size_t n = std::min(size - offset, size_t(16));
385   format("{:08x} ", offset).appendTo(line);
386
387   for (size_t i = 0; i < n; i++) {
388     if (i == 8) {
389       line.push_back(' ');
390     }
391     format(" {:02x}", p[i]).appendTo(line);
392   }
393
394   // 3 spaces for each byte we're not printing, one separating the halves
395   // if necessary
396   line.append(3 * (16 - n) + (n <= 8), ' ');
397   line.append("  |");
398
399   for (size_t i = 0; i < n; i++) {
400     char c = (p[i] >= 32 && p[i] <= 126 ? static_cast<char>(p[i]) : '.');
401     line.push_back(c);
402   }
403   line.append(16 - n, ' ');
404   line.push_back('|');
405   DCHECK_EQ(line.size(), 78);
406
407   return n;
408 }
409
410 } // namespace detail
411
412 }   // namespace folly