diff options
Diffstat (limited to 'libdevcore')
-rw-r--r-- | libdevcore/CMakeLists.txt | 20 | ||||
-rw-r--r-- | libdevcore/CommonData.cpp | 22 | ||||
-rw-r--r-- | libdevcore/CommonData.h | 22 | ||||
-rw-r--r-- | libdevcore/FixedHash.h | 2 | ||||
-rw-r--r-- | libdevcore/IndentedWriter.cpp | 2 | ||||
-rw-r--r-- | libdevcore/IndentedWriter.h | 4 | ||||
-rw-r--r-- | libdevcore/Result.h | 66 | ||||
-rw-r--r-- | libdevcore/StringUtils.cpp | 2 | ||||
-rw-r--r-- | libdevcore/StringUtils.h | 82 |
9 files changed, 204 insertions, 18 deletions
diff --git a/libdevcore/CMakeLists.txt b/libdevcore/CMakeLists.txt index 01a8bcc6..e68ac10a 100644 --- a/libdevcore/CMakeLists.txt +++ b/libdevcore/CMakeLists.txt @@ -1,18 +1,36 @@ set(sources + Algorithms.h + Assertions.h + boost_multiprecision_number_compare_bug_workaround.hpp + Common.h CommonData.cpp + CommonData.h CommonIO.cpp + CommonIO.h Exceptions.cpp + Exceptions.h + FixedHash.h IndentedWriter.cpp + IndentedWriter.h JSON.cpp + JSON.h Keccak256.cpp + Keccak256.h + Result.h StringUtils.cpp + StringUtils.h SwarmHash.cpp + SwarmHash.h UTF8.cpp + UTF8.h + vector_ref.h + Visitor.h Whiskers.cpp + Whiskers.h ) add_library(devcore ${sources}) -target_link_libraries(devcore PRIVATE jsoncpp ${Boost_FILESYSTEM_LIBRARIES} ${Boost_REGEX_LIBRARIES} ${Boost_SYSTEM_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) +target_link_libraries(devcore PUBLIC jsoncpp ${Boost_FILESYSTEM_LIBRARIES} ${Boost_REGEX_LIBRARIES} ${Boost_SYSTEM_LIBRARIES} Threads::Threads) target_include_directories(devcore PUBLIC "${CMAKE_SOURCE_DIR}") target_include_directories(devcore SYSTEM PUBLIC ${Boost_INCLUDE_DIRS}) add_dependencies(devcore solidity_BuildInfo.h) diff --git a/libdevcore/CommonData.cpp b/libdevcore/CommonData.cpp index 8d2639c9..1b0e9720 100644 --- a/libdevcore/CommonData.cpp +++ b/libdevcore/CommonData.cpp @@ -29,6 +29,28 @@ using namespace std; using namespace dev; +string dev::toHex(bytes const& _data, HexPrefix _prefix, HexCase _case) +{ + std::ostringstream ret; + if (_prefix == HexPrefix::Add) + ret << "0x"; + + 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; + + ret << std::hex << hexcase << std::setfill('0') << std::setw(2) << size_t(c); + } + + return ret.str(); +} + int dev::fromHex(char _i, WhenError _throw) { if (_i >= '0' && _i <= '9') diff --git a/libdevcore/CommonData.h b/libdevcore/CommonData.h index fedd3af2..7c59c505 100644 --- a/libdevcore/CommonData.h +++ b/libdevcore/CommonData.h @@ -50,18 +50,18 @@ enum class HexPrefix DontAdd = 0, Add = 1, }; + +enum class HexCase +{ + Lower = 0, + Upper = 1, + 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" -template <class T> -std::string toHex(T const& _data, int _w = 2, HexPrefix _prefix = HexPrefix::DontAdd) -{ - std::ostringstream ret; - unsigned ii = 0; - for (auto i: _data) - ret << std::hex << std::setfill('0') << std::setw(ii++ ? 2 : _w) << (int)(typename std::make_unsigned<decltype(i)>::type)i; - return (_prefix == HexPrefix::Add) ? "0x" + ret.str() : ret.str(); -} +std::string toHex(bytes const& _data, HexPrefix _prefix = HexPrefix::DontAdd, HexCase _case = HexCase::Lower); /// Converts a (printable) ASCII hex character into the correspnding integer value. /// @example fromHex('A') == 10 && fromHex('f') == 15 && fromHex('5') == 5 @@ -153,7 +153,7 @@ inline std::string formatNumber(bigint const& _value) if (_value < 0) return "-" + formatNumber(-_value); if (_value > 0x1000000) - return toHex(toCompactBigEndian(_value), 2, HexPrefix::Add); + return toHex(toCompactBigEndian(_value), HexPrefix::Add); else return _value.str(); } @@ -161,7 +161,7 @@ inline std::string formatNumber(bigint const& _value) inline std::string formatNumber(u256 const& _value) { if (_value > 0x1000000) - return toHex(toCompactBigEndian(_value), 2, HexPrefix::Add); + return toHex(toCompactBigEndian(_value), HexPrefix::Add); else return _value.str(); } diff --git a/libdevcore/FixedHash.h b/libdevcore/FixedHash.h index 24b89840..9245d726 100644 --- a/libdevcore/FixedHash.h +++ b/libdevcore/FixedHash.h @@ -95,7 +95,7 @@ public: uint8_t operator[](unsigned _i) const { return m_data[_i]; } /// @returns the hash as a user-readable hex string. - std::string hex() const { return toHex(ref()); } + std::string hex() const { return toHex(asBytes()); } /// @returns a mutable byte vector_ref to the object's data. bytesRef ref() { return bytesRef(m_data.data(), N); } diff --git a/libdevcore/IndentedWriter.cpp b/libdevcore/IndentedWriter.cpp index 96aaf0fa..1a85957b 100644 --- a/libdevcore/IndentedWriter.cpp +++ b/libdevcore/IndentedWriter.cpp @@ -36,7 +36,7 @@ string IndentedWriter::format() const void IndentedWriter::newLine() { if (!m_lines.back().contents.empty()) - m_lines.push_back({ string(), m_lines.back().indentation }); + m_lines.emplace_back(Line{string(), m_lines.back().indentation}); } void IndentedWriter::indent() diff --git a/libdevcore/IndentedWriter.h b/libdevcore/IndentedWriter.h index 4ddd87ed..563c4c96 100644 --- a/libdevcore/IndentedWriter.h +++ b/libdevcore/IndentedWriter.h @@ -34,8 +34,6 @@ DEV_SIMPLE_EXCEPTION(IndentedWriterError); class IndentedWriter { public: - explicit IndentedWriter(): m_lines(std::vector<Line>{{std::string(), 0}}) {} - // Returns the formatted output. std::string format() const; @@ -61,7 +59,7 @@ private: unsigned indentation; }; - std::vector<Line> m_lines; + std::vector<Line> m_lines{{std::string(), 0}}; }; } diff --git a/libdevcore/Result.h b/libdevcore/Result.h new file mode 100644 index 00000000..4f7a063b --- /dev/null +++ b/libdevcore/Result.h @@ -0,0 +1,66 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see <http://www.gnu.org/licenses/>. +*/ +#pragma once + +#include <string> + +namespace dev +{ + +/// Simple generic result that holds a value and an optional error message. +/// Results can be implicitly converted to and created from the type of +/// the value they hold. The class is mainly designed for a result type of +/// bool or pointer type. The idea is that the default constructed value of +/// the result type is interpreted as an error value. +/// +/// Result<bool> check() +/// { +/// if (false) +/// return Result<bool>("Error message.") +/// return true; +/// } +/// + +template <class ResultType> +class Result +{ +public: + Result(ResultType _value): Result(_value, std::string{}) {} + Result(std::string _message): Result(ResultType{}, std::move(_message)) {} + + /// @{ + /// @name Wrapper functions + /// Wrapper functions that provide implicit conversions to and explicit retrieval of + /// the value this result holds. + operator ResultType const&() const { return m_value; } + ResultType const& get() const { return m_value; } + /// @} + + /// @returns the error message (can be empty). + std::string const& message() const { return m_message; } + +private: + explicit Result(ResultType _value, std::string _message): + m_value(std::move(_value)), + m_message(std::move(_message)) + {} + + ResultType m_value; + std::string m_message; +}; + +} diff --git a/libdevcore/StringUtils.cpp b/libdevcore/StringUtils.cpp index 50bf7cce..196ac8f7 100644 --- a/libdevcore/StringUtils.cpp +++ b/libdevcore/StringUtils.cpp @@ -91,7 +91,7 @@ string dev::quotedAlternativesList(vector<string> const& suggestions) vector<string> quotedSuggestions; for (auto& suggestion: suggestions) - quotedSuggestions.push_back("\"" + suggestion + "\""); + quotedSuggestions.emplace_back("\"" + suggestion + "\""); return joinHumanReadable(quotedSuggestions, ", ", " or "); } diff --git a/libdevcore/StringUtils.h b/libdevcore/StringUtils.h index b02b9d12..64044cb2 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), 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)), prefix, hexcase) + + " * 2**" + std::to_string(i * 8) + + " - 1"; + } + + std::string str = toHex(toCompactBigEndian(_value), 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; +} + } |