1 // Aleth: Ethereum C++ client, tools and libraries.
2 // Copyright 2014-2019 Aleth Authors.
3 // Licensed under the GNU General Public License, Version 3.
4 
5 /// @file
6 /// Shared algorithms and data types.
7 #pragma once
8 
9 #include <vector>
10 #include <algorithm>
11 #include <unordered_set>
12 #include <type_traits>
13 #include <cstring>
14 #include <string>
15 #include "Common.h"
16 
17 namespace dev
18 {
19 
20 // String conversion functions, mainly to/from hex/nibble/byte representations.
21 
22 enum class WhenError
23 {
24 	DontThrow = 0,
25 	Throw = 1,
26 };
27 
28 template <class Iterator>
toHex(Iterator _it,Iterator _end,std::string const & _prefix)29 std::string toHex(Iterator _it, Iterator _end, std::string const& _prefix)
30 {
31 	typedef std::iterator_traits<Iterator> traits;
32 	static_assert(sizeof(typename traits::value_type) == 1, "toHex needs byte-sized element type");
33 
34 	static char const* hexdigits = "0123456789abcdef";
35 	size_t off = _prefix.size();
36 	std::string hex(std::distance(_it, _end)*2 + off, '0');
37 	hex.replace(0, off, _prefix);
38 	for (; _it != _end; _it++)
39 	{
40 		hex[off++] = hexdigits[(*_it >> 4) & 0x0f];
41 		hex[off++] = hexdigits[*_it & 0x0f];
42 	}
43 	return hex;
44 }
45 
46 /// Convert a series of bytes to the corresponding hex string.
47 /// @example toHex("A\x69") == "4169"
toHex(T const & _data)48 template <class T> std::string toHex(T const& _data)
49 {
50 	return toHex(_data.begin(), _data.end(), "");
51 }
52 
53 /// Convert a series of bytes to the corresponding hex string with 0x prefix.
54 /// @example toHexPrefixed("A\x69") == "0x4169"
toHexPrefixed(T const & _data)55 template <class T> std::string toHexPrefixed(T const& _data)
56 {
57 	return toHex(_data.begin(), _data.end(), "0x");
58 }
59 
60 /// Converts a (printable) ASCII hex string into the corresponding byte stream.
61 /// @example fromHex("41626261") == asBytes("Abba")
62 /// If _throw = ThrowType::DontThrow, it replaces bad hex characters with 0's, otherwise it will throw an exception.
63 bytes fromHex(std::string const& _s, WhenError _throw = WhenError::DontThrow);
64 
65 /// @returns true if @a _s is a hex string.
66 bool isHex(std::string const& _s) noexcept;
67 
68 /// @returns true if @a _hash is a hash conforming to FixedHash type @a T.
isHash(std::string const & _hash)69 template <class T> static bool isHash(std::string const& _hash)
70 {
71 	return (_hash.size() == T::size * 2 || (_hash.size() == T::size * 2 + 2 && _hash.substr(0, 2) == "0x")) && isHex(_hash);
72 }
73 
74 /// Converts byte array to a string containing the same (binary) data. Unless
75 /// the byte array happens to contain ASCII data, this won't be printable.
asString(bytes const & _b)76 inline std::string asString(bytes const& _b)
77 {
78 	return std::string((char const*)_b.data(), (char const*)(_b.data() + _b.size()));
79 }
80 
81 /// Converts byte array ref to a string containing the same (binary) data. Unless
82 /// the byte array happens to contain ASCII data, this won't be printable.
asString(bytesConstRef _b)83 inline std::string asString(bytesConstRef _b)
84 {
85 	return std::string((char const*)_b.data(), (char const*)(_b.data() + _b.size()));
86 }
87 
88 /// Converts a string to a byte array containing the string's (byte) data.
asBytes(std::string const & _b)89 inline bytes asBytes(std::string const& _b)
90 {
91 	return bytes((byte const*)_b.data(), (byte const*)(_b.data() + _b.size()));
92 }
93 
94 /// Converts a string into the big-endian base-16 stream of integers (NOT ASCII).
95 /// @example asNibbles("A")[0] == 4 && asNibbles("A")[1] == 1
96 bytes asNibbles(bytesConstRef const& _s);
97 
98 
99 // Big-endian to/from host endian conversion functions.
100 
101 /// Converts a templated integer value to the big-endian byte-stream represented on a templated collection.
102 /// The size of the collection object will be unchanged. If it is too small, it will not represent the
103 /// value properly, if too big then the additional elements will be zeroed out.
104 /// @a Out will typically be either std::string or bytes.
105 /// @a T will typically by unsigned, u160, u256 or bigint.
106 template <class T, class Out>
toBigEndian(T _val,Out & o_out)107 inline void toBigEndian(T _val, Out& o_out)
108 {
109 	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
110 	for (auto i = o_out.size(); i != 0; _val >>= 8, i--)
111 	{
112 		T v = _val & (T)0xff;
113 		o_out[i - 1] = (typename Out::value_type)(uint8_t)v;
114 	}
115 }
116 
117 /// Converts a big-endian byte-stream represented on a templated collection to a templated integer value.
118 /// @a _In will typically be either std::string or bytes.
119 /// @a T will typically by unsigned, u160, u256 or bigint.
120 template <class T, class _In>
fromBigEndian(_In const & _bytes)121 inline T fromBigEndian(_In const& _bytes)
122 {
123 	T ret = (T)0;
124 	for (auto i: _bytes)
125 		ret = (T)((ret << 8) | (byte)(typename std::make_unsigned<decltype(i)>::type)i);
126 	return ret;
127 }
128 
129 /// Convenience functions for toBigEndian
toBigEndianString(u256 _val)130 inline std::string toBigEndianString(u256 _val) { std::string ret(32, '\0'); toBigEndian(_val, ret); return ret; }
toBigEndianString(u160 _val)131 inline std::string toBigEndianString(u160 _val) { std::string ret(20, '\0'); toBigEndian(_val, ret); return ret; }
toBigEndian(u256 _val)132 inline bytes toBigEndian(u256 _val) { bytes ret(32); toBigEndian(_val, ret); return ret; }
toBigEndian(u160 _val)133 inline bytes toBigEndian(u160 _val) { bytes ret(20); toBigEndian(_val, ret); return ret; }
134 
135 /// Convenience function for toBigEndian.
136 /// @returns a byte array just big enough to represent @a _val.
137 template <class T>
138 inline bytes toCompactBigEndian(T _val, unsigned _min = 0)
139 {
140 	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
141 	int i = 0;
142 	for (T v = _val; v; ++i, v >>= 8) {}
143 	bytes ret(std::max<unsigned>(_min, i), 0);
144 	toBigEndian(_val, ret);
145 	return ret;
146 }
147 inline bytes toCompactBigEndian(byte _val, unsigned _min = 0)
148 {
149 	return (_min || _val) ? bytes{ _val } : bytes{};
150 }
151 
152 /// Convenience function for toBigEndian.
153 /// @returns a string just big enough to represent @a _val.
154 template <class T>
155 inline std::string toCompactBigEndianString(T _val, unsigned _min = 0)
156 {
157 	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
158 	int i = 0;
159 	for (T v = _val; v; ++i, v >>= 8) {}
160 	std::string ret(std::max<unsigned>(_min, i), '\0');
161 	toBigEndian(_val, ret);
162 	return ret;
163 }
164 
165 inline std::string toCompactHex(u256 _val, unsigned _min = 0)
166 {
167 	return toHex(toCompactBigEndian(_val, _min));
168 }
169 
170 inline std::string toCompactHexPrefixed(u256 _val, unsigned _min = 0)
171 {
172 	return toHexPrefixed(toCompactBigEndian(_val, _min));
173 }
174 
175 // Algorithms for string and string-like collections.
176 
177 /// Escapes a string into the C-string representation.
178 /// @p _all if true will escape all characters, not just the unprintable ones.
179 std::string escaped(std::string const& _s, bool _all = true);
180 
181 /// Determines the length of the common prefix of the two collections given.
182 /// @returns the number of elements both @a _t and @a _u share, in order, at the beginning.
183 /// @example commonPrefix("Hello world!", "Hello, world!") == 5
184 template <class T, class _U>
commonPrefix(T const & _t,_U const & _u)185 unsigned commonPrefix(T const& _t, _U const& _u)
186 {
187 	unsigned s = std::min<unsigned>(_t.size(), _u.size());
188 	for (unsigned i = 0;; ++i)
189 		if (i == s || _t[i] != _u[i])
190 			return i;
191 	return s;
192 }
193 
194 /// Determine bytes required to encode the given integer value. @returns 0 if @a _i is zero.
195 template <class T>
bytesRequired(T _i)196 inline unsigned bytesRequired(T _i)
197 {
198 	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
199 	unsigned i = 0;
200 	for (; _i != 0; ++i, _i >>= 8) {}
201 	return i;
202 }
203 
204 /// Trims a given number of elements from the front of a collection.
205 /// Only works for POD element types.
206 template <class T>
trimFront(T & _t,unsigned _elements)207 void trimFront(T& _t, unsigned _elements)
208 {
209 	static_assert(std::is_pod<typename T::value_type>::value, "");
210 	memmove(_t.data(), _t.data() + _elements, (_t.size() - _elements) * sizeof(_t[0]));
211 	_t.resize(_t.size() - _elements);
212 }
213 
214 /// Pushes an element on to the front of a collection.
215 /// Only works for POD element types.
216 template <class T, class _U>
pushFront(T & _t,_U _e)217 void pushFront(T& _t, _U _e)
218 {
219 	static_assert(std::is_pod<typename T::value_type>::value, "");
220 	_t.push_back(_e);
221 	memmove(_t.data() + 1, _t.data(), (_t.size() - 1) * sizeof(_e));
222 	_t[0] = _e;
223 }
224 
225 /// Concatenate the contents of a container onto a vector.
226 template <class T, class U>
227 inline std::vector<T>& operator+=(std::vector<T>& _a, U const& _b)
228 {
229     _a.insert(_a.end(), std::begin(_b), std::end(_b));
230     return _a;
231 }
232 
233 /// Insert the contents of a container into a set
234 template <class T, class U>
235 std::set<T>& operator+=(std::set<T>& _a, U const& _b)
236 {
237     _a.insert(std::begin(_b), std::end(_b));
238     return _a;
239 }
240 
241 /// Insert the contents of a container into an unordered_set
242 template <class T, class U>
243 std::unordered_set<T>& operator+=(std::unordered_set<T>& _a, U const& _b)
244 {
245     _a.insert(std::begin(_b), std::end(_b));
246     return _a;
247 }
248 
249 /// Insert the contents of a container into a set
250 template <class T, class U> std::set<T> operator+(std::set<T> _a, U const& _b)
251 {
252 	return _a += _b;
253 }
254 
255 /// Insert the contents of a container into an unordered_set
256 template <class T, class U> std::unordered_set<T> operator+(std::unordered_set<T> _a, U const& _b)
257 {
258 	return _a += _b;
259 }
260 
261 /// Concatenate the contents of a container onto a vector
262 template <class T, class U> std::vector<T> operator+(std::vector<T> _a, U const& _b)
263 {
264 	return _a += _b;
265 }
266 
267 /// Make normal string from fixed-length string.
268 std::string toString(string32 const& _s);
269 
270 template<class T, class U>
keysOf(std::map<T,U> const & _m)271 std::vector<T> keysOf(std::map<T, U> const& _m)
272 {
273 	std::vector<T> ret;
274 	for (auto const& i: _m)
275 		ret.push_back(i.first);
276 	return ret;
277 }
278 
279 template<class T, class U>
keysOf(std::unordered_map<T,U> const & _m)280 std::vector<T> keysOf(std::unordered_map<T, U> const& _m)
281 {
282 	std::vector<T> ret;
283 	for (auto const& i: _m)
284 		ret.push_back(i.first);
285 	return ret;
286 }
287 
288 template<class T, class U>
valuesOf(std::map<T,U> const & _m)289 std::vector<U> valuesOf(std::map<T, U> const& _m)
290 {
291 	std::vector<U> ret;
292 	ret.reserve(_m.size());
293 	for (auto const& i: _m)
294 		ret.push_back(i.second);
295 	return ret;
296 }
297 
298 template<class T, class U>
valuesOf(std::unordered_map<T,U> const & _m)299 std::vector<U> valuesOf(std::unordered_map<T, U> const& _m)
300 {
301 	std::vector<U> ret;
302 	ret.reserve(_m.size());
303 	for (auto const& i: _m)
304 		ret.push_back(i.second);
305 	return ret;
306 }
307 
308 template <class T, class V>
contains(T const & _t,V const & _v)309 bool contains(T const& _t, V const& _v)
310 {
311 	return std::end(_t) != std::find(std::begin(_t), std::end(_t), _v);
312 }
313 
314 template <class V>
contains(std::unordered_set<V> const & _set,V const & _v)315 bool contains(std::unordered_set<V> const& _set, V const& _v)
316 {
317     return _set.find(_v) != _set.end();
318 }
319 
320 template <class K, class V>
contains(std::unordered_map<K,V> const & _map,K const & _k)321 bool contains(std::unordered_map<K, V> const& _map, K const& _k)
322 {
323     return _map.find(_k) != _map.end();
324 }
325 
326 template <class V>
contains(std::set<V> const & _set,V const & _v)327 bool contains(std::set<V> const& _set, V const& _v)
328 {
329     return _set.find(_v) != _set.end();
330 }
331 
332 template <class K, class V>
contains(std::map<K,V> const & _map,K const & _k)333 bool contains(std::map<K, V> const& _map, K const& _k)
334 {
335     return _map.find(_k) != _map.end();
336 }
337 }
338