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
pull/1252/head
Abseil Team 3 years ago committed by Copybara-Service
parent 934f613818
commit fcfc7a6d15
  1. 8
      absl/strings/internal/charconv_bigint.cc
  2. 4
      absl/strings/internal/charconv_parse.cc
  3. 5
      absl/strings/internal/cord_internal.h
  4. 7
      absl/strings/internal/cord_rep_btree.cc
  5. 5
      absl/strings/internal/cord_rep_btree.h
  6. 10
      absl/strings/internal/cord_rep_btree_navigator.cc
  7. 13
      absl/strings/internal/cordz_info.cc
  8. 8
      absl/strings/internal/cordz_info.h
  9. 8
      absl/strings/internal/cordz_statistics.h
  10. 15
      absl/strings/internal/memutil.cc
  11. 35
      absl/strings/internal/str_format/arg.cc
  12. 5
      absl/strings/internal/str_format/bind.cc
  13. 3
      absl/strings/internal/str_format/extension.cc
  14. 390
      absl/strings/internal/str_format/float_conversion.cc

@ -242,7 +242,7 @@ int BigUnsigned<max_words>::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<max_words>::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<uint32_t>(digit);
++digits_queued;
if (digits_queued == kMaxSmallPowerOfTen) {
MultiplyBy(kTenToNth[kMaxSmallPowerOfTen]);
@ -341,8 +341,8 @@ std::string BigUnsigned<max_words>::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<char>(next_digit));
}
if (result.empty()) {
result.push_back('0');

@ -190,11 +190,11 @@ bool IsDigit<16>(char ch) {
template <>
unsigned ToDigit<10>(char ch) {
return ch - '0';
return static_cast<unsigned>(ch - '0');
}
template <>
unsigned ToDigit<16>(char ch) {
return kAsciiToInt[static_cast<unsigned char>(ch)];
return static_cast<unsigned>(kAsciiToInt[static_cast<unsigned char>(ch)]);
}
template <>

@ -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<size_t>(count_.load(std::memory_order_acquire) >>
kNumFlags);
}
// Returns whether the atomic integer is 1.

@ -17,6 +17,7 @@
#include <cassert>
#include <cstdint>
#include <iostream>
#include <ostream>
#include <string>
#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<CordRep*>(rep)->refcount.IsOne()

@ -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<int>(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

@ -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<uint8_t>(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<uint8_t>(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<uint8_t>(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<uint8_t>(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<uint8_t>(index);
return {tree, length};
}

@ -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<size_t>(absl::GetStackTrace(stack_,
/*max_depth=*/kMaxStackDepth,
/*skip_count=*/1))),
parent_stack_depth_(FillParentStack(src, parent_stack_)),
method_(method),
parent_method_(GetParentMethod(src)),

@ -196,7 +196,7 @@ class ABSL_LOCKABLE CordzInfo : public CordzHandle {
std::atomic<CordzInfo*> 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_;

@ -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;

@ -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<size_t>(p - 1 - s);
for (spanp = accept; (sc = *spanp++) != '\0';)
if (sc == c) goto cont;
return p - 1 - s;
return static_cast<size_t>(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<size_t>(p - 1 - s);
}
return p - s;
return static_cast<size_t>(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<const char*>(
memchr(phaystack, pneedle[0], hayend - phaystack)))) {
while (
(match = static_cast<const char*>(memchr(
phaystack, pneedle[0], static_cast<size_t>(hayend - phaystack))))) {
if (memcmp(match, pneedle, neelen) == 0)
return match;
else

@ -77,7 +77,7 @@ class IntDigits {
v >>= 3;
} while (v);
start_ = p;
size_ = storage_ + sizeof(storage_) - p;
size_ = static_cast<size_t>(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<T>::value, "");
start_ = storage_;
size_ = numbers_internal::FastIntToBuffer(v, storage_) - storage_;
size_ = static_cast<size_t>(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<size_t>(storage_ + sizeof(storage_) - p);
start_ = p;
}
@ -138,7 +139,7 @@ class IntDigits {
++p;
}
start_ = p;
size_ = storage_ + sizeof(storage_) - p;
size_ = static_cast<size_t>(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<size_t>(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<size_t>(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<size_t>(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<size_t>(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<int>(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<uint8_t>(conv.conversion_char())) {
case static_cast<uint8_t>(FormatConversionCharInternal::c):
return ConvertCharImpl(static_cast<unsigned char>(v), conv, sink);
return ConvertCharImpl(static_cast<char>(v), conv, sink);
case static_cast<uint8_t>(FormatConversionCharInternal::o):
as_digits.PrintAsOct(static_cast<U>(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<size_t>(std::find(v, v + conv.precision(), '\0') - v);
}
return {ConvertStringArg(string_view(v, len), conv, sink)};
}

@ -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<size_t>(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<size_t>(arg_position - 1) >= pack_.size()) return false;
arg = &pack_[arg_position - 1]; // 1-based
arg = &pack_[static_cast<size_t>(arg_position - 1)]; // 1-based
if (unbound->flags != Flags::kBasic) {
int width = unbound->width.value();

@ -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<size_t>(width);
size_t n = value.size();
if (precision >= 0) n = std::min(n, static_cast<size_t>(precision));
string_view shown(value.data(), n);

@ -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 <typename Int>
inline Int MultiplyBy10WithCarry(Int *v, Int carry) {
inline char MultiplyBy10WithCarry(Int* v, char carry) {
using BiggerInt = absl::conditional_t<sizeof(Int) == 4, uint64_t, uint128>;
BiggerInt tmp = 10 * static_cast<BiggerInt>(*v) + carry;
BiggerInt tmp =
10 * static_cast<BiggerInt>(*v) + static_cast<BiggerInt>(carry);
*v = static_cast<Int>(tmp);
return static_cast<Int>(tmp >> (sizeof(Int) * 8));
return static_cast<char>(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<uint64_t>(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<char>(next_carry % divisor);
}
using MaxFloatType =
@ -125,11 +128,11 @@ using MaxFloatType =
//
// Requires `0 <= exp` and `exp <= numeric_limits<MaxFloatType>::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<size_t>((128 + exp + 31) / 32 * 11 / 10);
}
public:
@ -140,7 +143,7 @@ class BinaryToDecimal {
assert(exp > 0);
assert(exp <= std::numeric_limits<MaxFloatType>::max_exponent);
static_assert(
static_cast<int>(StackArray::kMaxCapacity) >=
StackArray::kMaxCapacity >=
ChunksNeeded(std::numeric_limits<MaxFloatType>::max_exponent),
"");
@ -149,9 +152,9 @@ class BinaryToDecimal {
[=](absl::Span<uint32_t> input) { f(BinaryToDecimal(input, v, exp)); });
}
int TotalDigits() const {
return static_cast<int>((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<size_t>(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<uint32_t>(v << offset);
data_[after_chunk_index - 1] = static_cast<uint32_t>(v << offset);
for (v >>= (32 - offset); v; v >>= 32)
data_[++chunk_index] = static_cast<uint32_t>(v);
data_[++after_chunk_index - 1] = static_cast<uint32_t>(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<uint32_t>(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<uint32_t>(tmp / uint64_t{1000000000});
carry = static_cast<uint32_t>(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<uint32_t> 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<uint32_t> input) {
f(FractionalDigitGenerator(input, v, exp));
});
StackArray::RunWithCapacity(
static_cast<size_t>((Limits::digits + exp + 31) / 32),
[=](absl::Span<uint32_t> 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<uint32_t> data, uint128 v, int exp)
: chunk_index_(exp / 32), data_(data) {
: after_chunk_index_(static_cast<size_t>(exp / 32 + 1)), data_(data) {
const int offset = exp % 32;
// Right shift `v` by `exp` bits.
data_[chunk_index_] = static_cast<uint32_t>(v << (32 - offset));
data_[after_chunk_index_ - 1] = static_cast<uint32_t>(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<uint32_t>(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<uint32_t> data_;
};
@ -362,7 +369,7 @@ char *PrintIntegralDigitsFromRightFast(uint128 v, char *p) {
auto low = static_cast<uint64_t>(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<uint64_t>(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<size_t>(state.conv.width()) <= total_size) {
return {0, 0, 0};
}
int missing_chars = state.conv.width() - total_size;
size_t missing_chars = static_cast<size_t>(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<size_t>(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<size_t>(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<int>(state.precision - (fractional_digits_end -
fractional_digits_start)),
state.precision - static_cast<size_t>(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<size_t>(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<size_t>(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 <typename Int>
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<int>(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 <typename Int>
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<int>(nibble_index * 4);
n &= mask_low_nibble << shift;
return static_cast<uint8_t>((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 <typename Int>
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<int>(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 <typename Int>
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<int>(
4 * (std::max(kNumNibbles, nibble_index) - nibble_index));
}
// Return a mask with 1's below the given nibble.
template <typename Int>
Int MaskUpToNibbleExclusive(int nibble_index) {
return nibble_index <= 0 ? 0 : MaskUpToNibbleInclusive<Int>(nibble_index - 1);
Int MaskUpToNibbleExclusive(size_t nibble_index) {
return nibble_index == 0 ? 0 : MaskUpToNibbleInclusive<Int>(nibble_index - 1);
}
template <typename Int>
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<int>(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 <typename Float>
constexpr int HexFloatLeadingDigitSizeInBits() {
constexpr size_t HexFloatLeadingDigitSizeInBits() {
return std::numeric_limits<Float>::digits % 4 > 0
? std::numeric_limits<Float>::digits % 4
: 4;
? static_cast<size_t>(std::numeric_limits<Float>::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 <typename Int>
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<Int>(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 <typename Int>
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 <typename Int>
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<uint8_t>(*mantissa >> (kIntBits - kLeadDigitBitsCount));
*exp -= (*mantissa != 0) ? kLeadDigitBitsCount : *exp;
*mantissa <<= kLeadDigitBitsCount;
*leading = static_cast<uint8_t>(
*mantissa >> static_cast<int>(kIntBits - kLeadDigitBitsCount));
*exp -= (*mantissa != 0) ? static_cast<int>(kLeadDigitBitsCount) : *exp;
*mantissa <<= static_cast<int>(kLeadDigitBitsCount);
}
template <typename Int>
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<size_t>(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<size_t>(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<size_t>(n) < space.size()) {
result = absl::string_view(space.data(), n);
result = absl::string_view(space.data(), static_cast<size_t>(n));
break;
}
space.resize(n + 1);
space.resize(static_cast<size_t>(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<int>(end - begin); }
size_t size() const { return static_cast<size_t>(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<size_t>(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<char>(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<char>(exp / 10) + '0');
out->push_back(exp % 10 + '0');
}
}
@ -1115,8 +1137,8 @@ Decomposed<Float> Decompose(Float v) {
// In Fixed mode, we add a '.' at the end.
// In Precision mode, we add a '.' after the first digit.
template <FormatStyle mode, typename Int>
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<FormatStyle::Precision>(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 <typename Int, typename Float, FormatStyle mode>
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<Float, Int>()));
const int int_bits = std::numeric_limits<Int>::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<mode>(int_mantissa << exp, out);
int digits_to_zero_pad = precision;
size_t digits_printed = PrintIntegralDigits<mode>(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<int>(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<mode>(int_mantissa >> exp, out);
size_t digits_printed = PrintIntegralDigits<mode>(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<int>(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>(int_mantissa >> exp);
char digit = static_cast<char>(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<mode>(out, exp_out);
@ -1255,24 +1282,25 @@ bool FloatToBufferImpl(Int int_mantissa, int exp, int precision, Buffer *out,
}
template <FormatStyle mode, typename Float>
bool FloatToBuffer(Decomposed<Float> decomposed, int precision, Buffer *out,
int *exp) {
bool FloatToBuffer(Decomposed<Float> decomposed,
size_t precision,
Buffer* out,
int* exp) {
if (precision > kMaxFixedPrecision) return false;
// Try with uint64_t.
if (CanFitMantissa<Float, std::uint64_t>() &&
FloatToBufferImpl<std::uint64_t, Float, mode>(
static_cast<std::uint64_t>(decomposed.mantissa),
static_cast<std::uint64_t>(decomposed.exponent), precision, out, exp))
static_cast<std::uint64_t>(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<Float, __uint128_t>() &&
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<Float> 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<int>(str.size()) -
static_cast<int>(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<size_t>(conv.width());
const size_t existing_chars =
str.size() + static_cast<size_t>(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<size_t>(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<FormatStyle::Precision>(decomposed, precision, &buffer,
&exp)) {
return FallbackToSnprintf(v, conv, sink);
}
if (precision + 1 > exp && exp >= -4) {
if ((exp < 0 || precision + 1 > static_cast<size_t>(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<size_t>(buffer.end - buffer.begin)),
conv, sink);
return true;
}

Loading…
Cancel
Save