Skip to content

Commit 61febbd

Browse files
committed
formatNumberReadable now prints signed integers as well
1 parent b80f4ba commit 61febbd

File tree

6 files changed

+97
-14
lines changed

6 files changed

+97
-14
lines changed

libsolutil/StringUtils.h

+35-10
Original file line numberDiff line numberDiff line change
@@ -101,17 +101,9 @@ std::string joinHumanReadablePrefixed
101101
return _separator + joinHumanReadable(_list, _separator, _lastSeparator);
102102
}
103103

104-
/// Formats large numbers to be easily readable by humans.
105-
/// Returns decimal representation for smaller numbers; hex for large numbers.
106-
/// "Special" numbers, powers-of-two and powers-of-two minus 1, are returned in
107-
/// formulaic form like 0x01 * 2**24 - 1.
108-
/// @a T will typically by unsigned, u160, u256 or bigint.
109-
/// @param _value to be formatted
110-
/// @param _useTruncation if true, internal truncation is also applied,
111-
/// like 0x5555...{+56 more}...5555
112-
/// @example formatNumber((u256)0x7ffffff)
104+
/// Same as @ref formatNumberReadable but only for unsigned numbers
113105
template <class T>
114-
inline std::string formatNumberReadable(
106+
inline std::string formatUnsignedNumberReadable (
115107
T const& _value,
116108
bool _useTruncation = false
117109
)
@@ -181,6 +173,39 @@ inline std::string formatNumberReadable(
181173
return str;
182174
}
183175

176+
/// Formats large numbers to be easily readable by humans.
177+
/// Returns decimal representation for smaller numbers; hex for large numbers.
178+
/// "Special" numbers, powers-of-two and powers-of-two minus 1, are returned in
179+
/// formulaic form like 0x01 * 2**24 - 1.
180+
/// @a T can be any integer variable, will typically be u160, u256 or bigint.
181+
/// @param _value to be formatted
182+
/// @param _useTruncation if true, internal truncation is also applied,
183+
/// like 0x5555...{+56 more}...5555
184+
/// @example formatNumberReadable((u256)0x7ffffff) = "0x08 * 2**24"
185+
/// @example formatNumberReadable(-57896044618658097711785492504343953926634992332820282019728792003956564819968) = -0x80 * 2**248
186+
template <class T>
187+
inline std::string formatNumberReadable(
188+
T const& _value,
189+
bool _useTruncation = false
190+
)
191+
{
192+
static_assert(
193+
std::numeric_limits<T>::is_integer,
194+
"only integer numbers are supported"
195+
);
196+
197+
if (_value >= 0)
198+
{
199+
bigint const _v = bigint(_value);
200+
return formatUnsignedNumberReadable(_v, _useTruncation);
201+
}
202+
else
203+
{
204+
bigint const _abs_value = bigint(-1) * _value;
205+
return "-" + formatUnsignedNumberReadable(_abs_value, _useTruncation);
206+
}
207+
}
208+
184209
/// Safely converts an usigned integer as string into an unsigned int type.
185210
///
186211
/// @return the converted number or nullopt in case of an failure (including if it would not fit).

test/libsolidity/smtCheckerTests/overflow/signed_guard_sum_overflow.sol

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,5 @@ contract C {
88
// SMTEngine: all
99
// SMTIgnoreCex: yes
1010
// ----
11-
// Warning 3944: (78-83): CHC: Underflow (resulting value less than -57896044618658097711785492504343953926634992332820282019728792003956564819968) happens here.
11+
// Warning 3944: (78-83): CHC: Underflow (resulting value less than -0x80 * 2**248) happens here.
1212
// Warning 4984: (78-83): CHC: Overflow (resulting value larger than 0x80 * 2**248 - 1) happens here.

test/libsolidity/smtCheckerTests/overflow/signed_mul_overflow.sol

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,5 @@ contract C {
77
// SMTEngine: all
88
// SMTIgnoreCex: yes
99
// ----
10-
// Warning 3944: (77-82): CHC: Underflow (resulting value less than -57896044618658097711785492504343953926634992332820282019728792003956564819968) happens here.
10+
// Warning 3944: (77-82): CHC: Underflow (resulting value less than -0x80 * 2**248) happens here.
1111
// Warning 4984: (77-82): CHC: Overflow (resulting value larger than 0x80 * 2**248 - 1) happens here.

test/libsolidity/smtCheckerTests/overflow/signed_sub_overflow.sol

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,5 @@ contract C {
77
// SMTEngine: all
88
// SMTIgnoreCex: yes
99
// ----
10-
// Warning 3944: (77-82): CHC: Underflow (resulting value less than -57896044618658097711785492504343953926634992332820282019728792003956564819968) happens here.
10+
// Warning 3944: (77-82): CHC: Underflow (resulting value less than -0x80 * 2**248) happens here.
1111
// Warning 4984: (77-82): CHC: Overflow (resulting value larger than 0x80 * 2**248 - 1) happens here.

test/libsolidity/smtCheckerTests/overflow/signed_sum_overflow.sol

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,5 @@ contract C {
77
// SMTEngine: all
88
// SMTIgnoreCex: yes
99
// ----
10-
// Warning 3944: (77-82): CHC: Underflow (resulting value less than -57896044618658097711785492504343953926634992332820282019728792003956564819968) happens here.
10+
// Warning 3944: (77-82): CHC: Underflow (resulting value less than -0x80 * 2**248) happens here.
1111
// Warning 4984: (77-82): CHC: Overflow (resulting value larger than 0x80 * 2**248 - 1) happens here.

test/libsolutil/StringUtils.cpp

+58
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,64 @@ BOOST_AUTO_TEST_CASE(test_format_number_readable)
152152
formatNumberReadable(frontend::IntegerType(256).maxValue()), "2**256 - 1");
153153
}
154154

155+
BOOST_AUTO_TEST_CASE(test_format_number_readable_signed)
156+
{
157+
BOOST_CHECK_EQUAL(formatNumberReadable((-1) * s256(0x8000000)), "-0x08 * 2**24");
158+
BOOST_CHECK_EQUAL(formatNumberReadable((-1) * s256(0x80000000)), "-0x80 * 2**24");
159+
BOOST_CHECK_EQUAL(formatNumberReadable((-1) * s256(0x800000000)), "-0x08 * 2**32");
160+
BOOST_CHECK_EQUAL(formatNumberReadable((-1) * s256(0x8000000000)), "-0x80 * 2**32");
161+
BOOST_CHECK_EQUAL(formatNumberReadable((-1) * s256(0x80000000000)), "-0x08 * 2**40");
162+
163+
BOOST_CHECK_EQUAL(formatNumberReadable((-1) * s256(0x7ffffff)), "-0x08 * 2**24 - 1");
164+
BOOST_CHECK_EQUAL(formatNumberReadable((-1) * s256(0x7fffffff)), "-0x80 * 2**24 - 1");
165+
BOOST_CHECK_EQUAL(formatNumberReadable((-1) * s256(0x7ffffffff)), "-0x08 * 2**32 - 1");
166+
BOOST_CHECK_EQUAL(formatNumberReadable((-1) * s256(0x7fffffffff)), "-0x80 * 2**32 - 1");
167+
BOOST_CHECK_EQUAL(formatNumberReadable((-1) * s256(0x7ffffffffff)), "-0x08 * 2**40 - 1");
168+
169+
BOOST_CHECK_EQUAL(formatNumberReadable((-1) * s256(0x88000000)), "-0x88 * 2**24");
170+
BOOST_CHECK_EQUAL(formatNumberReadable((-1) * s256(0x8888888888000000)), "-0x8888888888 * 2**24");
171+
172+
s256 b = 0;
173+
for (int i = 0; i < 32; i++)
174+
{
175+
b <<= 8;
176+
b |= 0x55;
177+
}
178+
b = b * (-1);
179+
180+
s256 c = (-1) * u2s((u256)FixedHash<32>(
181+
fromHex("0x0bcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789")
182+
));
183+
184+
s256 d = (-1) * u2s(
185+
u256(0x5555555555555555) << 192 |
186+
u256(0xFFFFffffFFFFffff) << 128 |
187+
u256(0xFFFFffffFFFFffff) << 64 |
188+
u256(0xFFFFffffFFFFffff)
189+
);
190+
191+
BOOST_CHECK_EQUAL(formatNumberReadable(b, true), "-0x5555...{+56 more}...5555");
192+
BOOST_CHECK_EQUAL(formatNumberReadable(c, true), "-0x0BCD...{+56 more}...6789");
193+
BOOST_CHECK_EQUAL(formatNumberReadable(d, true), "-0x5555555555555556 * 2**192 - 1");
194+
195+
BOOST_CHECK_EQUAL(formatNumberReadable(s256(-1)), "-1");
196+
BOOST_CHECK_EQUAL(formatNumberReadable((-1) * s256(0x10000)), "-65536");
197+
BOOST_CHECK_EQUAL(formatNumberReadable((-1) * s256(0xFFFF)), "-65535");
198+
199+
BOOST_CHECK_EQUAL(
200+
formatNumberReadable(
201+
frontend::IntegerType(256, frontend::IntegerType::Modifier::Signed).minValue()
202+
),
203+
"-0x80 * 2**248"
204+
);
205+
BOOST_CHECK_EQUAL(
206+
formatNumberReadable(
207+
frontend::IntegerType(256, frontend::IntegerType::Modifier::Signed).maxValue()
208+
),
209+
"0x80 * 2**248 - 1"
210+
);
211+
}
212+
155213
BOOST_AUTO_TEST_SUITE_END()
156214

157215
}

0 commit comments

Comments
 (0)