diff --git a/CMake/abslConfig.cmake.in b/CMake/abslConfig.cmake.in index 6d23f63d3..62d246d01 100644 --- a/CMake/abslConfig.cmake.in +++ b/CMake/abslConfig.cmake.in @@ -5,4 +5,4 @@ find_dependency(Threads) @PACKAGE_INIT@ -include ("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake") \ No newline at end of file +include ("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake") diff --git a/absl/container/inlined_vector.h b/absl/container/inlined_vector.h index 36f388aef..f18dd4c78 100644 --- a/absl/container/inlined_vector.h +++ b/absl/container/inlined_vector.h @@ -535,7 +535,7 @@ class InlinedVector { // // 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. void resize(size_type n) { ABSL_HARDENING_ASSERT(n <= max_size()); diff --git a/absl/status/status.h b/absl/status/status.h index 67ff988f8..967e60644 100644 --- a/absl/status/status.h +++ b/absl/status/status.h @@ -78,7 +78,7 @@ class ABSL_MUST_USE_RESULT Status final { Status(); // 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. // // `msg` must be in UTF-8. The implementation may complain (e.g., diff --git a/absl/strings/internal/str_format/arg.cc b/absl/strings/internal/str_format/arg.cc index 3aa0296bf..12842276a 100644 --- a/absl/strings/internal/str_format/arg.cc +++ b/absl/strings/internal/str_format/arg.cc @@ -12,14 +12,13 @@ #include "absl/base/port.h" #include "absl/strings/internal/str_format/float_conversion.h" +#include "absl/strings/numbers.h" namespace absl { ABSL_NAMESPACE_BEGIN namespace str_format_internal { namespace { -const char kDigit[2][32] = { "0123456789abcdef", "0123456789ABCDEF" }; - // Reduce *capacity by s.size(), clipped to a 0 minimum. void ReducePadding(string_view s, size_t *capacity) { *capacity = Excess(s.size(), *capacity); @@ -48,94 +47,144 @@ struct IsSigned : std::true_type {}; template <> struct IsSigned : 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: + // Print the unsigned integer as octal. + // Supports unsigned integral types and uint128. template - ConvertedIntInfo(T v, ConversionChar conv) { - using Unsigned = typename MakeUnsigned::type; - auto u = static_cast(v); - if (IsNeg(v)) { - is_neg_ = true; - u = Unsigned{} - u; - } else { - is_neg_ = false; - } - UnsignedToStringRight(u, conv); + void PrintAsOct(T v) { + static_assert(!IsSigned::value, ""); + char *p = storage_ + sizeof(storage_); + do { + *--p = static_cast('0' + (static_cast(v) & 7)); + v >>= 3; + } while (v); + start_ = p; + size_ = storage_ + sizeof(storage_) - p; } - string_view digits() const { - return {end() - size_, static_cast(size_)}; + // Print the signed or unsigned integer as decimal. + // Supports all integral types. + template + void PrintAsDec(T v) { + static_assert(std::is_integral::value, ""); + start_ = storage_; + size_ = numbers_internal::FastIntToBuffer(v, storage_) - storage_; } - bool is_neg() const { return is_neg_; } + + void PrintAsDec(int128 v) { + auto u = static_cast(v); + bool add_neg = false; + if (v < 0) { + add_neg = true; + u = uint128{} - u; + } + PrintAsDec(u, add_neg); + } + + void PrintAsDec(uint128 v, bool add_neg = false) { + // 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(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; + } + + // Print the unsigned integer as hex using lowercase. + // Supports unsigned integral types and uint128. + template + void PrintAsHexLower(T v) { + static_assert(!IsSigned::value, ""); + char *p = storage_ + sizeof(storage_); + + do { + p -= 2; + constexpr const char* table = numbers_internal::kHexTable; + std::memcpy(p, table + 2 * (static_cast(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 + void PrintAsHexUpper(T v) { + static_assert(!IsSigned::value, ""); + char *p = storage_ + sizeof(storage_); + + // kHexTable is only lowercase, so do it manually for uppercase. + do { + *--p = "0123456789ABCDEF"[static_cast(v) & 15]; + v >>= 4; + } while (v); + start_ = p; + size_ = storage_ + sizeof(storage_) - p; + } + + // The printed value including the '-' sign if available. + // For inputs of value `0`, this will return "0" + string_view with_neg_and_zero() const { return {start_, size_}; } + + // The printed value not including the '-' sign. + // For inputs of value `0`, this will return "". + string_view without_neg_or_zero() const { + static_assert('-' < '0', "The check below verifies both."); + size_t advance = start_[0] <= '0' ? 1 : 0; + return {start_ + advance, size_ - advance}; + } + + bool is_negative() const { return start_[0] == '-'; } private: - template - struct IsNegImpl { - static bool Eval(T v) { return v < 0; } - }; - template - struct IsNegImpl { - static bool Eval(T) { - return false; - } - }; - - template - bool IsNeg(T v) { - return IsNegImpl::value>::Eval(v); - } - - template - void UnsignedToStringRight(T u, ConversionChar conv) { - char *p = end(); - switch (FormatConversionCharRadix(conv)) { - default: - case 10: - for (; u; u /= 10) - *--p = static_cast('0' + static_cast(u % 10)); - break; - case 8: - for (; u; u /= 8) - *--p = static_cast('0' + static_cast(u % 8)); - break; - case 16: { - const char *digits = kDigit[FormatConversionCharIsUpper(conv) ? 1 : 0]; - for (; u; u /= 16) *--p = digits[static_cast(u % 16)]; - break; - } - } - size_ = static_cast(end() - p); - } - - const char *end() const { return storage_ + sizeof(storage_); } - char *end() { return storage_ + sizeof(storage_); } - - bool is_neg_; - int size_; - // Max size: 128 bit value as octal -> 43 digits - char storage_[128 / 3 + 1]; + const char *start_; + size_t size_; + // 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 // 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) { - bool alt = conv.has_alt_flag(); - int radix = FormatConversionCharRadix(conv.conversion_char()); - if (conv.conversion_char() == ConversionChar::p) - alt = true; // always show 0x for %p. + // always show 0x for %p. + bool alt = conv.has_alt_flag() || conv.conversion_char() == ConversionChar::p; + bool hex = (conv.conversion_char() == FormatConversionChar::x || + conv.conversion_char() == FormatConversionChar::X || + conv.conversion_char() == FormatConversionChar::p); // From the POSIX description of '#' flag: // "For x or X conversion specifiers, a non-zero result shall have // 0x (or 0X) prefixed to it." - if (alt && radix == 16 && !info.digits().empty()) { - if (FormatConversionCharIsUpper(conv.conversion_char())) return "0X"; - return "0x"; + if (alt && hex && !as_digits.without_neg_or_zero().empty()) { + return conv.conversion_char() == FormatConversionChar::X ? "0X" : "0x"; } return {}; } 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 (conv.has_show_pos_flag()) return "+"; if (conv.has_sign_col_flag()) return " "; @@ -154,20 +203,20 @@ bool ConvertCharImpl(unsigned char v, const ConversionSpec conv, return true; } -bool ConvertIntImplInner(const ConvertedIntInfo &info, - const ConversionSpec conv, FormatSinkImpl *sink) { +bool ConvertIntImplInnerSlow(const IntDigits &as_digits, + const ConversionSpec conv, FormatSinkImpl *sink) { // Print as a sequence of Substrings: // [left_spaces][sign][base_indicator][zeroes][formatted][right_spaces] size_t fill = 0; if (conv.width() >= 0) fill = conv.width(); - string_view formatted = info.digits(); + string_view formatted = as_digits.without_neg_or_zero(); ReducePadding(formatted, &fill); - string_view sign = SignColumn(info.is_neg(), conv); + string_view sign = SignColumn(as_digits.is_negative(), conv); ReducePadding(sign, &fill); - string_view base_indicator = BaseIndicator(info, conv); + string_view base_indicator = BaseIndicator(as_digits, conv); ReducePadding(base_indicator, &fill); int precision = conv.precision(); @@ -209,34 +258,53 @@ bool ConvertIntImplInner(const ConvertedIntInfo &info, } template -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()); - } +bool ConvertIntArg(T v, const ConversionSpec conv, FormatSinkImpl *sink) { + using U = typename MakeUnsigned::type; + IntDigits as_digits; + + switch (conv.conversion_char()) { + case FormatConversionChar::c: + return ConvertCharImpl(static_cast(v), conv, sink); + + case FormatConversionChar::o: + as_digits.PrintAsOct(static_cast(v)); + break; + + case FormatConversionChar::x: + as_digits.PrintAsHexLower(static_cast(v)); + break; + case FormatConversionChar::X: + as_digits.PrintAsHexUpper(static_cast(v)); + break; + + case FormatConversionChar::u: + as_digits.PrintAsDec(static_cast(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(v), conv, sink); + + default: + return false; + } + + if (conv.is_basic()) { + sink->Append(as_digits.with_neg_and_zero()); return true; } - return ConvertIntImplInner(info, conv, sink); -} - -template -bool ConvertIntArg(T v, const ConversionSpec conv, FormatSinkImpl *sink) { - if (FormatConversionCharIsFloat(conv.conversion_char())) { - return FormatConvertImpl(static_cast(v), conv, sink).value; - } - if (conv.conversion_char() == ConversionChar::c) - return ConvertCharImpl(static_cast(v), conv, sink); - if (!FormatConversionCharIsIntegral(conv.conversion_char())) return false; - if (!FormatConversionCharIsSigned(conv.conversion_char()) && - IsSigned::value) { - using U = typename MakeUnsigned::type; - return FormatConvertImpl(static_cast(v), conv, sink).value; - } - return ConvertIntImplInner(v, conv, sink); + return ConvertIntImplInnerSlow(as_digits, conv, sink); } template @@ -296,7 +364,9 @@ ConvertResult FormatConvertImpl(VoidPtr v, const ConversionSpec conv, sink->Append("(nil)"); return {true}; } - return {ConvertIntImplInner(v.value, conv, sink)}; + IntDigits as_digits; + as_digits.PrintAsHexLower(v.value); + return {ConvertIntImplInnerSlow(as_digits, conv, sink)}; } // ==================== Floats ==================== diff --git a/absl/strings/internal/str_format/bind.h b/absl/strings/internal/str_format/bind.h index ee4475e07..d30fdf507 100644 --- a/absl/strings/internal/str_format/bind.h +++ b/absl/strings/internal/str_format/bind.h @@ -60,7 +60,7 @@ class UntypedFormatSpecImpl { size_t size_; }; -template +template struct MakeDependent { using type = T; }; @@ -68,7 +68,7 @@ struct MakeDependent { // Implicitly convertible from `const char*`, `string_view`, and the // `ExtendedParsedFormat` type. This abstraction allows all format functions to // operate on any without providing too many overloads. -template +template class FormatSpecTemplate : public MakeDependent::type { using Base = typename MakeDependent::type; @@ -105,13 +105,11 @@ class FormatSpecTemplate // Good format overload. FormatSpecTemplate(const char* s) // NOLINT - __attribute__((enable_if(ValidFormatImpl()...>(s), - "bad format trap"))) + __attribute__((enable_if(ValidFormatImpl(s), "bad format trap"))) : Base(s) {} FormatSpecTemplate(string_view s) // NOLINT - __attribute__((enable_if(ValidFormatImpl()...>(s), - "bad format trap"))) + __attribute__((enable_if(ValidFormatImpl(s), "bad format trap"))) : Base(s) {} #else // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER @@ -121,19 +119,14 @@ class FormatSpecTemplate #endif // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER - template (), - C)...)>::type> + template ::type> FormatSpecTemplate(const ExtendedParsedFormat& pc) // NOLINT : Base(&pc) {} }; -template -struct FormatSpecDeductionBarrier { - using type = FormatSpecTemplate; -}; - class Streamable { public: Streamable(const UntypedFormatSpecImpl& format, diff --git a/absl/strings/internal/str_format/extension.h b/absl/strings/internal/str_format/extension.h index bae2c0784..fb31a9db4 100644 --- a/absl/strings/internal/str_format/extension.h +++ b/absl/strings/internal/str_format/extension.h @@ -170,21 +170,6 @@ inline FormatConversionChar FormatConversionCharFromChar(char c) { 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) { switch (c) { 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) { switch (c) { case FormatConversionChar::a: diff --git a/absl/strings/str_format.h b/absl/strings/str_format.h index 2e0b33f7e..f48510b45 100644 --- a/absl/strings/str_format.h +++ b/absl/strings/str_format.h @@ -254,8 +254,8 @@ class FormatCountCapture { // argument, etc. template -using FormatSpec = - typename str_format_internal::FormatSpecDeductionBarrier::type; +using FormatSpec = str_format_internal::FormatSpecTemplate< + str_format_internal::ArgumentToConv()...>; // ParsedFormat // diff --git a/absl/types/CMakeLists.txt b/absl/types/CMakeLists.txt index 71b339ae5..0dc0d2c7c 100644 --- a/absl/types/CMakeLists.txt +++ b/absl/types/CMakeLists.txt @@ -246,10 +246,10 @@ absl_cc_library( "internal/conformance_aliases.h" "internal/conformance_archetype.h" "internal/conformance_profile.h" - "internal/conformance_testing.h", - "internal/conformance_testing_helpers.h", - "internal/parentheses.h", - "internal/transform_args.h", + "internal/conformance_testing.h" + "internal/conformance_testing_helpers.h" + "internal/parentheses.h" + "internal/transform_args.h" COPTS ${ABSL_DEFAULT_COPTS} DEPS