diff options
author | Kevin Kelley <kevin@kelleysoft.com> | 2018-11-22 08:02:25 +0800 |
---|---|---|
committer | chriseth <chris@ethereum.org> | 2018-12-06 05:15:02 +0800 |
commit | fb6fd1b3c25fd9c2bc9b8abb97fd150bc4ce219c (patch) | |
tree | 654e692585f825a6ca1ea50c1e27b06b7f2107e1 /libdevcore/StringUtils.h | |
parent | d3c8ba00ac00426b256998a678a8d4bfbf0acd83 (diff) | |
download | dexon-solidity-fb6fd1b3c25fd9c2bc9b8abb97fd150bc4ce219c.tar.gz dexon-solidity-fb6fd1b3c25fd9c2bc9b8abb97fd150bc4ce219c.tar.zst dexon-solidity-fb6fd1b3c25fd9c2bc9b8abb97fd150bc4ce219c.zip |
add a 'readable' format for large hex values
Diffstat (limited to 'libdevcore/StringUtils.h')
-rw-r--r-- | libdevcore/StringUtils.h | 82 |
1 files changed, 82 insertions, 0 deletions
diff --git a/libdevcore/StringUtils.h b/libdevcore/StringUtils.h index b02b9d12..43aa4bd1 100644 --- a/libdevcore/StringUtils.h +++ b/libdevcore/StringUtils.h @@ -26,6 +26,8 @@ #include <string> #include <vector> +#include <libdevcore/CommonData.h> + namespace dev { @@ -72,4 +74,84 @@ std::string joinHumanReadable return result; } +/// Formats large numbers to be easily readable by humans. +/// Returns decimal representation for smaller numbers; hex for large numbers. +/// "Special" numbers, powers-of-two and powers-of-two minus 1, are returned in +/// formulaic form like 0x01 * 2**24 - 1. +/// @a T will typically by unsigned, u160, u256 or bigint. +/// @param _value to be formatted +/// @param _useTruncation if true, internal truncation is also applied, +/// like 0x5555...{+56 more}...5555 +/// @example formatNumber((u256)0x7ffffff) +template <class T> +inline std::string formatNumberReadable( + T const& _value, + bool _useTruncation = false +) +{ + static_assert( + std::is_same<bigint, T>::value || !std::numeric_limits<T>::is_signed, + "only unsigned types or bigint supported" + ); //bigint does not carry sign bit on shift + + // smaller numbers return as decimal + if (_value <= 0x1000000) + return _value.str(); + + HexCase hexcase = HexCase::Mixed; + HexPrefix prefix = HexPrefix::Add; + + // when multiple trailing zero bytes, format as N * 2**x + int i = 0; + T v = _value; + for (; (v & 0xff) == 0; v >>= 8) + ++i; + if (i > 2) + { + // 0x100 yields 2**8 (N is 1 and redundant) + if (v == 1) + return "2**" + std::to_string(i * 8); + return toHex(toCompactBigEndian(v), 2, prefix, hexcase) + + " * 2**" + + std::to_string(i * 8); + } + + // when multiple trailing FF bytes, format as N * 2**x - 1 + i = 0; + for (v = _value; (v & 0xff) == 0xff; v >>= 8) + ++i; + if (i > 2) + { + // 0xFF yields 2**8 - 1 (v is 0 in that case) + if (v == 0) + return "2**" + std::to_string(i * 8) + " - 1"; + return toHex(toCompactBigEndian(T(v + 1)), 2, prefix, hexcase) + + " * 2**" + std::to_string(i * 8) + + " - 1"; + } + + std::string str = toHex(toCompactBigEndian(_value), 2, prefix, hexcase); + if (_useTruncation) + { + // return as interior-truncated hex. + int len = str.size(); + + if (len < 24) + return str; + + const int initialChars = (prefix == HexPrefix::Add) ? 6 : 4; + const int finalChars = 4; + int numSkipped = len - initialChars - finalChars; + + return str.substr(0, initialChars) + + "...{+" + + std::to_string(numSkipped) + + " more}..." + + str.substr(len-finalChars, len); + } + + // otherwise, show whole value. + return str; +} + } |