Index: include/llvm/Support/Format.h =================================================================== --- include/llvm/Support/Format.h +++ include/llvm/Support/Format.h @@ -252,6 +252,27 @@ ByteGroupSize, Upper, true); } +/// This is a helper class used for format_memory. +class FormattedMemory { + friend class raw_ostream; + const double NumBytes; + const unsigned Width; +public: + FormattedMemory(double NB, unsigned W = 2) : NumBytes(NB), Width(W) {} +}; + +/// format_memory - Output \p NB as human readable amount of memory. When the +/// amount is greater than half the amount for the next suffix the next suffix +/// is used. If no suffix exists for the amount of bytes, then the number is +/// printed as is. +/// OS << format_decimal(1024, 2) => "1.00 kB" +/// OS << format_decimal(524288, 2) => "0.50 MB" +/// OS << format_decimal(1048576, 4) => "1.0000 MB" +/// OS << format_decimal(pow(1024, 5), 3) => "1.000 PB" +inline FormattedMemory format_memory(double NB, unsigned W = 2) { + return FormattedMemory(NB, W); +} + } // end namespace llvm #endif Index: include/llvm/Support/raw_ostream.h =================================================================== --- include/llvm/Support/raw_ostream.h +++ include/llvm/Support/raw_ostream.h @@ -30,6 +30,7 @@ class FormattedString; class FormattedNumber; class FormattedBytes; +class FormattedMemory; namespace sys { namespace fs { @@ -235,6 +236,9 @@ // Formatted output, see the format_bytes() function in Support/Format.h. raw_ostream &operator<<(const FormattedBytes &); + // Formatted output, see the format_memory() function in Support/Format.h. + raw_ostream &operator<<(const FormattedMemory &); + /// indent - Insert 'NumSpaces' spaces. raw_ostream &indent(unsigned NumSpaces); Index: lib/Support/raw_ostream.cpp =================================================================== --- lib/Support/raw_ostream.cpp +++ lib/Support/raw_ostream.cpp @@ -448,6 +448,37 @@ return *this; } +raw_ostream &raw_ostream::operator<<(const FormattedMemory &FM) { + constexpr size_t NumSuffixes = 8; + struct ByteTable { + ByteTable() { + for (size_t I = 0; I <= NumSuffixes; ++I) + Table[I] = std::pow(1024, I + 1); + } + double operator[](int I) const { return Table[I]; } + double Table[NumSuffixes + 1]; + }; + + if (FM.NumBytes >= 1024) { + static const ByteTable BT; + static const char Suffix[NumSuffixes][3] = {"kB", "MB", "GB", "TB", + "PB", "EB", "ZB", "YB"}; + for (size_t I = 1; I <= NumSuffixes; ++I) { + if (FM.NumBytes < BT[I] * 0.5) { + this->operator<<( + llvm::format("%.*f ", FM.Width, FM.NumBytes / BT[I - 1])); + this->operator<<(Suffix[I - 1]); + return *this; + } + } + this->operator<<("?? "); + this->operator<<(FM.NumBytes); + this->operator<<(" ??"); + } + this->operator<<(llvm::format("%.0f B", FM.NumBytes)); + return *this; +} + /// indent - Insert 'NumSpaces' spaces. raw_ostream &raw_ostream::indent(unsigned NumSpaces) { static const char Spaces[] = " " Index: unittests/Support/raw_ostream_test.cpp =================================================================== --- unittests/Support/raw_ostream_test.cpp +++ unittests/Support/raw_ostream_test.cpp @@ -13,6 +13,8 @@ #include "llvm/Support/raw_ostream.h" #include "gtest/gtest.h" +#include + using namespace llvm; namespace { @@ -158,6 +160,28 @@ EXPECT_EQ("none", printToString(center_justify("none", 1), 1)); } +TEST(raw_ostreamTest, FormatMemory) { + EXPECT_EQ("1.00 kB", printToString(llvm::format_memory(1024))); + EXPECT_EQ("1.00 MB", printToString(llvm::format_memory(std::pow(1024, 2)))); + EXPECT_EQ("1.00 GB", printToString(llvm::format_memory(std::pow(1024, 3)))); + EXPECT_EQ("1.00 TB", printToString(llvm::format_memory(std::pow(1024, 4)))); + EXPECT_EQ("1.00 PB", printToString(llvm::format_memory(std::pow(1024, 5)))); + EXPECT_EQ("1.00 EB", printToString(llvm::format_memory(std::pow(1024, 6)))); + EXPECT_EQ("1.00 ZB", printToString(llvm::format_memory(std::pow(1024, 7)))); + EXPECT_EQ("1.00 YB", printToString(llvm::format_memory(std::pow(1024, 8)))); + + EXPECT_EQ("256.00 kB", printToString(llvm::format_memory(262144))); + EXPECT_EQ("0.50 MB", printToString(llvm::format_memory(262144*2))); + + EXPECT_EQ("0.50 PB", + printToString(llvm::format_memory(std::pow(1024, 5) * 0.5))); + EXPECT_EQ("409.60 TB", + printToString(llvm::format_memory(std::pow(1024, 5) * 0.4))); + + EXPECT_EQ("0.5010 TB", printToString(llvm::format_memory( + std::pow(1024, 3) + std::pow(1024, 4) * 0.5, 4))); +} + TEST(raw_ostreamTest, FormatHex) { EXPECT_EQ("0x1234", printToString(format_hex(0x1234, 6), 6)); EXPECT_EQ("0x001234", printToString(format_hex(0x1234, 8), 8));