Library libdevcore renamed to libsolutil.

This commit is contained in:
Christian Parpart
2020-01-07 15:51:50 +01:00
committed by Daniel Kirchner
parent 8ac6258d31
commit 345f9928ab
241 changed files with 355 additions and 355 deletions
+122
View File
@@ -0,0 +1,122 @@
/*
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 <functional>
#include <set>
namespace solidity::util
{
/**
* Detector for cycles in directed graphs. It returns the first
* vertex on the path towards a cycle or a nullptr if there is
* no reachable cycle starting from a given vertex.
*/
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(Visitor _visit):
m_visit(std::move(_visit))
{ }
/// Recursively perform cycle detection starting
/// (or continuing) with @param _vertex
/// @returns the first vertex on the path towards a cycle from @a _vertex
/// or nullptr if no cycle is reachable from @a _vertex.
V const* run(V const& _vertex)
{
if (m_firstCycleVertex)
return m_firstCycleVertex;
if (m_processed.count(&_vertex))
return nullptr;
else if (m_processing.count(&_vertex))
return m_firstCycleVertex = &_vertex;
m_processing.insert(&_vertex);
m_depth++;
m_visit(_vertex, *this, m_depth);
m_depth--;
if (m_firstCycleVertex && m_depth == 1)
m_firstCycleVertex = &_vertex;
m_processing.erase(&_vertex);
m_processed.insert(&_vertex);
return m_firstCycleVertex;
}
private:
Visitor m_visit;
std::set<V const*> m_processing;
std::set<V const*> m_processed;
size_t m_depth = 0;
V const* m_firstCycleVertex = nullptr;
};
/**
* Generic breadth first search.
*
* Note that V needs to be a comparable value type. If it is not, use a pointer type,
* but note that this might lead to non-deterministic traversal.
*
* Example: Gather all (recursive) children in a graph starting at (and including) ``root``:
*
* Node const* root = ...;
* std::set<Node const*> allNodes = BreadthFirstSearch<Node const*>{{root}}.run([](Node const* _node, auto&& _addChild) {
* // Potentially process ``_node``.
* for (Node const& _child: _node->children())
* // Potentially filter the children to be visited.
* _addChild(&_child);
* }).visited;
*/
template<typename V>
struct BreadthFirstSearch
{
/// Runs the breadth first search. The verticesToTraverse member of the struct needs to be initialized.
/// @param _forEachChild is a callable of the form [...](V const& _node, auto&& _addChild) { ... }
/// that is called for each visited node and is supposed to call _addChild(childNode) for every child
/// node of _node.
template<typename ForEachChild>
BreadthFirstSearch& run(ForEachChild&& _forEachChild)
{
while (!verticesToTraverse.empty())
{
V v = *verticesToTraverse.begin();
verticesToTraverse.erase(verticesToTraverse.begin());
visited.insert(v);
_forEachChild(v, [this](V _vertex) {
if (!visited.count(_vertex))
verticesToTraverse.emplace(std::move(_vertex));
});
}
return *this;
}
std::set<V> verticesToTraverse;
std::set<V> visited{};
};
}
+91
View File
@@ -0,0 +1,91 @@
/*
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 <ostream>
#include <vector>
namespace solidity::util
{
namespace formatting
{
// control codes
static constexpr char const* RESET = "\033[0m";
static constexpr char const* INVERSE = "\033[7m";
static constexpr char const* BOLD = "\033[1m";
static constexpr char const* BRIGHT = BOLD;
// standard foreground colors
static constexpr char const* BLACK = "\033[30m";
static constexpr char const* RED = "\033[31m";
static constexpr char const* GREEN = "\033[32m";
static constexpr char const* YELLOW = "\033[33m";
static constexpr char const* BLUE = "\033[34m";
static constexpr char const* MAGENTA = "\033[35m";
static constexpr char const* CYAN = "\033[36m";
static constexpr char const* WHITE = "\033[37m";
// standard background colors
static constexpr char const* BLACK_BACKGROUND = "\033[40m";
static constexpr char const* RED_BACKGROUND = "\033[41m";
static constexpr char const* GREEN_BACKGROUND = "\033[42m";
static constexpr char const* YELLOW_BACKGROUND = "\033[43m";
static constexpr char const* BLUE_BACKGROUND = "\033[44m";
static constexpr char const* MAGENTA_BACKGROUND = "\033[45m";
static constexpr char const* CYAN_BACKGROUND = "\033[46m";
static constexpr char const* WHITE_BACKGROUND = "\033[47m";
// 256-bit-colors (incomplete set)
static constexpr char const* RED_BACKGROUND_256 = "\033[48;5;160m";
static constexpr char const* ORANGE_BACKGROUND_256 = "\033[48;5;166m";
}
/// AnsiColorized provides a convenience helper to colorize ostream with formatting-reset assured.
class AnsiColorized
{
public:
AnsiColorized(std::ostream& _os, bool const _enabled, std::vector<char const*>&& _formatting):
m_stream{_os}, m_enabled{_enabled}, m_codes{std::move(_formatting)}
{
if (m_enabled)
for (auto const& code: m_codes)
m_stream << code;
}
~AnsiColorized()
{
if (m_enabled)
m_stream << formatting::RESET;
}
template <typename T>
std::ostream& operator<<(T&& _t)
{
return m_stream << std::forward<T>(_t);
}
private:
std::ostream& m_stream;
bool m_enabled;
std::vector<char const*> m_codes;
};
}
+57
View File
@@ -0,0 +1,57 @@
/*
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 Assertions.h
* @author Christian <c@ethdev.com>
* @date 2015
*
* Assertion handling.
*/
#pragma once
#include <libsolutil/Exceptions.h>
namespace solidity::util
{
#if defined(_MSC_VER)
#define ETH_FUNC __FUNCSIG__
#elif defined(__GNUC__)
#define ETH_FUNC __PRETTY_FUNCTION__
#else
#define ETH_FUNC __func__
#endif
/// Assertion that throws an exception containing the given description if it is not met.
/// Use it as assertThrow(1 == 1, ExceptionType, "Mathematics is wrong.");
/// Do NOT supply an exception object as the second parameter.
#define assertThrow(_condition, _ExceptionType, _description) \
do \
{ \
if (!(_condition)) \
::boost::throw_exception( \
_ExceptionType() << \
::solidity::util::errinfo_comment(_description) << \
::boost::throw_function(ETH_FUNC) << \
::boost::throw_file(__FILE__) << \
::boost::throw_line(__LINE__) \
); \
} \
while (false)
}
+43
View File
@@ -0,0 +1,43 @@
set(sources
Algorithms.h
AnsiColorized.h
Assertions.h
Common.h
CommonData.cpp
CommonData.h
CommonIO.cpp
CommonIO.h
Exceptions.cpp
Exceptions.h
FixedHash.h
IndentedWriter.cpp
IndentedWriter.h
InvertibleMap.h
IpfsHash.cpp
IpfsHash.h
JSON.cpp
JSON.h
Keccak256.cpp
Keccak256.h
picosha2.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 PUBLIC jsoncpp Boost::boost Boost::filesystem Boost::system)
target_include_directories(devcore PUBLIC "${CMAKE_SOURCE_DIR}")
add_dependencies(devcore solidity_BuildInfo.h)
if(SOLC_LINK_STATIC)
target_link_libraries(devcore PUBLIC Threads::Threads)
endif()
+130
View File
@@ -0,0 +1,130 @@
/*
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 Common.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*
* Very common stuff (i.e. that every other header needs except vector_ref.h).
*/
#pragma once
// way too many unsigned to size_t warnings in 32 bit build
#ifdef _M_IX86
#pragma warning(disable:4244)
#endif
#if _MSC_VER && _MSC_VER < 1900
#define _ALLOW_KEYWORD_MACROS
#define noexcept throw()
#endif
#ifdef __INTEL_COMPILER
#pragma warning(disable:3682) //call through incomplete class
#endif
#include <libsolutil/vector_ref.h>
#include <boost/version.hpp>
#if (BOOST_VERSION < 106500)
#error "Unsupported Boost version. At least 1.65 required."
#endif
#include <boost/multiprecision/cpp_int.hpp>
#include <map>
#include <vector>
#include <functional>
#include <string>
namespace solidity
{
// Binary data types.
using bytes = std::vector<uint8_t>;
using bytesRef = util::vector_ref<uint8_t>;
using bytesConstRef = util::vector_ref<uint8_t const>;
// Numeric types.
using bigint = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<>>;
using u256 = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<256, 256, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>;
using s256 = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<256, 256, boost::multiprecision::signed_magnitude, boost::multiprecision::unchecked, void>>;
using u160 = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<160, 160, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>;
// Map types.
using StringMap = std::map<std::string, std::string>;
// String types.
using strings = std::vector<std::string>;
/// Interprets @a _u as a two's complement signed number and returns the resulting s256.
inline s256 u2s(u256 _u)
{
static bigint const c_end = bigint(1) << 256;
if (boost::multiprecision::bit_test(_u, 255))
return s256(-(c_end - _u));
else
return s256(_u);
}
/// @returns the two's complement signed representation of the signed number _u.
inline u256 s2u(s256 _u)
{
static bigint const c_end = bigint(1) << 256;
if (_u >= 0)
return u256(_u);
else
return u256(c_end + _u);
}
inline u256 exp256(u256 _base, u256 _exponent)
{
using boost::multiprecision::limb_type;
u256 result = 1;
while (_exponent)
{
if (boost::multiprecision::bit_test(_exponent, 0))
result *= _base;
_base *= _base;
_exponent >>= 1;
}
return result;
}
inline std::ostream& operator<<(std::ostream& os, bytes const& _bytes)
{
std::ostringstream ss;
ss << std::hex;
std::copy(_bytes.begin(), _bytes.end(), std::ostream_iterator<int>(ss, ","));
std::string result = ss.str();
result.pop_back();
os << "[" + result + "]";
return os;
}
/// RAII utility class whose destructor calls a given function.
class ScopeGuard
{
public:
explicit ScopeGuard(std::function<void(void)> _f): m_f(_f) {}
~ScopeGuard() { m_f(); }
private:
std::function<void(void)> m_f;
};
}
+192
View File
@@ -0,0 +1,192 @@
/*
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 CommonData.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#include <libsolutil/CommonData.h>
#include <libsolutil/Exceptions.h>
#include <libsolutil/Assertions.h>
#include <libsolutil/Keccak256.h>
#include <libsolutil/FixedHash.h>
#include <boost/algorithm/string.hpp>
using namespace std;
using namespace solidity;
using namespace solidity::util;
namespace
{
static char const* upperHexChars = "0123456789ABCDEF";
static char const* lowerHexChars = "0123456789abcdef";
}
string solidity::util::toHex(uint8_t _data, HexCase _case)
{
assertThrow(_case != HexCase::Mixed, BadHexCase, "Mixed case can only be used for byte arrays.");
char const* chars = _case == HexCase::Upper ? upperHexChars : lowerHexChars;
return std::string{
chars[(unsigned(_data) / 16) & 0xf],
chars[unsigned(_data) & 0xf]
};
}
string solidity::util::toHex(bytes const& _data, HexPrefix _prefix, HexCase _case)
{
std::string ret(_data.size() * 2 + (_prefix == HexPrefix::Add ? 2 : 0), 0);
size_t i = 0;
if (_prefix == HexPrefix::Add)
{
ret[i++] = '0';
ret[i++] = 'x';
}
// Mixed case will be handled inside the loop.
char const* chars = _case == HexCase::Upper ? upperHexChars : lowerHexChars;
int rix = _data.size() - 1;
for (uint8_t c: _data)
{
// switch hex case every four hexchars
if (_case == HexCase::Mixed)
chars = (rix-- & 2) == 0 ? lowerHexChars : upperHexChars;
ret[i++] = chars[(unsigned(c) / 16) & 0xf];
ret[i++] = chars[unsigned(c) & 0xf];
}
assertThrow(i == ret.size(), Exception, "");
return ret;
}
int solidity::util::fromHex(char _i, WhenError _throw)
{
if (_i >= '0' && _i <= '9')
return _i - '0';
if (_i >= 'a' && _i <= 'f')
return _i - 'a' + 10;
if (_i >= 'A' && _i <= 'F')
return _i - 'A' + 10;
if (_throw == WhenError::Throw)
assertThrow(false, BadHexCharacter, to_string(_i));
else
return -1;
}
bytes solidity::util::fromHex(std::string const& _s, WhenError _throw)
{
unsigned s = (_s.size() >= 2 && _s[0] == '0' && _s[1] == 'x') ? 2 : 0;
std::vector<uint8_t> ret;
ret.reserve((_s.size() - s + 1) / 2);
if (_s.size() % 2)
{
int h = fromHex(_s[s++], _throw);
if (h != -1)
ret.push_back(h);
else
return bytes();
}
for (unsigned i = s; i < _s.size(); i += 2)
{
int h = fromHex(_s[i], _throw);
int l = fromHex(_s[i + 1], _throw);
if (h != -1 && l != -1)
ret.push_back((uint8_t)(h * 16 + l));
else
return bytes();
}
return ret;
}
bool solidity::util::passesAddressChecksum(string const& _str, bool _strict)
{
string s = _str.substr(0, 2) == "0x" ? _str : "0x" + _str;
if (s.length() != 42)
return false;
if (!_strict && (
s.find_first_of("abcdef") == string::npos ||
s.find_first_of("ABCDEF") == string::npos
))
return true;
return s == solidity::util::getChecksummedAddress(s);
}
string solidity::util::getChecksummedAddress(string const& _addr)
{
string s = _addr.substr(0, 2) == "0x" ? _addr.substr(2) : _addr;
assertThrow(s.length() == 40, InvalidAddress, "");
assertThrow(s.find_first_not_of("0123456789abcdefABCDEF") == string::npos, InvalidAddress, "");
h256 hash = keccak256(boost::algorithm::to_lower_copy(s, std::locale::classic()));
string ret = "0x";
for (size_t i = 0; i < 40; ++i)
{
char addressCharacter = s[i];
unsigned nibble = (unsigned(hash[i / 2]) >> (4 * (1 - (i % 2)))) & 0xf;
if (nibble >= 8)
ret += toupper(addressCharacter);
else
ret += tolower(addressCharacter);
}
return ret;
}
bool solidity::util::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 solidity::util::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;
}
string solidity::util::formatAsStringOrNumber(string const& _value)
{
assertThrow(_value.length() <= 32, StringTooLong, "String to be formatted longer than 32 bytes.");
for (auto const& c: _value)
if (c <= 0x1f || c >= 0x7f || c == '"')
return "0x" + h256(_value, h256::AlignLeft).hex();
return "\"" + _value + "\"";
}
+451
View File
@@ -0,0 +1,451 @@
/*
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 CommonData.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*
* Shared algorithms and data types.
*/
#pragma once
#include <iterator>
#include <libsolutil/Common.h>
#include <vector>
#include <type_traits>
#include <cstring>
#include <optional>
#include <string>
#include <set>
#include <functional>
#include <utility>
/// Operators need to stay in the global namespace.
/// Concatenate the contents of a container onto a vector
template <class T, class U> std::vector<T>& operator+=(std::vector<T>& _a, U const& _b)
{
for (auto const& i: _b)
_a.push_back(i);
return _a;
}
/// Concatenate the contents of a container onto a vector, move variant.
template <class T, class U> std::vector<T>& operator+=(std::vector<T>& _a, U&& _b)
{
std::move(_b.begin(), _b.end(), std::back_inserter(_a));
return _a;
}
/// Concatenate the contents of a container onto a multiset
template <class U, class... T> std::multiset<T...>& operator+=(std::multiset<T...>& _a, U const& _b)
{
_a.insert(_b.begin(), _b.end());
return _a;
}
/// Concatenate the contents of a container onto a multiset, move variant.
template <class U, class... T> std::multiset<T...>& operator+=(std::multiset<T...>& _a, U&& _b)
{
for (auto&& x: _b)
_a.insert(std::move(x));
return _a;
}
/// Concatenate the contents of a container onto a set
template <class U, class... T> std::set<T...>& operator+=(std::set<T...>& _a, U const& _b)
{
_a.insert(_b.begin(), _b.end());
return _a;
}
/// Concatenate the contents of a container onto a set, move variant.
template <class U, class... T> std::set<T...>& operator+=(std::set<T...>& _a, U&& _b)
{
for (auto&& x: _b)
_a.insert(std::move(x));
return _a;
}
/// Concatenate two vectors of elements.
template <class T>
inline std::vector<T> operator+(std::vector<T> const& _a, std::vector<T> const& _b)
{
std::vector<T> ret(_a);
ret += _b;
return ret;
}
/// Concatenate two vectors of elements, moving them.
template <class T>
inline std::vector<T> operator+(std::vector<T>&& _a, std::vector<T>&& _b)
{
std::vector<T> ret(std::move(_a));
if (&_a == &_b)
ret += ret;
else
ret += std::move(_b);
return ret;
}
/// Concatenate something to a sets of elements.
template <class T, class U>
inline std::set<T> operator+(std::set<T> const& _a, U&& _b)
{
std::set<T> ret(_a);
ret += std::forward<U>(_b);
return ret;
}
/// Concatenate something to a sets of elements, move variant.
template <class T, class U>
inline std::set<T> operator+(std::set<T>&& _a, U&& _b)
{
std::set<T> ret(std::move(_a));
ret += std::forward<U>(_b);
return ret;
}
/// Remove the elements of a container from a set.
template <class C, class... T>
inline std::set<T...>& operator-=(std::set<T...>& _a, C const& _b)
{
for (auto const& x: _b)
_a.erase(x);
return _a;
}
template <class C, class... T>
inline std::set<T...> operator-(std::set<T...> const& _a, C const& _b)
{
auto result = _a;
result -= _b;
return result;
}
/// Remove the elements of a container from a multiset.
template <class C, class... T>
inline std::multiset<T...>& operator-=(std::multiset<T...>& _a, C const& _b)
{
for (auto const& x: _b)
_a.erase(x);
return _a;
}
namespace solidity::util
{
template <class T, class U>
T convertContainer(U const& _from)
{
return T{_from.cbegin(), _from.cend()};
}
template <class T, class U>
T convertContainer(U&& _from)
{
return T{
std::make_move_iterator(_from.begin()),
std::make_move_iterator(_from.end())
};
}
// String conversion functions, mainly to/from hex/nibble/byte representations.
enum class WhenError
{
DontThrow = 0,
Throw = 1,
};
enum class HexPrefix
{
DontAdd = 0,
Add = 1,
};
enum class HexCase
{
Lower = 0,
Upper = 1,
Mixed = 2,
};
/// Convert a single byte to a string of hex characters (of length two),
/// optionally with uppercase hex letters.
std::string toHex(uint8_t _data, HexCase _case = HexCase::Lower);
/// Convert a series of bytes to the corresponding string of hex duplets,
/// optionally with "0x" prefix and with uppercase hex letters.
std::string toHex(bytes const& _data, HexPrefix _prefix = HexPrefix::DontAdd, HexCase _case = HexCase::Lower);
/// Converts a (printable) ASCII hex character into the corresponding 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((uint8_t const*)_b.data(), (uint8_t const*)(_b.data() + _b.size()));
}
// 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 <class T, class Out>
inline void toBigEndian(T _val, Out& o_out)
{
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
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 <class T, class _In>
inline T fromBigEndian(_In const& _bytes)
{
T ret = (T)0;
for (auto i: _bytes)
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; }
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 <class T>
inline bytes toCompactBigEndian(T _val, unsigned _min = 0)
{
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
int i = 0;
for (T v = _val; v; ++i, v >>= 8) {}
bytes ret(std::max<unsigned>(_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 toCompactHexWithPrefix(u256 const& _value)
{
return toHex(toCompactBigEndian(_value, 1), HexPrefix::Add);
}
/// Returns decimal representation for small numbers and hex for large numbers.
inline std::string formatNumber(bigint const& _value)
{
if (_value < 0)
return "-" + formatNumber(-_value);
if (_value > 0x1000000)
return toHex(toCompactBigEndian(_value, 1), HexPrefix::Add);
else
return _value.str();
}
inline std::string formatNumber(u256 const& _value)
{
if (_value > 0x1000000)
return toCompactHexWithPrefix(_value);
else
return _value.str();
}
// Algorithms for string and string-like collections.
/// Determine bytes required to encode the given integer value. @returns 0 if @a _i is zero.
template <class T>
inline unsigned bytesRequired(T _i)
{
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
unsigned i = 0;
for (; _i != 0; ++i, _i >>= 8) {}
return i;
}
template <class T, class V>
bool contains(T const& _t, V const& _v)
{
return std::end(_t) != std::find(std::begin(_t), std::end(_t), _v);
}
template <class T, class Predicate>
bool contains_if(T const& _t, Predicate const& _p)
{
return std::end(_t) != std::find_if(std::begin(_t), std::end(_t), _p);
}
/// 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, F const& _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 (std::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);
}
namespace detail
{
template <typename T, typename F, std::size_t... I>
void iterateReplacingWindow(std::vector<T>& _vector, F const& _f, std::index_sequence<I...>)
{
// Concept: _f must be Callable, must accept sizeof...(I) parameters of type T&, must return optional<vector<T>>
bool useModified = false;
std::vector<T> modifiedVector;
size_t i = 0;
for (; i + sizeof...(I) <= _vector.size(); ++i)
{
if (std::optional<std::vector<T>> r = _f(_vector[i + I]...))
{
if (!useModified)
{
std::move(_vector.begin(), _vector.begin() + i, back_inserter(modifiedVector));
useModified = true;
}
modifiedVector += std::move(*r);
i += sizeof...(I) - 1;
}
else if (useModified)
modifiedVector.emplace_back(std::move(_vector[i]));
}
if (useModified)
{
for (; i < _vector.size(); ++i)
modifiedVector.emplace_back(std::move(_vector[i]));
_vector = std::move(modifiedVector);
}
}
}
/// Function that iterates over the vector @param _vector,
/// calling the function @param _f on sequences of @tparam N of its
/// elements. If @param _f returns a vector, these elements are replaced by
/// the returned vector and the iteration continues with the next @tparam N elements.
/// If the function does not return a vector, the iteration continues with an overlapping
/// sequence of @tparam N elements that starts with the second element of the previous
/// iteration.
/// 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 <std::size_t N, typename T, typename F>
void iterateReplacingWindow(std::vector<T>& _vector, F const& _f)
{
// Concept: _f must be Callable, must accept N parameters of type T&, must return optional<vector<T>>
detail::iterateReplacingWindow(_vector, _f, std::make_index_sequence<N>{});
}
/// @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.
bool passesAddressChecksum(std::string const& _str, bool _strict);
/// @returns the checksummed version of an address
/// @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);
/// @returns a quoted string if all characters are printable ASCII chars,
/// or its hex representation otherwise.
/// _value cannot be longer than 32 bytes.
std::string formatAsStringOrNumber(std::string const& _value);
template<typename Container, typename Compare>
bool containerEqual(Container const& _lhs, Container const& _rhs, Compare&& _compare)
{
return std::equal(std::begin(_lhs), std::end(_lhs), std::begin(_rhs), std::end(_rhs), std::forward<Compare>(_compare));
}
inline std::string findAnyOf(std::string const& _haystack, std::vector<std::string> const& _needles)
{
for (std::string const& needle: _needles)
if (_haystack.find(needle) != std::string::npos)
return needle;
return "";
}
namespace detail
{
template<typename T>
void variadicEmplaceBack(std::vector<T>&) {}
template<typename T, typename A, typename... Args>
void variadicEmplaceBack(std::vector<T>& _vector, A&& _a, Args&&... _args)
{
_vector.emplace_back(std::forward<A>(_a));
variadicEmplaceBack(_vector, std::forward<Args>(_args)...);
}
}
template<typename T, typename... Args>
std::vector<T> make_vector(Args&&... _args)
{
std::vector<T> result;
result.reserve(sizeof...(_args));
detail::variadicEmplaceBack(result, std::forward<Args>(_args)...);
return result;
}
}
+151
View File
@@ -0,0 +1,151 @@
/*
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 CommonIO.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#include <libsolutil/CommonIO.h>
#include <libsolutil/Assertions.h>
#include <boost/filesystem.hpp>
#include <iostream>
#include <cstdlib>
#include <fstream>
#if defined(_WIN32)
#include <windows.h>
#else
#include <unistd.h>
#include <termios.h>
#endif
using namespace std;
using namespace solidity::util;
namespace
{
template <typename _T>
inline _T readFile(std::string const& _file)
{
_T ret;
size_t const c_elementSize = sizeof(typename _T::value_type);
std::ifstream is(_file, std::ifstream::binary);
if (!is)
return ret;
// get length of file:
is.seekg(0, is.end);
streamoff length = is.tellg();
if (length == 0)
return ret; // do not read empty file (MSVC does not like it)
is.seekg(0, is.beg);
ret.resize((length + c_elementSize - 1) / c_elementSize);
is.read(const_cast<char*>(reinterpret_cast<char const*>(ret.data())), length);
return ret;
}
}
string solidity::util::readFileAsString(string const& _file)
{
return readFile<string>(_file);
}
string solidity::util::readStandardInput()
{
string ret;
while (!cin.eof())
{
string tmp;
// NOTE: this will read until EOF or NL
getline(cin, tmp);
ret.append(tmp);
ret.append("\n");
}
return ret;
}
#if defined(_WIN32)
class DisableConsoleBuffering
{
public:
DisableConsoleBuffering()
{
m_stdin = GetStdHandle(STD_INPUT_HANDLE);
GetConsoleMode(m_stdin, &m_oldMode);
SetConsoleMode(m_stdin, m_oldMode & (~(ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT)));
}
~DisableConsoleBuffering()
{
SetConsoleMode(m_stdin, m_oldMode);
}
private:
HANDLE m_stdin;
DWORD m_oldMode;
};
#else
class DisableConsoleBuffering
{
public:
DisableConsoleBuffering()
{
tcgetattr(0, &m_termios);
m_termios.c_lflag &= ~ICANON;
m_termios.c_lflag &= ~ECHO;
m_termios.c_cc[VMIN] = 1;
m_termios.c_cc[VTIME] = 0;
tcsetattr(0, TCSANOW, &m_termios);
}
~DisableConsoleBuffering()
{
m_termios.c_lflag |= ICANON;
m_termios.c_lflag |= ECHO;
tcsetattr(0, TCSADRAIN, &m_termios);
}
private:
struct termios m_termios;
};
#endif
int solidity::util::readStandardInputChar()
{
DisableConsoleBuffering disableConsoleBuffering;
return cin.get();
}
string solidity::util::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 solidity::util::sanitizePath(string const& _path) {
return boost::filesystem::path(_path).generic_string();
}
+59
View File
@@ -0,0 +1,59 @@
/*
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 CommonIO.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*
* File & stream I/O routines.
*/
#pragma once
#include <libsolutil/Common.h>
#include <boost/filesystem.hpp>
#include <sstream>
#include <string>
namespace solidity::util
{
/// Retrieve and returns the contents of the given file as a std::string.
/// If the file doesn't exist or isn't readable, returns an empty container / bytes.
std::string readFileAsString(std::string const& _file);
/// Retrieve and returns the contents of standard input (until EOF).
std::string readStandardInput();
/// Retrieve and returns a character from standard input (without waiting for EOL).
int readStandardInputChar();
/// Converts arbitrary value to string representation using std::stringstream.
template <class _T>
std::string toString(_T const& _t)
{
std::ostringstream o;
o << _t;
return o.str();
}
/// @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);
}
+51
View File
@@ -0,0 +1,51 @@
/*
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/>.
*/
#include <libsolutil/Exceptions.h>
using namespace std;
using namespace solidity::util;
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.
return std::exception::what();
}
string Exception::lineInfo() const
{
char const* const* file = boost::get_error_info<boost::throw_file>(*this);
int const* line = boost::get_error_info<boost::throw_line>(*this);
string ret;
if (file)
ret += *file;
ret += ':';
if (line)
ret += to_string(*line);
return ret;
}
string const* Exception::comment() const noexcept
{
return boost::get_error_info<errinfo_comment>(*this);
}
+57
View File
@@ -0,0 +1,57 @@
/*
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 <boost/exception/exception.hpp>
#include <boost/exception/info.hpp>
#include <boost/exception/info_tuple.hpp>
#include <boost/exception/diagnostic_information.hpp>
#include <exception>
#include <string>
namespace solidity::util
{
/// Base class for all exceptions.
struct Exception: virtual std::exception, virtual boost::exception
{
char const* what() const noexcept override;
/// @returns "FileName:LineNumber" referring to the point where the exception was thrown.
std::string lineInfo() const;
/// @returns the errinfo_comment of this exception.
std::string const* comment() const noexcept;
private:
};
#define DEV_SIMPLE_EXCEPTION(X) struct X: virtual ::solidity::util::Exception { const char* what() const noexcept override { return #X; } }
DEV_SIMPLE_EXCEPTION(InvalidAddress);
DEV_SIMPLE_EXCEPTION(BadHexCharacter);
DEV_SIMPLE_EXCEPTION(BadHexCase);
DEV_SIMPLE_EXCEPTION(FileError);
DEV_SIMPLE_EXCEPTION(DataTooLong);
DEV_SIMPLE_EXCEPTION(StringTooLong);
// error information to be added to exceptions
using errinfo_comment = boost::error_info<struct tag_comment, std::string>;
}
+159
View File
@@ -0,0 +1,159 @@
/*
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 FixedHash.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*
* The FixedHash fixed-size "hash" container type.
*/
#pragma once
#include <libsolutil/CommonData.h>
#include <boost/functional/hash.hpp>
#include <boost/io/ios_state.hpp>
#include <array>
#include <cstdint>
#include <algorithm>
namespace solidity::util
{
/// Fixed-size raw-byte array container type, with an API optimised for storing hashes.
/// Transparently converts to/from the corresponding arithmetic type; this will
/// assume the data contained in the hash is big-endian.
template <unsigned N>
class FixedHash
{
public:
/// The corresponding arithmetic type.
using Arith = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<N * 8, N * 8, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>;
/// The size of the container.
enum { size = N };
/// Method to convert from a string.
enum ConstructFromStringType { FromHex, FromBinary };
/// Method to convert from a string.
enum ConstructFromHashType { AlignLeft, AlignRight, FailIfDifferent };
/// Construct an empty hash.
explicit FixedHash() { m_data.fill(0); }
/// Construct from another hash, filling with zeroes or cropping as necessary.
template <unsigned M> explicit FixedHash(FixedHash<M> const& _h, ConstructFromHashType _t = AlignLeft) { m_data.fill(0); unsigned c = std::min(M, N); for (unsigned i = 0; i < c; ++i) m_data[_t == AlignRight ? N - 1 - i : i] = _h[_t == AlignRight ? M - 1 - i : i]; }
/// Convert from the corresponding arithmetic type.
FixedHash(Arith const& _arith) { toBigEndian(_arith, m_data); }
/// Convert from unsigned
explicit FixedHash(unsigned _u) { toBigEndian(_u, m_data); }
/// Explicitly construct, copying from a byte array.
explicit FixedHash(bytes const& _b, ConstructFromHashType _t = FailIfDifferent) { if (_b.size() == N) memcpy(m_data.data(), _b.data(), std::min<unsigned>(_b.size(), N)); else { m_data.fill(0); if (_t != FailIfDifferent) { auto c = std::min<unsigned>(_b.size(), N); for (unsigned i = 0; i < c; ++i) m_data[_t == AlignRight ? N - 1 - i : i] = _b[_t == AlignRight ? _b.size() - 1 - i : i]; } } }
/// Explicitly construct, copying from a byte array.
explicit FixedHash(bytesConstRef _b, ConstructFromHashType _t = FailIfDifferent) { if (_b.size() == N) memcpy(m_data.data(), _b.data(), std::min<unsigned>(_b.size(), N)); else { m_data.fill(0); if (_t != FailIfDifferent) { auto c = std::min<unsigned>(_b.size(), N); for (unsigned i = 0; i < c; ++i) m_data[_t == AlignRight ? N - 1 - i : i] = _b[_t == AlignRight ? _b.size() - 1 - i : i]; } } }
/// Explicitly construct, copying from a string.
explicit FixedHash(std::string const& _s, ConstructFromStringType _t = FromHex, ConstructFromHashType _ht = FailIfDifferent): FixedHash(_t == FromHex ? fromHex(_s, WhenError::Throw) : solidity::util::asBytes(_s), _ht) {}
/// Convert to arithmetic type.
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(), [](uint8_t _b) { return _b != 0; }); }
// The obvious comparison operators.
bool operator==(FixedHash const& _c) const { return m_data == _c.m_data; }
bool operator!=(FixedHash const& _c) const { return m_data != _c.m_data; }
/// Required to sort objects of this type or use them as map keys.
bool operator<(FixedHash const& _c) const { for (unsigned i = 0; i < N; ++i) if (m_data[i] < _c.m_data[i]) return true; else if (m_data[i] > _c.m_data[i]) return false; return false; }
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.
uint8_t& operator[](unsigned _i) { return m_data[_i]; }
/// @returns a particular byte from the hash.
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(asBytes()); }
/// @returns a mutable byte vector_ref to the object's data.
bytesRef ref() { return bytesRef(m_data.data(), N); }
/// @returns a constant byte vector_ref to the object's data.
bytesConstRef ref() const { return bytesConstRef(m_data.data(), N); }
/// @returns a mutable byte pointer to the object's data.
uint8_t* data() { return m_data.data(); }
/// @returns a constant byte pointer to the object's 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<uint8_t, N>& asArray() { return m_data; }
/// @returns a constant reference to the object's data as an STL array.
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
{
unsigned ret = 0;
for (auto d: m_data)
if (d)
{
for (;; ++ret, d <<= 1)
if (d & 0x80)
return ret;
}
else
ret += 8;
return ret;
}
void clear() { m_data.fill(0); }
private:
std::array<uint8_t, N> m_data; ///< The binary data.
};
/// Stream I/O for the FixedHash class.
template <unsigned N>
inline std::ostream& operator<<(std::ostream& _out, FixedHash<N> const& _h)
{
boost::io::ios_all_saver guard(_out);
_out << std::noshowbase << std::hex << std::setfill('0');
for (unsigned i = 0; i < N; ++i)
_out << std::setw(2) << (int)_h[i];
_out << std::dec;
return _out;
}
// Common types of FixedHash.
using h256 = FixedHash<32>;
using h160 = FixedHash<20>;
}
+65
View File
@@ -0,0 +1,65 @@
/*
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/>.
*/
/**
* @date 2017
* Indented text writer.
*/
#include <libsolutil/IndentedWriter.h>
#include <libsolutil/Assertions.h>
using namespace std;
using namespace solidity::util;
string IndentedWriter::format() const
{
string result;
for (auto const& line: m_lines)
result += string(line.indentation * 4, ' ') + line.contents + "\n";
return result;
}
void IndentedWriter::newLine()
{
if (!m_lines.back().contents.empty())
m_lines.emplace_back(Line{string(), m_lines.back().indentation});
}
void IndentedWriter::indent()
{
newLine();
m_lines.back().indentation++;
}
void IndentedWriter::unindent()
{
newLine();
assertThrow(m_lines.back().indentation > 0, IndentedWriterError, "Negative indentation.");
m_lines.back().indentation--;
}
void IndentedWriter::add(string const& _str)
{
m_lines.back().contents += _str;
}
void IndentedWriter::addLine(string const& _line)
{
newLine();
add(_line);
newLine();
}
+65
View File
@@ -0,0 +1,65 @@
/*
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/>.
*/
/**
* @date 2017
* Indented text writer.
*/
#pragma once
#include <vector>
#include <string>
#include <libsolutil/Exceptions.h>
namespace solidity::util
{
DEV_SIMPLE_EXCEPTION(IndentedWriterError);
class IndentedWriter
{
public:
// Returns the formatted output.
std::string format() const;
// Go one indentation level in.
void indent();
// Go one indentation level out.
void unindent();
// Add text.
void add(std::string const& _str);
// Add text with new line.
void addLine(std::string const& _line);
// Add new line.
void newLine();
private:
struct Line
{
std::string contents;
unsigned indentation;
};
std::vector<Line> m_lines{{std::string(), 0}};
};
}
+93
View File
@@ -0,0 +1,93 @@
/*
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 <map>
#include <set>
/**
* Data structure that keeps track of values and keys of a mapping.
*/
template <class K, class V>
struct InvertibleMap
{
std::map<K, V> values;
// references[x] == {y | values[y] == x}
std::map<V, std::set<K>> references;
void set(K _key, V _value)
{
if (values.count(_key))
references[values[_key]].erase(_key);
values[_key] = _value;
references[_value].insert(_key);
}
void eraseKey(K _key)
{
if (values.count(_key))
references[values[_key]].erase(_key);
values.erase(_key);
}
void eraseValue(V _value)
{
if (references.count(_value))
{
for (V v: references[_value])
values.erase(v);
references.erase(_value);
}
}
void clear()
{
values.clear();
references.clear();
}
};
template <class T>
struct InvertibleRelation
{
/// forward[x] contains y <=> backward[y] contains x
std::map<T, std::set<T>> forward;
std::map<T, std::set<T>> backward;
void insert(T _key, T _value)
{
forward[_key].insert(_value);
backward[_value].insert(_key);
}
void set(T _key, std::set<T> _values)
{
for (T v: forward[_key])
backward[v].erase(_key);
for (T v: _values)
backward[v].insert(_key);
forward[_key] = std::move(_values);
}
void eraseKey(T _key)
{
for (auto const& v: forward[_key])
backward[v].erase(_key);
forward.erase(_key);
}
};
+91
View File
@@ -0,0 +1,91 @@
/*
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/>.
*/
#include <libsolutil/IpfsHash.h>
#include <libsolutil/Assertions.h>
#include <libsolutil/Exceptions.h>
#include <libsolutil/picosha2.h>
#include <libsolutil/CommonData.h>
using namespace std;
using namespace solidity;
using namespace solidity::util;
namespace
{
bytes varintEncoding(size_t _n)
{
bytes encoded;
while (_n > 0x7f)
{
encoded.emplace_back(uint8_t(0x80 | (_n & 0x7f)));
_n >>= 7;
}
encoded.emplace_back(_n);
return encoded;
}
string base58Encode(bytes const& _data)
{
static string const alphabet{"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"};
bigint data(toHex(_data, HexPrefix::Add));
string output;
while (data)
{
output += alphabet[size_t(data % alphabet.size())];
data /= alphabet.size();
}
reverse(output.begin(), output.end());
return output;
}
}
bytes solidity::util::ipfsHash(string _data)
{
assertThrow(_data.length() < 1024 * 256, DataTooLong, "IPFS hash for large (chunked) files not yet implemented.");
bytes lengthAsVarint = varintEncoding(_data.size());
bytes protobufEncodedData;
// Type: File
protobufEncodedData += bytes{0x08, 0x02};
if (!_data.empty())
{
// Data (length delimited bytes)
protobufEncodedData += bytes{0x12};
protobufEncodedData += lengthAsVarint;
protobufEncodedData += asBytes(std::move(_data));
}
// filesize: length as varint
protobufEncodedData += bytes{0x18} + lengthAsVarint;
// PBDag:
// Data: (length delimited bytes)
size_t protobufLength = protobufEncodedData.size();
bytes blockData = bytes{0x0a} + varintEncoding(protobufLength) + std::move(protobufEncodedData);
// TODO Handle "large" files with multiple blocks
// Multihash: sha2-256, 256 bits
bytes hash = bytes{0x12, 0x20} + picosha2::hash256(std::move(blockData));
return hash;
}
string solidity::util::ipfsHashBase58(string _data)
{
return base58Encode(ipfsHash(std::move(_data)));
}
+37
View File
@@ -0,0 +1,37 @@
/*
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 <libsolutil/Common.h>
#include <string>
namespace solidity::util
{
/// Compute the "ipfs hash" of a file with the content @a _data.
/// The output will be the multihash of the UnixFS protobuf encoded data.
/// As hash function it will use sha2-256.
/// The effect is that the hash should be identical to the one produced by
/// the command `ipfs add <filename>`.
bytes ipfsHash(std::string _data);
/// Compute the "ipfs hash" as above, but encoded in base58 as used by ipfs / bitcoin.
std::string ipfsHashBase58(std::string _data);
}
+114
View File
@@ -0,0 +1,114 @@
/*
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 JSON.cpp
* @author Alexander Arlt <alexander.arlt@arlt-labs.com>
* @date 2018
*/
#include <libsolutil/JSON.h>
#include <libsolutil/CommonIO.h>
#include <boost/algorithm/string/replace.hpp>
#include <sstream>
#include <map>
#include <memory>
using namespace std;
static_assert(
(JSONCPP_VERSION_MAJOR == 1) && (JSONCPP_VERSION_MINOR == 9) && (JSONCPP_VERSION_PATCH == 2),
"Unexpected jsoncpp version: " JSONCPP_VERSION_STRING ". Expecting 1.9.2."
);
namespace solidity::util
{
namespace
{
/// StreamWriterBuilder that can be constructed with specific settings
class StreamWriterBuilder: public Json::StreamWriterBuilder
{
public:
explicit StreamWriterBuilder(map<string, Json::Value> const& _settings)
{
for (auto const& iter: _settings)
this->settings_[iter.first] = iter.second;
}
};
/// CharReaderBuilder with strict-mode settings
class StrictModeCharReaderBuilder: public Json::CharReaderBuilder
{
public:
StrictModeCharReaderBuilder()
{
Json::CharReaderBuilder::strictMode(&this->settings_);
}
};
/// Serialise the JSON object (@a _input) with specific builder (@a _builder)
/// \param _input JSON input string
/// \param _builder StreamWriterBuilder that is used to create new Json::StreamWriter
/// \return serialized json object
string print(Json::Value const& _input, Json::StreamWriterBuilder const& _builder)
{
stringstream stream;
unique_ptr<Json::StreamWriter> writer(_builder.newStreamWriter());
writer->write(_input, &stream);
return stream.str();
}
/// Parse a JSON string (@a _input) with specified builder (@ _builder) and writes resulting JSON object to (@a _json)
/// \param _builder CharReaderBuilder that is used to create new Json::CharReaders
/// \param _input JSON input string
/// \param _json [out] resulting JSON object
/// \param _errs [out] Formatted error messages
/// \return \c true if the document was successfully parsed, \c false if an error occurred.
bool parse(Json::CharReaderBuilder& _builder, string const& _input, Json::Value& _json, string* _errs)
{
unique_ptr<Json::CharReader> reader(_builder.newCharReader());
return reader->parse(_input.c_str(), _input.c_str() + _input.length(), &_json, _errs);
}
} // end anonymous namespace
string jsonPrettyPrint(Json::Value const& _input)
{
static map<string, Json::Value> settings{{"indentation", " "}, {"enableYAMLCompatibility", true}};
static StreamWriterBuilder writerBuilder(settings);
string result = print(_input, writerBuilder);
boost::replace_all(result, " \n", "\n");
return result;
}
string jsonCompactPrint(Json::Value const& _input)
{
static map<string, Json::Value> settings{{"indentation", ""}};
static StreamWriterBuilder writerBuilder(settings);
return print(_input, writerBuilder);
}
bool jsonParseStrict(string const& _input, Json::Value& _json, string* _errs /* = nullptr */)
{
static StrictModeCharReaderBuilder readerBuilder;
return parse(readerBuilder, _input, _json, _errs);
}
} // namespace solidity::util
+44
View File
@@ -0,0 +1,44 @@
/*
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 JSON.h
* @date 2016
*
* JSON related helpers
*/
#pragma once
#include <json/json.h>
#include <string>
namespace solidity::util {
/// Serialise the JSON object (@a _input) with indentation
std::string jsonPrettyPrint(Json::Value const& _input);
/// Serialise the JSON object (@a _input) without indentation
std::string jsonCompactPrint(Json::Value const& _input);
/// Parse a JSON string (@a _input) with enabled strict-mode and writes resulting JSON object to (@a _json)
/// \param _input JSON input string
/// \param _json [out] resulting JSON object
/// \param _errs [out] Formatted error messages
/// \return \c true if the document was successfully parsed, \c false if an error occurred.
bool jsonParseStrict(std::string const& _input, Json::Value& _json, std::string* _errs = nullptr);
}
+185
View File
@@ -0,0 +1,185 @@
/*
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 <libsolutil/Keccak256.h>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;
namespace solidity::util
{
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 uint8_t const 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 uint8_t const 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 uint64_t const 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, \
uint8_t const* src, \
size_t len) { \
FOR(i, 1, len, S); \
}
#define mkapply_sd(NAME, S) \
static inline void NAME(uint8_t const* 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,
uint8_t const* 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;
}
}
+45
View File
@@ -0,0 +1,45 @@
/*
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.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*
* The FixedHash fixed-size "hash" container type.
*/
#pragma once
#include <libsolutil/FixedHash.h>
#include <string>
namespace solidity::util
{
/// Calculate Keccak-256 hash of the given input, returning as a 256-bit hash.
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)); }
/// Calculate Keccak-256 hash of the given input (presented as a binary-filled string), returning as a 256-bit hash.
inline h256 keccak256(std::string const& _input) { return keccak256(bytesConstRef(_input)); }
/// Calculate Keccak-256 hash of the given input (presented as a FixedHash), returns a 256-bit hash.
template<unsigned N> inline h256 keccak256(FixedHash<N> const& _input) { return keccak256(_input.ref()); }
}
+85
View File
@@ -0,0 +1,85 @@
/*
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 solidity::util
{
/// 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>::err("Error message.")
/// return true;
/// }
///
template <class ResultType>
class Result
{
public:
/// Constructs a result with _value and an empty message.
/// This is meant to be called with valid results. Please use
/// the static err() member function to signal an error.
Result(ResultType _value): Result(_value, std::string{}) {}
/// Constructs a result with a default-constructed value and an
/// error message.
static Result<ResultType> err(std::string _message)
{
return 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; }
/// Merges _other into this using the _merger
/// and appends the error messages. Meant to be called
/// with logical operators like logical_and, etc.
template<typename F>
void merge(Result<ResultType> const& _other, F _merger)
{
m_value = _merger(m_value, _other.get());
m_message += _other.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;
};
}
+115
View File
@@ -0,0 +1,115 @@
/*
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 StringUtils.h
* @author Balajiganapathi S <balajiganapathi.s@gmail.com>
* @date 2017
*
* String routines
*/
#include <libsolutil/StringUtils.h>
#include <algorithm>
#include <string>
#include <vector>
using namespace std;
using namespace solidity::util;
bool solidity::util::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
// this is to avoid irrelevant suggestions
return distance <= _maxDistance && distance < n1 && distance < n2;
}
size_t solidity::util::stringDistance(string const& _str1, string const& _str2)
{
size_t n1 = _str1.size();
size_t n2 = _str2.size();
// Optimize by storing only last 2 rows and current row. So first index is considered modulo 3
// This is a two-dimensional array of size 3 x (n2 + 1).
vector<size_t> dp(3 * (n2 + 1));
// In this dp formulation of DamerauLevenshtein distance we are assuming that the strings are 1-based to make base case storage easier.
// So index accesser to _name1 and _name2 have to be adjusted accordingly
for (size_t i1 = 0; i1 <= n1; ++i1)
for (size_t i2 = 0; i2 <= n2; ++i2)
{
size_t x = 0;
if (min(i1, i2) == 0) // base case
x = max(i1, i2);
else
{
size_t left = dp[(i1 - 1) % 3 + i2 * 3];
size_t up = dp[(i1 % 3) + (i2 - 1) * 3];
size_t upleft = dp[((i1 - 1) % 3) + (i2 - 1) * 3];
// deletion and insertion
x = min(left + 1, up + 1);
if (_str1[i1-1] == _str2[i2-1])
// same chars, can skip
x = min(x, upleft);
else
// different chars so try substitution
x = min(x, upleft + 1);
// transposing
if (i1 > 1 && i2 > 1 && _str1[i1 - 1] == _str2[i2 - 2] && _str1[i1 - 2] == _str2[i2 - 1])
x = min(x, dp[((i1 - 2) % 3) + (i2 - 2) * 3] + 1);
}
dp[(i1 % 3) + i2 * 3] = x;
}
return dp[(n1 % 3) + n2 * 3];
}
string solidity::util::quotedAlternativesList(vector<string> const& suggestions)
{
vector<string> quotedSuggestions;
for (auto& suggestion: suggestions)
quotedSuggestions.emplace_back("\"" + suggestion + "\"");
return joinHumanReadable(quotedSuggestions, ", ", " or ");
}
string solidity::util::suffixedVariableNameList(string const& _baseName, size_t _startSuffix, size_t _endSuffix)
{
string result;
if (_startSuffix < _endSuffix)
{
result = _baseName + to_string(_startSuffix++);
while (_startSuffix < _endSuffix)
result += ", " + _baseName + to_string(_startSuffix++);
}
else if (_endSuffix < _startSuffix)
{
result = _baseName + to_string(_endSuffix++);
while (_endSuffix < _startSuffix)
result = _baseName + to_string(_endSuffix++) + ", " + result;
}
return result;
}
+179
View File
@@ -0,0 +1,179 @@
/*
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 StringUtils.h
* @author Balajiganapathi S <balajiganapathi.s@gmail.com>
* @date 2017
*
* String routines
*/
#pragma once
#include <string>
#include <vector>
#include <libsolutil/CommonData.h>
namespace solidity::util
{
// Calculates the DamerauLevenshtein distance between _str1 and _str2 and returns true if that distance is not greater than _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 DamerauLevenshtein 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);
/// @returns a string containing a comma-separated list of variable names consisting of @a _baseName suffixed
/// with increasing integers in the range [@a _startSuffix, @a _endSuffix), if @a _startSuffix < @a _endSuffix,
/// and with decreasing integers in the range [@a _endSuffix, @a _startSuffix), if @a _endSuffix < @a _startSuffix.
/// If @a _startSuffix == @a _endSuffix, the empty string is returned.
std::string suffixedVariableNameList(std::string const& _baseName, size_t _startSuffix, size_t _endSuffix);
/// 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;
}
/// Joins collection of strings just like joinHumanReadable, but prepends the separator
/// unless the collection is empty.
template<class T>
std::string joinHumanReadablePrefixed
(
T const& _list,
std::string const& _separator = ", ",
std::string const& _lastSeparator = ""
)
{
if (begin(_list) == end(_list))
return {};
else
return _separator + joinHumanReadable(_list, _separator, _lastSeparator);
}
/// 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;
int const initialChars = (prefix == HexPrefix::Add) ? 6 : 4;
int const 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;
}
}
+117
View File
@@ -0,0 +1,117 @@
/*
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 SwarmHash.cpp
*/
#include <libsolutil/SwarmHash.h>
#include <libsolutil/Keccak256.h>
using namespace std;
using namespace solidity;
using namespace solidity::util;
namespace
{
bytes toLittleEndian(size_t _size)
{
bytes encoded(8);
for (size_t i = 0; i < 8; ++i)
encoded[i] = (_size >> (8 * i)) & 0xff;
return encoded;
}
h256 swarmHashSimple(bytesConstRef _data, size_t _size)
{
return keccak256(toLittleEndian(_size) + _data.toBytes());
}
h256 swarmHashIntermediate(string const& _input, size_t _offset, size_t _length)
{
bytesConstRef ref;
bytes innerNodes;
if (_length <= 0x1000)
ref = bytesConstRef(_input).cropped(_offset, _length);
else
{
size_t maxRepresentedSize = 0x1000;
while (maxRepresentedSize * (0x1000 / 32) < _length)
maxRepresentedSize *= (0x1000 / 32);
for (size_t i = 0; i < _length; i += maxRepresentedSize)
{
size_t size = std::min(maxRepresentedSize, _length - i);
innerNodes += swarmHashIntermediate(_input, _offset + i, size).asBytes();
}
ref = bytesConstRef(&innerNodes);
}
return swarmHashSimple(ref, _length);
}
h256 bmtHash(bytesConstRef _data)
{
if (_data.size() <= 64)
return keccak256(_data);
size_t midPoint = _data.size() / 2;
return keccak256(
bmtHash(_data.cropped(0, midPoint)).asBytes() +
bmtHash(_data.cropped(midPoint)).asBytes()
);
}
h256 chunkHash(bytesConstRef const _data, bool _forceHigherLevel = false)
{
bytes dataToHash;
if (_data.size() < 0x1000)
dataToHash = _data.toBytes();
else if (_data.size() == 0x1000 && !_forceHigherLevel)
dataToHash = _data.toBytes();
else
{
size_t maxRepresentedSize = 0x1000;
while (maxRepresentedSize * (0x1000 / 32) < _data.size())
maxRepresentedSize *= (0x1000 / 32);
// If remaining size is 0x1000, but maxRepresentedSize is not,
// we have to still do one level of the chunk hashes.
bool forceHigher = maxRepresentedSize > 0x1000;
for (size_t i = 0; i < _data.size(); i += maxRepresentedSize)
{
size_t size = std::min(maxRepresentedSize, _data.size() - i);
dataToHash += chunkHash(_data.cropped(i, size), forceHigher).asBytes();
}
}
dataToHash.resize(0x1000, 0);
return keccak256(toLittleEndian(_data.size()) + bmtHash(&dataToHash).asBytes());
}
}
h256 solidity::util::bzzr0Hash(string const& _input)
{
return swarmHashIntermediate(_input, 0, _input.size());
}
h256 solidity::util::bzzr1Hash(bytes const& _input)
{
if (_input.empty())
return h256{};
return chunkHash(&_input);
}
+40
View File
@@ -0,0 +1,40 @@
/*
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 SwarmHash.h
*/
#pragma once
#include <libsolutil/FixedHash.h>
#include <string>
namespace solidity::util
{
/// Compute the "swarm hash" of @a _input (OLD 0x1000-section version)
h256 bzzr0Hash(std::string const& _input);
/// Compute the "bzz hash" of @a _input (the NEW binary / BMT version)
h256 bzzr1Hash(bytes const& _input);
inline h256 bzzr1Hash(std::string const& _input)
{
return bzzr1Hash(asBytes(_input));
}
}
+141
View File
@@ -0,0 +1,141 @@
/*
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 UTF8.cpp
* @author Alex Beregszaszi
* @date 2016
*
* UTF-8 related helpers
*/
#include <libsolutil/UTF8.h>
namespace solidity::util
{
namespace
{
/// Validate byte sequence against Unicode chapter 3 Table 3-7.
bool isWellFormed(unsigned char byte1, unsigned char byte2)
{
if (byte1 == 0xc0 || byte1 == 0xc1)
return false;
else if (byte1 >= 0xc2 && byte1 <= 0xdf)
return true;
else if (byte1 == 0xe0)
{
if (byte2 < 0xa0)
return false;
else
return true;
}
else if (byte1 >= 0xe1 && byte1 <= 0xec)
return true;
else if (byte1 == 0xed)
{
if (byte2 > 0x9f)
return false;
else
return true;
}
else if (byte1 == 0xee || byte1 == 0xef)
return true;
else if (byte1 == 0xf0)
{
if (byte2 < 0x90)
return false;
else
return true;
}
else if (byte1 >= 0xf1 && byte1 <= 0xf3)
return true;
else if (byte1 == 0xf4)
{
if (byte2 > 0x8f)
return false;
else
return true;
}
/// 0xf5 .. 0xf7 is disallowed
/// Technically anything below 0xc0 or above 0xf7 is
/// not possible to encode using Table 3-6 anyway.
return false;
}
}
bool validateUTF8(unsigned char const* _input, size_t _length, size_t& _invalidPosition)
{
bool valid = true;
size_t i = 0;
for (; i < _length; i++)
{
// Check for Unicode Chapter 3 Table 3-6 conformity.
if (_input[i] < 0x80)
continue;
size_t count = 0;
if (_input[i] >= 0xc0 && _input[i] <= 0xdf)
count = 1;
else if (_input[i] >= 0xe0 && _input[i] <= 0xef)
count = 2;
else if (_input[i] >= 0xf0 && _input[i] <= 0xf7)
count = 3;
if (count == 0)
{
valid = false;
break;
}
if ((i + count) >= _length)
{
valid = false;
break;
}
for (size_t j = 0; j < count; j++)
{
i++;
if ((_input[i] & 0xc0) != 0x80)
{
valid = false;
break;
}
// Check for Unicode Chapter 3 Table 3-7 conformity.
if ((j == 0) && !isWellFormed(_input[i - 1], _input[i]))
{
valid = false;
break;
}
}
}
if (valid)
return true;
_invalidPosition = i;
return false;
}
bool validateUTF8(std::string const& _input, size_t& _invalidPosition)
{
return validateUTF8(reinterpret_cast<unsigned char const*>(_input.c_str()), _input.length(), _invalidPosition);
}
}
+41
View File
@@ -0,0 +1,41 @@
/*
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 UTF8.h
* @author Alex Beregszaszi
* @date 2016
*
* UTF-8 related helpers
*/
#pragma once
#include <string>
namespace solidity::util
{
/// Validate an input for UTF8 encoding
/// @returns false if it is invalid and the first invalid position in invalidPosition
bool validateUTF8(std::string const& _input, size_t& _invalidPosition);
inline bool validateUTF8(std::string const& _input)
{
size_t invalidPos;
return validateUTF8(_input, invalidPos);
}
}
+60
View File
@@ -0,0 +1,60 @@
/*
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
namespace solidity::util
{
/**
* Generic visitor used as follows:
* std::visit(GenericVisitor{
* [](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.
*
* Fallback with no return (it will not fail if you do not specify all variants):
* std::visit(GenericVisitor{
* VisitorFallback<>{},
* [](Class1& _c) { _c.f(); },
* [](Class2& _c) { _c.g(); }
* }, variant);
*
* Fallback with return type R (the fallback returns `R{}`:
* std::visit(GenericVisitor{
* VisitorFallback<R>{},
* [](Class1& _c) { _c.f(); },
* [](Class2& _c) { _c.g(); }
* }, variant);
*/
template <typename...> struct VisitorFallback;
template <typename R>
struct VisitorFallback<R> { template<typename T> R operator()(T&&) const { return {}; } };
template<>
struct VisitorFallback<> { template<typename T> void operator()(T&&) const {} };
template <typename... Visitors> struct GenericVisitor: Visitors... { using Visitors::operator()...; };
template <typename... Visitors> GenericVisitor(Visitors...) -> GenericVisitor<Visitors...>;
}
+195
View File
@@ -0,0 +1,195 @@
/*
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 Whiskers.cpp
* @author Chris <chis@ethereum.org>
* @date 2017
*
* Moustache-like templates.
*/
#include <libsolutil/Whiskers.h>
#include <libsolutil/Assertions.h>
#include <regex>
using namespace std;
using namespace solidity::util;
Whiskers::Whiskers(string _template):
m_template(move(_template))
{
}
Whiskers& Whiskers::operator()(string _parameter, string _value)
{
checkParameterValid(_parameter);
checkParameterUnknown(_parameter);
m_parameters[move(_parameter)] = move(_value);
return *this;
}
Whiskers& Whiskers::operator()(string _parameter, bool _value)
{
checkParameterValid(_parameter);
checkParameterUnknown(_parameter);
m_conditions[move(_parameter)] = _value;
return *this;
}
Whiskers& Whiskers::operator()(
string _listParameter,
vector<map<string, string>> _values
)
{
checkParameterValid(_listParameter);
checkParameterUnknown(_listParameter);
for (auto const& element: _values)
for (auto const& val: element)
checkParameterValid(val.first);
m_listParameters[move(_listParameter)] = move(_values);
return *this;
}
string Whiskers::render() const
{
return replace(m_template, m_parameters, m_conditions, m_listParameters);
}
void Whiskers::checkParameterValid(string const& _parameter) const
{
static regex validParam("^" + paramRegex() + "$");
assertThrow(
regex_match(_parameter, validParam),
WhiskersError,
"Parameter" + _parameter + " contains invalid characters."
);
}
void Whiskers::checkParameterUnknown(string const& _parameter) const
{
assertThrow(
!m_parameters.count(_parameter),
WhiskersError,
_parameter + " already set as value parameter."
);
assertThrow(
!m_conditions.count(_parameter),
WhiskersError,
_parameter + " already set as condition parameter."
);
assertThrow(
!m_listParameters.count(_parameter),
WhiskersError,
_parameter + " already set as list parameter."
);
}
namespace
{
template<class ReplaceCallback>
string regex_replace(
string const& _source,
regex const& _pattern,
ReplaceCallback _replace,
regex_constants::match_flag_type _flags = regex_constants::match_default
)
{
sregex_iterator curMatch(_source.begin(), _source.end(), _pattern, _flags);
sregex_iterator matchEnd;
string::const_iterator lastMatchedPos(_source.cbegin());
string result;
while (curMatch != matchEnd)
{
result.append(curMatch->prefix().first, curMatch->prefix().second);
result.append(_replace(*curMatch));
lastMatchedPos = (*curMatch)[0].second;
++curMatch;
}
result.append(lastMatchedPos, _source.cend());
return result;
}
}
string Whiskers::replace(
string const& _template,
StringMap const& _parameters,
map<string, bool> const& _conditions,
map<string, vector<StringMap>> const& _listParameters
)
{
static regex listOrTag("<(" + paramRegex() + ")>|<#(" + paramRegex() + ")>((?:.|\\r|\\n)*?)</\\2>|<\\?(" + paramRegex() + ")>((?:.|\\r|\\n)*?)(<!\\4>((?:.|\\r|\\n)*?))?</\\4>");
return regex_replace(_template, listOrTag, [&](match_results<string::const_iterator> _match) -> string
{
string tagName(_match[1]);
string listName(_match[2]);
string conditionName(_match[4]);
if (!tagName.empty())
{
assertThrow(
_parameters.count(tagName),
WhiskersError,
"Value for tag " + tagName + " not provided.\n" +
"Template:\n" +
_template
);
return _parameters.at(tagName);
}
else if (!listName.empty())
{
string templ(_match[3]);
assertThrow(
_listParameters.count(listName),
WhiskersError, "List parameter " + listName + " not set."
);
string replacement;
for (auto const& parameters: _listParameters.at(listName))
replacement += replace(templ, joinMaps(_parameters, parameters), _conditions);
return replacement;
}
else
{
assertThrow(!conditionName.empty(), WhiskersError, "");
assertThrow(
_conditions.count(conditionName),
WhiskersError, "Condition parameter " + conditionName + " not set."
);
return replace(
_conditions.at(conditionName) ? _match[5] : _match[7],
_parameters,
_conditions,
_listParameters
);
}
});
}
Whiskers::StringMap Whiskers::joinMaps(
Whiskers::StringMap const& _a,
Whiskers::StringMap const& _b
)
{
Whiskers::StringMap ret = _a;
for (auto const& x: _b)
assertThrow(
ret.insert(x).second,
WhiskersError,
"Parameter collision"
);
return ret;
}
+111
View File
@@ -0,0 +1,111 @@
/*
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 Whiskers.h
* @author Chris <chis@ethereum.org>
* @date 2017
*
* Moustache-like templates.
*/
#pragma once
#include <libsolutil/Exceptions.h>
#include <string>
#include <map>
#include <vector>
namespace solidity::util
{
DEV_SIMPLE_EXCEPTION(WhiskersError);
/**
* Moustache-like templates.
*
* Usage:
* std::vector<std::map<std::string, std::string>> listValues(2);
* listValues[0]["k"] = "key1";
* listValues[0]["v"] = "value1";
* listValues[1]["k"] = "key2";
* listValues[1]["v"] = "value2";
* auto s = Whiskers("<?c><p1><!c>y</c>\n<#list><k> -> <v>\n</list>")
* ("p1", "HEAD")
* ("c", true)
* ("list", listValues)
* .render();
*
* results in s == "HEAD\nkey1 -> value1\nkey2 -> value2\n"
*
* Note that lists cannot themselves contain lists - this would be a future feature.
*
* The elements are:
* - Regular parameter: <name>
* just replaced
* - Condition parameter: <?name>...<!name>...</name>, where "<!name>" is optional
* replaced (and recursively expanded) by the first part if the condition is true
* and by the second (or empty string if missing) if the condition is false
* - List parameter: <#list>...</list>
* The part between the tags is repeated as often as values are provided
* in the mapping. Each list element can have its own parameter -> value mapping.
*/
class Whiskers
{
public:
using StringMap = std::map<std::string, std::string>;
using StringListMap = std::map<std::string, std::vector<StringMap>>;
explicit Whiskers(std::string _template);
/// Sets a single regular parameter, <paramName>.
Whiskers& operator()(std::string _parameter, std::string _value);
Whiskers& operator()(std::string _parameter, char const* _value) { return (*this)(_parameter, std::string{_value}); }
/// Sets a condition parameter, <?paramName>...<!paramName>...</paramName>
Whiskers& operator()(std::string _parameter, bool _value);
/// Sets a list parameter, <#listName> </listName>.
Whiskers& operator()(
std::string _listParameter,
std::vector<StringMap> _values
);
std::string render() const;
private:
// Prevent implicit cast to bool
Whiskers& operator()(std::string _parameter, long long);
void checkParameterValid(std::string const& _parameter) const;
void checkParameterUnknown(std::string const& _parameter) const;
static std::string replace(
std::string const& _template,
StringMap const& _parameters,
std::map<std::string, bool> const& _conditions,
StringListMap const& _listParameters = StringListMap()
);
static std::string paramRegex() { return "[a-zA-Z0-9_$-]+"; }
/// Joins the two maps throwing an exception if two keys are equal.
static StringMap joinMaps(StringMap const& _a, StringMap const& _b);
std::string m_template;
StringMap m_parameters;
std::map<std::string, bool> m_conditions;
StringListMap m_listParameters;
};
}
+288
View File
@@ -0,0 +1,288 @@
/*
The MIT License (MIT)
Copyright (C) 2014 okdshin
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#pragma once
//picosha2:20140213
#include <cstdint>
#include <iostream>
#include <vector>
#include <iterator>
#include <cassert>
#include <sstream>
#include <algorithm>
namespace picosha2
{
namespace detail
{
inline uint8_t mask_8bit(uint8_t x)
{
return x & 0xff;
}
inline uint32_t mask_32bit(uint32_t x)
{
return x & 0xffffffff;
}
static uint32_t const add_constant[64] = {
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
};
static uint32_t const initial_message_digest[8] = {
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
};
inline uint32_t ch(uint32_t x, uint32_t y, uint32_t z)
{
return (x & y) ^ ((~x) & z);
}
inline uint32_t maj(uint32_t x, uint32_t y, uint32_t z)
{
return (x & y) ^ (x & z) ^ (y & z);
}
inline uint32_t rotr(uint32_t x, std::size_t n)
{
assert(n < 32);
return mask_32bit((x >> n) | (x << (32 - n)));
}
inline uint32_t bsig0(uint32_t x)
{
return rotr(x, 2) ^ rotr(x, 13) ^ rotr(x, 22);
}
inline uint32_t bsig1(uint32_t x)
{
return rotr(x, 6) ^ rotr(x, 11) ^ rotr(x, 25);
}
inline uint32_t shr(uint32_t x, std::size_t n)
{
assert(n < 32);
return x >> n;
}
inline uint32_t ssig0(uint32_t x)
{
return rotr(x, 7) ^ rotr(x, 18) ^ shr(x, 3);
}
inline uint32_t ssig1(uint32_t x)
{
return rotr(x, 17) ^ rotr(x, 19) ^ shr(x, 10);
}
template<typename RaIter1, typename RaIter2>
void hash256_block(RaIter1 message_digest, RaIter2 first, RaIter2 last)
{
(void)last; // FIXME: check this is valid
uint32_t w[64];
std::fill(w, w+64, 0);
for (std::size_t i = 0; i < 16; ++i)
w[i] = (static_cast<uint32_t>(mask_8bit(*(first + i * 4))) << 24)
| (static_cast<uint32_t>(mask_8bit(*(first + i * 4 + 1))) << 16)
| (static_cast<uint32_t>(mask_8bit(*(first + i * 4 + 2))) << 8)
| (static_cast<uint32_t>(mask_8bit(*(first + i * 4 + 3))));
for (std::size_t i = 16; i < 64; ++i)
w[i] = mask_32bit(ssig1(w[i-2])+w[i-7]+ssig0(w[i-15])+w[i-16]);
uint32_t a = *message_digest;
uint32_t b = *(message_digest + 1);
uint32_t c = *(message_digest + 2);
uint32_t d = *(message_digest + 3);
uint32_t e = *(message_digest + 4);
uint32_t f = *(message_digest + 5);
uint32_t g = *(message_digest + 6);
uint32_t h = *(message_digest + 7);
for (std::size_t i = 0; i < 64; ++i)
{
uint32_t temp1 = h+bsig1(e)+ch(e,f,g)+add_constant[i]+w[i];
uint32_t temp2 = bsig0(a)+maj(a,b,c);
h = g;
g = f;
f = e;
e = mask_32bit(d+temp1);
d = c;
c = b;
b = a;
a = mask_32bit(temp1+temp2);
}
*message_digest += a;
*(message_digest+1) += b;
*(message_digest+2) += c;
*(message_digest+3) += d;
*(message_digest+4) += e;
*(message_digest+5) += f;
*(message_digest+6) += g;
*(message_digest+7) += h;
for (std::size_t i = 0; i < 8; ++i)
*(message_digest+i) = mask_32bit(*(message_digest+i));
}
}//namespace detail
class hash256_one_by_one
{
public:
hash256_one_by_one()
{
init();
}
void init()
{
buffer_.clear();
std::fill(data_length_digits_, data_length_digits_ + 4, 0);
std::copy(detail::initial_message_digest, detail::initial_message_digest+8, h_);
}
template<typename RaIter>
void process(RaIter first, RaIter last)
{
add_to_data_length(std::distance(first, last));
std::copy(first, last, std::back_inserter(buffer_));
std::size_t i = 0;
for (;i + 64 <= buffer_.size(); i+=64)
detail::hash256_block(h_, buffer_.begin()+i, buffer_.begin()+i+64);
buffer_.erase(buffer_.begin(), buffer_.begin()+i);
}
void finish()
{
uint8_t temp[64];
std::fill(temp, temp+64, 0);
std::size_t remains = buffer_.size();
std::copy(buffer_.begin(), buffer_.end(), temp);
temp[remains] = 0x80;
if (remains > 55)
{
std::fill(temp+remains+1, temp+64, 0);
detail::hash256_block(h_, temp, temp+64);
std::fill(temp, temp+64-4, 0);
}
else
std::fill(temp+remains+1, temp+64-4, 0);
write_data_bit_length(&(temp[56]));
detail::hash256_block(h_, temp, temp+64);
}
template<typename OutIter>
void get_hash_bytes(OutIter first, OutIter last) const
{
for (uint32_t const* iter = h_; iter != h_ + 8; ++iter)
for (std::size_t i = 0; i < 4 && first != last; ++i)
*(first++) = detail::mask_8bit(static_cast<uint8_t>(*iter >> (24 - 8 * i)));
}
private:
void add_to_data_length(uint32_t n)
{
uint32_t carry = 0;
data_length_digits_[0] += n;
for (std::size_t i = 0; i < 4; ++i)
{
data_length_digits_[i] += carry;
if (data_length_digits_[i] >= 65536u)
{
carry = data_length_digits_[i] >> 16;
data_length_digits_[i] &= 65535u;
}
else
break;
}
}
void write_data_bit_length(uint8_t* begin)
{
uint32_t data_bit_length_digits[4];
std::copy(
data_length_digits_, data_length_digits_ + 4,
data_bit_length_digits
);
// convert byte length to bit length (multiply 8 or shift 3 times left)
uint32_t carry = 0;
for (std::size_t i = 0; i < 4; ++i)
{
uint32_t before_val = data_bit_length_digits[i];
data_bit_length_digits[i] <<= 3;
data_bit_length_digits[i] |= carry;
data_bit_length_digits[i] &= 65535u;
carry = (before_val >> (16-3)) & 65535u;
}
// write data_bit_length
for (int i = 3; i >= 0; --i)
{
(*begin++) = static_cast<uint8_t>(data_bit_length_digits[i] >> 8);
(*begin++) = static_cast<uint8_t>(data_bit_length_digits[i]);
}
}
std::vector<uint8_t> buffer_;
uint32_t data_length_digits_[4]; //as 64bit integer (16bit x 4 integer)
uint32_t h_[8];
};
template<typename RaIter, typename OutIter>
void hash256(RaIter first, RaIter last, OutIter first2, OutIter last2)
{
hash256_one_by_one hasher;
//hasher.init();
hasher.process(first, last);
hasher.finish();
hasher.get_hash_bytes(first2, last2);
}
template <typename RaContainer>
std::vector<uint8_t> hash256(RaContainer const& _src)
{
std::vector<uint8_t> ret(32);
hash256(_src.begin(), _src.end(), ret.begin(), ret.end());
return ret;
}
}//namespace picosha2
+79
View File
@@ -0,0 +1,79 @@
#pragma once
#include <cstring>
#include <cassert>
#include <type_traits>
#include <vector>
#include <string>
#ifdef __INTEL_COMPILER
#pragma warning(disable:597) // will not be called for implicit or explicit conversions
#endif
namespace solidity::util
{
/**
* A modifiable reference to an existing object or vector in memory.
*/
template <class _T>
class vector_ref
{
public:
using value_type = _T;
using element_type = _T;
using mutable_value_type = typename std::conditional<std::is_const<_T>::value, typename std::remove_const<_T>::type, _T>::type;
using string_type = typename std::conditional<std::is_const<_T>::value, std::string const, std::string>::type;
using vector_type = typename std::conditional<std::is_const<_T>::value, std::vector<typename std::remove_const<_T>::type> const, std::vector<_T>>::type;
using iterator = _T*;
using const_iterator = _T const*;
static_assert(std::is_pod<value_type>::value, "vector_ref can only be used with PODs due to its low-level treatment of data.");
vector_ref(): m_data(nullptr), m_count(0) {}
/// Creates a new vector_ref to point to @a _count elements starting at @a _data.
vector_ref(_T* _data, size_t _count): m_data(_data), m_count(_count) {}
/// Creates a new vector_ref pointing to the data part of a string (given as pointer).
vector_ref(string_type* _data): m_data(reinterpret_cast<_T*>(_data->data())), m_count(_data->size() / sizeof(_T)) {}
/// Creates a new vector_ref pointing to the data part of a string (given as reference).
vector_ref(string_type& _data): vector_ref(&_data) {}
/// Creates a new vector_ref pointing to the data part of a vector (given as pointer).
vector_ref(vector_type* _data): m_data(_data->data()), m_count(_data->size()) {}
explicit operator bool() const { return m_data && m_count; }
std::vector<unsigned char> toBytes() const { return std::vector<unsigned char>(reinterpret_cast<unsigned char const*>(m_data), reinterpret_cast<unsigned char const*>(m_data) + m_count * sizeof(_T)); }
std::string toString() const { return std::string((char const*)m_data, ((char const*)m_data) + m_count * sizeof(_T)); }
template <class _T2> explicit operator vector_ref<_T2>() const { assert(m_count * sizeof(_T) / sizeof(_T2) * sizeof(_T2) / sizeof(_T) == m_count); return vector_ref<_T2>(reinterpret_cast<_T2*>(m_data), m_count * sizeof(_T) / sizeof(_T2)); }
operator vector_ref<_T const>() const { return vector_ref<_T const>(m_data, m_count); }
_T* data() const { return m_data; }
/// @returns the number of elements referenced (not necessarily number of bytes).
size_t size() const { return m_count; }
bool empty() const { return !m_count; }
/// @returns a new vector_ref which is a shifted and shortened view of the original data.
/// If this goes out of bounds in any way, returns an empty vector_ref.
/// If @a _count is ~size_t(0), extends the view to the end of the data.
vector_ref<_T> cropped(size_t _begin, size_t _count) const { if (m_data && _begin <= m_count && _count <= m_count && _begin + _count <= m_count) return vector_ref<_T>(m_data + _begin, _count == ~size_t(0) ? m_count - _begin : _count); else return vector_ref<_T>(); }
/// @returns a new vector_ref which is a shifted view of the original data (not going beyond it).
vector_ref<_T> cropped(size_t _begin) const { if (m_data && _begin <= m_count) return vector_ref<_T>(m_data + _begin, m_count - _begin); else return vector_ref<_T>(); }
_T* begin() { return m_data; }
_T* end() { return m_data + m_count; }
_T const* begin() const { return m_data; }
_T const* end() const { return m_data + m_count; }
_T& operator[](size_t _i) { assert(m_data); assert(_i < m_count); return m_data[_i]; }
_T const& operator[](size_t _i) const { assert(m_data); assert(_i < m_count); return m_data[_i]; }
bool operator==(vector_ref<_T> const& _cmp) const { return m_data == _cmp.m_data && m_count == _cmp.m_count; }
bool operator!=(vector_ref<_T> const& _cmp) const { return !operator==(_cmp); }
void reset() { m_data = nullptr; m_count = 0; }
private:
_T* m_data = nullptr;
size_t m_count = 0;
};
}