From a214dbb44bba5cb43d9ca714a69666c096f4953e Mon Sep 17 00:00:00 2001 From: chriseth Date: Mon, 25 Nov 2019 18:16:35 +0100 Subject: [PATCH] Reimplement toHex manually. --- libdevcore/CommonData.cpp | 46 ++++++++++++++++++++++++++++++--------- libdevcore/CommonData.h | 28 +++++++++++------------- libdevcore/Exceptions.h | 1 + 3 files changed, 50 insertions(+), 25 deletions(-) diff --git a/libdevcore/CommonData.cpp b/libdevcore/CommonData.cpp index 1b0e97204..ebdc81a38 100644 --- a/libdevcore/CommonData.cpp +++ b/libdevcore/CommonData.cpp @@ -29,26 +29,52 @@ using namespace std; using namespace dev; +namespace +{ + +static char const* upperHexChars = "0123456789ABCDEF"; +static char const* lowerHexChars = "0123456789abcdef"; + +} + +string dev::toHex(uint8_t _data, HexCase _case) +{ + assertThrow(_case != HexCase::Mixed, BadHexCase, "Mixed case can only be used for byte arrays."); + + char const* chars = _case == HexCase::Upper ? upperHexChars : lowerHexChars; + + return std::string{ + chars[(unsigned(_data) / 16) & 0xf], + chars[unsigned(_data) & 0xf] + }; +} + string dev::toHex(bytes const& _data, HexPrefix _prefix, HexCase _case) { - std::ostringstream ret; - if (_prefix == HexPrefix::Add) - ret << "0x"; + std::string ret(_data.size() * 2 + (_prefix == HexPrefix::Add ? 2 : 0), 0); + size_t i = 0; + if (_prefix == HexPrefix::Add) + { + ret[i++] = '0'; + ret[i++] = 'x'; + } + + // Mixed case will be handled inside the loop. + char const* chars = _case == HexCase::Upper ? upperHexChars : lowerHexChars; int rix = _data.size() - 1; for (uint8_t c: _data) { // switch hex case every four hexchars - auto hexcase = std::nouppercase; - if (_case == HexCase::Upper) - hexcase = std::uppercase; - else if (_case == HexCase::Mixed) - hexcase = (rix-- & 2) == 0 ? std::nouppercase : std::uppercase; + if (_case == HexCase::Mixed) + chars = (rix-- & 2) == 0 ? lowerHexChars : upperHexChars; - ret << std::hex << hexcase << std::setfill('0') << std::setw(2) << size_t(c); + ret[i++] = chars[(unsigned(c) / 16) & 0xf]; + ret[i++] = chars[unsigned(c) & 0xf]; } + assertThrow(i == ret.size(), Exception, ""); - return ret.str(); + return ret; } int dev::fromHex(char _i, WhenError _throw) diff --git a/libdevcore/CommonData.h b/libdevcore/CommonData.h index 017a632dc..d6e8f349e 100644 --- a/libdevcore/CommonData.h +++ b/libdevcore/CommonData.h @@ -130,9 +130,12 @@ enum class HexCase Mixed = 2, }; -/// Convert a series of bytes to the corresponding string of hex duplets. -/// @param _w specifies the width of the first of the elements. Defaults to two - enough to represent a byte. -/// @example toHex("A\x69") == "4169" +/// Convert a single byte to a string of hex characters (of length two), +/// optionally with uppercase hex letters. +std::string toHex(uint8_t _data, HexCase _case = HexCase::Lower); + +/// Convert a series of bytes to the corresponding string of hex duplets, +/// optionally with "0x" prefix and with uppercase hex letters. std::string toHex(bytes const& _data, HexPrefix _prefix = HexPrefix::DontAdd, HexCase _case = HexCase::Lower); /// Converts a (printable) ASCII hex character into the corresponding integer value. @@ -207,10 +210,6 @@ inline bytes toCompactBigEndian(T _val, unsigned _min = 0) toBigEndian(_val, ret); return ret; } -inline bytes toCompactBigEndian(uint8_t _val, unsigned _min = 0) -{ - return (_min || _val) ? bytes{ _val } : bytes{}; -} /// Convenience function for conversion of a u256 to hex inline std::string toHex(u256 val, HexPrefix prefix = HexPrefix::DontAdd) @@ -219,13 +218,18 @@ inline std::string toHex(u256 val, HexPrefix prefix = HexPrefix::DontAdd) return (prefix == HexPrefix::Add) ? "0x" + str : str; } +inline std::string toCompactHexWithPrefix(u256 const& _value) +{ + return toHex(toCompactBigEndian(_value, 1), HexPrefix::Add); +} + /// Returns decimal representation for small numbers and hex for large numbers. inline std::string formatNumber(bigint const& _value) { if (_value < 0) return "-" + formatNumber(-_value); if (_value > 0x1000000) - return toHex(toCompactBigEndian(_value), HexPrefix::Add); + return toHex(toCompactBigEndian(_value, 1), HexPrefix::Add); else return _value.str(); } @@ -233,17 +237,11 @@ inline std::string formatNumber(bigint const& _value) inline std::string formatNumber(u256 const& _value) { if (_value > 0x1000000) - return toHex(toCompactBigEndian(_value), HexPrefix::Add); + return toCompactHexWithPrefix(_value); else return _value.str(); } -inline std::string toCompactHexWithPrefix(u256 val) -{ - std::ostringstream ret; - ret << std::hex << val; - return "0x" + ret.str(); -} // Algorithms for string and string-like collections. diff --git a/libdevcore/Exceptions.h b/libdevcore/Exceptions.h index 943379d7a..a0ab7c6b5 100644 --- a/libdevcore/Exceptions.h +++ b/libdevcore/Exceptions.h @@ -46,6 +46,7 @@ private: DEV_SIMPLE_EXCEPTION(InvalidAddress); DEV_SIMPLE_EXCEPTION(BadHexCharacter); +DEV_SIMPLE_EXCEPTION(BadHexCase); DEV_SIMPLE_EXCEPTION(FileError); DEV_SIMPLE_EXCEPTION(DataTooLong);