aboutsummaryrefslogtreecommitdiffstats
path: root/libdevcore
diff options
context:
space:
mode:
authorchriseth <chris@ethereum.org>2018-11-14 02:33:35 +0800
committerGitHub <noreply@github.com>2018-11-14 02:33:35 +0800
commit1d4f565a64988a3400847d2655ca24f73f234bc6 (patch)
treecaaa6c26e307513505349b50ca4f2a8a9506752b /libdevcore
parent59dbf8f1085b8b92e8b7eb0ce380cbeb642e97eb (diff)
parent91b6b8a88e76016e0324036cb7a7f9300a1e2439 (diff)
downloaddexon-solidity-1d4f565a64988a3400847d2655ca24f73f234bc6.tar
dexon-solidity-1d4f565a64988a3400847d2655ca24f73f234bc6.tar.gz
dexon-solidity-1d4f565a64988a3400847d2655ca24f73f234bc6.tar.bz2
dexon-solidity-1d4f565a64988a3400847d2655ca24f73f234bc6.tar.lz
dexon-solidity-1d4f565a64988a3400847d2655ca24f73f234bc6.tar.xz
dexon-solidity-1d4f565a64988a3400847d2655ca24f73f234bc6.tar.zst
dexon-solidity-1d4f565a64988a3400847d2655ca24f73f234bc6.zip
Merge pull request #5416 from ethereum/develop
Merge develop into release for 0.5.0
Diffstat (limited to 'libdevcore')
-rw-r--r--libdevcore/Algorithms.h8
-rw-r--r--libdevcore/Common.h10
-rw-r--r--libdevcore/CommonData.cpp37
-rw-r--r--libdevcore/CommonData.h43
-rw-r--r--libdevcore/CommonIO.cpp60
-rw-r--r--libdevcore/CommonIO.h14
-rw-r--r--libdevcore/Exceptions.cpp6
-rw-r--r--libdevcore/FixedHash.h16
-rw-r--r--libdevcore/Keccak256.cpp186
-rw-r--r--libdevcore/Keccak256.h (renamed from libdevcore/SHA3.h)8
-rw-r--r--libdevcore/SHA3.cpp240
-rw-r--r--libdevcore/StringUtils.cpp19
-rw-r--r--libdevcore/StringUtils.h38
-rw-r--r--libdevcore/SwarmHash.cpp2
-rw-r--r--libdevcore/Visitor.h128
-rw-r--r--libdevcore/boost_multiprecision_number_compare_bug_workaround.hpp68
16 files changed, 509 insertions, 374 deletions
diff --git a/libdevcore/Algorithms.h b/libdevcore/Algorithms.h
index b2540668..7fe2472d 100644
--- a/libdevcore/Algorithms.h
+++ b/libdevcore/Algorithms.h
@@ -32,11 +32,13 @@ template <typename V>
class CycleDetector
{
public:
+ using Visitor = std::function<void(V const&, CycleDetector&, size_t)>;
+
/// Initializes the cycle detector
/// @param _visit function that is given the current vertex
/// and is supposed to call @a run on all
/// adjacent vertices.
- explicit CycleDetector(std::function<void(V const&, CycleDetector&)> _visit):
+ explicit CycleDetector(Visitor _visit):
m_visit(std::move(_visit))
{ }
@@ -55,7 +57,7 @@ public:
m_processing.insert(&_vertex);
m_depth++;
- m_visit(_vertex, *this);
+ m_visit(_vertex, *this, m_depth);
m_depth--;
if (m_firstCycleVertex && m_depth == 1)
m_firstCycleVertex = &_vertex;
@@ -66,7 +68,7 @@ public:
}
private:
- std::function<void(V const&, CycleDetector&)> m_visit;
+ Visitor m_visit;
std::set<V const*> m_processing;
std::set<V const*> m_processed;
size_t m_depth = 0;
diff --git a/libdevcore/Common.h b/libdevcore/Common.h
index 2543855d..6208424e 100644
--- a/libdevcore/Common.h
+++ b/libdevcore/Common.h
@@ -40,7 +40,6 @@
#include <libdevcore/vector_ref.h>
#if defined(__GNUC__)
-#pragma warning(push)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#endif // defined(__GNUC__)
@@ -57,7 +56,6 @@
#include <boost/multiprecision/cpp_int.hpp>
#if defined(__GNUC__)
-#pragma warning(pop)
#pragma GCC diagnostic pop
#endif // defined(__GNUC__)
@@ -66,15 +64,13 @@
#include <functional>
#include <string>
-using byte = uint8_t;
-
namespace dev
{
// Binary data types.
-using bytes = std::vector<byte>;
-using bytesRef = vector_ref<byte>;
-using bytesConstRef = vector_ref<byte const>;
+using bytes = std::vector<uint8_t>;
+using bytesRef = vector_ref<uint8_t>;
+using bytesConstRef = vector_ref<uint8_t const>;
// Numeric types.
using bigint = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<>>;
diff --git a/libdevcore/CommonData.cpp b/libdevcore/CommonData.cpp
index 445d11cd..8d2639c9 100644
--- a/libdevcore/CommonData.cpp
+++ b/libdevcore/CommonData.cpp
@@ -22,7 +22,7 @@
#include <libdevcore/CommonData.h>
#include <libdevcore/Exceptions.h>
#include <libdevcore/Assertions.h>
-#include <libdevcore/SHA3.h>
+#include <libdevcore/Keccak256.h>
#include <boost/algorithm/string.hpp>
@@ -64,7 +64,7 @@ bytes dev::fromHex(std::string const& _s, WhenError _throw)
int h = fromHex(_s[i], WhenError::DontThrow);
int l = fromHex(_s[i + 1], WhenError::DontThrow);
if (h != -1 && l != -1)
- ret.push_back((byte)(h * 16 + l));
+ ret.push_back((uint8_t)(h * 16 + l));
else if (_throw == WhenError::Throw)
BOOST_THROW_EXCEPTION(BadHexCharacter());
else
@@ -76,18 +76,18 @@ bytes dev::fromHex(std::string const& _s, WhenError _throw)
bool dev::passesAddressChecksum(string const& _str, bool _strict)
{
- string s = _str.substr(0, 2) == "0x" ? _str.substr(2) : _str;
+ string s = _str.substr(0, 2) == "0x" ? _str : "0x" + _str;
- if (s.length() != 40)
+ if (s.length() != 42)
return false;
if (!_strict && (
- _str.find_first_of("abcdef") == string::npos ||
- _str.find_first_of("ABCDEF") == string::npos
+ s.find_first_of("abcdef") == string::npos ||
+ s.find_first_of("ABCDEF") == string::npos
))
return true;
- return _str == dev::getChecksummedAddress(_str);
+ return s == dev::getChecksummedAddress(s);
}
string dev::getChecksummedAddress(string const& _addr)
@@ -110,3 +110,26 @@ string dev::getChecksummedAddress(string const& _addr)
}
return ret;
}
+
+bool dev::isValidHex(string const& _string)
+{
+ if (_string.substr(0, 2) != "0x")
+ return false;
+ if (_string.find_first_not_of("0123456789abcdefABCDEF", 2) != string::npos)
+ return false;
+ return true;
+}
+
+bool dev::isValidDecimal(string const& _string)
+{
+ if (_string.empty())
+ return false;
+ if (_string == "0")
+ return true;
+ // No leading zeros
+ if (_string.front() == '0')
+ return false;
+ if (_string.find_first_not_of("0123456789") != string::npos)
+ return false;
+ return true;
+}
diff --git a/libdevcore/CommonData.h b/libdevcore/CommonData.h
index e410af5c..fedd3af2 100644
--- a/libdevcore/CommonData.h
+++ b/libdevcore/CommonData.h
@@ -25,11 +25,14 @@
#include <libdevcore/Common.h>
+#include <boost/optional.hpp>
+
#include <vector>
#include <type_traits>
#include <cstring>
#include <string>
#include <set>
+#include <functional>
namespace dev
{
@@ -85,7 +88,7 @@ inline std::string asString(bytesConstRef _b)
/// 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()));
+ return bytes((uint8_t const*)_b.data(), (uint8_t const*)(_b.data() + _b.size()));
}
// Big-endian to/from host endian conversion functions.
@@ -114,7 +117,7 @@ inline T fromBigEndian(_In const& _bytes)
{
T ret = (T)0;
for (auto i: _bytes)
- ret = (T)((ret << 8) | (byte)(typename std::make_unsigned<typename _In::value_type>::type)i);
+ ret = (T)((ret << 8) | (uint8_t)(typename std::make_unsigned<typename _In::value_type>::type)i);
return ret;
}
inline bytes toBigEndian(u256 _val) { bytes ret(32); toBigEndian(_val, ret); return ret; }
@@ -132,7 +135,7 @@ inline bytes toCompactBigEndian(T _val, unsigned _min = 0)
toBigEndian(_val, ret);
return ret;
}
-inline bytes toCompactBigEndian(byte _val, unsigned _min = 0)
+inline bytes toCompactBigEndian(uint8_t _val, unsigned _min = 0)
{
return (_min || _val) ? bytes{ _val } : bytes{};
}
@@ -229,6 +232,37 @@ bool contains(T const& _t, V const& _v)
return std::end(_t) != std::find(std::begin(_t), std::end(_t), _v);
}
+
+/// Function that iterates over a vector, calling a function on each of its
+/// elements. If that function returns a vector, the element is replaced by
+/// the returned vector. During the iteration, the original vector is only valid
+/// on the current element and after that. The actual replacement takes
+/// place at the end, but already visited elements might be invalidated.
+/// If nothing is replaced, no copy is performed.
+template <typename T, typename F>
+void iterateReplacing(std::vector<T>& _vector, const F& _f)
+{
+ // Concept: _f must be Callable, must accept param T&, must return optional<vector<T>>
+ bool useModified = false;
+ std::vector<T> modifiedVector;
+ for (size_t i = 0; i < _vector.size(); ++i)
+ {
+ if (boost::optional<std::vector<T>> r = _f(_vector[i]))
+ {
+ if (!useModified)
+ {
+ std::move(_vector.begin(), _vector.begin() + i, back_inserter(modifiedVector));
+ useModified = true;
+ }
+ modifiedVector += std::move(*r);
+ }
+ else if (useModified)
+ modifiedVector.emplace_back(std::move(_vector[i]));
+ }
+ if (useModified)
+ _vector = std::move(modifiedVector);
+}
+
/// @returns true iff @a _str passess the hex address checksum test.
/// @param _strict if false, hex strings with only uppercase or only lowercase letters
/// are considered valid.
@@ -238,4 +272,7 @@ bool passesAddressChecksum(std::string const& _str, bool _strict);
/// @param hex strings that look like an address
std::string getChecksummedAddress(std::string const& _addr);
+bool isValidHex(std::string const& _string);
+bool isValidDecimal(std::string const& _string);
+
}
diff --git a/libdevcore/CommonIO.cpp b/libdevcore/CommonIO.cpp
index 0063a8d4..cc730575 100644
--- a/libdevcore/CommonIO.cpp
+++ b/libdevcore/CommonIO.cpp
@@ -23,7 +23,6 @@
#include <iostream>
#include <cstdlib>
#include <fstream>
-#include <stdio.h>
#if defined(_WIN32)
#include <windows.h>
#else
@@ -81,45 +80,6 @@ string dev::readStandardInput()
return ret;
}
-void dev::writeFile(std::string const& _file, bytesConstRef _data, bool _writeDeleteRename)
-{
- namespace fs = boost::filesystem;
- if (_writeDeleteRename)
- {
- fs::path tempPath = fs::unique_path(_file + "-%%%%%%");
- writeFile(tempPath.string(), _data, false);
- // will delete _file if it exists
- fs::rename(tempPath, _file);
- }
- else
- {
- // create directory if not existent
- fs::path p(_file);
- if (!fs::exists(p.parent_path()))
- {
- fs::create_directories(p.parent_path());
- try
- {
- fs::permissions(p.parent_path(), fs::owner_all);
- }
- catch (...)
- {
- }
- }
-
- ofstream s(_file, ios::trunc | ios::binary);
- s.write(reinterpret_cast<char const*>(_data.data()), _data.size());
- assertThrow(s, FileError, "Could not write to file: " + _file);
- try
- {
- fs::permissions(_file, fs::owner_read|fs::owner_write);
- }
- catch (...)
- {
- }
- }
-}
-
#if defined(_WIN32)
class DisableConsoleBuffering
{
@@ -187,3 +147,23 @@ boost::filesystem::path dev::weaklyCanonicalFilesystemPath(boost::filesystem::pa
return head / tail;
}
}
+
+string dev::absolutePath(string const& _path, string const& _reference)
+{
+ boost::filesystem::path p(_path);
+ // Anything that does not start with `.` is an absolute path.
+ if (p.begin() == p.end() || (*p.begin() != "." && *p.begin() != ".."))
+ return _path;
+ boost::filesystem::path result(_reference);
+ result.remove_filename();
+ for (boost::filesystem::path::iterator it = p.begin(); it != p.end(); ++it)
+ if (*it == "..")
+ result = result.parent_path();
+ else if (*it != ".")
+ result /= *it;
+ return result.generic_string();
+}
+
+string dev::sanitizePath(string const& _path) {
+ return boost::filesystem::path(_path).generic_string();
+}
diff --git a/libdevcore/CommonIO.h b/libdevcore/CommonIO.h
index 9ba68e74..b9f941ea 100644
--- a/libdevcore/CommonIO.h
+++ b/libdevcore/CommonIO.h
@@ -41,14 +41,6 @@ std::string readStandardInput();
/// Retrieve and returns a character from standard input (without waiting for EOL).
int readStandardInputChar();
-/// Write the given binary data into the given file, replacing the file if it pre-exists.
-/// Throws exception on error.
-/// @param _writeDeleteRename useful not to lose any data: If set, first writes to another file in
-/// the same directory and then moves that file.
-void writeFile(std::string const& _file, bytesConstRef _data, bool _writeDeleteRename = false);
-/// Write the given binary data into the given file, replacing the file if it pre-exists.
-inline void writeFile(std::string const& _file, bytes const& _data, bool _writeDeleteRename = false) { writeFile(_file, bytesConstRef(&_data), _writeDeleteRename); }
-inline void writeFile(std::string const& _file, std::string const& _data, bool _writeDeleteRename = false) { writeFile(_file, bytesConstRef(_data), _writeDeleteRename); }
/// Converts arbitrary value to string representation using std::stringstream.
template <class _T>
std::string toString(_T const& _t)
@@ -62,4 +54,10 @@ std::string toString(_T const& _t)
/// Should be replaced by the boost implementation as soon as support for boost<1.60 can be dropped.
boost::filesystem::path weaklyCanonicalFilesystemPath(boost::filesystem::path const &_path);
+/// @returns the absolute path corresponding to @a _path relative to @a _reference.
+std::string absolutePath(std::string const& _path, std::string const& _reference);
+
+/// Helper function to return path converted strings.
+std::string sanitizePath(std::string const& _path);
+
}
diff --git a/libdevcore/Exceptions.cpp b/libdevcore/Exceptions.cpp
index f204dbc2..cff5abf4 100644
--- a/libdevcore/Exceptions.cpp
+++ b/libdevcore/Exceptions.cpp
@@ -17,8 +17,6 @@
#include <libdevcore/Exceptions.h>
-#include <boost/lexical_cast.hpp>
-
using namespace std;
using namespace dev;
@@ -27,7 +25,7 @@ char const* Exception::what() const noexcept
// Return the comment if available.
if (string const* cmt = comment())
return cmt->data();
-
+
// Fallback to base what().
// Boost accepts nullptr, but the C++ standard doesn't
// and crashes on some platforms.
@@ -43,7 +41,7 @@ string Exception::lineInfo() const
ret += *file;
ret += ':';
if (line)
- ret += boost::lexical_cast<string>(*line);
+ ret += to_string(*line);
return ret;
}
diff --git a/libdevcore/FixedHash.h b/libdevcore/FixedHash.h
index cd6e1da1..24b89840 100644
--- a/libdevcore/FixedHash.h
+++ b/libdevcore/FixedHash.h
@@ -79,7 +79,7 @@ public:
operator Arith() const { return fromBigEndian<Arith>(m_data); }
/// @returns true iff this is the empty hash.
- explicit operator bool() const { return std::any_of(m_data.begin(), m_data.end(), [](byte _b) { return _b != 0; }); }
+ explicit operator bool() const { return std::any_of(m_data.begin(), m_data.end(), [](uint8_t _b) { return _b != 0; }); }
// The obvious comparison operators.
bool operator==(FixedHash const& _c) const { return m_data == _c.m_data; }
@@ -90,9 +90,9 @@ public:
FixedHash operator~() const { FixedHash ret; for (unsigned i = 0; i < N; ++i) ret[i] = ~m_data[i]; return ret; }
/// @returns a particular byte from the hash.
- byte& operator[](unsigned _i) { return m_data[_i]; }
+ uint8_t& operator[](unsigned _i) { return m_data[_i]; }
/// @returns a particular byte from the hash.
- byte operator[](unsigned _i) const { return m_data[_i]; }
+ 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()); }
@@ -104,19 +104,19 @@ public:
bytesConstRef ref() const { return bytesConstRef(m_data.data(), N); }
/// @returns a mutable byte pointer to the object's data.
- byte* data() { return m_data.data(); }
+ uint8_t* data() { return m_data.data(); }
/// @returns a constant byte pointer to the object's data.
- byte const* data() const { return m_data.data(); }
+ uint8_t const* data() const { return m_data.data(); }
/// @returns a copy of the object's data as a byte vector.
bytes asBytes() const { return bytes(data(), data() + N); }
/// @returns a mutable reference to the object's data as an STL array.
- std::array<byte, N>& asArray() { return m_data; }
+ std::array<uint8_t, N>& asArray() { return m_data; }
/// @returns a constant reference to the object's data as an STL array.
- std::array<byte, N> const& asArray() const { return m_data; }
+ std::array<uint8_t, N> const& asArray() const { return m_data; }
/// Returns the index of the first bit set to one, or size() * 8 if no bits are set.
inline unsigned firstBitSet() const
@@ -137,7 +137,7 @@ public:
void clear() { m_data.fill(0); }
private:
- std::array<byte, N> m_data; ///< The binary data.
+ std::array<uint8_t, N> m_data; ///< The binary data.
};
/// Stream I/O for the FixedHash class.
diff --git a/libdevcore/Keccak256.cpp b/libdevcore/Keccak256.cpp
new file mode 100644
index 00000000..7933fc7e
--- /dev/null
+++ b/libdevcore/Keccak256.cpp
@@ -0,0 +1,186 @@
+/*
+ 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/>.
+*/
+/** @file SHA3.cpp
+ * @author Gav Wood <i@gavwood.com>
+ * @date 2014
+ */
+
+#include <libdevcore/Keccak256.h>
+
+#include <cstdint>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+
+using namespace std;
+using namespace dev;
+
+namespace dev
+{
+
+namespace
+{
+
+/** libkeccak-tiny
+ *
+ * A single-file implementation of SHA-3 and SHAKE.
+ *
+ * Implementor: David Leon Gil
+ * License: CC0, attribution kindly requested. Blame taken too,
+ * but not liability.
+ */
+
+/******** The Keccak-f[1600] permutation ********/
+
+/*** Constants. ***/
+static const uint8_t rho[24] = \
+ { 1, 3, 6, 10, 15, 21,
+ 28, 36, 45, 55, 2, 14,
+ 27, 41, 56, 8, 25, 43,
+ 62, 18, 39, 61, 20, 44};
+static const uint8_t pi[24] = \
+ {10, 7, 11, 17, 18, 3,
+ 5, 16, 8, 21, 24, 4,
+ 15, 23, 19, 13, 12, 2,
+ 20, 14, 22, 9, 6, 1};
+static const uint64_t RC[24] = \
+ {1ULL, 0x8082ULL, 0x800000000000808aULL, 0x8000000080008000ULL,
+ 0x808bULL, 0x80000001ULL, 0x8000000080008081ULL, 0x8000000000008009ULL,
+ 0x8aULL, 0x88ULL, 0x80008009ULL, 0x8000000aULL,
+ 0x8000808bULL, 0x800000000000008bULL, 0x8000000000008089ULL, 0x8000000000008003ULL,
+ 0x8000000000008002ULL, 0x8000000000000080ULL, 0x800aULL, 0x800000008000000aULL,
+ 0x8000000080008081ULL, 0x8000000000008080ULL, 0x80000001ULL, 0x8000000080008008ULL};
+
+/*** Helper macros to unroll the permutation. ***/
+#define rol(x, s) (((x) << s) | ((x) >> (64 - s)))
+#define REPEAT6(e) e e e e e e
+#define REPEAT24(e) REPEAT6(e e e e)
+#define REPEAT5(e) e e e e e
+#define FOR5(v, s, e) \
+ v = 0; \
+ REPEAT5(e; v += s;)
+
+/*** Keccak-f[1600] ***/
+static inline void keccakf(void* state) {
+ uint64_t* a = (uint64_t*)state;
+ uint64_t b[5] = {0};
+
+ for (int i = 0; i < 24; i++)
+ {
+ uint8_t x, y;
+ // Theta
+ FOR5(x, 1,
+ b[x] = 0;
+ FOR5(y, 5,
+ b[x] ^= a[x + y]; ))
+ FOR5(x, 1,
+ FOR5(y, 5,
+ a[y + x] ^= b[(x + 4) % 5] ^ rol(b[(x + 1) % 5], 1); ))
+ // Rho and pi
+ uint64_t t = a[1];
+ x = 0;
+ REPEAT24(b[0] = a[pi[x]];
+ a[pi[x]] = rol(t, rho[x]);
+ t = b[0];
+ x++; )
+ // Chi
+ FOR5(y,
+ 5,
+ FOR5(x, 1,
+ b[x] = a[y + x];)
+ FOR5(x, 1,
+ a[y + x] = b[x] ^ ((~b[(x + 1) % 5]) & b[(x + 2) % 5]); ))
+ // Iota
+ a[0] ^= RC[i];
+ }
+}
+
+/******** The FIPS202-defined functions. ********/
+
+/*** Some helper macros. ***/
+
+#define _(S) do { S } while (0)
+#define FOR(i, ST, L, S) \
+ _(for (size_t i = 0; i < L; i += ST) { S; })
+#define mkapply_ds(NAME, S) \
+ static inline void NAME(uint8_t* dst, \
+ const uint8_t* src, \
+ size_t len) { \
+ FOR(i, 1, len, S); \
+ }
+#define mkapply_sd(NAME, S) \
+ static inline void NAME(const uint8_t* src, \
+ uint8_t* dst, \
+ size_t len) { \
+ FOR(i, 1, len, S); \
+ }
+
+mkapply_ds(xorin, dst[i] ^= src[i]) // xorin
+mkapply_sd(setout, dst[i] = src[i]) // setout
+
+#define P keccakf
+#define Plen 200
+
+// Fold P*F over the full blocks of an input.
+#define foldP(I, L, F) \
+ while (L >= rate) { \
+ F(a, I, rate); \
+ P(a); \
+ I += rate; \
+ L -= rate; \
+ }
+
+/** The sponge-based hash construction. **/
+inline void hash(
+ uint8_t* out,
+ size_t outlen,
+ const uint8_t* in,
+ size_t inlen,
+ size_t rate,
+ uint8_t delim
+)
+{
+ uint8_t a[Plen] = {0};
+ // Absorb input.
+ foldP(in, inlen, xorin);
+ // Xor in the DS and pad frame.
+ a[inlen] ^= delim;
+ a[rate - 1] ^= 0x80;
+ // Xor in the last block.
+ xorin(a, in, inlen);
+ // Apply P
+ P(a);
+ // Squeeze output.
+ foldP(out, outlen, setout);
+ setout(a, out, outlen);
+ memset(a, 0, 200);
+}
+
+}
+
+h256 keccak256(bytesConstRef _input)
+{
+ h256 output;
+ // Parameters used:
+ // The 0x01 is the specific padding for keccak (sha3 uses 0x06) and
+ // the way the round size (or window or whatever it was) is calculated.
+ // 200 - (256 / 4) is the "rate"
+ hash(output.data(), output.size, _input.data(), _input.size(), 200 - (256 / 4), 0x01);
+ return output;
+}
+
+}
diff --git a/libdevcore/SHA3.h b/libdevcore/Keccak256.h
index d1e2cc98..0d5f69bb 100644
--- a/libdevcore/SHA3.h
+++ b/libdevcore/Keccak256.h
@@ -30,14 +30,8 @@
namespace dev
{
-// Keccak-256 convenience routines.
-
-/// Calculate Keccak-256 hash of the given input and load it into the given output.
-/// @returns false if o_output.size() != 32.
-bool keccak256(bytesConstRef _input, bytesRef o_output);
-
/// Calculate Keccak-256 hash of the given input, returning as a 256-bit hash.
-inline h256 keccak256(bytesConstRef _input) { h256 ret; keccak256(_input, ret.ref()); return ret; }
+h256 keccak256(bytesConstRef _input);
/// Calculate Keccak-256 hash of the given input, returning as a 256-bit hash.
inline h256 keccak256(bytes const& _input) { return keccak256(bytesConstRef(&_input)); }
diff --git a/libdevcore/SHA3.cpp b/libdevcore/SHA3.cpp
deleted file mode 100644
index b0e40ccb..00000000
--- a/libdevcore/SHA3.cpp
+++ /dev/null
@@ -1,240 +0,0 @@
-/*
- 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/>.
-*/
-/** @file SHA3.cpp
- * @author Gav Wood <i@gavwood.com>
- * @date 2014
- */
-
-#include "SHA3.h"
-#include <cstdint>
-#include <cstdio>
-#include <cstdlib>
-#include <cstring>
-
-using namespace std;
-using namespace dev;
-
-namespace dev
-{
-
-namespace keccak
-{
-
-/** libkeccak-tiny
- *
- * A single-file implementation of SHA-3 and SHAKE.
- *
- * Implementor: David Leon Gil
- * License: CC0, attribution kindly requested. Blame taken too,
- * but not liability.
- */
-
-#define decshake(bits) \
- int shake##bits(uint8_t*, size_t, const uint8_t*, size_t);
-
-#define decsha3(bits) \
- int sha3_##bits(uint8_t*, size_t, const uint8_t*, size_t);
-
-#define deckeccak(bits) \
- int keccak##bits(uint8_t*, size_t, const uint8_t*, size_t);
-
-decshake(128)
-decshake(256)
-decsha3(224)
-decsha3(256)
-decsha3(384)
-decsha3(512)
-deckeccak(224)
-deckeccak(256)
-deckeccak(384)
-deckeccak(512)
-
-/******** The Keccak-f[1600] permutation ********/
-
-/*** Constants. ***/
-static const uint8_t rho[24] = \
- { 1, 3, 6, 10, 15, 21,
- 28, 36, 45, 55, 2, 14,
- 27, 41, 56, 8, 25, 43,
- 62, 18, 39, 61, 20, 44};
-static const uint8_t pi[24] = \
- {10, 7, 11, 17, 18, 3,
- 5, 16, 8, 21, 24, 4,
- 15, 23, 19, 13, 12, 2,
- 20, 14, 22, 9, 6, 1};
-static const uint64_t RC[24] = \
- {1ULL, 0x8082ULL, 0x800000000000808aULL, 0x8000000080008000ULL,
- 0x808bULL, 0x80000001ULL, 0x8000000080008081ULL, 0x8000000000008009ULL,
- 0x8aULL, 0x88ULL, 0x80008009ULL, 0x8000000aULL,
- 0x8000808bULL, 0x800000000000008bULL, 0x8000000000008089ULL, 0x8000000000008003ULL,
- 0x8000000000008002ULL, 0x8000000000000080ULL, 0x800aULL, 0x800000008000000aULL,
- 0x8000000080008081ULL, 0x8000000000008080ULL, 0x80000001ULL, 0x8000000080008008ULL};
-
-/*** Helper macros to unroll the permutation. ***/
-#define rol(x, s) (((x) << s) | ((x) >> (64 - s)))
-#define REPEAT6(e) e e e e e e
-#define REPEAT24(e) REPEAT6(e e e e)
-#define REPEAT5(e) e e e e e
-#define FOR5(v, s, e) \
- v = 0; \
- REPEAT5(e; v += s;)
-
-/*** Keccak-f[1600] ***/
-static inline void keccakf(void* state) {
- uint64_t* a = (uint64_t*)state;
- uint64_t b[5] = {0};
-
- for (int i = 0; i < 24; i++) {
- uint8_t x, y;
- // Theta
- FOR5(x, 1,
- b[x] = 0;
- FOR5(y, 5,
- b[x] ^= a[x + y]; ))
- FOR5(x, 1,
- FOR5(y, 5,
- a[y + x] ^= b[(x + 4) % 5] ^ rol(b[(x + 1) % 5], 1); ))
- // Rho and pi
- uint64_t t = a[1];
- x = 0;
- REPEAT24(b[0] = a[pi[x]];
- a[pi[x]] = rol(t, rho[x]);
- t = b[0];
- x++; )
- // Chi
- FOR5(y,
- 5,
- FOR5(x, 1,
- b[x] = a[y + x];)
- FOR5(x, 1,
- a[y + x] = b[x] ^ ((~b[(x + 1) % 5]) & b[(x + 2) % 5]); ))
- // Iota
- a[0] ^= RC[i];
- }
-}
-
-/******** The FIPS202-defined functions. ********/
-
-/*** Some helper macros. ***/
-
-#define _(S) do { S } while (0)
-#define FOR(i, ST, L, S) \
- _(for (size_t i = 0; i < L; i += ST) { S; })
-#define mkapply_ds(NAME, S) \
- static inline void NAME(uint8_t* dst, \
- const uint8_t* src, \
- size_t len) { \
- FOR(i, 1, len, S); \
- }
-#define mkapply_sd(NAME, S) \
- static inline void NAME(const uint8_t* src, \
- uint8_t* dst, \
- size_t len) { \
- FOR(i, 1, len, S); \
- }
-
-mkapply_ds(xorin, dst[i] ^= src[i]) // xorin
-mkapply_sd(setout, dst[i] = src[i]) // setout
-
-#define P keccakf
-#define Plen 200
-
-// Fold P*F over the full blocks of an input.
-#define foldP(I, L, F) \
- while (L >= rate) { \
- F(a, I, rate); \
- P(a); \
- I += rate; \
- L -= rate; \
- }
-
-/** The sponge-based hash construction. **/
-static inline int hash(uint8_t* out, size_t outlen,
- const uint8_t* in, size_t inlen,
- size_t rate, uint8_t delim) {
- if ((out == NULL) || ((in == NULL) && inlen != 0) || (rate >= Plen)) {
- return -1;
- }
- uint8_t a[Plen] = {0};
- // Absorb input.
- foldP(in, inlen, xorin);
- // Xor in the DS and pad frame.
- a[inlen] ^= delim;
- a[rate - 1] ^= 0x80;
- // Xor in the last block.
- xorin(a, in, inlen);
- // Apply P
- P(a);
- // Squeeze output.
- foldP(out, outlen, setout);
- setout(a, out, outlen);
- memset(a, 0, 200);
- return 0;
-}
-
-/*** Helper macros to define SHA3 and SHAKE instances. ***/
-#define defshake(bits) \
- int shake##bits(uint8_t* out, size_t outlen, \
- const uint8_t* in, size_t inlen) { \
- return hash(out, outlen, in, inlen, 200 - (bits / 4), 0x1f); \
- }
-#define defsha3(bits) \
- int sha3_##bits(uint8_t* out, size_t outlen, \
- const uint8_t* in, size_t inlen) { \
- if (outlen > (bits/8)) { \
- return -1; \
- } \
- return hash(out, outlen, in, inlen, 200 - (bits / 4), 0x06); \
- }
-#define defkeccak(bits) \
- int keccak##bits(uint8_t* out, size_t outlen, \
- const uint8_t* in, size_t inlen) { \
- if (outlen > (bits/8)) { \
- return -1; \
- } \
- return hash(out, outlen, in, inlen, 200 - (bits / 4), 0x01); \
- }
-
-/*** FIPS202 SHAKE VOFs ***/
-defshake(128)
-defshake(256)
-
-/*** FIPS202 SHA3 FOFs ***/
-defsha3(224)
-defsha3(256)
-defsha3(384)
-defsha3(512)
-
-/*** KECCAK FOFs ***/
-defkeccak(224)
-defkeccak(256)
-defkeccak(384)
-defkeccak(512)
-
-}
-
-bool keccak256(bytesConstRef _input, bytesRef o_output)
-{
- // FIXME: What with unaligned memory?
- if (o_output.size() != 32)
- return false;
- keccak::keccak256(o_output.data(), 32, _input.data(), _input.size());
-// keccak::keccak(ret.data(), 32, (uint64_t const*)_input.data(), _input.size());
- return true;
-}
-
-}
diff --git a/libdevcore/StringUtils.cpp b/libdevcore/StringUtils.cpp
index 2ff86bd5..50bf7cce 100644
--- a/libdevcore/StringUtils.cpp
+++ b/libdevcore/StringUtils.cpp
@@ -29,13 +29,16 @@
using namespace std;
using namespace dev;
-bool dev::stringWithinDistance(string const& _str1, string const& _str2, size_t _maxDistance)
+bool dev::stringWithinDistance(string const& _str1, string const& _str2, size_t _maxDistance, size_t _lenThreshold)
{
if (_str1 == _str2)
return true;
size_t n1 = _str1.size();
size_t n2 = _str2.size();
+ if (_lenThreshold > 0 && n1 * n2 > _lenThreshold)
+ return false;
+
size_t distance = stringDistance(_str1, _str2);
// if distance is not greater than _maxDistance, and distance is strictly less than length of both names, they can be considered similar
@@ -85,17 +88,11 @@ size_t dev::stringDistance(string const& _str1, string const& _str2)
string dev::quotedAlternativesList(vector<string> const& suggestions)
{
- if (suggestions.empty())
- return "";
- if (suggestions.size() == 1)
- return "\"" + suggestions.front() + "\"";
-
- string choices = "\"" + suggestions.front() + "\"";
- for (size_t i = 1; i + 1 < suggestions.size(); ++i)
- choices += ", \"" + suggestions[i] + "\"";
+ vector<string> quotedSuggestions;
- choices += " or \"" + suggestions.back() + "\"";
+ for (auto& suggestion: suggestions)
+ quotedSuggestions.push_back("\"" + suggestion + "\"");
- return choices;
+ return joinHumanReadable(quotedSuggestions, ", ", " or ");
}
diff --git a/libdevcore/StringUtils.h b/libdevcore/StringUtils.h
index acd93e32..b02b9d12 100644
--- a/libdevcore/StringUtils.h
+++ b/libdevcore/StringUtils.h
@@ -30,10 +30,46 @@ namespace dev
{
// Calculates the Damerau–Levenshtein distance between _str1 and _str2 and returns true if that distance is not greater than _maxDistance
-bool stringWithinDistance(std::string const& _str1, std::string const& _str2, size_t _maxDistance);
+// if _lenThreshold > 0 and the product of the strings length is greater than _lenThreshold, the function will return false
+bool stringWithinDistance(std::string const& _str1, std::string const& _str2, size_t _maxDistance, size_t _lenThreshold = 0);
// Calculates the Damerau–Levenshtein distance between _str1 and _str2
size_t stringDistance(std::string const& _str1, std::string const& _str2);
// Return a string having elements of suggestions as quoted, alternative suggestions. e.g. "a", "b" or "c"
std::string quotedAlternativesList(std::vector<std::string> const& suggestions);
+/// Joins collection of strings into one string with separators between, last separator can be different.
+/// @param _list collection of strings to join
+/// @param _separator defaults to ", "
+/// @param _lastSeparator (optional) will be used to separate last two strings instead of _separator
+/// @example join(vector<string>{"a", "b", "c"}, "; ", " or ") == "a; b or c"
+template<class T>
+std::string joinHumanReadable
+(
+ T const& _list,
+ std::string const& _separator = ", ",
+ std::string const& _lastSeparator = ""
+)
+{
+ auto const itEnd = end(_list);
+
+ std::string result;
+
+ for (auto it = begin(_list); it != itEnd; )
+ {
+ std::string element = *it;
+ bool first = (it == begin(_list));
+ ++it;
+ if (!first)
+ {
+ if (it == itEnd && !_lastSeparator.empty())
+ result += _lastSeparator; // last iteration
+ else
+ result += _separator;
+ }
+ result += std::move(element);
+ }
+
+ return result;
+}
+
}
diff --git a/libdevcore/SwarmHash.cpp b/libdevcore/SwarmHash.cpp
index 1c718200..3b8d2f3e 100644
--- a/libdevcore/SwarmHash.cpp
+++ b/libdevcore/SwarmHash.cpp
@@ -19,7 +19,7 @@
#include <libdevcore/SwarmHash.h>
-#include <libdevcore/SHA3.h>
+#include <libdevcore/Keccak256.h>
using namespace std;
using namespace dev;
diff --git a/libdevcore/Visitor.h b/libdevcore/Visitor.h
new file mode 100644
index 00000000..4030c928
--- /dev/null
+++ b/libdevcore/Visitor.h
@@ -0,0 +1,128 @@
+/*
+ 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/>.
+*/
+/**
+ * Visitor templates.
+ */
+
+#pragma once
+
+#include <functional>
+#include <boost/variant/static_visitor.hpp>
+
+namespace dev
+{
+
+/// Generic visitor used as follows:
+/// boost::apply_visitor(GenericVisitor<Class1, Class2>(
+/// [](Class1& _c) { _c.f(); },
+/// [](Class2& _c) { _c.g(); }
+/// ), variant);
+/// This one does not have a fallback and will fail at
+/// compile-time if you do not specify all variants.
+
+template <class...>
+struct GenericVisitor{};
+
+template <class Visitable, class... Others>
+struct GenericVisitor<Visitable, Others...>: public GenericVisitor<Others...>
+{
+ using GenericVisitor<Others...>::operator ();
+ explicit GenericVisitor(
+ std::function<void(Visitable&)> _visitor,
+ std::function<void(Others&)>... _otherVisitors
+ ):
+ GenericVisitor<Others...>(std::move(_otherVisitors)...),
+ m_visitor(std::move(_visitor))
+ {}
+
+ void operator()(Visitable& _v) const { m_visitor(_v); }
+
+ std::function<void(Visitable&)> m_visitor;
+};
+template <>
+struct GenericVisitor<>: public boost::static_visitor<> {
+ void operator()() const {}
+};
+
+/// Generic visitor with fallback:
+/// boost::apply_visitor(GenericFallbackVisitor<Class1, Class2>(
+/// [](Class1& _c) { _c.f(); },
+/// [](Class2& _c) { _c.g(); }
+/// ), variant);
+/// This one DOES have a fallback and will NOT fail at
+/// compile-time if you do not specify all variants.
+
+template <class...>
+struct GenericFallbackVisitor{};
+
+template <class Visitable, class... Others>
+struct GenericFallbackVisitor<Visitable, Others...>: public GenericFallbackVisitor<Others...>
+{
+ explicit GenericFallbackVisitor(
+ std::function<void(Visitable&)> _visitor,
+ std::function<void(Others&)>... _otherVisitors
+ ):
+ GenericFallbackVisitor<Others...>(std::move(_otherVisitors)...),
+ m_visitor(std::move(_visitor))
+ {}
+
+ using GenericFallbackVisitor<Others...>::operator ();
+ void operator()(Visitable& _v) const { m_visitor(_v); }
+
+ std::function<void(Visitable&)> m_visitor;
+};
+template <>
+struct GenericFallbackVisitor<>: public boost::static_visitor<> {
+ template <class T>
+ void operator()(T&) const { }
+};
+
+/// Generic visitor with fallback that can return a value:
+/// boost::apply_visitor(GenericFallbackReturnsVisitor<ReturnType, Class1, Class2>(
+/// [](Class1& _c) { return _c.f(); },
+/// [](Class2& _c) { return _c.g(); }
+/// ), variant);
+/// This one DOES have a fallback and will NOT fail at
+/// compile-time if you do not specify all variants.
+/// The fallback {}-constructs the return value.
+
+template <class R, class...>
+struct GenericFallbackReturnsVisitor{};
+
+template <class R, class Visitable, class... Others>
+struct GenericFallbackReturnsVisitor<R, Visitable, Others...>: public GenericFallbackReturnsVisitor<R, Others...>
+{
+ explicit GenericFallbackReturnsVisitor(
+ std::function<R(Visitable&)> _visitor,
+ std::function<R(Others&)>... _otherVisitors
+ ):
+ GenericFallbackReturnsVisitor<R, Others...>(std::move(_otherVisitors)...),
+ m_visitor(std::move(_visitor))
+ {}
+
+ using GenericFallbackReturnsVisitor<R, Others...>::operator ();
+ R operator()(Visitable& _v) const { return m_visitor(_v); }
+
+ std::function<R(Visitable&)> m_visitor;
+};
+template <class R>
+struct GenericFallbackReturnsVisitor<R>: public boost::static_visitor<R> {
+ template <class T>
+ R operator()(T&) const { return {}; }
+};
+
+}
diff --git a/libdevcore/boost_multiprecision_number_compare_bug_workaround.hpp b/libdevcore/boost_multiprecision_number_compare_bug_workaround.hpp
index dae591df..2568e17d 100644
--- a/libdevcore/boost_multiprecision_number_compare_bug_workaround.hpp
+++ b/libdevcore/boost_multiprecision_number_compare_bug_workaround.hpp
@@ -1,8 +1,8 @@
-// This is a copy of boost/multiprecision/detail/number_compare.hpp from boost 1.59 to replace buggy version from 1.58.
+// This is a copy of boost/multiprecision/detail/number_compare.hpp from boost 1.59 to replace buggy version from 1.58.
#ifdef BOOST_MP_COMPARE_HPP
-#error This bug workaround header must be included before original boost/multiprecision/detail/number_compare.hpp
+#error This bug workaround header must be included before original boost/multiprecision/detail/number_compare.hpp
#endif
///////////////////////////////////////////////////////////////////////////////
@@ -150,11 +150,11 @@ template <class B, expression_template_option ET>
struct is_valid_mixed_compare<number<B, ET>, number<B, ET> > : public mpl::false_ {};
template <class B, expression_template_option ET, class tag, class Arg1, class Arg2, class Arg3, class Arg4>
-struct is_valid_mixed_compare<number<B, ET>, expression<tag, Arg1, Arg2, Arg3, Arg4> >
+struct is_valid_mixed_compare<number<B, ET>, expression<tag, Arg1, Arg2, Arg3, Arg4> >
: public mpl::bool_<is_convertible<expression<tag, Arg1, Arg2, Arg3, Arg4>, number<B, ET> >::value> {};
template <class tag, class Arg1, class Arg2, class Arg3, class Arg4, class B, expression_template_option ET>
-struct is_valid_mixed_compare<expression<tag, Arg1, Arg2, Arg3, Arg4>, number<B, ET> >
+struct is_valid_mixed_compare<expression<tag, Arg1, Arg2, Arg3, Arg4>, number<B, ET> >
: public mpl::bool_<is_convertible<expression<tag, Arg1, Arg2, Arg3, Arg4>, number<B, ET> >::value> {};
template <class Backend, expression_template_option ExpressionTemplates>
@@ -196,7 +196,7 @@ inline bool operator == (const number<Backend, ExpressionTemplates>& a, const nu
return eval_eq(a.backend(), b.backend());
}
template <class Backend, expression_template_option ExpressionTemplates, class Arithmetic>
-inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type
+inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type
operator == (const number<Backend, ExpressionTemplates>& a, const Arithmetic& b)
{
using default_ops::eval_eq;
@@ -204,7 +204,7 @@ inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, Expre
return eval_eq(a.backend(), number<Backend, ExpressionTemplates>::canonical_value(b));
}
template <class Arithmetic, class Backend, expression_template_option ExpressionTemplates>
-inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type
+inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type
operator == (const Arithmetic& a, const number<Backend, ExpressionTemplates>& b)
{
using default_ops::eval_eq;
@@ -212,7 +212,7 @@ inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, Expre
return eval_eq(b.backend(), number<Backend, ExpressionTemplates>::canonical_value(a));
}
template <class Arithmetic, class Tag, class A1, class A2, class A3, class A4>
-inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type
+inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type
operator == (const Arithmetic& a, const detail::expression<Tag, A1, A2, A3, A4>& b)
{
typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type;
@@ -222,7 +222,7 @@ inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expr
return eval_eq(t.backend(), result_type::canonical_value(a));
}
template <class Tag, class A1, class A2, class A3, class A4, class Arithmetic>
-inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type
+inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type
operator == (const detail::expression<Tag, A1, A2, A3, A4>& a, const Arithmetic& b)
{
typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type;
@@ -232,7 +232,7 @@ inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expr
return eval_eq(t.backend(), result_type::canonical_value(b));
}
template <class Tag, class A1, class A2, class A3, class A4, class Tagb, class A1b, class A2b, class A3b, class A4b>
-inline typename enable_if<is_same<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type>, bool>::type
+inline typename enable_if<is_same<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type>, bool>::type
operator == (const detail::expression<Tag, A1, A2, A3, A4>& a, const detail::expression<Tagb, A1b, A2b, A3b, A4b>& b)
{
using default_ops::eval_eq;
@@ -250,7 +250,7 @@ inline bool operator != (const number<Backend, ExpressionTemplates>& a, const nu
return !eval_eq(a.backend(), b.backend());
}
template <class Backend, expression_template_option ExpressionTemplates, class Arithmetic>
-inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type
+inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type
operator != (const number<Backend, ExpressionTemplates>& a, const Arithmetic& b)
{
using default_ops::eval_eq;
@@ -258,7 +258,7 @@ inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, Expre
return !eval_eq(a.backend(), number<Backend, et_on>::canonical_value(b));
}
template <class Arithmetic, class Backend, expression_template_option ExpressionTemplates>
-inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type
+inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type
operator != (const Arithmetic& a, const number<Backend, ExpressionTemplates>& b)
{
using default_ops::eval_eq;
@@ -266,7 +266,7 @@ inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, Expre
return !eval_eq(b.backend(), number<Backend, et_on>::canonical_value(a));
}
template <class Arithmetic, class Tag, class A1, class A2, class A3, class A4>
-inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type
+inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type
operator != (const Arithmetic& a, const detail::expression<Tag, A1, A2, A3, A4>& b)
{
typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type;
@@ -276,7 +276,7 @@ inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expr
return !eval_eq(t.backend(), result_type::canonical_value(a));
}
template <class Tag, class A1, class A2, class A3, class A4, class Arithmetic>
-inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type
+inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type
operator != (const detail::expression<Tag, A1, A2, A3, A4>& a, const Arithmetic& b)
{
typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type;
@@ -286,7 +286,7 @@ inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expr
return !eval_eq(t.backend(), result_type::canonical_value(b));
}
template <class Tag, class A1, class A2, class A3, class A4, class Tagb, class A1b, class A2b, class A3b, class A4b>
-inline typename enable_if<is_same<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type>, bool>::type
+inline typename enable_if<is_same<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type>, bool>::type
operator != (const detail::expression<Tag, A1, A2, A3, A4>& a, const detail::expression<Tagb, A1b, A2b, A3b, A4b>& b)
{
using default_ops::eval_eq;
@@ -304,7 +304,7 @@ inline bool operator < (const number<Backend, ExpressionTemplates>& a, const num
return eval_lt(a.backend(), b.backend());
}
template <class Backend, expression_template_option ExpressionTemplates, class Arithmetic>
-inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type
+inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type
operator < (const number<Backend, ExpressionTemplates>& a, const Arithmetic& b)
{
using default_ops::eval_lt;
@@ -312,7 +312,7 @@ inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, Expre
return eval_lt(a.backend(), number<Backend, ExpressionTemplates>::canonical_value(b));
}
template <class Arithmetic, class Backend, expression_template_option ExpressionTemplates>
-inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type
+inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type
operator < (const Arithmetic& a, const number<Backend, ExpressionTemplates>& b)
{
using default_ops::eval_gt;
@@ -320,7 +320,7 @@ inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, Expre
return eval_gt(b.backend(), number<Backend, ExpressionTemplates>::canonical_value(a));
}
template <class Arithmetic, class Tag, class A1, class A2, class A3, class A4>
-inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type
+inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type
operator < (const Arithmetic& a, const detail::expression<Tag, A1, A2, A3, A4>& b)
{
typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type;
@@ -330,7 +330,7 @@ inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expr
return eval_gt(t.backend(), result_type::canonical_value(a));
}
template <class Tag, class A1, class A2, class A3, class A4, class Arithmetic>
-inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type
+inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type
operator < (const detail::expression<Tag, A1, A2, A3, A4>& a, const Arithmetic& b)
{
typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type;
@@ -340,7 +340,7 @@ inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expr
return eval_lt(t.backend(), result_type::canonical_value(b));
}
template <class Tag, class A1, class A2, class A3, class A4, class Tagb, class A1b, class A2b, class A3b, class A4b>
-inline typename enable_if<is_same<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type>, bool>::type
+inline typename enable_if<is_same<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type>, bool>::type
operator < (const detail::expression<Tag, A1, A2, A3, A4>& a, const detail::expression<Tagb, A1b, A2b, A3b, A4b>& b)
{
using default_ops::eval_lt;
@@ -358,7 +358,7 @@ inline bool operator > (const number<Backend, ExpressionTemplates>& a, const num
return eval_gt(a.backend(), b.backend());
}
template <class Backend, expression_template_option ExpressionTemplates, class Arithmetic>
-inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type
+inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type
operator > (const number<Backend, ExpressionTemplates>& a, const Arithmetic& b)
{
using default_ops::eval_gt;
@@ -366,7 +366,7 @@ inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, Expre
return eval_gt(a.backend(), number<Backend, ExpressionTemplates>::canonical_value(b));
}
template <class Arithmetic, class Backend, expression_template_option ExpressionTemplates>
-inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type
+inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type
operator > (const Arithmetic& a, const number<Backend, ExpressionTemplates>& b)
{
using default_ops::eval_lt;
@@ -374,7 +374,7 @@ inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, Expre
return eval_lt(b.backend(), number<Backend, ExpressionTemplates>::canonical_value(a));
}
template <class Arithmetic, class Tag, class A1, class A2, class A3, class A4>
-inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type
+inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type
operator > (const Arithmetic& a, const detail::expression<Tag, A1, A2, A3, A4>& b)
{
typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type;
@@ -384,7 +384,7 @@ inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expr
return a > t;
}
template <class Tag, class A1, class A2, class A3, class A4, class Arithmetic>
-inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type
+inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type
operator > (const detail::expression<Tag, A1, A2, A3, A4>& a, const Arithmetic& b)
{
typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type;
@@ -394,7 +394,7 @@ inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expr
return t > b;
}
template <class Tag, class A1, class A2, class A3, class A4, class Tagb, class A1b, class A2b, class A3b, class A4b>
-inline typename enable_if<is_same<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type>, bool>::type
+inline typename enable_if<is_same<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type>, bool>::type
operator > (const detail::expression<Tag, A1, A2, A3, A4>& a, const detail::expression<Tagb, A1b, A2b, A3b, A4b>& b)
{
using default_ops::eval_gt;
@@ -412,7 +412,7 @@ inline bool operator <= (const number<Backend, ExpressionTemplates>& a, const nu
return !eval_gt(a.backend(), b.backend());
}
template <class Backend, expression_template_option ExpressionTemplates, class Arithmetic>
-inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type
+inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type
operator <= (const number<Backend, ExpressionTemplates>& a, const Arithmetic& b)
{
using default_ops::eval_gt;
@@ -420,7 +420,7 @@ inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, Expre
return !eval_gt(a.backend(), number<Backend, ExpressionTemplates>::canonical_value(b));
}
template <class Arithmetic, class Backend, expression_template_option ExpressionTemplates>
-inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type
+inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type
operator <= (const Arithmetic& a, const number<Backend, ExpressionTemplates>& b)
{
using default_ops::eval_lt;
@@ -428,7 +428,7 @@ inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, Expre
return !eval_lt(b.backend(), number<Backend, ExpressionTemplates>::canonical_value(a));
}
template <class Arithmetic, class Tag, class A1, class A2, class A3, class A4>
-inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type
+inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type
operator <= (const Arithmetic& a, const detail::expression<Tag, A1, A2, A3, A4>& b)
{
typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type;
@@ -440,7 +440,7 @@ inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expr
return !eval_lt(t.backend(), result_type::canonical_value(a));
}
template <class Tag, class A1, class A2, class A3, class A4, class Arithmetic>
-inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type
+inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type
operator <= (const detail::expression<Tag, A1, A2, A3, A4>& a, const Arithmetic& b)
{
typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type;
@@ -450,7 +450,7 @@ inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expr
return !eval_gt(t.backend(), result_type::canonical_value(b));
}
template <class Tag, class A1, class A2, class A3, class A4, class Tagb, class A1b, class A2b, class A3b, class A4b>
-inline typename enable_if<is_same<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type>, bool>::type
+inline typename enable_if<is_same<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type>, bool>::type
operator <= (const detail::expression<Tag, A1, A2, A3, A4>& a, const detail::expression<Tagb, A1b, A2b, A3b, A4b>& b)
{
using default_ops::eval_gt;
@@ -468,7 +468,7 @@ inline bool operator >= (const number<Backend, ExpressionTemplates>& a, const nu
return !eval_lt(a.backend(), b.backend());
}
template <class Backend, expression_template_option ExpressionTemplates, class Arithmetic>
-inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type
+inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type
operator >= (const number<Backend, ExpressionTemplates>& a, const Arithmetic& b)
{
using default_ops::eval_lt;
@@ -476,7 +476,7 @@ inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, Expre
return !eval_lt(a.backend(), number<Backend, ExpressionTemplates>::canonical_value(b));
}
template <class Arithmetic, class Backend, expression_template_option ExpressionTemplates>
-inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type
+inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type
operator >= (const Arithmetic& a, const number<Backend, ExpressionTemplates>& b)
{
using default_ops::eval_gt;
@@ -484,7 +484,7 @@ inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, Expre
return !eval_gt(b.backend(), number<Backend, ExpressionTemplates>::canonical_value(a));
}
template <class Arithmetic, class Tag, class A1, class A2, class A3, class A4>
-inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type
+inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type
operator >= (const Arithmetic& a, const detail::expression<Tag, A1, A2, A3, A4>& b)
{
typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type;
@@ -494,7 +494,7 @@ inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expr
return !eval_gt(t.backend(), result_type::canonical_value(a));
}
template <class Tag, class A1, class A2, class A3, class A4, class Arithmetic>
-inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type
+inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type
operator >= (const detail::expression<Tag, A1, A2, A3, A4>& a, const Arithmetic& b)
{
typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type;
@@ -504,7 +504,7 @@ inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expr
return !eval_lt(t.backend(), result_type::canonical_value(b));
}
template <class Tag, class A1, class A2, class A3, class A4, class Tagb, class A1b, class A2b, class A3b, class A4b>
-inline typename enable_if<is_same<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type>, bool>::type
+inline typename enable_if<is_same<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type>, bool>::type
operator >= (const detail::expression<Tag, A1, A2, A3, A4>& a, const detail::expression<Tagb, A1b, A2b, A3b, A4b>& b)
{
using default_ops::eval_lt;