X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=folly%2FFormat-inl.h;h=a4568b13b0dcfe631d42ec417eec2bf1820bc572;hb=764261c12ab059cd15607a1c2d2a7ff015dfe7ce;hp=944e2869ad68ccd0975a01c4a7b55e69e4a0ff9b;hpb=24f6247d54a7cebdd3d7752e34c02291734a6904;p=folly.git diff --git a/folly/Format-inl.h b/folly/Format-inl.h index 944e2869..a4568b13 100644 --- a/folly/Format-inl.h +++ b/folly/Format-inl.h @@ -1,5 +1,5 @@ /* - * Copyright 2012 Facebook, Inc. + * Copyright 2014 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,6 +18,9 @@ #error This file may only be included from Format.h. #endif +#include "folly/Exception.h" +#include "folly/Traits.h" + namespace folly { namespace detail { @@ -43,7 +46,9 @@ const size_t kMaxBinaryLength = 8 * sizeof(uintmax_t); template size_t uintToHex(char* buffer, size_t bufLen, Uint v, const char (&repr)[256][2]) { - for (; v >= 256; v >>= 8) { + // 'v >>= 7, v >>= 1' is no more than a work around to get rid of shift size + // warning when Uint = uint8_t (it's false as v >= 256 implies sizeof(v) > 1). + for (; !less_than(v); v >>= 7, v >>= 1) { auto b = v & 0xff; bufLen -= 2; buffer[bufLen] = repr[b][0]; @@ -85,7 +90,9 @@ inline size_t uintToHexUpper(char* buffer, size_t bufLen, Uint v) { template size_t uintToOctal(char* buffer, size_t bufLen, Uint v) { auto& repr = formatOctal; - for (; v >= 512; v >>= 9) { + // 'v >>= 7, v >>= 2' is no more than a work around to get rid of shift size + // warning when Uint = uint8_t (it's false as v >= 512 implies sizeof(v) > 1). + for (; !less_than(v); v >>= 7, v >>= 2) { auto b = v & 0x1ff; bufLen -= 3; buffer[bufLen] = repr[b][0]; @@ -117,7 +124,7 @@ size_t uintToBinary(char* buffer, size_t bufLen, Uint v) { buffer[--bufLen] = '0'; return bufLen; } - for (; v; v >>= 8) { + for (; v; v >>= 7, v >>= 1) { auto b = v & 0xff; bufLen -= 8; memcpy(buffer + bufLen, &(repr[b][0]), 8); @@ -140,9 +147,51 @@ Formatter::Formatter(StringPiece str, Args&&... args) "Exactly one argument required in container mode"); } +template +void Formatter::handleFormatStrError() const { + if (crashOnError_) { + LOG(FATAL) << "folly::format: bad format string \"" << str_ << "\": " << + folly::exceptionStr(std::current_exception()); + } + throw; +} + template template void Formatter::operator()(Output& out) const { + // Catch BadFormatArg and range_error exceptions, and call + // handleFormatStrError(). + // + // These exception types indicate a problem with the format string. Most + // format strings are string literals specified by the programmer. If they + // have a problem, this is usually a programmer bug. We want to crash to + // ensure that these are found early on during development. + // + // BadFormatArg is thrown by the Format.h code, while range_error is thrown + // by Conv.h, which is used in several places in our format string + // processing. + // + // (Note: This behavior is slightly dangerous. If the Output object throws a + // BadFormatArg or a range_error, we will also crash the program, even if it + // wasn't an issue with the format string. This seems highly unlikely + // though, and none of our current Output objects can throw these errors.) + // + // We also throw out_of_range errors if the format string references an + // argument that isn't present (or a key that isn't present in one of the + // argument containers). However, at the moment we don't crash on these + // errors, as it is likely that the container is dynamic at runtime. + try { + appendOutput(out); + } catch (const BadFormatArg& ex) { + handleFormatStrError(); + } catch (const std::range_error& ex) { + handleFormatStrError(); + } +} + +template +template +void Formatter::appendOutput(Output& out) const { auto p = str_.begin(); auto end = str_.end(); @@ -163,8 +212,7 @@ void Formatter::operator()(Output& out) const { p = q; if (p == end || *p != '}') { - throw std::invalid_argument( - "folly::format: single '}' in format string"); + throw BadFormatArg("folly::format: single '}' in format string"); } ++p; } @@ -183,8 +231,7 @@ void Formatter::operator()(Output& out) const { p = q + 1; if (p == end) { - throw std::invalid_argument( - "folly::format: '}' at end of format string"); + throw BadFormatArg("folly::format: '}' at end of format string"); } // "{{" -> "{" @@ -196,8 +243,8 @@ void Formatter::operator()(Output& out) const { // Format string q = static_cast(memchr(p, '}', end - p)); - if (q == end) { - throw std::invalid_argument("folly::format: missing ending '}'"); + if (q == nullptr) { + throw BadFormatArg("folly::format: missing ending '}'"); } FormatArg arg(StringPiece(p, q)); p = q + 1; @@ -228,7 +275,7 @@ void Formatter::operator()(Output& out) const { } if (hasDefaultArgIndex && hasExplicitArgIndex) { - throw std::invalid_argument( + throw BadFormatArg( "folly::format: may not have both default and explicit arg indexes"); } @@ -236,6 +283,17 @@ void Formatter::operator()(Output& out) const { } } +template +void writeTo(FILE* fp, const Formatter& formatter) { + auto writer = [fp] (StringPiece sp) { + ssize_t n = fwrite(sp.data(), 1, sp.size(), fp); + if (n < sp.size()) { + throwSystemError("Formatter writeTo", "fwrite failed"); + } + }; + formatter(writer); +} + namespace format_value { template @@ -373,7 +431,7 @@ class FormatValue< UT uval; char sign; if (std::is_signed::value) { - if (val_ < 0) { + if (folly::is_negative(val_)) { uval = static_cast(-val_); sign = '-'; } else { @@ -558,8 +616,6 @@ class FormatValue { arg.precision = 6; } - bool done = false; - // 2+: for null terminator and optional sign shenanigans. char buf[2 + std::max({ (2 + DoubleToStringConverter::kMaxFixedDigitsBeforePoint + @@ -617,7 +673,7 @@ class FormatValue { exponentSymbol, -4, arg.precision, 0, 0); - CHECK(conv.ToExponential(val, arg.precision, &builder)); + arg.enforce(conv.ToExponential(val, arg.precision, &builder)); } break; case 'n': // should be locale-aware, but isn't @@ -637,7 +693,7 @@ class FormatValue { exponentSymbol, -4, arg.precision, 0, 0); - CHECK(conv.ToShortest(val, &builder)); + arg.enforce(conv.ToShortest(val, &builder)); } break; default: @@ -1105,7 +1161,7 @@ class FormatValue, void> { */ template typename std::enable_if< - detail::IsSomeString::value>::type + IsSomeString::value>::type toAppend(const Formatter& value, Tgt * result) { value.appendTo(*result); }