Export of internal Abseil changes

--
2aa4544070113a4943f93464df74759f043bab92 by CJ Johnson <johnsoncj@google.com>:

Spelling fix in InlinedVector

PiperOrigin-RevId: 308241764

--
0d8a8ff71023df845c490c73811da598a42f12d9 by Todd Jackson <tjackson@google.com>:

Fix CMake warnings on absl/types/CMakeLists.txt.

PiperOrigin-RevId: 308123331

--
f35fbd79437ba999097b1499770103b7865078e5 by Samuel Benzaquen <sbenza@google.com>:

Speed up the integral printer.

PiperOrigin-RevId: 308081531

--
b1676b869ed0547e1cca23c83bb370f459bdf2cb by Samuel Benzaquen <sbenza@google.com>:

Collapse the template arguments to enums earlier to reduce the number of
instantiations of FormatSpecTemplate.
This doesn't affect opt builds much, but reduces the bloat in non-opt builds.

PiperOrigin-RevId: 308066155

--
edda0c227adad392cfff2af6ed532822c481f013 by Abseil Team <absl-team@google.com>:

Minor documentation fix for `absl::Status` CTOR.

PiperOrigin-RevId: 308037725

--
8326b85569f0fdb15632b0076e38baba4c69794b by Derek Mauro <dmauro@google.com>:

Internal change

PiperOrigin-RevId: 307914168
GitOrigin-RevId: 2aa4544070113a4943f93464df74759f043bab92
Change-Id: I553ce3838c5e35d04954f560dc75ec24033919af
pull/673/head
Abseil Team 5 years ago committed by Derek Mauro
parent 68494aae95
commit cde2e2410e
  1. 2
      CMake/abslConfig.cmake.in
  2. 2
      absl/container/inlined_vector.h
  3. 2
      absl/status/status.h
  4. 254
      absl/strings/internal/str_format/arg.cc
  5. 23
      absl/strings/internal/str_format/bind.h
  6. 39
      absl/strings/internal/str_format/extension.h
  7. 4
      absl/strings/str_format.h
  8. 8
      absl/types/CMakeLists.txt

@ -5,4 +5,4 @@ find_dependency(Threads)
@PACKAGE_INIT@ @PACKAGE_INIT@
include ("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake") include ("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake")

@ -535,7 +535,7 @@ class InlinedVector {
// //
// Resizes the inlined vector to contain `n` elements. // Resizes the inlined vector to contain `n` elements.
// //
// NOTE: if `n` is smaller than `size()`, extra elements are destroyed. If `n` // NOTE: If `n` is smaller than `size()`, extra elements are destroyed. If `n`
// is larger than `size()`, new elements are value-initialized. // is larger than `size()`, new elements are value-initialized.
void resize(size_type n) { void resize(size_type n) {
ABSL_HARDENING_ASSERT(n <= max_size()); ABSL_HARDENING_ASSERT(n <= max_size());

@ -78,7 +78,7 @@ class ABSL_MUST_USE_RESULT Status final {
Status(); Status();
// Create a status in the canonical error space with the specified code and // Create a status in the canonical error space with the specified code and
// error message. If `code == util::error::OK`, `msg` is ignored and an // error message. If `code == absl::StatusCode::kOk`, `msg` is ignored and an
// object identical to an OK status is constructed. // object identical to an OK status is constructed.
// //
// `msg` must be in UTF-8. The implementation may complain (e.g., // `msg` must be in UTF-8. The implementation may complain (e.g.,

@ -12,14 +12,13 @@
#include "absl/base/port.h" #include "absl/base/port.h"
#include "absl/strings/internal/str_format/float_conversion.h" #include "absl/strings/internal/str_format/float_conversion.h"
#include "absl/strings/numbers.h"
namespace absl { namespace absl {
ABSL_NAMESPACE_BEGIN ABSL_NAMESPACE_BEGIN
namespace str_format_internal { namespace str_format_internal {
namespace { namespace {
const char kDigit[2][32] = { "0123456789abcdef", "0123456789ABCDEF" };
// Reduce *capacity by s.size(), clipped to a 0 minimum. // Reduce *capacity by s.size(), clipped to a 0 minimum.
void ReducePadding(string_view s, size_t *capacity) { void ReducePadding(string_view s, size_t *capacity) {
*capacity = Excess(s.size(), *capacity); *capacity = Excess(s.size(), *capacity);
@ -48,94 +47,144 @@ struct IsSigned<absl::int128> : std::true_type {};
template <> template <>
struct IsSigned<absl::uint128> : std::false_type {}; struct IsSigned<absl::uint128> : std::false_type {};
class ConvertedIntInfo { // Integral digit printer.
// Call one of the PrintAs* routines after construction once.
// Use with_neg_and_zero/without_neg_or_zero/is_negative to access the results.
class IntDigits {
public: public:
// Print the unsigned integer as octal.
// Supports unsigned integral types and uint128.
template <typename T>
void PrintAsOct(T v) {
static_assert(!IsSigned<T>::value, "");
char *p = storage_ + sizeof(storage_);
do {
*--p = static_cast<char>('0' + (static_cast<size_t>(v) & 7));
v >>= 3;
} while (v);
start_ = p;
size_ = storage_ + sizeof(storage_) - p;
}
// Print the signed or unsigned integer as decimal.
// Supports all integral types.
template <typename T> template <typename T>
ConvertedIntInfo(T v, ConversionChar conv) { void PrintAsDec(T v) {
using Unsigned = typename MakeUnsigned<T>::type; static_assert(std::is_integral<T>::value, "");
auto u = static_cast<Unsigned>(v); start_ = storage_;
if (IsNeg(v)) { size_ = numbers_internal::FastIntToBuffer(v, storage_) - storage_;
is_neg_ = true; }
u = Unsigned{} - u;
} else { void PrintAsDec(int128 v) {
is_neg_ = false; auto u = static_cast<uint128>(v);
bool add_neg = false;
if (v < 0) {
add_neg = true;
u = uint128{} - u;
} }
UnsignedToStringRight(u, conv); PrintAsDec(u, add_neg);
} }
string_view digits() const { void PrintAsDec(uint128 v, bool add_neg = false) {
return {end() - size_, static_cast<size_t>(size_)}; // This function can be sped up if needed. We can call FastIntToBuffer
// twice, or fix FastIntToBuffer to support uint128.
char *p = storage_ + sizeof(storage_);
do {
p -= 2;
numbers_internal::PutTwoDigits(static_cast<size_t>(v % 100), p);
v /= 100;
} while (v);
if (p[0] == '0') {
// We printed one too many hexits.
++p;
}
if (add_neg) {
*--p = '-';
}
size_ = storage_ + sizeof(storage_) - p;
start_ = p;
} }
bool is_neg() const { return is_neg_; }
private: // Print the unsigned integer as hex using lowercase.
template <typename T, bool IsSigned> // Supports unsigned integral types and uint128.
struct IsNegImpl {
static bool Eval(T v) { return v < 0; }
};
template <typename T> template <typename T>
struct IsNegImpl<T, false> { void PrintAsHexLower(T v) {
static bool Eval(T) { static_assert(!IsSigned<T>::value, "");
return false; char *p = storage_ + sizeof(storage_);
do {
p -= 2;
constexpr const char* table = numbers_internal::kHexTable;
std::memcpy(p, table + 2 * (static_cast<size_t>(v) & 0xFF), 2);
if (sizeof(T) == 1) break;
v >>= 8;
} while (v);
if (p[0] == '0') {
// We printed one too many digits.
++p;
} }
}; start_ = p;
size_ = storage_ + sizeof(storage_) - p;
}
// Print the unsigned integer as hex using uppercase.
// Supports unsigned integral types and uint128.
template <typename T> template <typename T>
bool IsNeg(T v) { void PrintAsHexUpper(T v) {
return IsNegImpl<T, IsSigned<T>::value>::Eval(v); static_assert(!IsSigned<T>::value, "");
char *p = storage_ + sizeof(storage_);
// kHexTable is only lowercase, so do it manually for uppercase.
do {
*--p = "0123456789ABCDEF"[static_cast<size_t>(v) & 15];
v >>= 4;
} while (v);
start_ = p;
size_ = storage_ + sizeof(storage_) - p;
} }
template <typename T> // The printed value including the '-' sign if available.
void UnsignedToStringRight(T u, ConversionChar conv) { // For inputs of value `0`, this will return "0"
char *p = end(); string_view with_neg_and_zero() const { return {start_, size_}; }
switch (FormatConversionCharRadix(conv)) {
default: // The printed value not including the '-' sign.
case 10: // For inputs of value `0`, this will return "".
for (; u; u /= 10) string_view without_neg_or_zero() const {
*--p = static_cast<char>('0' + static_cast<size_t>(u % 10)); static_assert('-' < '0', "The check below verifies both.");
break; size_t advance = start_[0] <= '0' ? 1 : 0;
case 8: return {start_ + advance, size_ - advance};
for (; u; u /= 8)
*--p = static_cast<char>('0' + static_cast<size_t>(u % 8));
break;
case 16: {
const char *digits = kDigit[FormatConversionCharIsUpper(conv) ? 1 : 0];
for (; u; u /= 16) *--p = digits[static_cast<size_t>(u % 16)];
break;
}
}
size_ = static_cast<int>(end() - p);
} }
const char *end() const { return storage_ + sizeof(storage_); } bool is_negative() const { return start_[0] == '-'; }
char *end() { return storage_ + sizeof(storage_); }
bool is_neg_; private:
int size_; const char *start_;
// Max size: 128 bit value as octal -> 43 digits size_t size_;
char storage_[128 / 3 + 1]; // Max size: 128 bit value as octal -> 43 digits, plus sign char
char storage_[128 / 3 + 1 + 1];
}; };
// Note: 'o' conversions do not have a base indicator, it's just that // Note: 'o' conversions do not have a base indicator, it's just that
// the '#' flag is specified to modify the precision for 'o' conversions. // the '#' flag is specified to modify the precision for 'o' conversions.
string_view BaseIndicator(const ConvertedIntInfo &info, string_view BaseIndicator(const IntDigits &as_digits,
const ConversionSpec conv) { const ConversionSpec conv) {
bool alt = conv.has_alt_flag(); // always show 0x for %p.
int radix = FormatConversionCharRadix(conv.conversion_char()); bool alt = conv.has_alt_flag() || conv.conversion_char() == ConversionChar::p;
if (conv.conversion_char() == ConversionChar::p) bool hex = (conv.conversion_char() == FormatConversionChar::x ||
alt = true; // always show 0x for %p. conv.conversion_char() == FormatConversionChar::X ||
conv.conversion_char() == FormatConversionChar::p);
// From the POSIX description of '#' flag: // From the POSIX description of '#' flag:
// "For x or X conversion specifiers, a non-zero result shall have // "For x or X conversion specifiers, a non-zero result shall have
// 0x (or 0X) prefixed to it." // 0x (or 0X) prefixed to it."
if (alt && radix == 16 && !info.digits().empty()) { if (alt && hex && !as_digits.without_neg_or_zero().empty()) {
if (FormatConversionCharIsUpper(conv.conversion_char())) return "0X"; return conv.conversion_char() == FormatConversionChar::X ? "0X" : "0x";
return "0x";
} }
return {}; return {};
} }
string_view SignColumn(bool neg, const ConversionSpec conv) { string_view SignColumn(bool neg, const ConversionSpec conv) {
if (FormatConversionCharIsSigned(conv.conversion_char())) { if (conv.conversion_char() == FormatConversionChar::d ||
conv.conversion_char() == FormatConversionChar::i) {
if (neg) return "-"; if (neg) return "-";
if (conv.has_show_pos_flag()) return "+"; if (conv.has_show_pos_flag()) return "+";
if (conv.has_sign_col_flag()) return " "; if (conv.has_sign_col_flag()) return " ";
@ -154,20 +203,20 @@ bool ConvertCharImpl(unsigned char v, const ConversionSpec conv,
return true; return true;
} }
bool ConvertIntImplInner(const ConvertedIntInfo &info, bool ConvertIntImplInnerSlow(const IntDigits &as_digits,
const ConversionSpec conv, FormatSinkImpl *sink) { const ConversionSpec conv, FormatSinkImpl *sink) {
// Print as a sequence of Substrings: // Print as a sequence of Substrings:
// [left_spaces][sign][base_indicator][zeroes][formatted][right_spaces] // [left_spaces][sign][base_indicator][zeroes][formatted][right_spaces]
size_t fill = 0; size_t fill = 0;
if (conv.width() >= 0) fill = conv.width(); if (conv.width() >= 0) fill = conv.width();
string_view formatted = info.digits(); string_view formatted = as_digits.without_neg_or_zero();
ReducePadding(formatted, &fill); ReducePadding(formatted, &fill);
string_view sign = SignColumn(info.is_neg(), conv); string_view sign = SignColumn(as_digits.is_negative(), conv);
ReducePadding(sign, &fill); ReducePadding(sign, &fill);
string_view base_indicator = BaseIndicator(info, conv); string_view base_indicator = BaseIndicator(as_digits, conv);
ReducePadding(base_indicator, &fill); ReducePadding(base_indicator, &fill);
int precision = conv.precision(); int precision = conv.precision();
@ -208,35 +257,54 @@ bool ConvertIntImplInner(const ConvertedIntInfo &info,
return true; return true;
} }
template <typename T>
bool ConvertIntImplInner(T v, const ConversionSpec conv, FormatSinkImpl *sink) {
ConvertedIntInfo info(v, conv.conversion_char());
if (conv.is_basic() && (conv.conversion_char() != ConversionChar::p)) {
if (info.is_neg()) sink->Append(1, '-');
if (info.digits().empty()) {
sink->Append(1, '0');
} else {
sink->Append(info.digits());
}
return true;
}
return ConvertIntImplInner(info, conv, sink);
}
template <typename T> template <typename T>
bool ConvertIntArg(T v, const ConversionSpec conv, FormatSinkImpl *sink) { bool ConvertIntArg(T v, const ConversionSpec conv, FormatSinkImpl *sink) {
if (FormatConversionCharIsFloat(conv.conversion_char())) { using U = typename MakeUnsigned<T>::type;
return FormatConvertImpl(static_cast<double>(v), conv, sink).value; IntDigits as_digits;
switch (conv.conversion_char()) {
case FormatConversionChar::c:
return ConvertCharImpl(static_cast<unsigned char>(v), conv, sink);
case FormatConversionChar::o:
as_digits.PrintAsOct(static_cast<U>(v));
break;
case FormatConversionChar::x:
as_digits.PrintAsHexLower(static_cast<U>(v));
break;
case FormatConversionChar::X:
as_digits.PrintAsHexUpper(static_cast<U>(v));
break;
case FormatConversionChar::u:
as_digits.PrintAsDec(static_cast<U>(v));
break;
case FormatConversionChar::d:
case FormatConversionChar::i:
as_digits.PrintAsDec(v);
break;
case FormatConversionChar::a:
case FormatConversionChar::e:
case FormatConversionChar::f:
case FormatConversionChar::g:
case FormatConversionChar::A:
case FormatConversionChar::E:
case FormatConversionChar::F:
case FormatConversionChar::G:
return ConvertFloatImpl(static_cast<double>(v), conv, sink);
default:
return false;
} }
if (conv.conversion_char() == ConversionChar::c)
return ConvertCharImpl(static_cast<unsigned char>(v), conv, sink); if (conv.is_basic()) {
if (!FormatConversionCharIsIntegral(conv.conversion_char())) return false; sink->Append(as_digits.with_neg_and_zero());
if (!FormatConversionCharIsSigned(conv.conversion_char()) && return true;
IsSigned<T>::value) {
using U = typename MakeUnsigned<T>::type;
return FormatConvertImpl(static_cast<U>(v), conv, sink).value;
} }
return ConvertIntImplInner(v, conv, sink); return ConvertIntImplInnerSlow(as_digits, conv, sink);
} }
template <typename T> template <typename T>
@ -296,7 +364,9 @@ ConvertResult<Conv::p> FormatConvertImpl(VoidPtr v, const ConversionSpec conv,
sink->Append("(nil)"); sink->Append("(nil)");
return {true}; return {true};
} }
return {ConvertIntImplInner(v.value, conv, sink)}; IntDigits as_digits;
as_digits.PrintAsHexLower(v.value);
return {ConvertIntImplInnerSlow(as_digits, conv, sink)};
} }
// ==================== Floats ==================== // ==================== Floats ====================

@ -60,7 +60,7 @@ class UntypedFormatSpecImpl {
size_t size_; size_t size_;
}; };
template <typename T, typename...> template <typename T, FormatConversionCharSet...>
struct MakeDependent { struct MakeDependent {
using type = T; using type = T;
}; };
@ -68,7 +68,7 @@ struct MakeDependent {
// Implicitly convertible from `const char*`, `string_view`, and the // Implicitly convertible from `const char*`, `string_view`, and the
// `ExtendedParsedFormat` type. This abstraction allows all format functions to // `ExtendedParsedFormat` type. This abstraction allows all format functions to
// operate on any without providing too many overloads. // operate on any without providing too many overloads.
template <typename... Args> template <FormatConversionCharSet... Args>
class FormatSpecTemplate class FormatSpecTemplate
: public MakeDependent<UntypedFormatSpec, Args...>::type { : public MakeDependent<UntypedFormatSpec, Args...>::type {
using Base = typename MakeDependent<UntypedFormatSpec, Args...>::type; using Base = typename MakeDependent<UntypedFormatSpec, Args...>::type;
@ -105,13 +105,11 @@ class FormatSpecTemplate
// Good format overload. // Good format overload.
FormatSpecTemplate(const char* s) // NOLINT FormatSpecTemplate(const char* s) // NOLINT
__attribute__((enable_if(ValidFormatImpl<ArgumentToConv<Args>()...>(s), __attribute__((enable_if(ValidFormatImpl<Args...>(s), "bad format trap")))
"bad format trap")))
: Base(s) {} : Base(s) {}
FormatSpecTemplate(string_view s) // NOLINT FormatSpecTemplate(string_view s) // NOLINT
__attribute__((enable_if(ValidFormatImpl<ArgumentToConv<Args>()...>(s), __attribute__((enable_if(ValidFormatImpl<Args...>(s), "bad format trap")))
"bad format trap")))
: Base(s) {} : Base(s) {}
#else // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER #else // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER
@ -121,19 +119,14 @@ class FormatSpecTemplate
#endif // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER #endif // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER
template <Conv... C, typename = typename std::enable_if< template <Conv... C,
AllOf(sizeof...(C) == sizeof...(Args), typename = typename std::enable_if<
Contains(ArgumentToConv<Args>(), AllOf(sizeof...(C) == sizeof...(Args), Contains(Args,
C)...)>::type> C)...)>::type>
FormatSpecTemplate(const ExtendedParsedFormat<C...>& pc) // NOLINT FormatSpecTemplate(const ExtendedParsedFormat<C...>& pc) // NOLINT
: Base(&pc) {} : Base(&pc) {}
}; };
template <typename... Args>
struct FormatSpecDeductionBarrier {
using type = FormatSpecTemplate<Args...>;
};
class Streamable { class Streamable {
public: public:
Streamable(const UntypedFormatSpecImpl& format, Streamable(const UntypedFormatSpecImpl& format,

@ -170,21 +170,6 @@ inline FormatConversionChar FormatConversionCharFromChar(char c) {
return FormatConversionChar::kNone; return FormatConversionChar::kNone;
} }
inline int FormatConversionCharRadix(FormatConversionChar c) {
switch (c) {
case FormatConversionChar::x:
case FormatConversionChar::X:
case FormatConversionChar::a:
case FormatConversionChar::A:
case FormatConversionChar::p:
return 16;
case FormatConversionChar::o:
return 8;
default:
return 10;
}
}
inline bool FormatConversionCharIsUpper(FormatConversionChar c) { inline bool FormatConversionCharIsUpper(FormatConversionChar c) {
switch (c) { switch (c) {
case FormatConversionChar::X: case FormatConversionChar::X:
@ -198,30 +183,6 @@ inline bool FormatConversionCharIsUpper(FormatConversionChar c) {
} }
} }
inline bool FormatConversionCharIsSigned(FormatConversionChar c) {
switch (c) {
case FormatConversionChar::d:
case FormatConversionChar::i:
return true;
default:
return false;
}
}
inline bool FormatConversionCharIsIntegral(FormatConversionChar c) {
switch (c) {
case FormatConversionChar::d:
case FormatConversionChar::i:
case FormatConversionChar::u:
case FormatConversionChar::o:
case FormatConversionChar::x:
case FormatConversionChar::X:
return true;
default:
return false;
}
}
inline bool FormatConversionCharIsFloat(FormatConversionChar c) { inline bool FormatConversionCharIsFloat(FormatConversionChar c) {
switch (c) { switch (c) {
case FormatConversionChar::a: case FormatConversionChar::a:

@ -254,8 +254,8 @@ class FormatCountCapture {
// argument, etc. // argument, etc.
template <typename... Args> template <typename... Args>
using FormatSpec = using FormatSpec = str_format_internal::FormatSpecTemplate<
typename str_format_internal::FormatSpecDeductionBarrier<Args...>::type; str_format_internal::ArgumentToConv<Args>()...>;
// ParsedFormat // ParsedFormat
// //

@ -246,10 +246,10 @@ absl_cc_library(
"internal/conformance_aliases.h" "internal/conformance_aliases.h"
"internal/conformance_archetype.h" "internal/conformance_archetype.h"
"internal/conformance_profile.h" "internal/conformance_profile.h"
"internal/conformance_testing.h", "internal/conformance_testing.h"
"internal/conformance_testing_helpers.h", "internal/conformance_testing_helpers.h"
"internal/parentheses.h", "internal/parentheses.h"
"internal/transform_args.h", "internal/transform_args.h"
COPTS COPTS
${ABSL_DEFAULT_COPTS} ${ABSL_DEFAULT_COPTS}
DEPS DEPS

Loading…
Cancel
Save