| // Copyright 2025 The Chromium Authors | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | #include "base/byte_size.h" | 
 |  | 
 | #include <ostream> | 
 | #include <string> | 
 |  | 
 | #include "base/strings/strcat.h" | 
 | #include "base/strings/string_number_conversions.h" | 
 |  | 
 | namespace base { | 
 |  | 
 | namespace { | 
 |  | 
 | constexpr uint64_t kOneKiB = KiBU(1).InBytes(); | 
 | constexpr uint64_t kOneMiB = MiBU(1).InBytes(); | 
 | constexpr uint64_t kOneGiB = GiBU(1).InBytes(); | 
 | constexpr uint64_t kOneTiB = TiBU(1).InBytes(); | 
 | constexpr uint64_t kOnePiB = PiBU(1).InBytes(); | 
 | constexpr uint64_t kOneEiB = EiBU(1).InBytes(); | 
 |  | 
 | void AppendMagnitude(std::string* dest, | 
 |                      ByteSize magnitude, | 
 |                      const std::string& sign_prefix = "") { | 
 |   uint64_t bytes = magnitude.InBytes(); | 
 |  | 
 |   StrAppend(dest, {sign_prefix}); | 
 |  | 
 |   // If it's an exact number of [EPTGMK]kB then stream that, unless it's a | 
 |   // quantity measurable by the next magnitude prefix (e.g. if the value is in | 
 |   // the pebibyte range but it happens to be divisible by 1024 it shouldn't be | 
 |   // logged in KiB). | 
 |   if (bytes % kOneEiB == 0) { | 
 |     StrAppend(dest, {NumberToString(magnitude.InEiB()), "EiB"}); | 
 |   } else if (bytes % kOnePiB == 0 && bytes / kOneEiB == 0) { | 
 |     StrAppend(dest, {NumberToString(magnitude.InPiB()), "PiB"}); | 
 |   } else if (bytes % kOneTiB == 0 && bytes / kOnePiB == 0) { | 
 |     StrAppend(dest, {NumberToString(magnitude.InTiB()), "TiB"}); | 
 |   } else if (bytes % kOneGiB == 0 && bytes / kOneTiB == 0) { | 
 |     StrAppend(dest, {NumberToString(magnitude.InGiB()), "GiB"}); | 
 |   } else if (bytes % kOneMiB == 0 && bytes / kOneGiB == 0) { | 
 |     StrAppend(dest, {NumberToString(magnitude.InMiB()), "MiB"}); | 
 |   } else if (bytes % kOneKiB == 0 && bytes / kOneMiB == 0) { | 
 |     StrAppend(dest, {NumberToString(magnitude.InKiB()), "KiB"}); | 
 |   } else { | 
 |     // If not, then stream the exact byte count plus (if larger than 1KiB) an | 
 |     // estimate for scale. | 
 |     StrAppend(dest, {NumberToString(bytes), "B"}); | 
 |     if (bytes > kOneKiB) { | 
 |       StrAppend(dest, {" (", sign_prefix}); | 
 |       if (bytes > kOneEiB) { | 
 |         StrAppend( | 
 |             dest, | 
 |             {NumberToStringWithFixedPrecision(magnitude.InEiBF(), 3), "EiB"}); | 
 |       } else if (bytes > kOnePiB) { | 
 |         StrAppend( | 
 |             dest, | 
 |             {NumberToStringWithFixedPrecision(magnitude.InPiBF(), 3), "PiB"}); | 
 |       } else if (bytes > kOneTiB) { | 
 |         StrAppend( | 
 |             dest, | 
 |             {NumberToStringWithFixedPrecision(magnitude.InTiBF(), 3), "TiB"}); | 
 |       } else if (bytes > kOneGiB) { | 
 |         StrAppend( | 
 |             dest, | 
 |             {NumberToStringWithFixedPrecision(magnitude.InGiBF(), 3), "GiB"}); | 
 |       } else if (bytes > kOneMiB) { | 
 |         StrAppend( | 
 |             dest, | 
 |             {NumberToStringWithFixedPrecision(magnitude.InMiBF(), 3), "MiB"}); | 
 |       } else { | 
 |         StrAppend( | 
 |             dest, | 
 |             {NumberToStringWithFixedPrecision(magnitude.InKiBF(), 3), "KiB"}); | 
 |       } | 
 |       StrAppend(dest, {")"}); | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | }  // namespace | 
 |  | 
 | std::ostream& operator<<(std::ostream& os, ByteSize size) { | 
 |   // If it's exactly 0 then stream and return. | 
 |   if (size.is_zero()) { | 
 |     return os << "0B"; | 
 |   } | 
 |  | 
 |   // Reserve enough space (e.g. "1152920504606846976B (1023.999PiB)" which is | 
 |   // a full 64-bit value with four digits before the decimal). | 
 |   std::string result; | 
 |   result.reserve(34); | 
 |  | 
 |   AppendMagnitude(&result, size); | 
 |   return os << result; | 
 | } | 
 |  | 
 | std::ostream& operator<<(std::ostream& os, ByteSizeDelta delta) { | 
 |   // If it's exactly 0 then stream and return. | 
 |   if (delta.is_zero()) { | 
 |     return os << "0B"; | 
 |   } | 
 |  | 
 |   // If it's exactly INT64_MIN then stream and return. Later in this function, | 
 |   // negative values are handled by processing their absolute value, but | 
 |   // INT64_MIN, like all two's complement minimums, has no corresponding | 
 |   // positive value within range. | 
 |   if (delta.is_min()) { | 
 |     return os << "-8EiB"; | 
 |   } | 
 |  | 
 |   // Reserve enough space (e.g. "-1152920504606846976B (-1023.999PiB)" which is | 
 |   // a full 64-bit negative value with four digits before the decimal). | 
 |   std::string result; | 
 |   result.reserve(36); | 
 |  | 
 |   // Format that magnitude, with negative signs prepended if necessary. | 
 |   AppendMagnitude(&result, delta.Magnitude(), delta.is_negative() ? "-" : ""); | 
 |   return os << result; | 
 | } | 
 |  | 
 | }  // namespace base |