aboutsummaryrefslogtreecommitdiffstats
path: root/libdevcore/StringUtils.h
diff options
context:
space:
mode:
authorKevin Kelley <kevin@kelleysoft.com>2018-11-22 08:02:25 +0800
committerchriseth <chris@ethereum.org>2018-12-06 05:15:02 +0800
commitfb6fd1b3c25fd9c2bc9b8abb97fd150bc4ce219c (patch)
tree654e692585f825a6ca1ea50c1e27b06b7f2107e1 /libdevcore/StringUtils.h
parentd3c8ba00ac00426b256998a678a8d4bfbf0acd83 (diff)
downloaddexon-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.h82
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;
+}
+
}