Commit 6b0311f3 authored by Adrien Béraud's avatar Adrien Béraud

build: use C++17

Change-Id: I94c88a504ae2a98043be8fd201f95227002d99c4
parent 67d8fe9f
...@@ -155,8 +155,8 @@ DOLT ...@@ -155,8 +155,8 @@ DOLT
lt_cv_deplibs_check_method=pass_all lt_cv_deplibs_check_method=pass_all
dnl Check for C++14 support dnl Check for C++17 support
AX_CXX_COMPILE_STDCXX(14,[ext],[mandatory]) AX_CXX_COMPILE_STDCXX(17,[ext],[mandatory])
dnl Check for header files dnl Check for header files
AC_FUNC_ALLOCA AC_FUNC_ALLOCA
......
...@@ -33,19 +33,19 @@ ...@@ -33,19 +33,19 @@
# Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov <sokolov@google.com> # Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov <sokolov@google.com>
# Copyright (c) 2015 Paul Norman <penorman@mac.com> # Copyright (c) 2015 Paul Norman <penorman@mac.com>
# Copyright (c) 2015 Moritz Klammler <moritz@klammler.eu> # Copyright (c) 2015 Moritz Klammler <moritz@klammler.eu>
# Copyright (c) 2016 Krzesimir Nowak <qdlacz@gmail.com> # Copyright (c) 2016, 2018 Krzesimir Nowak <qdlacz@gmail.com>
# Copyright (c) 2019 Enji Cooper <yaneurabeya@gmail.com>
# #
# Copying and distribution of this file, with or without modification, are # Copying and distribution of this file, with or without modification, are
# permitted in any medium without royalty provided the copyright notice # permitted in any medium without royalty provided the copyright notice
# and this notice are preserved. This file is offered as-is, without any # and this notice are preserved. This file is offered as-is, without any
# warranty. # warranty.
#serial 7 #serial 11
dnl This macro is based on the code from the AX_CXX_COMPILE_STDCXX_11 macro dnl This macro is based on the code from the AX_CXX_COMPILE_STDCXX_11 macro
dnl (serial version number 13). dnl (serial version number 13).
AX_REQUIRE_DEFINED([AC_MSG_WARN])
AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl
m4_if([$1], [11], [ax_cxx_compile_alternatives="11 0x"], m4_if([$1], [11], [ax_cxx_compile_alternatives="11 0x"],
[$1], [14], [ax_cxx_compile_alternatives="14 1y"], [$1], [14], [ax_cxx_compile_alternatives="14 1y"],
...@@ -61,14 +61,6 @@ AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl ...@@ -61,14 +61,6 @@ AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl
[m4_fatal([invalid third argument `$3' to AX_CXX_COMPILE_STDCXX])]) [m4_fatal([invalid third argument `$3' to AX_CXX_COMPILE_STDCXX])])
AC_LANG_PUSH([C++])dnl AC_LANG_PUSH([C++])dnl
ac_success=no ac_success=no
AC_CACHE_CHECK(whether $CXX supports C++$1 features by default,
ax_cv_cxx_compile_cxx$1,
[AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
[ax_cv_cxx_compile_cxx$1=yes],
[ax_cv_cxx_compile_cxx$1=no])])
if test x$ax_cv_cxx_compile_cxx$1 = xyes; then
ac_success=yes
fi
m4_if([$2], [noext], [], [dnl m4_if([$2], [noext], [], [dnl
if test x$ac_success = xno; then if test x$ac_success = xno; then
...@@ -139,7 +131,6 @@ AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl ...@@ -139,7 +131,6 @@ AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl
[define if the compiler supports basic C++$1 syntax]) [define if the compiler supports basic C++$1 syntax])
fi fi
AC_SUBST(HAVE_CXX$1) AC_SUBST(HAVE_CXX$1)
m4_if([$1], [17], [AC_MSG_WARN([C++17 is not yet standardized, so the checks may change in incompatible ways anytime])])
]) ])
...@@ -199,11 +190,13 @@ namespace cxx11 ...@@ -199,11 +190,13 @@ namespace cxx11
struct Base struct Base
{ {
virtual ~Base() {}
virtual void f() {} virtual void f() {}
}; };
struct Derived : public Base struct Derived : public Base
{ {
virtual ~Derived() override {}
virtual void f() override {} virtual void f() override {}
}; };
...@@ -587,20 +580,12 @@ m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_17], [[ ...@@ -587,20 +580,12 @@ m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_17], [[
#error "This is not a C++ compiler" #error "This is not a C++ compiler"
#elif __cplusplus <= 201402L #elif __cplusplus < 201703L
#error "This is not a C++17 compiler" #error "This is not a C++17 compiler"
#else #else
#if defined(__clang__)
#define REALLY_CLANG
#else
#if defined(__GNUC__)
#define REALLY_GCC
#endif
#endif
#include <initializer_list> #include <initializer_list>
#include <utility> #include <utility>
#include <type_traits> #include <type_traits>
...@@ -608,16 +593,12 @@ m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_17], [[ ...@@ -608,16 +593,12 @@ m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_17], [[
namespace cxx17 namespace cxx17
{ {
#if !defined(REALLY_CLANG)
namespace test_constexpr_lambdas namespace test_constexpr_lambdas
{ {
// TODO: test it with clang++ from git
constexpr int foo = [](){return 42;}(); constexpr int foo = [](){return 42;}();
} }
#endif // !defined(REALLY_CLANG)
namespace test::nested_namespace::definitions namespace test::nested_namespace::definitions
{ {
...@@ -852,12 +833,9 @@ namespace cxx17 ...@@ -852,12 +833,9 @@ namespace cxx17
} }
#if !defined(REALLY_CLANG)
namespace test_template_argument_deduction_for_class_templates namespace test_template_argument_deduction_for_class_templates
{ {
// TODO: test it with clang++ from git
template <typename T1, typename T2> template <typename T1, typename T2>
struct pair struct pair
{ {
...@@ -876,7 +854,6 @@ namespace cxx17 ...@@ -876,7 +854,6 @@ namespace cxx17
} }
} }
#endif // !defined(REALLY_CLANG)
namespace test_non_type_auto_template_parameters namespace test_non_type_auto_template_parameters
{ {
...@@ -890,12 +867,9 @@ namespace cxx17 ...@@ -890,12 +867,9 @@ namespace cxx17
} }
#if !defined(REALLY_CLANG)
namespace test_structured_bindings namespace test_structured_bindings
{ {
// TODO: test it with clang++ from git
int arr[2] = { 1, 2 }; int arr[2] = { 1, 2 };
std::pair<int, int> pr = { 1, 2 }; std::pair<int, int> pr = { 1, 2 };
...@@ -927,14 +901,10 @@ namespace cxx17 ...@@ -927,14 +901,10 @@ namespace cxx17
const auto [ x3, y3 ] = f3(); const auto [ x3, y3 ] = f3();
} }
#endif // !defined(REALLY_CLANG)
#if !defined(REALLY_CLANG)
namespace test_exception_spec_type_system namespace test_exception_spec_type_system
{ {
// TODO: test it with clang++ from git
struct Good {}; struct Good {};
struct Bad {}; struct Bad {};
...@@ -952,7 +922,6 @@ namespace cxx17 ...@@ -952,7 +922,6 @@ namespace cxx17
static_assert (std::is_same_v<Good, decltype(f(g1, g2))>); static_assert (std::is_same_v<Good, decltype(f(g1, g2))>);
} }
#endif // !defined(REALLY_CLANG)
namespace test_inline_variables namespace test_inline_variables
{ {
...@@ -977,6 +946,6 @@ namespace cxx17 ...@@ -977,6 +946,6 @@ namespace cxx17
} // namespace cxx17 } // namespace cxx17
#endif // __cplusplus <= 201402L #endif // __cplusplus < 201703L
]]) ]])
project('jami-daemon', ['c', 'cpp'], project('jami-daemon', ['c', 'cpp'],
version: '9.2.0', version: '9.2.0',
license: 'GPL3+', license: 'GPL3+',
default_options: ['cpp_std=gnu++14', 'buildtype=debugoptimized'], default_options: ['cpp_std=gnu++17', 'buildtype=debugoptimized'],
meson_version:'>= 0.54' meson_version:'>= 0.54'
) )
......
...@@ -47,9 +47,6 @@ ...@@ -47,9 +47,6 @@
#include <chrono> #include <chrono>
#include "vector_ref.h" #include "vector_ref.h"
// CryptoPP defines byte in the global namespace, so must we.
using byte = uint8_t;
// Quote a given token stream to turn it into a string. // Quote a given token stream to turn it into a string.
#define DEV_QUOTED_HELPER(s) #s #define DEV_QUOTED_HELPER(s) #s
#define DEV_QUOTED(s) DEV_QUOTED_HELPER(s) #define DEV_QUOTED(s) DEV_QUOTED_HELPER(s)
...@@ -66,9 +63,9 @@ extern char const* Version; ...@@ -66,9 +63,9 @@ extern char const* Version;
extern std::string const EmptyString; extern std::string const EmptyString;
// Binary data types. // Binary data types.
using bytes = std::vector<byte>; using bytes = std::vector<uint8_t>;
using bytesRef = vector_ref<byte>; using bytesRef = vector_ref<uint8_t>;
using bytesConstRef = vector_ref<byte const>; using bytesConstRef = vector_ref<uint8_t const>;
template <class T> template <class T>
class secure_vector class secure_vector
...@@ -109,7 +106,7 @@ private: ...@@ -109,7 +106,7 @@ private:
std::vector<T> m_data; std::vector<T> m_data;
}; };
using bytesSec = secure_vector<byte>; using bytesSec = secure_vector<uint8_t>;
// Map types. // Map types.
using StringMap = std::map<std::string, std::string>; using StringMap = std::map<std::string, std::string>;
...@@ -147,66 +144,6 @@ private: ...@@ -147,66 +144,6 @@ private:
std::function<void(void)> m_f; std::function<void(void)> m_f;
}; };
/// Inheritable for classes that have invariants.
class HasInvariants
{
public:
/// Reimplement to specify the invariants.
virtual bool invariants() const = 0;
virtual ~HasInvariants() = 0;
};
/// Scope guard for invariant check in a class derived from HasInvariants.
#if ETH_DEBUG
#define DEV_INVARIANT_CHECK ::dev::InvariantChecker __dev_invariantCheck(this, BOOST_CURRENT_FUNCTION, __FILE__, __LINE__)
#define DEV_INVARIANT_CHECK_HERE ::dev::InvariantChecker::checkInvariants(this, BOOST_CURRENT_FUNCTION, __FILE__, __LINE__, true)
#else
#define DEV_INVARIANT_CHECK (void)0;
#define DEV_INVARIANT_CHECK_HERE (void)0;
#endif
/// Simple scope-based timer helper.
class TimerHelper
{
public:
TimerHelper(std::string const& _id, unsigned _msReportWhenGreater = 0): m_t(std::chrono::high_resolution_clock::now()), m_id(_id), m_ms(_msReportWhenGreater) {}
~TimerHelper();
private:
std::chrono::high_resolution_clock::time_point m_t;
std::string m_id;
unsigned m_ms;
};
class Timer
{
public:
Timer() { restart(); }
std::chrono::high_resolution_clock::duration duration() const { return std::chrono::high_resolution_clock::now() - m_t; }
double elapsed() const { return std::chrono::duration_cast<std::chrono::microseconds>(duration()).count() / 1000000.0; }
void restart() { m_t = std::chrono::high_resolution_clock::now(); }
private:
std::chrono::high_resolution_clock::time_point m_t;
};
#define DEV_TIMED(S) for (::std::pair<::dev::TimerHelper, bool> __eth_t(S, true); __eth_t.second; __eth_t.second = false)
#define DEV_TIMED_SCOPE(S) ::dev::TimerHelper __eth_t(S)
#if defined(_WIN32)
#define DEV_TIMED_FUNCTION DEV_TIMED_SCOPE(__FUNCSIG__)
#else
#define DEV_TIMED_FUNCTION DEV_TIMED_SCOPE(__PRETTY_FUNCTION__)
#endif
#define DEV_TIMED_ABOVE(S, MS) for (::std::pair<::dev::TimerHelper, bool> __eth_t(::dev::TimerHelper(S, MS), true); __eth_t.second; __eth_t.second = false)
#define DEV_TIMED_SCOPE_ABOVE(S, MS) ::dev::TimerHelper __eth_t(S, MS)
#if defined(_WIN32)
#define DEV_TIMED_FUNCTION_ABOVE(MS) DEV_TIMED_SCOPE_ABOVE(__FUNCSIG__, MS)
#else
#define DEV_TIMED_FUNCTION_ABOVE(MS) DEV_TIMED_SCOPE_ABOVE(__PRETTY_FUNCTION__, MS)
#endif
#ifdef _MSC_VER #ifdef _MSC_VER
// TODO. // TODO.
#define DEV_UNUSED #define DEV_UNUSED
......
...@@ -48,34 +48,6 @@ bool dev::isHex(string const& _s) noexcept ...@@ -48,34 +48,6 @@ bool dev::isHex(string const& _s) noexcept
return std::all_of(it, _s.end(), [](char c){ return fromHexChar(c) != -1; }); return std::all_of(it, _s.end(), [](char c){ return fromHexChar(c) != -1; });
} }
std::string dev::escaped(std::string const& _s, bool _all)
{
static const map<char, char> prettyEscapes{{'\r', 'r'}, {'\n', 'n'}, {'\t', 't'}, {'\v', 'v'}};
std::string ret;
ret.reserve(_s.size() + 2);
ret.push_back('"');
for (auto i: _s)
if (i == '"' && !_all)
ret += "\\\"";
else if (i == '\\' && !_all)
ret += "\\\\";
else if (prettyEscapes.count(i) && !_all)
{
ret += '\\';
ret += prettyEscapes.find(i)->second;
}
else if (i < ' ' || _all)
{
ret += "\\x";
ret.push_back("0123456789abcdef"[(uint8_t)i / 16]);
ret.push_back("0123456789abcdef"[(uint8_t)i % 16]);
}
else
ret.push_back(i);
ret.push_back('"');
return ret;
}
bytes dev::fromHex(std::string const& _s, WhenError _throw) bytes dev::fromHex(std::string const& _s, WhenError _throw)
{ {
unsigned s = (_s.size() >= 2 && _s[0] == '0' && _s[1] == 'x') ? 2 : 0; unsigned s = (_s.size() >= 2 && _s[0] == '0' && _s[1] == 'x') ? 2 : 0;
...@@ -97,7 +69,7 @@ bytes dev::fromHex(std::string const& _s, WhenError _throw) ...@@ -97,7 +69,7 @@ bytes dev::fromHex(std::string const& _s, WhenError _throw)
int h = fromHexChar(_s[i]); int h = fromHexChar(_s[i]);
int l = fromHexChar(_s[i + 1]); int l = fromHexChar(_s[i + 1]);
if (h != -1 && l != -1) if (h != -1 && l != -1)
ret.push_back((byte)(h * 16 + l)); ret.push_back((uint8_t)(h * 16 + l));
else if (_throw == WhenError::Throw) else if (_throw == WhenError::Throw)
throw std::runtime_error("BadHexCharacter"); throw std::runtime_error("BadHexCharacter");
else else
......
...@@ -105,7 +105,7 @@ inline std::string asString(bytesConstRef _b) ...@@ -105,7 +105,7 @@ inline std::string asString(bytesConstRef _b)
/// Converts a string to a byte array containing the string's (byte) data. /// Converts a string to a byte array containing the string's (byte) data.
inline bytes asBytes(std::string const& _b) inline bytes asBytes(std::string const& _b)
{ {
return bytes((byte const*)_b.data(), (byte const*)(_b.data() + _b.size())); return bytes((uint8_t const*)_b.data(), (uint8_t const*)(_b.data() + _b.size()));
} }
/// Converts a string into the big-endian base-16 stream of integers (NOT ASCII). /// Converts a string into the big-endian base-16 stream of integers (NOT ASCII).
...@@ -123,21 +123,17 @@ inline T fromBigEndian(_In const& _bytes) ...@@ -123,21 +123,17 @@ inline T fromBigEndian(_In const& _bytes)
{ {
T ret = (T)0; T ret = (T)0;
for (auto i: _bytes) for (auto i: _bytes)
ret = (T)((ret << 8) | (byte)(typename std::make_unsigned<decltype(i)>::type)i); ret = (T)((ret << 8) | (uint8_t)(typename std::make_unsigned<decltype(i)>::type)i);
return ret; return ret;
} }
inline bytes toCompactBigEndian(byte _val, unsigned _min = 0) inline bytes toCompactBigEndian(uint8_t _val, unsigned _min = 0)
{ {
return (_min || _val) ? bytes{ _val } : bytes{}; return (_min || _val) ? bytes{ _val } : bytes{};
} }
// Algorithms for string and string-like collections. // 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);
/// Determines the length of the common prefix of the two collections given. /// Determines the length of the common prefix of the two collections given.
/// @returns the number of elements both @a _t and @a _u share, in order, at the beginning. /// @returns the number of elements both @a _t and @a _u share, in order, at the beginning.
/// @example commonPrefix("Hello world!", "Hello, world!") == 5 /// @example commonPrefix("Hello world!", "Hello, world!") == 5
......
...@@ -76,13 +76,13 @@ public: ...@@ -76,13 +76,13 @@ public:
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]; } } } 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. /// Explicitly construct, copying from a bytes in memory with given pointer.
explicit FixedHash(byte const* _bs, ConstructFromPointerType) { memcpy(m_data.data(), _bs, N); } explicit FixedHash(uint8_t const* _bs, ConstructFromPointerType) { memcpy(m_data.data(), _bs, N); }
/// Explicitly construct, copying from a string. /// 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) : dev::asBytes(_s), _ht) {} explicit FixedHash(std::string const& _s, ConstructFromStringType _t = FromHex, ConstructFromHashType _ht = FailIfDifferent): FixedHash(_t == FromHex ? fromHex(_s, WhenError::Throw) : dev::asBytes(_s), _ht) {}
/// @returns true iff this is the empty hash. /// @returns true iff this is the empty hash.
explicit operator bool() const { return std::any_of(m_data.begin(), m_data.end(), [](byte _b) { return _b != 0; }); } explicit operator bool() const { return std::any_of(m_data.begin(), m_data.end(), [](uint8_t _b) { return _b != 0; }); }
// The obvious comparison operators. // 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; }
...@@ -108,9 +108,9 @@ public: ...@@ -108,9 +108,9 @@ public:
bool contains(FixedHash const& _c) const { return (*this & _c) == _c; } bool contains(FixedHash const& _c) const { return (*this & _c) == _c; }
/// @returns a particular byte from the hash. /// @returns a particular byte from the hash.
byte& operator[](unsigned _i) { return m_data[_i]; } uint8_t& operator[](unsigned _i) { return m_data[_i]; }
/// @returns a particular byte from the hash. /// @returns a particular byte from the hash.
byte operator[](unsigned _i) const { return m_data[_i]; } uint8_t operator[](unsigned _i) const { return m_data[_i]; }
/// @returns an abridged version of the hash as a user-readable hex string. /// @returns an abridged version of the hash as a user-readable hex string.
std::string abridged() const { return toHex(ref().cropped(0, 4)) + "\342\200\246"; } std::string abridged() const { return toHex(ref().cropped(0, 4)) + "\342\200\246"; }
...@@ -128,25 +128,25 @@ public: ...@@ -128,25 +128,25 @@ public:
bytesConstRef ref() const { return bytesConstRef(m_data.data(), N); } bytesConstRef ref() const { return bytesConstRef(m_data.data(), N); }
/// @returns a mutable byte pointer to the object's data. /// @returns a mutable byte pointer to the object's data.
byte* data() { return m_data.data(); } uint8_t* data() { return m_data.data(); }
/// @returns a constant byte pointer to the object's data. /// @returns a constant byte pointer to the object's data.
byte const* data() const { return m_data.data(); } uint8_t const* data() const { return m_data.data(); }
/// @returns begin iterator. /// @returns begin iterator.
auto begin() const -> typename std::array<byte, N>::const_iterator { return m_data.begin(); } auto begin() const -> typename std::array<uint8_t, N>::const_iterator { return m_data.begin(); }
/// @returns end iterator. /// @returns end iterator.
auto end() const -> typename std::array<byte, N>::const_iterator { return m_data.end(); } auto end() const -> typename std::array<uint8_t, N>::const_iterator { return m_data.end(); }
/// @returns a copy of the object's data as a byte vector. /// @returns a copy of the object's data as a byte vector.
bytes asBytes() const { return bytes(data(), data() + N); } bytes asBytes() const { return bytes(data(), data() + N); }
/// @returns a mutable reference to the object's data as an STL array. /// @returns a mutable reference to the object's data as an STL array.
std::array<byte, N>& asArray() { return m_data; } std::array<uint8_t, N>& asArray() { return m_data; }
/// @returns a constant reference to the object's data as an STL array. /// @returns a constant reference to the object's data as an STL array.
std::array<byte, N> const& asArray() const { return m_data; } std::array<uint8_t, N> const& asArray() const { return m_data; }
/// Populate with random data. /// Populate with random data.
template <class Engine> template <class Engine>
...@@ -179,7 +179,7 @@ public: ...@@ -179,7 +179,7 @@ public:
static_assert(P * c_bloomBytes <= N, "out of range"); static_assert(P * c_bloomBytes <= N, "out of range");
FixedHash<M> ret; FixedHash<M> ret;
byte const* p = data(); uint8_t const* p = data();
for (unsigned i = 0; i < P; ++i) for (unsigned i = 0; i < P; ++i)
{ {
unsigned index = 0; unsigned index = 0;
...@@ -209,7 +209,7 @@ public: ...@@ -209,7 +209,7 @@ public:
void clear() { m_data.fill(0); } void clear() { m_data.fill(0); }
private: private:
std::array<byte, N> m_data; ///< The binary data. std::array<uint8_t, N> m_data; ///< The binary data.
}; };
template <unsigned T> template <unsigned T>
...@@ -282,7 +282,7 @@ public: ...@@ -282,7 +282,7 @@ public:
using FixedHash<T>::abridgedMiddle; using FixedHash<T>::abridgedMiddle;
bytesConstRef ref() const { return FixedHash<T>::ref(); } bytesConstRef ref() const { return FixedHash<T>::ref(); }
byte const* data() const { return FixedHash<T>::data(); } uint8_t const* data() const { return FixedHash<T>::data(); }
static SecureFixedHash<T> random() { SecureFixedHash<T> ret; ret.randomize(s_fixedHashEngine); return ret; }