add ParseArbitraryInt() for diversifier index
This commit is contained in:
parent
c908a3b059
commit
d0b85b69f3
|
@ -492,4 +492,107 @@ BOOST_AUTO_TEST_CASE(test_ParseFixedPoint)
|
|||
BOOST_CHECK(!ParseFixedPoint("1.", 8, &amount));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_ParseArbitraryInt)
|
||||
{
|
||||
// Negation not allowed.
|
||||
BOOST_CHECK(!ParseArbitraryInt("-1"));
|
||||
|
||||
// no legal digits
|
||||
BOOST_CHECK(!ParseArbitraryInt(""));
|
||||
BOOST_CHECK(!ParseArbitraryInt(" "));
|
||||
|
||||
// Hex not allowed (only decimal).
|
||||
BOOST_CHECK(!ParseArbitraryInt("ab"));
|
||||
BOOST_CHECK(!ParseArbitraryInt("0xab"));
|
||||
|
||||
// Decimal point not allowed.
|
||||
BOOST_CHECK(!ParseArbitraryInt("1."));
|
||||
|
||||
std::optional<std::vector<unsigned char>> v;
|
||||
|
||||
// simple success case
|
||||
v = ParseArbitraryInt("1");
|
||||
BOOST_CHECK(v.has_value());
|
||||
BOOST_CHECK_EQUAL(v->size(), 1);
|
||||
BOOST_CHECK_EQUAL((*v)[0], 1);
|
||||
|
||||
// Leading and trailing whitespace (spaces and tabs) is allowed.
|
||||
v = ParseArbitraryInt(" 1");
|
||||
BOOST_CHECK(v.has_value());
|
||||
BOOST_CHECK_EQUAL(v->size(), 1);
|
||||
BOOST_CHECK_EQUAL((*v)[0], 1);
|
||||
v = ParseArbitraryInt(" 1");
|
||||
BOOST_CHECK(v.has_value());
|
||||
BOOST_CHECK_EQUAL(v->size(), 1);
|
||||
BOOST_CHECK_EQUAL((*v)[0], 1);
|
||||
v = ParseArbitraryInt(" \t1 ");
|
||||
BOOST_CHECK(v.has_value());
|
||||
BOOST_CHECK_EQUAL(v->size(), 1);
|
||||
BOOST_CHECK_EQUAL((*v)[0], 1);
|
||||
|
||||
// Leading zeros have no effect, does not mean octal
|
||||
v = ParseArbitraryInt("010\t");
|
||||
BOOST_CHECK(v.has_value());
|
||||
BOOST_CHECK_EQUAL(v->size(), 1);
|
||||
BOOST_CHECK_EQUAL((*v)[0], 10);
|
||||
|
||||
v = ParseArbitraryInt(" 255\t");
|
||||
BOOST_CHECK(v.has_value());
|
||||
BOOST_CHECK_EQUAL(v->size(), 1);
|
||||
BOOST_CHECK_EQUAL((*v)[0], 255);
|
||||
|
||||
v = ParseArbitraryInt("\t 256");
|
||||
BOOST_CHECK(v.has_value());
|
||||
BOOST_CHECK_EQUAL(v->size(), 2);
|
||||
BOOST_CHECK_EQUAL((*v)[0], 0);
|
||||
BOOST_CHECK_EQUAL((*v)[1], 1);
|
||||
|
||||
v = ParseArbitraryInt("257 \t");
|
||||
BOOST_CHECK(v.has_value());
|
||||
BOOST_CHECK_EQUAL(v->size(), 2);
|
||||
BOOST_CHECK_EQUAL((*v)[0], 1);
|
||||
BOOST_CHECK_EQUAL((*v)[1], 1);
|
||||
|
||||
v = ParseArbitraryInt("65535");
|
||||
BOOST_CHECK(v.has_value());
|
||||
BOOST_CHECK_EQUAL(v->size(), 2);
|
||||
BOOST_CHECK_EQUAL((*v)[0], 255);
|
||||
BOOST_CHECK_EQUAL((*v)[1], 255);
|
||||
|
||||
v = ParseArbitraryInt("65536");
|
||||
BOOST_CHECK(v.has_value());
|
||||
BOOST_CHECK_EQUAL(v->size(), 3);
|
||||
BOOST_CHECK_EQUAL((*v)[0], 0);
|
||||
BOOST_CHECK_EQUAL((*v)[1], 0);
|
||||
BOOST_CHECK_EQUAL((*v)[2], 1);
|
||||
|
||||
// This decimal string came from:
|
||||
// $ echo 16i 102030405060708090A0B0C0D0E0F0F1F2F3F4F5F6F7 p | dc
|
||||
v = ParseArbitraryInt("6033354224708459019450009057293028077350189222196983");
|
||||
BOOST_CHECK(v.has_value());
|
||||
BOOST_CHECK_EQUAL(v->size(), 22);
|
||||
BOOST_CHECK_EQUAL((*v)[0], 0xf7);
|
||||
BOOST_CHECK_EQUAL((*v)[1], 0xf6);
|
||||
BOOST_CHECK_EQUAL((*v)[2], 0xf5);
|
||||
BOOST_CHECK_EQUAL((*v)[3], 0xf4);
|
||||
BOOST_CHECK_EQUAL((*v)[4], 0xf3);
|
||||
BOOST_CHECK_EQUAL((*v)[5], 0xf2);
|
||||
BOOST_CHECK_EQUAL((*v)[6], 0xf1);
|
||||
BOOST_CHECK_EQUAL((*v)[7], 0xf0);
|
||||
BOOST_CHECK_EQUAL((*v)[8], 0xe0);
|
||||
BOOST_CHECK_EQUAL((*v)[9], 0xd0);
|
||||
BOOST_CHECK_EQUAL((*v)[10], 0xc0);
|
||||
BOOST_CHECK_EQUAL((*v)[11], 0xb0);
|
||||
BOOST_CHECK_EQUAL((*v)[12], 0xa0);
|
||||
BOOST_CHECK_EQUAL((*v)[13], 0x90);
|
||||
BOOST_CHECK_EQUAL((*v)[14], 0x80);
|
||||
BOOST_CHECK_EQUAL((*v)[15], 0x70);
|
||||
BOOST_CHECK_EQUAL((*v)[16], 0x60);
|
||||
BOOST_CHECK_EQUAL((*v)[17], 0x50);
|
||||
BOOST_CHECK_EQUAL((*v)[18], 0x40);
|
||||
BOOST_CHECK_EQUAL((*v)[19], 0x30);
|
||||
BOOST_CHECK_EQUAL((*v)[20], 0x20);
|
||||
BOOST_CHECK_EQUAL((*v)[21], 0x10);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
|
|
@ -506,3 +506,25 @@ bool ParseFixedPoint(const std::string &val, int decimals, int64_t *amount_out)
|
|||
return true;
|
||||
}
|
||||
|
||||
/// Parse the decimal string into a little-endian byte vector.
|
||||
std::optional<std::vector<uint8_t>> ParseArbitraryInt(const std::string& num_string)
|
||||
{
|
||||
std::vector<unsigned char> result;
|
||||
const size_t start = num_string.find_first_not_of(WHITESPACE);
|
||||
if (start == std::string::npos) return std::nullopt;
|
||||
const size_t end = num_string.find_last_not_of(WHITESPACE);
|
||||
assert(end != std::string::npos);
|
||||
for (char c : num_string.substr(start, end-start+1)) {
|
||||
if (c < '0' || c > '9') {
|
||||
return std::nullopt;
|
||||
}
|
||||
uint16_t v = c - '0';
|
||||
for (auto& r : result) {
|
||||
v += r * 10;
|
||||
r = v & 0xFF; // store low byte of the value
|
||||
v >>= 8; // carry to the next result position
|
||||
}
|
||||
if (v > 0) result.push_back(v);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -12,6 +12,9 @@
|
|||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <optional>
|
||||
|
||||
constexpr char WHITESPACE[] = " \t";
|
||||
|
||||
#define BEGIN(a) ((char*)&(a))
|
||||
#define END(a) ((char*)&((&(a))[1]))
|
||||
|
@ -164,4 +167,6 @@ bool ConvertBits(const O& outfn, I it, I end) {
|
|||
return true;
|
||||
}
|
||||
|
||||
std::optional<std::vector<uint8_t>> ParseArbitraryInt(const std::string& s);
|
||||
|
||||
#endif // BITCOIN_UTILSTRENCODINGS_H
|
||||
|
|
Loading…
Reference in New Issue