From fcfc7a6d15eab5aff86d7b90c9e38fa386a103fa Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Wed, 17 Aug 2022 09:17:56 -0700 Subject: Fix "unsafe narrowing" warnings in absl, 5/n. Addresses failures with the following, in some files: -Wshorten-64-to-32 -Wimplicit-int-conversion -Wsign-compare -Wsign-conversion -Wtautological-unsigned-zero-compare (This specific CL focuses on .cc files in strings/internal/.) Bug: chromium:1292951 PiperOrigin-RevId: 468215101 Change-Id: I07fa487bcf2cf62d403489c3be7a5997cdef8987 --- absl/strings/internal/charconv_bigint.cc | 8 +- absl/strings/internal/charconv_parse.cc | 4 +- absl/strings/internal/cord_internal.h | 5 +- absl/strings/internal/cord_rep_btree.cc | 7 +- absl/strings/internal/cord_rep_btree.h | 5 +- absl/strings/internal/cord_rep_btree_navigator.cc | 10 +- absl/strings/internal/cordz_info.cc | 13 +- absl/strings/internal/cordz_info.h | 8 +- absl/strings/internal/cordz_statistics.h | 8 +- absl/strings/internal/memutil.cc | 15 +- absl/strings/internal/str_format/arg.cc | 35 +- absl/strings/internal/str_format/bind.cc | 5 +- absl/strings/internal/str_format/extension.cc | 3 +- .../internal/str_format/float_conversion.cc | 390 +++++++++++---------- 14 files changed, 283 insertions(+), 233 deletions(-) diff --git a/absl/strings/internal/charconv_bigint.cc b/absl/strings/internal/charconv_bigint.cc index ebf8c079..282b639e 100644 --- a/absl/strings/internal/charconv_bigint.cc +++ b/absl/strings/internal/charconv_bigint.cc @@ -242,7 +242,7 @@ int BigUnsigned::ReadDigits(const char* begin, const char* end, // decimal exponent to compensate. --exponent_adjust; } - int digit = (*begin - '0'); + char digit = (*begin - '0'); --significant_digits; if (significant_digits == 0 && std::next(begin) != end && (digit == 0 || digit == 5)) { @@ -255,7 +255,7 @@ int BigUnsigned::ReadDigits(const char* begin, const char* end, // 500000...000000000001 to correctly round up, rather than to nearest. ++digit; } - queued = 10 * queued + digit; + queued = 10 * queued + static_cast(digit); ++digits_queued; if (digits_queued == kMaxSmallPowerOfTen) { MultiplyBy(kTenToNth[kMaxSmallPowerOfTen]); @@ -341,8 +341,8 @@ std::string BigUnsigned::ToString() const { std::string result; // Build result in reverse order while (copy.size() > 0) { - int next_digit = copy.DivMod<10>(); - result.push_back('0' + next_digit); + uint32_t next_digit = copy.DivMod<10>(); + result.push_back('0' + static_cast(next_digit)); } if (result.empty()) { result.push_back('0'); diff --git a/absl/strings/internal/charconv_parse.cc b/absl/strings/internal/charconv_parse.cc index d29acaf4..98823def 100644 --- a/absl/strings/internal/charconv_parse.cc +++ b/absl/strings/internal/charconv_parse.cc @@ -190,11 +190,11 @@ bool IsDigit<16>(char ch) { template <> unsigned ToDigit<10>(char ch) { - return ch - '0'; + return static_cast(ch - '0'); } template <> unsigned ToDigit<16>(char ch) { - return kAsciiToInt[static_cast(ch)]; + return static_cast(kAsciiToInt[static_cast(ch)]); } template <> diff --git a/absl/strings/internal/cord_internal.h b/absl/strings/internal/cord_internal.h index 29954112..601457ee 100644 --- a/absl/strings/internal/cord_internal.h +++ b/absl/strings/internal/cord_internal.h @@ -129,8 +129,9 @@ class RefcountAndFlags { } // Returns the current reference count using acquire semantics. - inline int32_t Get() const { - return count_.load(std::memory_order_acquire) >> kNumFlags; + inline size_t Get() const { + return static_cast(count_.load(std::memory_order_acquire) >> + kNumFlags); } // Returns whether the atomic integer is 1. diff --git a/absl/strings/internal/cord_rep_btree.cc b/absl/strings/internal/cord_rep_btree.cc index cacbf3da..7ce36128 100644 --- a/absl/strings/internal/cord_rep_btree.cc +++ b/absl/strings/internal/cord_rep_btree.cc @@ -17,6 +17,7 @@ #include #include #include +#include #include #include "absl/base/attributes.h" @@ -55,8 +56,10 @@ inline bool exhaustive_validation() { // Prints the entire tree structure or 'rep'. External callers should // not specify 'depth' and leave it to its default (0) value. // Rep may be a CordRepBtree tree, or a SUBSTRING / EXTERNAL / FLAT node. -void DumpAll(const CordRep* rep, bool include_contents, std::ostream& stream, - int depth = 0) { +void DumpAll(const CordRep* rep, + bool include_contents, + std::ostream& stream, + size_t depth = 0) { // Allow for full height trees + substring -> flat / external nodes. assert(depth <= CordRepBtree::kMaxDepth + 2); std::string sharing = const_cast(rep)->refcount.IsOne() diff --git a/absl/strings/internal/cord_rep_btree.h b/absl/strings/internal/cord_rep_btree.h index 2cbc09ec..eed5609e 100644 --- a/absl/strings/internal/cord_rep_btree.h +++ b/absl/strings/internal/cord_rep_btree.h @@ -95,8 +95,9 @@ class CordRepBtree : public CordRep { // local stack variable compared to Cord's current near 400 bytes stack use. // The maximum `height` value of a node is then `kMaxDepth - 1` as node height // values start with a value of 0 for leaf nodes. - static constexpr int kMaxDepth = 12; - static constexpr int kMaxHeight = kMaxDepth - 1; + static constexpr size_t kMaxDepth = 12; + // See comments on height() for why this is an int and not a size_t. + static constexpr int kMaxHeight = static_cast(kMaxDepth - 1); // `Action` defines the action for unwinding changes done at the btree's leaf // level that need to be propagated up to the parent node(s). Each operation diff --git a/absl/strings/internal/cord_rep_btree_navigator.cc b/absl/strings/internal/cord_rep_btree_navigator.cc index 9b896a3d..6ed20c23 100644 --- a/absl/strings/internal/cord_rep_btree_navigator.cc +++ b/absl/strings/internal/cord_rep_btree_navigator.cc @@ -90,7 +90,7 @@ CordRepBtreeNavigator::Position CordRepBtreeNavigator::Skip(size_t n) { // edges that must be skipped. while (height > 0) { node = edge->btree(); - index_[height] = index; + index_[height] = static_cast(index); node_[--height] = node; index = node->begin(); edge = node->Edge(index); @@ -101,7 +101,7 @@ CordRepBtreeNavigator::Position CordRepBtreeNavigator::Skip(size_t n) { edge = node->Edge(index); } } - index_[0] = index; + index_[0] = static_cast(index); return {edge, n}; } @@ -126,7 +126,7 @@ ReadResult CordRepBtreeNavigator::Read(size_t edge_offset, size_t n) { do { length -= edge->length; while (++index == node->end()) { - index_[height] = index; + index_[height] = static_cast(index); if (++height > height_) { subtree->set_end(subtree_end); if (length == 0) return {subtree, 0}; @@ -154,7 +154,7 @@ ReadResult CordRepBtreeNavigator::Read(size_t edge_offset, size_t n) { // edges that must be read, adding 'down' nodes to `subtree`. while (height > 0) { node = edge->btree(); - index_[height] = index; + index_[height] = static_cast(index); node_[--height] = node; index = node->begin(); edge = node->Edge(index); @@ -178,7 +178,7 @@ ReadResult CordRepBtreeNavigator::Read(size_t edge_offset, size_t n) { subtree->edges_[subtree_end++] = Substring(edge, 0, length); } subtree->set_end(subtree_end); - index_[0] = index; + index_[0] = static_cast(index); return {tree, length}; } diff --git a/absl/strings/internal/cordz_info.cc b/absl/strings/internal/cordz_info.cc index dac3fd8b..530f33be 100644 --- a/absl/strings/internal/cordz_info.cc +++ b/absl/strings/internal/cordz_info.cc @@ -35,7 +35,7 @@ namespace cord_internal { using ::absl::base_internal::SpinLockHolder; #ifdef ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL -constexpr int CordzInfo::kMaxStackDepth; +constexpr size_t CordzInfo::kMaxStackDepth; #endif ABSL_CONST_INIT CordzInfo::List CordzInfo::global_list_{absl::kConstInit}; @@ -291,7 +291,7 @@ CordzInfo::MethodIdentifier CordzInfo::GetParentMethod(const CordzInfo* src) { : src->method_; } -int CordzInfo::FillParentStack(const CordzInfo* src, void** stack) { +size_t CordzInfo::FillParentStack(const CordzInfo* src, void** stack) { assert(stack); if (src == nullptr) return 0; if (src->parent_stack_depth_) { @@ -302,11 +302,14 @@ int CordzInfo::FillParentStack(const CordzInfo* src, void** stack) { return src->stack_depth_; } -CordzInfo::CordzInfo(CordRep* rep, const CordzInfo* src, +CordzInfo::CordzInfo(CordRep* rep, + const CordzInfo* src, MethodIdentifier method) : rep_(rep), - stack_depth_(absl::GetStackTrace(stack_, /*max_depth=*/kMaxStackDepth, - /*skip_count=*/1)), + stack_depth_( + static_cast(absl::GetStackTrace(stack_, + /*max_depth=*/kMaxStackDepth, + /*skip_count=*/1))), parent_stack_depth_(FillParentStack(src, parent_stack_)), method_(method), parent_method_(GetParentMethod(src)), diff --git a/absl/strings/internal/cordz_info.h b/absl/strings/internal/cordz_info.h index 026d5b99..8e86f223 100644 --- a/absl/strings/internal/cordz_info.h +++ b/absl/strings/internal/cordz_info.h @@ -196,7 +196,7 @@ class ABSL_LOCKABLE CordzInfo : public CordzHandle { std::atomic head ABSL_GUARDED_BY(mutex){nullptr}; }; - static constexpr int kMaxStackDepth = 64; + static constexpr size_t kMaxStackDepth = 64; explicit CordzInfo(CordRep* rep, const CordzInfo* src, MethodIdentifier method); @@ -216,7 +216,7 @@ class ABSL_LOCKABLE CordzInfo : public CordzHandle { // `stack_` depending on `parent_stack_` being empty, returning the size of // the parent stack. // Returns 0 if `src` is null. - static int FillParentStack(const CordzInfo* src, void** stack); + static size_t FillParentStack(const CordzInfo* src, void** stack); void ODRCheck() const { #ifndef NDEBUG @@ -244,8 +244,8 @@ class ABSL_LOCKABLE CordzInfo : public CordzHandle { void* stack_[kMaxStackDepth]; void* parent_stack_[kMaxStackDepth]; - const int stack_depth_; - const int parent_stack_depth_; + const size_t stack_depth_; + const size_t parent_stack_depth_; const MethodIdentifier method_; const MethodIdentifier parent_method_; CordzUpdateTracker update_tracker_; diff --git a/absl/strings/internal/cordz_statistics.h b/absl/strings/internal/cordz_statistics.h index 57071905..9f558df4 100644 --- a/absl/strings/internal/cordz_statistics.h +++ b/absl/strings/internal/cordz_statistics.h @@ -45,12 +45,12 @@ struct CordzStatistics { }; // The size of the cord in bytes. This matches the result of Cord::size(). - int64_t size = 0; + size_t size = 0; // The estimated memory used by the sampled cord. This value matches the // value as reported by Cord::EstimatedMemoryUsage(). // A value of 0 implies the property has not been recorded. - int64_t estimated_memory_usage = 0; + size_t estimated_memory_usage = 0; // The effective memory used by the sampled cord, inversely weighted by the // effective indegree of each allocated node. This is a representation of the @@ -59,14 +59,14 @@ struct CordzStatistics { // by multiple Cord instances, and for cases where a Cord includes the same // node multiple times (either directly or indirectly). // A value of 0 implies the property has not been recorded. - int64_t estimated_fair_share_memory_usage = 0; + size_t estimated_fair_share_memory_usage = 0; // The total number of nodes referenced by this cord. // For ring buffer Cords, this includes the 'ring buffer' node. // For btree Cords, this includes all 'CordRepBtree' tree nodes as well as all // the substring, flat and external nodes referenced by the tree. // A value of 0 implies the property has not been recorded. - int64_t node_count = 0; + size_t node_count = 0; // Detailed node counts per type NodeCounts node_counts; diff --git a/absl/strings/internal/memutil.cc b/absl/strings/internal/memutil.cc index 2519c688..44996a75 100644 --- a/absl/strings/internal/memutil.cc +++ b/absl/strings/internal/memutil.cc @@ -54,10 +54,11 @@ size_t memspn(const char* s, size_t slen, const char* accept) { cont: c = *p++; - if (slen-- == 0) return p - 1 - s; + if (slen-- == 0) + return static_cast(p - 1 - s); for (spanp = accept; (sc = *spanp++) != '\0';) if (sc == c) goto cont; - return p - 1 - s; + return static_cast(p - 1 - s); } size_t memcspn(const char* s, size_t slen, const char* reject) { @@ -68,9 +69,10 @@ size_t memcspn(const char* s, size_t slen, const char* reject) { while (slen-- != 0) { c = *p++; for (spanp = reject; (sc = *spanp++) != '\0';) - if (sc == c) return p - 1 - s; + if (sc == c) + return static_cast(p - 1 - s); } - return p - s; + return static_cast(p - s); } char* mempbrk(const char* s, size_t slen, const char* accept) { @@ -97,8 +99,9 @@ const char* memmatch(const char* phaystack, size_t haylen, const char* pneedle, const char* hayend = phaystack + haylen - neelen + 1; // A static cast is used here to work around the fact that memchr returns // a void* on Posix-compliant systems and const void* on Windows. - while ((match = static_cast( - memchr(phaystack, pneedle[0], hayend - phaystack)))) { + while ( + (match = static_cast(memchr( + phaystack, pneedle[0], static_cast(hayend - phaystack))))) { if (memcmp(match, pneedle, neelen) == 0) return match; else diff --git a/absl/strings/internal/str_format/arg.cc b/absl/strings/internal/str_format/arg.cc index 02aeeebe..007e8e83 100644 --- a/absl/strings/internal/str_format/arg.cc +++ b/absl/strings/internal/str_format/arg.cc @@ -77,7 +77,7 @@ class IntDigits { v >>= 3; } while (v); start_ = p; - size_ = storage_ + sizeof(storage_) - p; + size_ = static_cast(storage_ + sizeof(storage_) - p); } // Print the signed or unsigned integer as decimal. @@ -86,7 +86,8 @@ class IntDigits { void PrintAsDec(T v) { static_assert(std::is_integral::value, ""); start_ = storage_; - size_ = numbers_internal::FastIntToBuffer(v, storage_) - storage_; + size_ = static_cast(numbers_internal::FastIntToBuffer(v, storage_) - + storage_); } void PrintAsDec(int128 v) { @@ -115,7 +116,7 @@ class IntDigits { if (add_neg) { *--p = '-'; } - size_ = storage_ + sizeof(storage_) - p; + size_ = static_cast(storage_ + sizeof(storage_) - p); start_ = p; } @@ -138,7 +139,7 @@ class IntDigits { ++p; } start_ = p; - size_ = storage_ + sizeof(storage_) - p; + size_ = static_cast(storage_ + sizeof(storage_) - p); } // Print the unsigned integer as hex using uppercase. @@ -154,7 +155,7 @@ class IntDigits { v >>= 4; } while (v); start_ = p; - size_ = storage_ + sizeof(storage_) - p; + size_ = static_cast(storage_ + sizeof(storage_) - p); } // The printed value including the '-' sign if available. @@ -208,10 +209,12 @@ string_view SignColumn(bool neg, const FormatConversionSpecImpl conv) { return {}; } -bool ConvertCharImpl(unsigned char v, const FormatConversionSpecImpl conv, - FormatSinkImpl *sink) { +bool ConvertCharImpl(char v, + const FormatConversionSpecImpl conv, + FormatSinkImpl* sink) { size_t fill = 0; - if (conv.width() >= 0) fill = conv.width(); + if (conv.width() >= 0) + fill = static_cast(conv.width()); ReducePadding(1, &fill); if (!conv.has_left_flag()) sink->Append(fill, ' '); sink->Append(1, v); @@ -225,7 +228,8 @@ bool ConvertIntImplInnerSlow(const IntDigits &as_digits, // 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(); + if (conv.width() >= 0) + fill = static_cast(conv.width()); string_view formatted = as_digits.without_neg_or_zero(); ReducePadding(formatted, &fill); @@ -236,10 +240,9 @@ bool ConvertIntImplInnerSlow(const IntDigits &as_digits, string_view base_indicator = BaseIndicator(as_digits, conv); ReducePadding(base_indicator, &fill); - int precision = conv.precision(); - bool precision_specified = precision >= 0; - if (!precision_specified) - precision = 1; + bool precision_specified = conv.precision() >= 0; + size_t precision = + precision_specified ? static_cast(conv.precision()) : size_t{1}; if (conv.has_alt_flag() && conv.conversion_char() == FormatConversionCharInternal::o) { @@ -247,7 +250,7 @@ bool ConvertIntImplInnerSlow(const IntDigits &as_digits, // "For o conversion, it increases the precision (if necessary) to // force the first digit of the result to be zero." if (formatted.empty() || *formatted.begin() != '0') { - int needed = static_cast(formatted.size()) + 1; + size_t needed = formatted.size() + 1; precision = std::max(precision, needed); } } @@ -287,7 +290,7 @@ bool ConvertIntArg(T v, const FormatConversionSpecImpl conv, // FormatConversionChar is declared, but not defined. switch (static_cast(conv.conversion_char())) { case static_cast(FormatConversionCharInternal::c): - return ConvertCharImpl(static_cast(v), conv, sink); + return ConvertCharImpl(static_cast(v), conv, sink); case static_cast(FormatConversionCharInternal::o): as_digits.PrintAsOct(static_cast(v)); @@ -375,7 +378,7 @@ FormatConvertImpl(const char *v, const FormatConversionSpecImpl conv, len = std::strlen(v); } else { // If precision is set, we look for the NUL-terminator on the valid range. - len = std::find(v, v + conv.precision(), '\0') - v; + len = static_cast(std::find(v, v + conv.precision(), '\0') - v); } return {ConvertStringArg(string_view(v, len), conv, sink)}; } diff --git a/absl/strings/internal/str_format/bind.cc b/absl/strings/internal/str_format/bind.cc index c988ba8f..77a42223 100644 --- a/absl/strings/internal/str_format/bind.cc +++ b/absl/strings/internal/str_format/bind.cc @@ -32,7 +32,8 @@ inline bool BindFromPosition(int position, int* value, return false; } // -1 because positions are 1-based - return FormatArgImplFriend::ToInt(pack[position - 1], value); + return FormatArgImplFriend::ToInt(pack[static_cast(position) - 1], + value); } class ArgContext { @@ -56,7 +57,7 @@ inline bool ArgContext::Bind(const UnboundConversion* unbound, const FormatArgImpl* arg = nullptr; int arg_position = unbound->arg_position; if (static_cast(arg_position - 1) >= pack_.size()) return false; - arg = &pack_[arg_position - 1]; // 1-based + arg = &pack_[static_cast(arg_position - 1)]; // 1-based if (unbound->flags != Flags::kBasic) { int width = unbound->width.value(); diff --git a/absl/strings/internal/str_format/extension.cc b/absl/strings/internal/str_format/extension.cc index f93153d5..2a0ceb13 100644 --- a/absl/strings/internal/str_format/extension.cc +++ b/absl/strings/internal/str_format/extension.cc @@ -58,7 +58,8 @@ constexpr FormatConversionCharSet FormatConversionCharSetInternal::kPointer; bool FormatSinkImpl::PutPaddedString(string_view value, int width, int precision, bool left) { size_t space_remaining = 0; - if (width >= 0) space_remaining = width; + if (width >= 0) + space_remaining = static_cast(width); size_t n = value.size(); if (precision >= 0) n = std::min(n, static_cast(precision)); string_view shown(value.data(), n); diff --git a/absl/strings/internal/str_format/float_conversion.cc b/absl/strings/internal/str_format/float_conversion.cc index b1c40684..3895001a 100644 --- a/absl/strings/internal/str_format/float_conversion.cc +++ b/absl/strings/internal/str_format/float_conversion.cc @@ -92,27 +92,30 @@ class StackArray { // Calculates `10 * (*v) + carry` and stores the result in `*v` and returns // the carry. +// Requires: `0 <= carry <= 9` template -inline Int MultiplyBy10WithCarry(Int *v, Int carry) { +inline char MultiplyBy10WithCarry(Int* v, char carry) { using BiggerInt = absl::conditional_t; - BiggerInt tmp = 10 * static_cast(*v) + carry; + BiggerInt tmp = + 10 * static_cast(*v) + static_cast(carry); *v = static_cast(tmp); - return static_cast(tmp >> (sizeof(Int) * 8)); + return static_cast(tmp >> (sizeof(Int) * 8)); } // Calculates `(2^64 * carry + *v) / 10`. // Stores the quotient in `*v` and returns the remainder. // Requires: `0 <= carry <= 9` -inline uint64_t DivideBy10WithCarry(uint64_t *v, uint64_t carry) { +inline char DivideBy10WithCarry(uint64_t* v, char carry) { constexpr uint64_t divisor = 10; // 2^64 / divisor = chunk_quotient + chunk_remainder / divisor constexpr uint64_t chunk_quotient = (uint64_t{1} << 63) / (divisor / 2); constexpr uint64_t chunk_remainder = uint64_t{} - chunk_quotient * divisor; + const uint64_t carry_u64 = static_cast(carry); const uint64_t mod = *v % divisor; - const uint64_t next_carry = chunk_remainder * carry + mod; - *v = *v / divisor + carry * chunk_quotient + next_carry / divisor; - return next_carry % divisor; + const uint64_t next_carry = chunk_remainder * carry_u64 + mod; + *v = *v / divisor + carry_u64 * chunk_quotient + next_carry / divisor; + return static_cast(next_carry % divisor); } using MaxFloatType = @@ -125,11 +128,11 @@ using MaxFloatType = // // Requires `0 <= exp` and `exp <= numeric_limits::max_exponent`. class BinaryToDecimal { - static constexpr int ChunksNeeded(int exp) { + static constexpr size_t ChunksNeeded(int exp) { // We will left shift a uint128 by `exp` bits, so we need `128+exp` total // bits. Round up to 32. // See constructor for details about adding `10%` to the value. - return (128 + exp + 31) / 32 * 11 / 10; + return static_cast((128 + exp + 31) / 32 * 11 / 10); } public: @@ -140,7 +143,7 @@ class BinaryToDecimal { assert(exp > 0); assert(exp <= std::numeric_limits::max_exponent); static_assert( - static_cast(StackArray::kMaxCapacity) >= + StackArray::kMaxCapacity >= ChunksNeeded(std::numeric_limits::max_exponent), ""); @@ -149,9 +152,9 @@ class BinaryToDecimal { [=](absl::Span input) { f(BinaryToDecimal(input, v, exp)); }); } - int TotalDigits() const { - return static_cast((decimal_end_ - decimal_start_) * kDigitsPerChunk + - CurrentDigits().size()); + size_t TotalDigits() const { + return (decimal_end_ - decimal_start_) * kDigitsPerChunk + + CurrentDigits().size(); } // See the current block of digits. @@ -190,30 +193,31 @@ class BinaryToDecimal { // the decimal representation is around 7% less efficient in space than the // binary one. We allocate an extra 10% memory to account for this. See // ChunksNeeded for this calculation. - int chunk_index = exp / 32; + size_t after_chunk_index = static_cast(exp / 32 + 1); decimal_start_ = decimal_end_ = ChunksNeeded(exp); const int offset = exp % 32; // Left shift v by exp bits. - data_[chunk_index] = static_cast(v << offset); + data_[after_chunk_index - 1] = static_cast(v << offset); for (v >>= (32 - offset); v; v >>= 32) - data_[++chunk_index] = static_cast(v); + data_[++after_chunk_index - 1] = static_cast(v); - while (chunk_index >= 0) { + while (after_chunk_index > 0) { // While we have more than one chunk available, go in steps of 1e9. - // `data_[chunk_index]` holds the highest non-zero binary chunk, so keep - // the variable updated. + // `data_[after_chunk_index - 1]` holds the highest non-zero binary chunk, + // so keep the variable updated. uint32_t carry = 0; - for (int i = chunk_index; i >= 0; --i) { - uint64_t tmp = uint64_t{data_[i]} + (uint64_t{carry} << 32); - data_[i] = static_cast(tmp / uint64_t{1000000000}); + for (size_t i = after_chunk_index; i > 0; --i) { + uint64_t tmp = uint64_t{data_[i - 1]} + (uint64_t{carry} << 32); + data_[i - 1] = static_cast(tmp / uint64_t{1000000000}); carry = static_cast(tmp % uint64_t{1000000000}); } // If the highest chunk is now empty, remove it from view. - if (data_[chunk_index] == 0) --chunk_index; + if (data_[after_chunk_index - 1] == 0) + --after_chunk_index; --decimal_start_; - assert(decimal_start_ != chunk_index); + assert(decimal_start_ != after_chunk_index - 1); data_[decimal_start_] = carry; } @@ -225,13 +229,13 @@ class BinaryToDecimal { } private: - static constexpr int kDigitsPerChunk = 9; + static constexpr size_t kDigitsPerChunk = 9; - int decimal_start_; - int decimal_end_; + size_t decimal_start_; + size_t decimal_end_; char digits_[kDigitsPerChunk]; - int size_ = 0; + size_t size_ = 0; absl::Span data_; }; @@ -251,25 +255,26 @@ class FractionalDigitGenerator { static_assert(StackArray::kMaxCapacity >= (Limits::digits + 128 - Limits::min_exponent + 31) / 32, ""); - StackArray::RunWithCapacity((Limits::digits + exp + 31) / 32, - [=](absl::Span input) { - f(FractionalDigitGenerator(input, v, exp)); - }); + StackArray::RunWithCapacity( + static_cast((Limits::digits + exp + 31) / 32), + [=](absl::Span input) { + f(FractionalDigitGenerator(input, v, exp)); + }); } // Returns true if there are any more non-zero digits left. - bool HasMoreDigits() const { return next_digit_ != 0 || chunk_index_ >= 0; } + bool HasMoreDigits() const { return next_digit_ != 0 || after_chunk_index_; } // Returns true if the remainder digits are greater than 5000... bool IsGreaterThanHalf() const { - return next_digit_ > 5 || (next_digit_ == 5 && chunk_index_ >= 0); + return next_digit_ > 5 || (next_digit_ == 5 && after_chunk_index_); } // Returns true if the remainder digits are exactly 5000... - bool IsExactlyHalf() const { return next_digit_ == 5 && chunk_index_ < 0; } + bool IsExactlyHalf() const { return next_digit_ == 5 && !after_chunk_index_; } struct Digits { - int digit_before_nine; - int num_nines; + char digit_before_nine; + size_t num_nines; }; // Get the next set of digits. @@ -288,35 +293,37 @@ class FractionalDigitGenerator { private: // Return the next digit. - int GetOneDigit() { - if (chunk_index_ < 0) return 0; + char GetOneDigit() { + if (!after_chunk_index_) + return 0; - uint32_t carry = 0; - for (int i = chunk_index_; i >= 0; --i) { - carry = MultiplyBy10WithCarry(&data_[i], carry); + char carry = 0; + for (size_t i = after_chunk_index_; i > 0; --i) { + carry = MultiplyBy10WithCarry(&data_[i - 1], carry); } // If the lowest chunk is now empty, remove it from view. - if (data_[chunk_index_] == 0) --chunk_index_; + if (data_[after_chunk_index_ - 1] == 0) + --after_chunk_index_; return carry; } FractionalDigitGenerator(absl::Span data, uint128 v, int exp) - : chunk_index_(exp / 32), data_(data) { + : after_chunk_index_(static_cast(exp / 32 + 1)), data_(data) { const int offset = exp % 32; // Right shift `v` by `exp` bits. - data_[chunk_index_] = static_cast(v << (32 - offset)); + data_[after_chunk_index_ - 1] = static_cast(v << (32 - offset)); v >>= offset; // Make sure we don't overflow the data. We already calculated that // non-zero bits fit, so we might not have space for leading zero bits. - for (int pos = chunk_index_; v; v >>= 32) + for (size_t pos = after_chunk_index_ - 1; v; v >>= 32) data_[--pos] = static_cast(v); // Fill next_digit_, as GetDigits expects it to be populated always. next_digit_ = GetOneDigit(); } - int next_digit_; - int chunk_index_; + char next_digit_; + size_t after_chunk_index_; absl::Span data_; }; @@ -362,7 +369,7 @@ char *PrintIntegralDigitsFromRightFast(uint128 v, char *p) { auto low = static_cast(v); while (high != 0) { - uint64_t carry = DivideBy10WithCarry(&high, 0); + char carry = DivideBy10WithCarry(&high, 0); carry = DivideBy10WithCarry(&low, carry); *--p = carry + '0'; } @@ -373,13 +380,15 @@ char *PrintIntegralDigitsFromRightFast(uint128 v, char *p) { // shifting. // Performs rounding if necessary to fit within `precision`. // Returns the pointer to one after the last character written. -char *PrintFractionalDigitsFast(uint64_t v, char *start, int exp, - int precision) { +char* PrintFractionalDigitsFast(uint64_t v, + char* start, + int exp, + size_t precision) { char *p = start; v <<= (64 - exp); while (precision > 0) { if (!v) return p; - *p++ = MultiplyBy10WithCarry(&v, uint64_t{0}) + '0'; + *p++ = MultiplyBy10WithCarry(&v, 0) + '0'; --precision; } @@ -393,8 +402,6 @@ char *PrintFractionalDigitsFast(uint64_t v, char *start, int exp, RoundToEven(p - 1); } - assert(precision == 0); - // Precision can only be zero here. return p; } @@ -402,8 +409,10 @@ char *PrintFractionalDigitsFast(uint64_t v, char *start, int exp, // after shifting. // Performs rounding if necessary to fit within `precision`. // Returns the pointer to one after the last character written. -char *PrintFractionalDigitsFast(uint128 v, char *start, int exp, - int precision) { +char* PrintFractionalDigitsFast(uint128 v, + char* start, + int exp, + size_t precision) { char *p = start; v <<= (128 - exp); auto high = static_cast(v >> 64); @@ -412,7 +421,7 @@ char *PrintFractionalDigitsFast(uint128 v, char *start, int exp, // While we have digits to print and `low` is not empty, do the long // multiplication. while (precision > 0 && low != 0) { - uint64_t carry = MultiplyBy10WithCarry(&low, uint64_t{0}); + char carry = MultiplyBy10WithCarry(&low, 0); carry = MultiplyBy10WithCarry(&high, carry); *p++ = carry + '0'; @@ -424,7 +433,7 @@ char *PrintFractionalDigitsFast(uint128 v, char *start, int exp, // above. while (precision > 0) { if (!high) return p; - *p++ = MultiplyBy10WithCarry(&high, uint64_t{0}) + '0'; + *p++ = MultiplyBy10WithCarry(&high, 0) + '0'; --precision; } @@ -438,14 +447,12 @@ char *PrintFractionalDigitsFast(uint128 v, char *start, int exp, RoundToEven(p - 1); } - assert(precision == 0); - // Precision can only be zero here. return p; } struct FormatState { char sign_char; - int precision; + size_t precision; const FormatConversionSpecImpl &conv; FormatSinkImpl *sink; @@ -455,9 +462,9 @@ struct FormatState { }; struct Padding { - int left_spaces; - int zeros; - int right_spaces; + size_t left_spaces; + size_t zeros; + size_t right_spaces; }; Padding ExtraWidthToPadding(size_t total_size, const FormatState &state) { @@ -465,7 +472,7 @@ Padding ExtraWidthToPadding(size_t total_size, const FormatState &state) { static_cast(state.conv.width()) <= total_size) { return {0, 0, 0}; } - int missing_chars = state.conv.width() - total_size; + size_t missing_chars = static_cast(state.conv.width()) - total_size; if (state.conv.has_left_flag()) { return {0, 0, missing_chars}; } else if (state.conv.has_zero_flag()) { @@ -475,8 +482,10 @@ Padding ExtraWidthToPadding(size_t total_size, const FormatState &state) { } } -void FinalPrint(const FormatState &state, absl::string_view data, - int padding_offset, int trailing_zeros, +void FinalPrint(const FormatState& state, + absl::string_view data, + size_t padding_offset, + size_t trailing_zeros, absl::string_view data_postfix) { if (state.conv.width() < 0) { // No width specified. Fast-path. @@ -487,10 +496,10 @@ void FinalPrint(const FormatState &state, absl::string_view data, return; } - auto padding = ExtraWidthToPadding((state.sign_char != '\0' ? 1 : 0) + - data.size() + data_postfix.size() + - static_cast(trailing_zeros), - state); + auto padding = + ExtraWidthToPadding((state.sign_char != '\0' ? 1 : 0) + data.size() + + data_postfix.size() + trailing_zeros, + state); state.sink->Append(padding.left_spaces, ' '); if (state.sign_char != '\0') state.sink->Append(1, state.sign_char); @@ -547,15 +556,16 @@ void FormatFFast(Int v, int exp, const FormatState &state) { if (integral_digits_start[-1] != '0') --integral_digits_start; } - size_t size = fractional_digits_end - integral_digits_start; + size_t size = + static_cast(fractional_digits_end - integral_digits_start); // In `alt` mode (flag #) we keep the `.` even if there are no fractional // digits. In non-alt mode, we strip it. if (!state.ShouldPrintDot()) --size; FinalPrint(state, absl::string_view(integral_digits_start, size), /*padding_offset=*/0, - static_cast(state.precision - (fractional_digits_end - - fractional_digits_start)), + state.precision - static_cast(fractional_digits_end - + fractional_digits_start), /*data_postfix=*/""); } @@ -567,21 +577,22 @@ void FormatFFast(Int v, int exp, const FormatState &state) { void FormatFPositiveExpSlow(uint128 v, int exp, const FormatState &state) { BinaryToDecimal::RunConversion(v, exp, [&](BinaryToDecimal btd) { const size_t total_digits = - btd.TotalDigits() + - (state.ShouldPrintDot() ? static_cast(state.precision) + 1 : 0); + btd.TotalDigits() + (state.ShouldPrintDot() ? state.precision + 1 : 0); const auto padding = ExtraWidthToPadding( total_digits + (state.sign_char != '\0' ? 1 : 0), state); state.sink->Append(padding.left_spaces, ' '); - if (state.sign_char != '\0') state.sink->Append(1, state.sign_char); + if (state.sign_char != '\0') + state.sink->Append(1, state.sign_char); state.sink->Append(padding.zeros, '0'); do { state.sink->Append(btd.CurrentDigits()); } while (btd.AdvanceDigits()); - if (state.ShouldPrintDot()) state.sink->Append(1, '.'); + if (state.ShouldPrintDot()) + state.sink->Append(1, '.'); state.sink->Append(state.precision, '0'); state.sink->Append(padding.right_spaces, ' '); }); @@ -594,8 +605,7 @@ void FormatFPositiveExpSlow(uint128 v, int exp, const FormatState &state) { // digits. void FormatFNegativeExpSlow(uint128 v, int exp, const FormatState &state) { const size_t total_digits = - /* 0 */ 1 + - (state.ShouldPrintDot() ? static_cast(state.precision) + 1 : 0); + /* 0 */ 1 + (state.ShouldPrintDot() ? state.precision + 1 : 0); auto padding = ExtraWidthToPadding(total_digits + (state.sign_char ? 1 : 0), state); padding.zeros += 1; @@ -606,7 +616,7 @@ void FormatFNegativeExpSlow(uint128 v, int exp, const FormatState &state) { if (state.ShouldPrintDot()) state.sink->Append(1, '.'); // Print digits - int digits_to_go = state.precision; + size_t digits_to_go = state.precision; FractionalDigitGenerator::RunConversion( v, exp, [&](FractionalDigitGenerator digit_gen) { @@ -666,7 +676,8 @@ void FormatFNegativeExpSlow(uint128 v, int exp, const FormatState &state) { template void FormatF(Int mantissa, int exp, const FormatState &state) { if (exp >= 0) { - const int total_bits = sizeof(Int) * 8 - LeadingZeros(mantissa) + exp; + const int total_bits = + static_cast(sizeof(Int) * 8) - LeadingZeros(mantissa) + exp; // Fallback to the slow stack-based approach if we can't do it in a 64 or // 128 bit state. @@ -686,9 +697,9 @@ void FormatF(Int mantissa, int exp, const FormatState &state) { // Grab the group of four bits (nibble) from `n`. E.g., nibble 1 corresponds to // bits 4-7. template -uint8_t GetNibble(Int n, int nibble_index) { +uint8_t GetNibble(Int n, size_t nibble_index) { constexpr Int mask_low_nibble = Int{0xf}; - int shift = nibble_index * 4; + int shift = static_cast(nibble_index * 4); n &= mask_low_nibble << shift; return static_cast((n >> shift) & 0xf); } @@ -696,9 +707,9 @@ uint8_t GetNibble(Int n, int nibble_index) { // Add one to the given nibble, applying carry to higher nibbles. Returns true // if overflow, false otherwise. template -bool IncrementNibble(int nibble_index, Int *n) { - constexpr int kShift = sizeof(Int) * 8 - 1; - constexpr int kNumNibbles = sizeof(Int) * 8 / 4; +bool IncrementNibble(size_t nibble_index, Int* n) { + constexpr size_t kShift = sizeof(Int) * 8 - 1; + constexpr size_t kNumNibbles = sizeof(Int) * 8 / 4; Int before = *n >> kShift; // Here we essentially want to take the number 1 and move it into the requsted // nibble, then add it to *n to effectively increment the nibble. However, @@ -706,28 +717,32 @@ bool IncrementNibble(int nibble_index, Int *n) { // i.e., if the nibble_index is out of range. So therefore we check for this // and if we are out of range we just add 0 which leaves *n unchanged, which // seems like the reasonable thing to do in that case. - *n += ((nibble_index >= kNumNibbles) ? 0 : (Int{1} << (nibble_index * 4))); + *n += ((nibble_index >= kNumNibbles) + ? 0 + : (Int{1} << static_cast(nibble_index * 4))); Int after = *n >> kShift; return (before && !after) || (nibble_index >= kNumNibbles); } // Return a mask with 1's in the given nibble and all lower nibbles. template -Int MaskUpToNibbleInclusive(int nibble_index) { - constexpr int kNumNibbles = sizeof(Int) * 8 / 4; +Int MaskUpToNibbleInclusive(size_t nibble_index) { + constexpr size_t kNumNibbles = sizeof(Int) * 8 / 4; static const Int ones = ~Int{0}; - return ones >> std::max(0, 4 * (kNumNibbles - nibble_index - 1)); + ++nibble_index; + return ones >> static_cast( + 4 * (std::max(kNumNibbles, nibble_index) - nibble_index)); } // Return a mask with 1's below the given nibble. template -Int MaskUpToNibbleExclusive(int nibble_index) { - return nibble_index <= 0 ? 0 : MaskUpToNibbleInclusive(nibble_index - 1); +Int MaskUpToNibbleExclusive(size_t nibble_index) { + return nibble_index == 0 ? 0 : MaskUpToNibbleInclusive(nibble_index - 1); } template -Int MoveToNibble(uint8_t nibble, int nibble_index) { - return Int{nibble} << (4 * nibble_index); +Int MoveToNibble(uint8_t nibble, size_t nibble_index) { + return Int{nibble} << static_cast(4 * nibble_index); } // Given mantissa size, find optimal # of mantissa bits to put in initial digit. @@ -744,10 +759,10 @@ Int MoveToNibble(uint8_t nibble, int nibble_index) { // a multiple of four. Once again, the goal is to have all fractional digits // represent real precision. template -constexpr int HexFloatLeadingDigitSizeInBits() { +constexpr size_t HexFloatLeadingDigitSizeInBits() { return std::numeric_limits::digits % 4 > 0 - ? std::numeric_limits::digits % 4 - : 4; + ? static_cast(std::numeric_limits::digits % 4) + : size_t{4}; } // This function captures the rounding behavior of glibc for hex float @@ -757,16 +772,17 @@ constexpr int HexFloatLeadingDigitSizeInBits() { // point that is not followed by 800000..., it disregards the parity and rounds // up if > 8 and rounds down if < 8. template -bool HexFloatNeedsRoundUp(Int mantissa, int final_nibble_displayed, +bool HexFloatNeedsRoundUp(Int mantissa, + size_t final_nibble_displayed, uint8_t leading) { // If the last nibble (hex digit) to be displayed is the lowest on in the // mantissa then that means that we don't have any further nibbles to inform // rounding, so don't round. - if (final_nibble_displayed <= 0) { + if (final_nibble_displayed == 0) { return false; } - int rounding_nibble_idx = final_nibble_displayed - 1; - constexpr int kTotalNibbles = sizeof(Int) * 8 / 4; + size_t rounding_nibble_idx = final_nibble_displayed - 1; + constexpr size_t kTotalNibbles = sizeof(Int) * 8 / 4; assert(final_nibble_displayed <= kTotalNibbles); Int mantissa_up_to_rounding_nibble_inclusive = mantissa & MaskUpToNibbleInclusive(rounding_nibble_idx); @@ -793,7 +809,7 @@ struct HexFloatTypeParams { } int min_exponent; - int leading_digit_size_bits; + size_t leading_digit_size_bits; }; // Hex Float Rounding. First check if we need to round; if so, then we do that @@ -803,10 +819,12 @@ struct HexFloatTypeParams { template void FormatARound(bool precision_specified, const FormatState &state, uint8_t *leading, Int *mantissa, int *exp) { - constexpr int kTotalNibbles = sizeof(Int) * 8 / 4; + constexpr size_t kTotalNibbles = sizeof(Int) * 8 / 4; // Index of the last nibble that we could display given precision. - int final_nibble_displayed = - precision_specified ? std::max(0, (kTotalNibbles - state.precision)) : 0; + size_t final_nibble_displayed = + precision_specified + ? (std::max(kTotalNibbles, state.precision) - state.precision) + : 0; if (HexFloatNeedsRoundUp(*mantissa, final_nibble_displayed, *leading)) { // Need to round up. bool overflow = IncrementNibble(final_nibble_displayed, mantissa); @@ -830,9 +848,9 @@ void FormatARound(bool precision_specified, const FormatState &state, template void FormatANormalize(const HexFloatTypeParams float_traits, uint8_t *leading, Int *mantissa, int *exp) { - constexpr int kIntBits = sizeof(Int) * 8; + constexpr size_t kIntBits = sizeof(Int) * 8; static const Int kHighIntBit = Int{1} << (kIntBits - 1); - const int kLeadDigitBitsCount = float_traits.leading_digit_size_bits; + const size_t kLeadDigitBitsCount = float_traits.leading_digit_size_bits; // Normalize mantissa so that highest bit set is in MSB position, unless we // get interrupted by the exponent threshold. while (*mantissa && !(*mantissa & kHighIntBit)) { @@ -846,18 +864,18 @@ void FormatANormalize(const HexFloatTypeParams float_traits, uint8_t *leading, } // Extract bits for leading digit then shift them away leaving the // fractional part. - *leading = - static_cast(*mantissa >> (kIntBits - kLeadDigitBitsCount)); - *exp -= (*mantissa != 0) ? kLeadDigitBitsCount : *exp; - *mantissa <<= kLeadDigitBitsCount; + *leading = static_cast( + *mantissa >> static_cast(kIntBits - kLeadDigitBitsCount)); + *exp -= (*mantissa != 0) ? static_cast(kLeadDigitBitsCount) : *exp; + *mantissa <<= static_cast(kLeadDigitBitsCount); } template void FormatA(const HexFloatTypeParams float_traits, Int mantissa, int exp, bool uppercase, const FormatState &state) { // Int properties. - constexpr int kIntBits = sizeof(Int) * 8; - constexpr int kTotalNibbles = sizeof(Int) * 8 / 4; + constexpr size_t kIntBits = sizeof(Int) * 8; + constexpr size_t kTotalNibbles = sizeof(Int) * 8 / 4; // Did the user specify a precision explicitly? const bool precision_specified = state.conv.precision() >= 0; @@ -903,16 +921,19 @@ void FormatA(const HexFloatTypeParams float_traits, Int mantissa, int exp, } // ============ Fractional Digits ============ - int digits_emitted = 0; + size_t digits_emitted = 0; while (mantissa > 0) { *digits_iter++ = digits[GetNibble(mantissa, kTotalNibbles - 1)]; mantissa <<= 4; ++digits_emitted; } - int trailing_zeros = - precision_specified ? state.precision - digits_emitted : 0; - assert(trailing_zeros >= 0); - auto digits_result = string_view(digits_buffer, digits_iter - digits_buffer); + size_t trailing_zeros = 0; + if (precision_specified) { + assert(state.precision >= digits_emitted); + trailing_zeros = state.precision - digits_emitted; + } + auto digits_result = string_view( + digits_buffer, static_cast(digits_iter - digits_buffer)); // =============== Exponent ================== constexpr size_t kBufSizeForExpDecRepr = @@ -925,11 +946,11 @@ void FormatA(const HexFloatTypeParams float_traits, Int mantissa, int exp, numbers_internal::FastIntToBuffer(exp < 0 ? -exp : exp, exp_buffer + 2); // ============ Assemble Result ============== - FinalPrint(state, // - digits_result, // 0xN.NNN... - 2, // offset in `data` to start padding if needed. - trailing_zeros, // num remaining mantissa padding zeros - exp_buffer); // exponent + FinalPrint(state, + digits_result, // 0xN.NNN... + 2, // offset of any padding + static_cast(trailing_zeros), // remaining mantissa padding + exp_buffer); // exponent } char *CopyStringTo(absl::string_view v, char *out) { @@ -961,10 +982,10 @@ bool FallbackToSnprintf(const Float v, const FormatConversionSpecImpl &conv, int n = snprintf(&space[0], space.size(), fmt, w, p, v); if (n < 0) return false; if (static_cast(n) < space.size()) { - result = absl::string_view(space.data(), n); + result = absl::string_view(space.data(), static_cast(n)); break; } - space.resize(n + 1); + space.resize(static_cast(n) + 1); } sink->Append(result); return true; @@ -972,13 +993,13 @@ bool FallbackToSnprintf(const Float v, const FormatConversionSpecImpl &conv, // 128-bits in decimal: ceil(128*log(2)/log(10)) // or std::numeric_limits<__uint128_t>::digits10 -constexpr int kMaxFixedPrecision = 39; +constexpr size_t kMaxFixedPrecision = 39; -constexpr int kBufferLength = /*sign*/ 1 + - /*integer*/ kMaxFixedPrecision + - /*point*/ 1 + - /*fraction*/ kMaxFixedPrecision + - /*exponent e+123*/ 5; +constexpr size_t kBufferLength = /*sign*/ 1 + + /*integer*/ kMaxFixedPrecision + + /*point*/ 1 + + /*fraction*/ kMaxFixedPrecision + + /*exponent e+123*/ 5; struct Buffer { void push_front(char c) { @@ -1001,7 +1022,7 @@ struct Buffer { char last_digit() const { return end[-1] == '.' ? end[-2] : end[-1]; } - int size() const { return static_cast(end - begin); } + size_t size() const { return static_cast(end - begin); } char data[kBufferLength]; char *begin; @@ -1030,8 +1051,9 @@ bool ConvertNonNumericFloats(char sign_char, Float v, return false; } - return sink->PutPaddedString(string_view(text, ptr - text), conv.width(), -1, - conv.has_left_flag()); + return sink->PutPaddedString( + string_view(text, static_cast(ptr - text)), conv.width(), -1, + conv.has_left_flag()); } // Round up the last digit of the value. @@ -1068,11 +1090,11 @@ void PrintExponent(int exp, char e, Buffer *out) { } // Exponent digits. if (exp > 99) { - out->push_back(exp / 100 + '0'); + out->push_back(static_cast(exp / 100) + '0'); out->push_back(exp / 10 % 10 + '0'); out->push_back(exp % 10 + '0'); } else { - out->push_back(exp / 10 + '0'); + out->push_back(static_cast(exp / 10) + '0'); out->push_back(exp % 10 + '0'); } } @@ -1115,8 +1137,8 @@ Decomposed Decompose(Float v) { // In Fixed mode, we add a '.' at the end. // In Precision mode, we add a '.' after the first digit. template -int PrintIntegralDigits(Int digits, Buffer *out) { - int printed = 0; +size_t PrintIntegralDigits(Int digits, Buffer* out) { + size_t printed = 0; if (digits) { for (; digits; digits /= 10) out->push_front(digits % 10 + '0'); printed = out->size(); @@ -1135,10 +1157,10 @@ int PrintIntegralDigits(Int digits, Buffer *out) { } // Back out 'extra_digits' digits and round up if necessary. -bool RemoveExtraPrecision(int extra_digits, bool has_leftover_value, - Buffer *out, int *exp_out) { - if (extra_digits <= 0) return false; - +void RemoveExtraPrecision(size_t extra_digits, + bool has_leftover_value, + Buffer* out, + int* exp_out) { // Back out the extra digits out->end -= extra_digits; @@ -1158,15 +1180,17 @@ bool RemoveExtraPrecision(int extra_digits, bool has_leftover_value, if (needs_to_round_up) { RoundUp(out, exp_out); } - return true; } // Print the value into the buffer. // This will not include the exponent, which will be returned in 'exp_out' for // Precision mode. template -bool FloatToBufferImpl(Int int_mantissa, int exp, int precision, Buffer *out, - int *exp_out) { +bool FloatToBufferImpl(Int int_mantissa, + int exp, + size_t precision, + Buffer* out, + int* exp_out) { assert((CanFitMantissa())); const int int_bits = std::numeric_limits::digits; @@ -1182,14 +1206,16 @@ bool FloatToBufferImpl(Int int_mantissa, int exp, int precision, Buffer *out, // The value will overflow the Int return false; } - int digits_printed = PrintIntegralDigits(int_mantissa << exp, out); - int digits_to_zero_pad = precision; + size_t digits_printed = PrintIntegralDigits(int_mantissa << exp, out); + size_t digits_to_zero_pad = precision; if (mode == FormatStyle::Precision) { - *exp_out = digits_printed - 1; - digits_to_zero_pad -= digits_printed - 1; - if (RemoveExtraPrecision(-digits_to_zero_pad, false, out, exp_out)) { + *exp_out = static_cast(digits_printed - 1); + if (digits_to_zero_pad < digits_printed - 1) { + RemoveExtraPrecision(digits_printed - 1 - digits_to_zero_pad, false, + out, exp_out); return true; } + digits_to_zero_pad -= digits_printed - 1; } for (; digits_to_zero_pad-- > 0;) out->push_back('0'); return true; @@ -1203,10 +1229,10 @@ bool FloatToBufferImpl(Int int_mantissa, int exp, int precision, Buffer *out, const Int mask = (Int{1} << exp) - 1; // Print the integral part first. - int digits_printed = PrintIntegralDigits(int_mantissa >> exp, out); + size_t digits_printed = PrintIntegralDigits(int_mantissa >> exp, out); int_mantissa &= mask; - int fractional_count = precision; + size_t fractional_count = precision; if (mode == FormatStyle::Precision) { if (digits_printed == 0) { // Find the first non-zero digit, when in Precision mode. @@ -1222,20 +1248,21 @@ bool FloatToBufferImpl(Int int_mantissa, int exp, int precision, Buffer *out, int_mantissa &= mask; } else { // We already have a digit, and a '.' - *exp_out = digits_printed - 1; - fractional_count -= *exp_out; - if (RemoveExtraPrecision(-fractional_count, int_mantissa != 0, out, - exp_out)) { + *exp_out = static_cast(digits_printed - 1); + if (fractional_count < digits_printed - 1) { // If we had enough digits, return right away. // The code below will try to round again otherwise. + RemoveExtraPrecision(digits_printed - 1 - fractional_count, + int_mantissa != 0, out, exp_out); return true; } + fractional_count -= digits_printed - 1; } } auto get_next_digit = [&] { int_mantissa *= 10; - int digit = static_cast(int_mantissa >> exp); + char digit = static_cast(int_mantissa >> exp); int_mantissa &= mask; return digit; }; @@ -1245,7 +1272,7 @@ bool FloatToBufferImpl(Int int_mantissa, int exp, int precision, Buffer *out, out->push_back(get_next_digit() + '0'); } - int next_digit = get_next_digit(); + char next_digit = get_next_digit(); if (next_digit > 5 || (next_digit == 5 && (int_mantissa || out->last_digit() % 2 == 1))) { RoundUp(out, exp_out); @@ -1255,24 +1282,25 @@ bool FloatToBufferImpl(Int int_mantissa, int exp, int precision, Buffer *out, } template -bool FloatToBuffer(Decomposed decomposed, int precision, Buffer *out, - int *exp) { +bool FloatToBuffer(Decomposed decomposed, + size_t precision, + Buffer* out, + int* exp) { if (precision > kMaxFixedPrecision) return false; // Try with uint64_t. if (CanFitMantissa() && FloatToBufferImpl( - static_cast(decomposed.mantissa), - static_cast(decomposed.exponent), precision, out, exp)) + static_cast(decomposed.mantissa), decomposed.exponent, + precision, out, exp)) return true; #if defined(ABSL_HAVE_INTRINSIC_INT128) // If that is not enough, try with __uint128_t. return CanFitMantissa() && FloatToBufferImpl<__uint128_t, Float, mode>( - static_cast<__uint128_t>(decomposed.mantissa), - static_cast<__uint128_t>(decomposed.exponent), precision, out, - exp); + static_cast<__uint128_t>(decomposed.mantissa), decomposed.exponent, + precision, out, exp); #endif return false; } @@ -1280,12 +1308,15 @@ bool FloatToBuffer(Decomposed decomposed, int precision, Buffer *out, void WriteBufferToSink(char sign_char, absl::string_view str, const FormatConversionSpecImpl &conv, FormatSinkImpl *sink) { - int left_spaces = 0, zeros = 0, right_spaces = 0; - int missing_chars = - conv.width() >= 0 ? std::max(conv.width() - static_cast(str.size()) - - static_cast(sign_char != 0), - 0) - : 0; + size_t left_spaces = 0, zeros = 0, right_spaces = 0; + size_t missing_chars = 0; + if (conv.width() >= 0) { + const size_t conv_width_size_t = static_cast(conv.width()); + const size_t existing_chars = + str.size() + static_cast(sign_char != 0); + if (conv_width_size_t > existing_chars) + missing_chars = conv_width_size_t - existing_chars; + } if (conv.has_left_flag()) { right_spaces = missing_chars; } else if (conv.has_zero_flag()) { @@ -1321,7 +1352,8 @@ bool FloatToSink(const Float v, const FormatConversionSpecImpl &conv, return true; } - int precision = conv.precision() < 0 ? 6 : conv.precision(); + size_t precision = + conv.precision() < 0 ? 6 : static_cast(conv.precision()); int exp = 0; @@ -1348,12 +1380,12 @@ bool FloatToSink(const Float v, const FormatConversionSpecImpl &conv, &buffer); } else if (c == FormatConversionCharInternal::g || c == FormatConversionCharInternal::G) { - precision = std::max(0, precision - 1); + precision = std::max(precision, size_t{1}) - 1; if (!FloatToBuffer(decomposed, precision, &buffer, &exp)) { return FallbackToSnprintf(v, conv, sink); } - if (precision + 1 > exp && exp >= -4) { + if ((exp < 0 || precision + 1 > static_cast(exp)) && exp >= -4) { if (exp < 0) { // Have 1.23456, needs 0.00123456 // Move the first digit @@ -1388,9 +1420,11 @@ bool FloatToSink(const Float v, const FormatConversionSpecImpl &conv, return false; } - WriteBufferToSink(sign_char, - absl::string_view(buffer.begin, buffer.end - buffer.begin), - conv, sink); + WriteBufferToSink( + sign_char, + absl::string_view(buffer.begin, + static_cast(buffer.end - buffer.begin)), + conv, sink); return true; } -- cgit v1.2.3