This commit is contained in:
Dobromir Popov
2025-09-07 15:03:47 +03:00
parent 00cda24e71
commit 2d2653551b
132 changed files with 34281 additions and 5 deletions

View File

@@ -0,0 +1,9 @@
file(GLOB HEADERS "*.h")
file(GLOB SOURCES "*.cpp")
find_package(Threads)
add_library(devcore ${SOURCES} ${HEADERS})
target_link_libraries(devcore PUBLIC Boost::boost Boost::system)
target_link_libraries(devcore PRIVATE Threads::Threads)

51
zano/libdevcore/Common.h Normal file
View File

@@ -0,0 +1,51 @@
// progminer -- Ethereum miner with OpenCL, CUDA and stratum support.
// Copyright 2018 progminer Authors.
// Licensed under GNU General Public License, Version 3. See the LICENSE file.
/// @file
/// Very common stuff (i.e. that every other header needs except vector_ref.h).
#pragma once
#include "vector_ref.h"
#include <string>
#include <vector>
#include <boost/multiprecision/cpp_int.hpp>
using byte = uint8_t;
namespace dev
{
// Binary data types.
using bytes = std::vector<byte>;
using bytesRef = vector_ref<byte>;
using bytesConstRef = vector_ref<byte const>;
// Numeric types.
using bigint = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<>>;
using u64 = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<64, 64,
boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>;
using u128 = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<128, 128,
boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>;
using u256 = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<256, 256,
boost::multiprecision::unsigned_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>>;
using u512 = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<512, 512,
boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>;
// Null/Invalid values for convenience.
static const u256 Invalid256 = ~(u256)0;
/// 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();
}
} // namespace dev

View File

@@ -0,0 +1,201 @@
/*
This file is part of progminer.
progminer 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.
progminer 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 progminer. If not, see <http://www.gnu.org/licenses/>.
*/
#include <cstdlib>
#include "CommonData.h"
#include "Exceptions.h"
using namespace std;
using namespace dev;
int dev::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)
BOOST_THROW_EXCEPTION(BadHexCharacter() << errinfo_invalidSymbol(_i));
else
return -1;
}
bytes dev::fromHex(std::string const& _s, WhenError _throw)
{
unsigned s = (_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++], WhenError::DontThrow);
if (h != -1)
ret.push_back(h);
else if (_throw == WhenError::Throw)
BOOST_THROW_EXCEPTION(BadHexCharacter());
else
return bytes();
}
for (unsigned i = s; i < _s.size(); i += 2)
{
int h = fromHex(_s[i], WhenError::DontThrow);
int l = fromHex(_s[i + 1], WhenError::DontThrow);
if (h != -1 && l != -1)
ret.push_back((byte)(h * 16 + l));
else if (_throw == WhenError::Throw)
BOOST_THROW_EXCEPTION(BadHexCharacter());
else
return bytes();
}
return ret;
}
bool dev::setenv(const char name[], const char value[], bool override)
{
#if _WIN32
if (!override && std::getenv(name) != nullptr)
return true;
return ::_putenv_s(name, value) == 0;
#else
return ::setenv(name, value, override ? 1 : 0) == 0;
#endif
}
std::string dev::getTargetFromDiff(double diff, HexPrefix _prefix)
{
using namespace boost::multiprecision;
using BigInteger = boost::multiprecision::cpp_int;
static BigInteger base("0x00000000ffff0000000000000000000000000000000000000000000000000000");
BigInteger product;
if (diff == 0)
{
product = BigInteger("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
}
else
{
diff = 1 / diff;
BigInteger idiff(diff);
product = base * idiff;
std::string sdiff = boost::lexical_cast<std::string>(diff);
size_t ldiff = sdiff.length();
size_t offset = sdiff.find(".");
if (offset != std::string::npos)
{
// Number of decimal places
size_t precision = (ldiff - 1) - offset;
// Effective sequence of decimal places
string decimals = sdiff.substr(offset + 1);
// Strip leading zeroes. If a string begins with
// 0 or 0x boost parser considers it hex
decimals = decimals.erase(0, decimals.find_first_not_of('0'));
// Build up the divisor as string - just in case
// parser does some implicit conversion with 10^precision
string decimalDivisor = "1";
decimalDivisor.resize(precision + 1, '0');
// This is the multiplier for the decimal part
BigInteger multiplier(decimals);
// This is the divisor for the decimal part
BigInteger divisor(decimalDivisor);
BigInteger decimalproduct;
decimalproduct = base * multiplier;
decimalproduct /= divisor;
// Add the computed decimal part
// to product
product += decimalproduct;
}
}
// Normalize to 64 chars hex with "0x" prefix
stringstream ss;
ss << (_prefix == HexPrefix::Add ? "0x" : "") << setw(64) << setfill('0') << std::hex
<< product;
string target = ss.str();
boost::algorithm::to_lower(target);
return target;
}
double dev::getHashesToTarget(string _target)
{
using namespace boost::multiprecision;
using BigInteger = boost::multiprecision::cpp_int;
static BigInteger dividend(
"0xffff000000000000000000000000000000000000000000000000000000000000");
BigInteger divisor(_target);
return double(dividend / divisor);
}
std::string dev::getScaledSize(double _value, double _divisor, int _precision, string _sizes[],
size_t _numsizes, ScaleSuffix _suffix)
{
double _newvalue = _value;
size_t i = 0;
while (_newvalue > _divisor && i <= (_numsizes - 1))
{
_newvalue /= _divisor;
i++;
}
std::stringstream _ret;
_ret << fixed << setprecision(_precision) << _newvalue;
if (_suffix == ScaleSuffix::Add)
_ret << " " << _sizes[i];
return _ret.str();
}
std::string dev::getFormattedHashes(double _hr, ScaleSuffix _suffix, int _precision)
{
static string suffixes[] = {"h", "Kh", "Mh", "Gh"};
return dev::getScaledSize(_hr, 1000.0, _precision, suffixes, 4, _suffix);
}
std::string dev::getFormattedMemory(double _mem, ScaleSuffix _suffix, int _precision)
{
static string suffixes[] = {"B", "KB", "MB", "GB"};
return dev::getScaledSize(_mem, 1024.0, _precision, suffixes, 4, _suffix);
}
std::string dev::padLeft(std::string _value, size_t _length, char _fillChar)
{
if (_length > _value.size())
_value.insert(0, (_length - _value.size()), _fillChar);
return _value;
}
std::string dev::padRight(std::string _value, size_t _length, char _fillChar)
{
if (_length > _value.size())
_value.resize(_length, _fillChar);
return _value;
}

View File

@@ -0,0 +1,253 @@
/*
This file is part of progminer.
progminer 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.
progminer 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 progminer. 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 <algorithm>
#include <cstring>
#include <string>
#include <type_traits>
#include <unordered_set>
#include <vector>
#include <boost/algorithm/string.hpp>
#include "Common.h"
namespace dev
{
// String conversion functions, mainly to/from hex/nibble/byte representations.
enum class WhenError
{
DontThrow = 0,
Throw = 1,
};
enum class HexPrefix
{
DontAdd = 0,
Add = 1,
};
enum class ScaleSuffix
{
DontAdd = 0,
Add = 1
};
/// Convert a series of bytes to the corresponding string of hex duplets.
/// @param _w specifies the width of the first of the elements. Defaults to two - enough to
/// represent a byte.
/// @example toHex("A\x69") == "4169"
template <class T>
std::string toHex(T const& _data, int _w = 2, HexPrefix _prefix = HexPrefix::DontAdd)
{
std::ostringstream ret;
unsigned ii = 0;
for (auto i : _data)
ret << std::hex << std::setfill('0') << std::setw(ii++ ? 2 : _w)
<< (int)(typename std::make_unsigned<decltype(i)>::type)i;
return (_prefix == HexPrefix::Add) ? "0x" + ret.str() : ret.str();
}
/// Converts a (printable) ASCII hex character into the correspnding integer value.
/// @example fromHex('A') == 10 && fromHex('f') == 15 && fromHex('5') == 5
int fromHex(char _i, WhenError _throw);
/// Converts a (printable) ASCII hex string into the corresponding byte stream.
/// @example fromHex("41626261") == asBytes("Abba")
/// If _throw = ThrowType::DontThrow, it replaces bad hex characters with 0's, otherwise it will
/// throw an exception.
bytes fromHex(std::string const& _s, WhenError _throw = WhenError::DontThrow);
/// Converts byte array to a string containing the same (binary) data. Unless
/// the byte array happens to contain ASCII data, this won't be printable.
inline std::string asString(bytes const& _b)
{
return std::string((char const*)_b.data(), (char const*)(_b.data() + _b.size()));
}
/// Converts a string to a byte array containing the string's (byte) data.
inline bytes asBytes(std::string const& _b)
{
return bytes((byte const*)_b.data(), (byte const*)(_b.data() + _b.size()));
}
// 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) | (byte)(typename std::make_unsigned<typename _In::value_type>::type)i);
return ret;
}
/// Convenience functions for toBigEndian
inline bytes toBigEndian(u256 _val)
{
bytes ret(32);
toBigEndian(std::move(_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 toHex(uint64_t _n, HexPrefix _prefix = HexPrefix::DontAdd, int _bytes = 16)
{
// sizeof returns the number of bytes (not the number of bits)
// thus if CHAR_BIT != 8 sizeof(uint64_t) will return != 8
// Use fixed constant multiplier of 16
std::ostringstream ret;
ret << std::hex << std::setfill('0') << std::setw(_bytes) << _n;
return (_prefix == HexPrefix::Add) ? "0x" + ret.str() : ret.str();
}
inline std::string toHex(uint32_t _n, HexPrefix _prefix = HexPrefix::DontAdd, int _bytes = 8)
{
// sizeof returns the number of bytes (not the number of bits)
// thus if CHAR_BIT != 8 sizeof(uint64_t) will return != 4
// Use fixed constant multiplier of 8
std::ostringstream ret;
ret << std::hex << std::setfill('0') << std::setw(_bytes) << _n;
return (_prefix == HexPrefix::Add) ? "0x" + ret.str() : ret.str();
}
inline std::string toCompactHex(uint64_t _n, HexPrefix _prefix = HexPrefix::DontAdd)
{
std::ostringstream ret;
ret << std::hex << _n;
return (_prefix == HexPrefix::Add) ? "0x" + ret.str() : ret.str();
}
inline std::string toCompactHex(uint32_t _n, HexPrefix _prefix = HexPrefix::DontAdd)
{
std::ostringstream ret;
ret << std::hex << _n;
return (_prefix == HexPrefix::Add) ? "0x" + ret.str() : ret.str();
}
// Algorithms for string and string-like collections.
/// Escapes a string into the C-string representation.
/// @p _all if true will escape all characters, not just the unprintable ones.
std::string escaped(std::string const& _s, bool _all = true);
// General datatype convenience functions.
/// 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;
}
/// Sets environment variable.
///
/// Portable wrapper for setenv / _putenv C library functions.
bool setenv(const char name[], const char value[], bool override = false);
/// Gets a target hash from given difficulty
std::string getTargetFromDiff(double diff, HexPrefix _prefix = HexPrefix::Add);
/// Gets the difficulty expressed in hashes to target
double getHashesToTarget(std::string _target);
/// Generic function to scale a value
std::string getScaledSize(double _value, double _divisor, int _precision, std::string _sizes[],
size_t _numsizes, ScaleSuffix _suffix = ScaleSuffix::Add);
/// Formats hashrate
std::string getFormattedHashes(double _hr, ScaleSuffix _suffix = ScaleSuffix::Add, int _precision = 2);
/// Formats hashrate
std::string getFormattedMemory(
double _mem, ScaleSuffix _suffix = ScaleSuffix::Add, int _precision = 2);
/// Adjust string to a fixed length filling chars to the Left
std::string padLeft(std::string _value, size_t _length, char _fillChar);
/// Adjust string to a fixed length filling chars to the Right
std::string padRight(std::string _value, size_t _length, char _fillChar);
} // namespace dev

View File

@@ -0,0 +1,70 @@
/*
This file is part of progminer.
progminer 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.
progminer 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 progminer. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file Exceptions.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#pragma once
#include <exception>
#include <string>
#include <boost/exception/all.hpp>
#include <boost/throw_exception.hpp>
#include "CommonData.h"
#include "FixedHash.h"
namespace dev
{
/// Base class for all exceptions.
struct Exception : virtual std::exception, virtual boost::exception
{
Exception(const std::string& _message = std::string()) : m_message(std::move(_message)) {}
const char* what() const noexcept override
{
return m_message.empty() ? std::exception::what() : m_message.c_str();
}
private:
std::string m_message;
};
#define DEV_SIMPLE_EXCEPTION(X) \
struct X : virtual Exception \
{ \
const char* what() const noexcept override { return #X; } \
}
DEV_SIMPLE_EXCEPTION(BadHexCharacter);
struct ExternalFunctionFailure : virtual Exception
{
public:
ExternalFunctionFailure(const std::string& _f) : Exception("Function " + _f + "() failed.") {}
};
// error information to be added to exceptions
using errinfo_invalidSymbol = boost::error_info<struct tag_invalidSymbol, char>;
using errinfo_comment = boost::error_info<struct tag_comment, std::string>;
using errinfo_required = boost::error_info<struct tag_required, bigint>;
using errinfo_got = boost::error_info<struct tag_got, bigint>;
using RequirementError = boost::tuple<errinfo_required, errinfo_got>;
} // namespace dev

View File

@@ -0,0 +1,29 @@
/*
This file is part of progminer.
progminer 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.
progminer 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 progminer. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file FixedHash.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#include <boost/algorithm/string.hpp>
#include "FixedHash.h"
using namespace std;
using namespace dev;
std::random_device dev::s_fixedHashEngine;

338
zano/libdevcore/FixedHash.h Normal file
View File

@@ -0,0 +1,338 @@
/*
This file is part of progminer.
progminer 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.
progminer 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 progminer. 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 <algorithm>
#include <array>
#include <cstdint>
#include <random>
#include "CommonData.h"
namespace dev
{
extern std::random_device s_fixedHashEngine;
/// 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:
#if defined(_WIN32)
const char* k_ellipsis = "...";
#else
const char* k_ellipsis = "\342\200\246";
#endif
/// 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
};
/// A dummy flag to avoid accidental construction from pointer.
enum ConstructFromPointerType
{
ConstructFromPointer
};
/// Method to convert from a string.
enum ConstructFromHashType
{
AlignLeft,
AlignRight,
FailIfDifferent
};
/// Construct an empty hash.
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 bytes in memory with given pointer.
explicit FixedHash(byte const* _bs, ConstructFromPointerType /*unused*/)
{
memcpy(m_data.data(), _bs, N);
}
/// Explicitly construct, copying from a string.
explicit FixedHash(std::string const& _s)
: FixedHash(fromHex(_s, WhenError::Throw), FailIfDifferent)
{}
/// 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(), [](byte _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; }
bool operator<(FixedHash const& _c) const
{
for (unsigned i = 0; i < N; ++i)
{
if (m_data[i] < _c.m_data[i])
return true;
if (m_data[i] > _c.m_data[i])
return false;
}
return false;
}
bool operator>=(FixedHash const& _c) const { return !operator<(_c); }
bool operator<=(FixedHash const& _c) const { return operator==(_c) || operator<(_c); }
bool operator>(FixedHash const& _c) const { return !operator<=(_c); }
// The obvious binary operators.
FixedHash& operator^=(FixedHash const& _c)
{
for (unsigned i = 0; i < N; ++i)
m_data[i] ^= _c.m_data[i];
return *this;
}
FixedHash operator^(FixedHash const& _c) const { return FixedHash(*this) ^= _c; }
FixedHash& operator|=(FixedHash const& _c)
{
for (unsigned i = 0; i < N; ++i)
m_data[i] |= _c.m_data[i];
return *this;
}
FixedHash operator|(FixedHash const& _c) const { return FixedHash(*this) |= _c; }
FixedHash& operator&=(FixedHash const& _c)
{
for (unsigned i = 0; i < N; ++i)
m_data[i] &= _c.m_data[i];
return *this;
}
FixedHash operator&(FixedHash const& _c) const { return FixedHash(*this) &= _c; }
FixedHash operator~() const
{
FixedHash ret;
for (unsigned i = 0; i < N; ++i)
ret[i] = ~m_data[i];
return ret;
}
// Big-endian increment.
FixedHash& operator++()
{
for (unsigned i = size; i > 0 && !++m_data[--i];)
{
}
return *this;
}
/// @returns a particular byte from the hash.
byte& operator[](unsigned _i) { return m_data[_i]; }
/// @returns a particular byte from the hash.
byte operator[](unsigned _i) const { return m_data[_i]; }
/// @returns an abridged version of the hash as a user-readable hex string.
std::string abridged() const { return toHex(ref().cropped(0, 4)) + k_ellipsis; }
/// @returns the hash as a user-readable hex string.
std::string hex(HexPrefix _prefix = HexPrefix::DontAdd) const { return toHex(ref(), 2, _prefix); }
/// @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.
byte* data() { return m_data.data(); }
/// @returns a constant byte pointer to the object's data.
byte const* data() const { return m_data.data(); }
/// Populate with random data.
template <class Engine>
void randomize(Engine& _eng)
{
for (auto& i : m_data)
i = (uint8_t)std::uniform_int_distribution<uint16_t>(0, 255)(_eng);
}
/// @returns a random valued object.
static FixedHash random()
{
FixedHash ret;
ret.randomize(s_fixedHashEngine);
return ret;
}
struct hash
{
/// Make a hash of the object's data.
size_t operator()(FixedHash const& _value) const
{
return boost::hash_range(_value.m_data.cbegin(), _value.m_data.cend());
}
};
void clear() { m_data.fill(0); }
private:
std::array<byte, N> m_data; ///< The binary data.
};
/// Fast equality operator for h256.
template <>
inline bool FixedHash<32>::operator==(FixedHash<32> const& _other) const
{
const uint64_t* hash1 = (const uint64_t*)data();
const uint64_t* hash2 = (const uint64_t*)_other.data();
return (hash1[0] == hash2[0]) && (hash1[1] == hash2[1]) && (hash1[2] == hash2[2]) &&
(hash1[3] == hash2[3]);
}
/// Fast std::hash compatible hash function object for h256.
template <>
inline size_t FixedHash<32>::hash::operator()(FixedHash<32> const& value) const
{
uint64_t const* data = reinterpret_cast<uint64_t const*>(value.data());
return boost::hash_range(data, data + 4);
}
/// Stream I/O for the FixedHash class.
template <unsigned N>
inline std::ostream& operator<<(std::ostream& _out, FixedHash<N> const& _h)
{
_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 h2048 = FixedHash<256>;
using h1024 = FixedHash<128>;
using h520 = FixedHash<65>;
using h512 = FixedHash<64>;
using h256 = FixedHash<32>;
using h160 = FixedHash<20>;
using h128 = FixedHash<16>;
using h64 = FixedHash<8>;
using h512s = std::vector<h512>;
using h256s = std::vector<h256>;
using h160s = std::vector<h160>;
inline std::string toString(h256s const& _bs)
{
std::ostringstream out;
out << "[ ";
for (auto i : _bs)
out << i.abridged() << ", ";
out << "]";
return out.str();
}
} // namespace dev
namespace std
{
/// Forward std::hash<dev::FixedHash> to dev::FixedHash::hash.
template <>
struct hash<dev::h64> : dev::h64::hash
{
};
template <>
struct hash<dev::h128> : dev::h128::hash
{
};
template <>
struct hash<dev::h160> : dev::h160::hash
{
};
template <>
struct hash<dev::h256> : dev::h256::hash
{
};
template <>
struct hash<dev::h512> : dev::h512::hash
{
};
} // namespace std

76
zano/libdevcore/Guards.h Normal file
View File

@@ -0,0 +1,76 @@
/*
This file is part of progminer.
progminer 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.
progminer 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 progminer. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file Guards.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#pragma once
#include <atomic>
#include <mutex>
namespace dev
{
using Mutex = std::mutex;
using Guard = std::lock_guard<std::mutex>;
using UniqueGuard = std::unique_lock<std::mutex>;
template <class GuardType, class MutexType>
struct GenericGuardBool : GuardType
{
GenericGuardBool(MutexType& _m) : GuardType(_m) {}
bool b = true;
};
/** @brief Simple block guard.
* The expression/block following is guarded though the given mutex.
* Usage:
* @code
* Mutex m;
* unsigned d;
* ...
* ETH_(m) d = 1;
* ...
* ETH_(m) { for (auto d = 10; d > 0; --d) foo(d); d = 0; }
* @endcode
*
* There are several variants of this basic mechanism for different Mutex types and Guards.
*
* There is also the UNGUARD variant which allows an unguarded expression/block to exist within a
* guarded expression. eg:
*
* @code
* Mutex m;
* int d;
* ...
* ETH_GUARDED(m)
* {
* for (auto d = 50; d > 25; --d)
* foo(d);
* ETH_UNGUARDED(m)
* bar();
* for (; d > 0; --d)
* foo(d);
* }
* @endcode
*/
#define DEV_GUARDED(MUTEX) \
for (GenericGuardBool<Guard, Mutex> __eth_l(MUTEX); __eth_l.b; __eth_l.b = false)
} // namespace dev

134
zano/libdevcore/Log.cpp Normal file
View File

@@ -0,0 +1,134 @@
/*
This file is part of progminer.
progminer 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.
progminer 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 progminer. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Log.h"
#include <map>
#include <thread>
#ifdef __APPLE__
#include <pthread.h>
#endif
#include "Guards.h"
using namespace std;
using namespace dev;
//⊳⊲◀▶■▣▢□▷◁▧▨▩▲◆◉◈◇◎●◍◌○◼☑☒☎☢☣☰☀♽♥♠✩✭❓✔✓✖✕✘✓✔✅⚒⚡⦸⬌∅⁕«««»»»⚙
// Logging
unsigned g_logOptions = 0;
bool g_logNoColor = false;
bool g_logSyslog = false;
bool g_logStdout = false;
const char* LogChannel::name()
{
return EthGray "..";
}
const char* WarnChannel::name()
{
return EthRed " X";
}
const char* NoteChannel::name()
{
return EthBlue " i";
}
LogOutputStreamBase::LogOutputStreamBase(char const* _id)
{
static std::locale logLocl = std::locale("");
m_sstr.imbue(logLocl);
if (g_logSyslog)
m_sstr << std::left << std::setw(8) << getThreadName() << " " EthReset;
else
{
time_t rawTime = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
char buf[24];
if (strftime(buf, 24, "%X", localtime(&rawTime)) == 0)
buf[0] = '\0'; // empty if case strftime fails
m_sstr << _id << " " EthViolet << buf << " " EthBlue << std::left << std::setw(9)
<< getThreadName() << " " EthReset;
}
}
/// Associate a name with each thread for nice logging.
struct ThreadLocalLogName
{
ThreadLocalLogName(char const* _name) { name = _name; }
thread_local static char const* name;
};
thread_local char const* ThreadLocalLogName::name;
ThreadLocalLogName g_logThreadName("main");
string dev::getThreadName()
{
#if defined(__linux__) || defined(__APPLE__)
char buffer[128];
pthread_getname_np(pthread_self(), buffer, 127);
buffer[127] = 0;
return buffer;
#else
return ThreadLocalLogName::name ? ThreadLocalLogName::name : "<unknown>";
#endif
}
void dev::setThreadName(char const* _n)
{
#if defined(__linux__)
pthread_setname_np(pthread_self(), _n);
#elif defined(__APPLE__)
pthread_setname_np(_n);
#else
ThreadLocalLogName::name = _n;
#endif
}
void dev::simpleDebugOut(std::string const& _s)
{
try
{
std::ostream& os = g_logStdout ? std::cout : std::clog;
if (!g_logNoColor)
{
os << _s + '\n';
os.flush();
return;
}
bool skip = false;
std::stringstream ss;
for (auto it : _s)
{
if (!skip && it == '\x1b')
skip = true;
else if (skip && it == 'm')
skip = false;
else if (!skip)
ss << it;
}
ss << '\n';
os << ss.str();
os.flush();
}
catch (...)
{
return;
}
}

123
zano/libdevcore/Log.h Normal file
View File

@@ -0,0 +1,123 @@
/*
This file is part of progminer.
progminer 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.
progminer 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 progminer. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file Log.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*
* The logging subsystem.
*/
#pragma once
#include <chrono>
#include <ctime>
#include "Common.h"
#include "CommonData.h"
#include "FixedHash.h"
#include "Terminal.h"
#include "vector_ref.h"
/// The logging system's current verbosity.
#define LOG_JSON 1
#define LOG_PER_GPU 2
#ifndef DEV_BUILD
#define LOG_NEXT 4
#else
#define LOG_CONNECT 32
#define LOG_SWITCH 64
#define LOG_SUBMIT 128
#define LOG_COMPILE 256
#define LOG_NEXT 512
#endif
extern unsigned g_logOptions;
extern bool g_logNoColor;
extern bool g_logSyslog;
extern bool g_logStdout;
namespace dev
{
/// A simple log-output function that prints log messages to stdout.
void simpleDebugOut(std::string const&);
/// Set the current thread's log name.
void setThreadName(char const* _n);
/// Set the current thread's log name.
std::string getThreadName();
/// The default logging channels. Each has an associated verbosity and three-letter prefix (name()
/// ). Channels should inherit from LogChannel and define name() and verbosity.
struct LogChannel
{
static const char* name();
};
struct WarnChannel : public LogChannel
{
static const char* name();
};
struct NoteChannel : public LogChannel
{
static const char* name();
};
class LogOutputStreamBase
{
public:
LogOutputStreamBase(char const* _id);
template <class T>
void append(T const& _t)
{
m_sstr << _t;
}
protected:
std::stringstream m_sstr; ///< The accrued log entry.
};
/// Logging class, iostream-like, that can be shifted to.
template <class Id>
class LogOutputStream : LogOutputStreamBase
{
public:
/// Construct a new object.
/// If _term is true the the prefix info is terminated with a ']' character; if not it ends only
/// with a '|' character.
LogOutputStream() : LogOutputStreamBase(Id::name()) {}
/// Destructor. Posts the accrued log entry to the g_logPost function.
~LogOutputStream() { simpleDebugOut(m_sstr.str()); }
/// Shift arbitrary data to the log. Spaces will be added between items as required.
template <class T>
LogOutputStream& operator<<(T const& _t)
{
append(_t);
return *this;
}
};
#define clog(X) dev::LogOutputStream<X>()
// Simple cout-like stream objects for accessing common log channels.
// Dirties the global namespace, but oh so convenient...
#define cnote clog(dev::NoteChannel)
#define cwarn clog(dev::WarnChannel)
} // namespace dev

View File

@@ -0,0 +1,74 @@
#pragma once
namespace dev
{
namespace con
{
#define EthReset "\x1b[0m" // Text Reset
// Regular Colors
#define EthBlack "\x1b[30m" // Black
#define EthCoal "\x1b[90m" // Black
#define EthGray "\x1b[37m" // White
#define EthWhite "\x1b[97m" // White
#define EthMaroon "\x1b[31m" // Red
#define EthRed "\x1b[91m" // Red
#define EthGreen "\x1b[32m" // Green
#define EthLime "\x1b[92m" // Green
#define EthOrange "\x1b[33m" // Yellow
#define EthYellow "\x1b[93m" // Yellow
#define EthNavy "\x1b[34m" // Blue
#define EthBlue "\x1b[94m" // Blue
#define EthViolet "\x1b[35m" // Purple
#define EthPurple "\x1b[95m" // Purple
#define EthTeal "\x1b[36m" // Cyan
#define EthCyan "\x1b[96m" // Cyan
#define EthBlackBold "\x1b[1;30m" // Black
#define EthCoalBold "\x1b[1;90m" // Black
#define EthGrayBold "\x1b[1;37m" // White
#define EthWhiteBold "\x1b[1;97m" // White
#define EthMaroonBold "\x1b[1;31m" // Red
#define EthRedBold "\x1b[1;91m" // Red
#define EthGreenBold "\x1b[1;32m" // Green
#define EthLimeBold "\x1b[1;92m" // Green
#define EthOrangeBold "\x1b[1;33m" // Yellow
#define EthYellowBold "\x1b[1;93m" // Yellow
#define EthNavyBold "\x1b[1;34m" // Blue
#define EthBlueBold "\x1b[1;94m" // Blue
#define EthVioletBold "\x1b[1;35m" // Purple
#define EthPurpleBold "\x1b[1;95m" // Purple
#define EthTealBold "\x1b[1;36m" // Cyan
#define EthCyanBold "\x1b[1;96m" // Cyan
// Background
#define EthOnBlack "\x1b[40m" // Black
#define EthOnCoal "\x1b[100m" // Black
#define EthOnGray "\x1b[47m" // White
#define EthOnWhite "\x1b[107m" // White
#define EthOnMaroon "\x1b[41m" // Red
#define EthOnRed "\x1b[101m" // Red
#define EthOnGreen "\x1b[42m" // Green
#define EthOnLime "\x1b[102m" // Green
#define EthOnOrange "\x1b[43m" // Yellow
#define EthOnYellow "\x1b[103m" // Yellow
#define EthOnNavy "\x1b[44m" // Blue
#define EthOnBlue "\x1b[104m" // Blue
#define EthOnViolet "\x1b[45m" // Purple
#define EthOnPurple "\x1b[105m" // Purple
#define EthOnTeal "\x1b[46m" // Cyan
#define EthOnCyan "\x1b[106m" // Cyan
// Underline
#define EthBlackUnder "\x1b[4;30m" // Black
#define EthGrayUnder "\x1b[4;37m" // White
#define EthMaroonUnder "\x1b[4;31m" // Red
#define EthGreenUnder "\x1b[4;32m" // Green
#define EthOrangeUnder "\x1b[4;33m" // Yellow
#define EthNavyUnder "\x1b[4;34m" // Blue
#define EthVioletUnder "\x1b[4;35m" // Purple
#define EthTealUnder "\x1b[4;36m" // Cyan
} // namespace con
} // namespace dev

120
zano/libdevcore/Worker.cpp Normal file
View File

@@ -0,0 +1,120 @@
/*
This file is part of progminer.
progminer 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.
progminer 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 progminer. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file Worker.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#include <chrono>
#include <thread>
#include "Log.h"
#include "Worker.h"
using namespace std;
using namespace dev;
void Worker::startWorking()
{
// cnote << "startWorking for thread" << m_name;
Guard l(x_work);
if (m_work)
{
WorkerState ex = WorkerState::Stopped;
m_state.compare_exchange_weak(ex, WorkerState::Starting, std::memory_order_relaxed);
}
else
{
m_state = WorkerState::Starting;
m_work.reset(new thread([&]() {
setThreadName(m_name.c_str());
// cnote << "Thread begins";
while (m_state != WorkerState::Killing)
{
WorkerState ex = WorkerState::Starting;
bool ok = m_state.compare_exchange_weak(
ex, WorkerState::Started, std::memory_order_relaxed);
// cnote << "Trying to set Started: Thread was" << (unsigned)ex << "; "
//<< ok;
(void)ok;
try
{
workLoop();
}
catch (std::exception const& _e)
{
clog(WarnChannel) << "Exception thrown in Worker thread: " << _e.what();
if (g_exitOnError)
{
clog(WarnChannel) << "Terminating due to --exit";
raise(SIGTERM);
}
}
// ex = WorkerState::Stopping;
// m_state.compare_exchange_weak(ex, WorkerState::Stopped,
// std::memory_order_relaxed));
ex = m_state.exchange(WorkerState::Stopped);
// cnote << "State: Stopped: Thread was" << (unsigned)ex;
if (ex == WorkerState::Killing || ex == WorkerState::Starting)
m_state.exchange(ex);
while (m_state == WorkerState::Stopped)
this_thread::sleep_for(chrono::milliseconds(20));
}
}));
// cnote << "Spawning" << m_name;
}
while (m_state == WorkerState::Starting)
this_thread::sleep_for(chrono::microseconds(20));
}
void Worker::triggerStopWorking()
{
DEV_GUARDED(x_work)
if (m_work)
{
WorkerState ex = WorkerState::Started;
m_state.compare_exchange_weak(ex, WorkerState::Stopping, std::memory_order_relaxed);
}
}
void Worker::stopWorking()
{
DEV_GUARDED(x_work)
if (m_work)
{
WorkerState ex = WorkerState::Started;
m_state.compare_exchange_weak(ex, WorkerState::Stopping, std::memory_order_relaxed);
while (m_state != WorkerState::Stopped)
this_thread::sleep_for(chrono::microseconds(20));
}
}
Worker::~Worker()
{
DEV_GUARDED(x_work)
if (m_work)
{
m_state.exchange(WorkerState::Killing);
m_work->join();
m_work.reset();
}
}

79
zano/libdevcore/Worker.h Normal file
View File

@@ -0,0 +1,79 @@
/*
This file is part of progminer.
progminer 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.
progminer 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 progminer. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file Worker.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#pragma once
#include <signal.h>
#include <atomic>
#include <cassert>
#include <string>
#include <thread>
#include "Guards.h"
extern bool g_exitOnError;
namespace dev
{
enum class WorkerState
{
Starting,
Started,
Stopping,
Stopped,
Killing
};
class Worker
{
public:
Worker(std::string _name) : m_name(std::move(_name)) {}
Worker(Worker const&) = delete;
Worker& operator=(Worker const&) = delete;
virtual ~Worker();
/// Starts worker thread; causes startedWorking() to be called.
void startWorking();
/// Triggers worker thread it should stop
void triggerStopWorking();
/// Stop worker thread; causes call to stopWorking() and waits till thread has stopped.
void stopWorking();
/// Whether or not this worker should stop
bool shouldStop() const { return m_state != WorkerState::Started; }
std::string name() { return m_name; }
private:
virtual void workLoop() = 0;
std::string m_name;
mutable Mutex x_work; ///< Lock for the network existence.
std::unique_ptr<std::thread> m_work; ///< The network thread.
std::atomic<WorkerState> m_state = {WorkerState::Starting};
};
} // namespace dev

View File

@@ -0,0 +1,225 @@
#pragma once
#include <cassert>
#include <cstring>
#include <string>
#include <type_traits>
#include <vector>
#include <cstdint>
namespace dev
{
/**
* 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;
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(
typename std::conditional<std::is_const<_T>::value, std::string const*, std::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 vector (given as pointer).
vector_ref(typename std::conditional<std::is_const<_T>::value,
std::vector<typename std::remove_const<_T>::type> const*, std::vector<_T>*>::type _data)
: m_data(_data->data()), m_count(_data->size())
{}
/// Creates a new vector_ref pointing to the data part of a string (given as reference).
vector_ref(
typename std::conditional<std::is_const<_T>::value, std::string const&, std::string&>::type
_data)
: m_data(reinterpret_cast<_T*>(_data.data())), m_count(_data.size() / sizeof(_T))
{}
#if DEV_LDB
vector_ref(ldb::Slice const& _s)
: m_data(reinterpret_cast<_T*>(_s.data())), m_count(_s.size() / sizeof(_T))
{}
#endif
explicit operator bool() const { return m_data && m_count; }
bool contentsEqual(std::vector<mutable_value_type> const& _c) const
{
if (!m_data || m_count == 0)
return _c.empty();
return _c.size() == m_count && !memcmp(_c.data(), m_data, m_count * sizeof(_T));
}
std::vector<mutable_value_type> toVector() const
{
return std::vector<mutable_value_type>(m_data, 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 count() const { return m_count; }
/// @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 pointing at the next chunk of @a size() elements.
vector_ref<_T> next() const
{
if (!m_data)
return *this;
return vector_ref<_T>(m_data + m_count, 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);
return {};
}
/// @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);
return {};
}
void retarget(_T* _d, size_t _s)
{
m_data = _d;
m_count = _s;
}
void retarget(std::vector<_T> const& _t)
{
m_data = _t.data();
m_count = _t.size();
}
template <class T>
bool overlapsWith(vector_ref<T> _t) const
{
void const* f1 = data();
void const* t1 = data() + size();
void const* f2 = _t.data();
void const* t2 = _t.data() + _t.size();
return f1 < t2 && t1 > f2;
}
/// Copies the contents of this vector_ref to the contents of @a _t, up to the max size of @a
/// _t.
void copyTo(vector_ref<typename std::remove_const<_T>::type> _t) const
{
if (overlapsWith(_t))
memmove(_t.data(), m_data, std::min(_t.size(), m_count) * sizeof(_T));
else
memcpy(_t.data(), m_data, std::min(_t.size(), m_count) * sizeof(_T));
}
/// Copies the contents of this vector_ref to the contents of @a _t, and zeros further trailing
/// elements in @a _t.
void populate(vector_ref<typename std::remove_const<_T>::type> _t) const
{
copyTo(_t);
memset(_t.data() + m_count, 0, std::max(_t.size(), m_count) - m_count);
}
/// Securely overwrite the memory.
/// @note adapted from OpenSSL's implementation.
void cleanse()
{
static unsigned char s_cleanseCounter = 0;
auto* p = (uint8_t*)begin();
size_t const len = (uint8_t*)end() - p;
size_t loop = len;
size_t count = s_cleanseCounter;
while (loop--)
{
*(p++) = (uint8_t)count;
count += (17 + ((size_t)p & 0xf));
}
p = (uint8_t*)memchr((uint8_t*)begin(), (uint8_t)count, len);
if (p)
count += (63 + (size_t)p);
s_cleanseCounter = (uint8_t)count;
memset((uint8_t*)begin(), 0, len);
}
_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;
size_t m_count;
};
template <class _T>
vector_ref<_T const> ref(_T const& _t)
{
return vector_ref<_T const>(&_t, 1);
}
template <class _T>
vector_ref<_T> ref(_T& _t)
{
return vector_ref<_T>(&_t, 1);
}
template <class _T>
vector_ref<_T const> ref(std::vector<_T> const& _t)
{
return vector_ref<_T const>(&_t);
}
template <class _T>
vector_ref<_T> ref(std::vector<_T>& _t)
{
return vector_ref<_T>(&_t);
}
} // namespace dev