/* This file is part of cpp-ethereum. cpp-ethereum 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. cpp-ethereum 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 cpp-ethereum. If not, see . */ /** @file CommonData.h * @author Gav Wood * @date 2014 * * Shared algorithms and data types. */ #pragma once #include #include #include #include #include #include #include "Common.h" namespace dev { // String conversion functions, mainly to/from hex/nibble/byte representations. enum class WhenError { DontThrow = 0, Throw = 1, }; enum class HexPrefix { DontAdd = 0, Add = 1, }; /// 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 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::type)i; return (_prefix == HexPrefix::Add) ? "0x" + ret.str() : ret.str(); } /// Converts a (printable) ASCII hex character into the correspnding integer value. /// @example fromHex('A') == 10 && fromHex('f') == 15 && fromHex('5') == 5 int fromHex(char _i, WhenError _throw); /// Converts a (printable) ASCII hex string into the corresponding byte stream. /// @example fromHex("41626261") == asBytes("Abba") /// If _throw = ThrowType::DontThrow, it replaces bad hex characters with 0's, otherwise it will throw an exception. bytes fromHex(std::string const& _s, WhenError _throw = WhenError::DontThrow); /// Converts byte array to a string containing the same (binary) data. Unless /// the byte array happens to contain ASCII data, this won't be printable. inline std::string asString(bytes const& _b) { return std::string((char const*)_b.data(), (char const*)(_b.data() + _b.size())); } /// Converts byte array ref to a string containing the same (binary) data. Unless /// the byte array happens to contain ASCII data, this won't be printable. inline std::string asString(bytesConstRef _b) { return std::string((char const*)_b.data(), (char const*)(_b.data() + _b.size())); } /// Converts a string to a byte array containing the string's (byte) data. inline bytes asBytes(std::string const& _b) { return bytes((byte const*)_b.data(), (byte const*)(_b.data() + _b.size())); } /// Converts a string into the big-endian base-16 stream of integers (NOT ASCII). /// @example asNibbles("A")[0] == 4 && asNibbles("A")[1] == 1 bytes asNibbles(bytesConstRef const& _s); // Big-endian to/from host endian conversion functions. /// Converts a templated integer value to the big-endian byte-stream represented on a templated collection. /// The size of the collection object will be unchanged. If it is too small, it will not represent the /// value properly, if too big then the additional elements will be zeroed out. /// @a Out will typically be either std::string or bytes. /// @a T will typically by unsigned, u160, u256 or bigint. template inline void toBigEndian(T _val, Out& o_out) { for (auto i = o_out.size(); i != 0; _val >>= 8, i--) { T v = _val & (T)0xff; o_out[i - 1] = (typename Out::value_type)(uint8_t)v; } } /// Converts a big-endian byte-stream represented on a templated collection to a templated integer value. /// @a _In will typically be either std::string or bytes. /// @a T will typically by unsigned, u160, u256 or bigint. template inline T fromBigEndian(_In const& _bytes) { T ret = (T)0; for (auto i: _bytes) ret = (T)((ret << 8) | (byte)(typename std::make_unsigned::type)i); return ret; } /// Convenience functions for toBigEndian inline std::string toBigEndianString(u256 _val) { std::string ret(32, '\0'); toBigEndian(_val, ret); return ret; } inline std::string toBigEndianString(u160 _val) { std::string ret(20, '\0'); toBigEndian(_val, ret); return ret; } inline bytes toBigEndian(u256 _val) { bytes ret(32); toBigEndian(_val, ret); return ret; } inline bytes toBigEndian(u160 _val) { bytes ret(20); toBigEndian(_val, ret); return ret; } /// Convenience function for toBigEndian. /// @returns a byte array just big enough to represent @a _val. template inline bytes toCompactBigEndian(T _val, unsigned _min = 0) { int i = 0; for (T v = _val; v; ++i, v >>= 8) {} bytes ret(std::max(_min, i), 0); toBigEndian(_val, ret); return ret; } inline bytes toCompactBigEndian(byte _val, unsigned _min = 0) { return (_min || _val) ? bytes{ _val } : bytes{}; } /// Convenience function for toBigEndian. /// @returns a string just big enough to represent @a _val. template inline std::string toCompactBigEndianString(T _val, unsigned _min = 0) { int i = 0; for (T v = _val; v; ++i, v >>= 8) {} std::string ret(std::max(_min, i), '\0'); toBigEndian(_val, ret); return ret; } /// Convenience function for conversion of a u256 to hex inline std::string toHex(u256 val, HexPrefix prefix = HexPrefix::DontAdd) { std::string str = toHex(toBigEndian(val)); return (prefix == HexPrefix::Add) ? "0x" + str : str; } inline std::string toCompactHex(u256 val, HexPrefix prefix = HexPrefix::DontAdd, unsigned _min = 0) { std::string str = toHex(toCompactBigEndian(val, _min)); return (prefix == HexPrefix::Add) ? "0x" + str : str; } // Algorithms for string and string-like collections. /// Escapes a string into the C-string representation. /// @p _all if true will escape all characters, not just the unprintable ones. std::string escaped(std::string const& _s, bool _all = true); /// Determines the length of the common prefix of the two collections given. /// @returns the number of elements both @a _t and @a _u share, in order, at the beginning. /// @example commonPrefix("Hello world!", "Hello, world!") == 5 template unsigned commonPrefix(T const& _t, _U const& _u) { unsigned s = std::min(_t.size(), _u.size()); for (unsigned i = 0;; ++i) if (i == s || _t[i] != _u[i]) return i; return s; } /// Creates a random, printable, word. std::string randomWord(); // General datatype convenience functions. /// Determine bytes required to encode the given integer value. @returns 0 if @a _i is zero. template inline unsigned bytesRequired(T _i) { unsigned i = 0; for (; _i != 0; ++i, _i >>= 8) {} return i; } /// Trims a given number of elements from the front of a collection. /// Only works for POD element types. template void trimFront(T& _t, unsigned _elements) { static_assert(std::is_pod::value, ""); memmove(_t.data(), _t.data() + _elements, (_t.size() - _elements) * sizeof(_t[0])); _t.resize(_t.size() - _elements); } /// Pushes an element on to the front of a collection. /// Only works for POD element types. template void pushFront(T& _t, _U _e) { static_assert(std::is_pod::value, ""); _t.push_back(_e); memmove(_t.data() + 1, _t.data(), (_t.size() - 1) * sizeof(_e)); _t[0] = _e; } /// Concatenate two vectors of elements of POD types. template inline std::vector& operator+=(std::vector::value, T>::type>& _a, std::vector const& _b) { auto s = _a.size(); _a.resize(_a.size() + _b.size()); memcpy(_a.data() + s, _b.data(), _b.size() * sizeof(T)); return _a; } /// Concatenate two vectors of elements. template inline std::vector& operator+=(std::vector::value, T>::type>& _a, std::vector const& _b) { _a.reserve(_a.size() + _b.size()); for (auto& i: _b) _a.push_back(i); return _a; } /// Insert the contents of a container into a set template std::set& operator+=(std::set& _a, U const& _b) { for (auto const& i: _b) _a.insert(i); return _a; } /// Insert the contents of a container into an unordered_set template std::unordered_set& operator+=(std::unordered_set& _a, U const& _b) { for (auto const& i: _b) _a.insert(i); return _a; } /// Concatenate the contents of a container onto a vector template std::vector& operator+=(std::vector& _a, U const& _b) { for (auto const& i: _b) _a.push_back(i); return _a; } /// Insert the contents of a container into a set template std::set operator+(std::set _a, U const& _b) { return _a += _b; } /// Insert the contents of a container into an unordered_set template std::unordered_set operator+(std::unordered_set _a, U const& _b) { return _a += _b; } /// Concatenate the contents of a container onto a vector template std::vector operator+(std::vector _a, U const& _b) { return _a += _b; } /// Concatenate two vectors of elements. template inline std::vector operator+(std::vector const& _a, std::vector const& _b) { std::vector ret(_a); return ret += _b; } /// Merge two sets of elements. template inline std::set& operator+=(std::set& _a, std::set const& _b) { for (auto& i: _b) _a.insert(i); return _a; } /// Merge two sets of elements. template inline std::set operator+(std::set const& _a, std::set const& _b) { std::set ret(_a); return ret += _b; } template std::unordered_map& operator+=(std::unordered_map& _x, std::unordered_map const& _y) { for (auto const& i: _y) _x.insert(i); return _x; } template std::unordered_map operator+(std::unordered_map const& _x, std::unordered_map const& _y) { std::unordered_map ret(_x); return ret += _y; } /// Make normal string from fixed-length string. std::string toString(string32 const& _s); template std::vector keysOf(std::map const& _m) { std::vector ret; for (auto const& i: _m) ret.push_back(i.first); return ret; } template std::vector keysOf(std::unordered_map const& _m) { std::vector ret; for (auto const& i: _m) ret.push_back(i.first); return ret; } template bool contains(T const& _t, V const& _v) { return std::end(_t) != std::find(std::begin(_t), std::end(_t), _v); } }