diff --git a/CodingStandards.txt b/CodingStandards.txt index afe4db0e9..727e53efb 100644 --- a/CodingStandards.txt +++ b/CodingStandards.txt @@ -1,7 +1,11 @@ 0. Formatting -a. Use tabs for indentation; 4 spaces wide. One indentation level -> exactly one byte (i.e. a tab character) in the source file. -b. Don't worry about having lines > 80-char wide. We're not editing on terminals anymore. +a. Use tabs for indentation! +- 1 tab is 4 spaces wide. +- One indentation level -> exactly one byte (i.e. a tab character) in the source file. +b. Line widths: +- Don't worry about having lines of code > 80-char wide. +- Lines of comments should be formatted according to ease of viewing, but simplicity is to be prefered over beauty. c. Don't use braces for condition-body one-liners. d. Never place condition bodies on same line as condition. e. Space between first paren and keyword, but *not* following first paren or preceeding final paren. @@ -21,7 +25,7 @@ if (a == b[i]) 1. Namespaces; -a. No "using" declarations in header files. +a. No "using namespace" declarations in header files. b. All symbols should be declared in a namespace except for final applications. c. Preprocessor symbols should be prefixed with the namespace in all-caps and an underscore. @@ -90,6 +94,7 @@ d. Favour declarations close to use; don't habitually declare at top of scope al e. Always pass non-trivial parameters with a const& suffix. f. If a function returns multiple values, use std::tuple (std::pair acceptable). Prefer not using */& arguments, except where efficiency requires. g. Never use a macro where adequate non-preprocessor C++ can be written. +h. Prefer "using NewType = OldType" to "typedef OldType NewType". (WRONG) const double d = 0; @@ -125,7 +130,25 @@ e. No implementations with the class declaration, except: -9. Commenting +9. Naming + +a. Collection conventions: +- -s means std::vector e.g. using MyTypes = std::vector +- -Set means std::set e.g. using MyTypeSet = std::set +- -Hash means std::unordered_set e.g. using MyTypeHash = std::unordered_set +b. Class conventions: +- -Face means the interface of some shared concept. (e.g. FooFace might be a pure virtual class.) +c. Avoid unpronouncable names; +- If you need to shorten a name favour a pronouncable slice of the original to a scatterred set of consonants. +- e.g. Manager shortens to Man rather than Mgr. +d. Avoid prefixes of initials (e.g. DON'T use IMyInterface, CMyImplementation) +e. A dictionary and thesaurus are your friends. +- Spell correctly. +- Find short, memorable & (at least semi-) descriptive names for commonly used classes or name-fragments. + + + +10. Commenting a. Comments should be doxygen-compilable, using @notation rather than \notation. diff --git a/libethereum/Common.cpp b/libethereum/Common.cpp index 471fcd0ce..b5c44d660 100644 --- a/libethereum/Common.cpp +++ b/libethereum/Common.cpp @@ -106,7 +106,7 @@ bytes eth::toHex(std::string const& _s) ((uint32_t) *((strptr)+1) << 8) | \ ((uint32_t) *(strptr))) -u256 eth::ripemd160(bytesConstRef _message) +u160 eth::ripemd160(bytesConstRef _message) /* * returns RMD(message) * message should be a string terminated by '\0' @@ -144,7 +144,7 @@ u256 eth::ripemd160(bytesConstRef _message) hashcode[i+3] = (MDbuf[i>>2] >> 24); } - u256 ret = 0; + u160 ret = 0; for (i = 0; i < RMDsize / 8; ++i) ret = (ret << 8) | hashcode[i]; return ret; diff --git a/libethereum/Common.h b/libethereum/Common.h index ae28ff883..4b0b408ff 100644 --- a/libethereum/Common.h +++ b/libethereum/Common.h @@ -35,12 +35,13 @@ namespace eth { +// Binary data types. using byte = uint8_t; using bytes = std::vector; - using bytesRef = vector_ref; using bytesConstRef = vector_ref; +// Numeric types. using bigint = boost::multiprecision::number>; using u256 = boost::multiprecision::number>; using s256 = boost::multiprecision::number>; @@ -51,13 +52,16 @@ using sint = int64_t; using u256s = std::vector; using u160s = std::vector; +// Map types. using StringMap = std::map; using u256Map = std::map; using HexMap = std::map; +// Null/Invalid values for convenience. static const u256 Invalid256 = ~(u256)0; static const bytes NullBytes; +/// Converts arbitrary value to string representation using std::stringstream. template std::string toString(_T const& _t) { @@ -66,11 +70,22 @@ std::string toString(_T const& _t) return o.str(); } +/// 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 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())); +} + +/// Convert a series of bytes to the corresponding string of hex duplets. +/// @param _w specifies the width of each of the elements. Defaults to two - enough to represent a byte. +/// @example asHex("A\x69") == "4169" template std::string asHex(_T const& _data, int _w = 2) { @@ -80,27 +95,51 @@ std::string asHex(_T const& _data, int _w = 2) return ret.str(); } +/// Trims a given number of elements from the front of a collection. +/// Only works for POD element types. template void trimFront(_T& _t, uint _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; } +/// Creates a random, printable, word. std::string randomWord(); + +/// 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); + +/// 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); + +/// Converts a (printable) ASCII hex string into the corresponding byte stream. +/// @example fromUserHex("41626261") == asBytes("Abba") bytes fromUserHex(std::string const& _s); + +/// Converts a string into the big-endian base-16 stream of integers (NOT ASCII). +/// @example toHex("A")[0] == 4 && toHex("A")[1] == 1 bytes toHex(std::string const& _s); +/// 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 uint, u160, u256 or bigint. template inline void toBigEndian(_T _val, _Out& o_out) { @@ -109,6 +148,9 @@ inline void toBigEndian(_T _val, _Out& o_out) o_out[s - 1 - i] = (typename _Out::value_type)(uint8_t)_val; } +/// 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 uint, u160, u256 or bigint. template inline _T fromBigEndian(_In const& _bytes) { @@ -118,12 +160,14 @@ inline _T fromBigEndian(_In const& _bytes) 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 string just big enough to represent @a _val. template inline std::string toCompactBigEndianString(_T _val) { @@ -134,6 +178,9 @@ inline std::string toCompactBigEndianString(_T _val) return ret; } +/// 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 uint commonPrefix(_T const& _t, _U const& _u) { @@ -144,22 +191,24 @@ uint commonPrefix(_T const& _t, _U const& _u) return s; } -u256 ripemd160(bytesConstRef _message); - +/// Convert the given value into u160 (160-bit unsigned integer) by taking the lowest order 160-bits and discarding the rest. template inline u160 low160(_T const& _t) { return (u160)(_t & ((((_T)1) << 160) - 1)); } +/// Convert the given value safely into u160 (160-bit unsigned integer). +/// @note Currently unsafe. template inline u160 as160(_T const& _t) { - return (u160)(_t & ((((_T)1) << 160) - 1)); + return low160(_t); } +/// Concatenate two vectors of elements. _T must be POD. template -inline std::vector<_T>& operator+=(std::vector<_T>& _a, std::vector<_T> const& _b) +inline std::vector<_T>& operator+=(std::vector::value, _T>::type>& _a, std::vector<_T> const& _b) { auto s = _a.size(); _a.resize(_a.size() + _b.size()); @@ -168,11 +217,15 @@ inline std::vector<_T>& operator+=(std::vector<_T>& _a, std::vector<_T> const& _ } +/// Concatenate two vectors of elements. _T must be POD. template -inline std::vector<_T> operator+(std::vector<_T> const& _a, std::vector<_T> const& _b) +inline std::vector<_T> operator+(std::vector::value, _T>::type> const& _a, std::vector<_T> const& _b) { std::vector<_T> ret(_a); return ret += _b; } +/// Calculate RIPEMD-160 hash of the given message. +u160 ripemd160(bytesConstRef _message); + }