Merge pull request #1816

93e10f1c Simplified the implementation and features of span (Lee Clagett)
4a8f96f9 Improvements for epee binary to hex functions: (Lee Clagett)
This commit is contained in:
Riccardo Spagni 2017-04-24 10:29:19 +02:00
commit a059e91d7f
No known key found for this signature in database
GPG key ID: 55432DF31CCD4FCD
14 changed files with 728 additions and 76 deletions

View file

@ -0,0 +1,65 @@
// Copyright (c) 2017, The Monero Project
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#pragma once
#include <array>
#include <cstdint>
#include <iosfwd>
#include <string>
#include "span.h"
namespace epee
{
struct to_hex
{
//! \return A std::string containing hex of `src`.
static std::string string(const span<const std::uint8_t> src);
//! \return An array containing hex of `src`.
template<std::size_t N>
static std::array<char, N * 2> array(const std::array<std::uint8_t, N>& src) noexcept
{
std::array<char, N * 2> out{{}};
static_assert(N <= 128, "keep the stack size down");
buffer_unchecked(out.data(), {src.data(), src.size()});
return out;
}
//! Append `src` as hex to `out`.
static void buffer(std::ostream& out, const span<const std::uint8_t> src);
//! Append `< + src + >` as hex to `out`.
static void formatted(std::ostream& out, const span<const std::uint8_t> src);
private:
//! Write `src` bytes as hex to `out`. `out` must be twice the length
static void buffer_unchecked(char* out, const span<const std::uint8_t> src) noexcept;
};
}

130
contrib/epee/include/span.h Normal file
View file

@ -0,0 +1,130 @@
// Copyright (c) 2017, The Monero Project
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#pragma once
#include <cstdint>
#include <memory>
#include <type_traits>
namespace epee
{
/*!
\brief Non-owning sequence of data. Does not deep copy
Inspired by `gsl::span` and/or `boost::iterator_range`. This class is
intended to be used as a parameter type for functions that need to take a
writable or read-only sequence of data. Most common cases are `span<char>`
and `span<std::uint8_t>`. Using as a class member is only recommended if
clearly documented as not doing a deep-copy. C-arrays are easily convertible
to this type.
\note Conversion from C string literal to `span<const char>` will include
the NULL-terminator.
\note Never allows derived-to-base pointer conversion; an array of derived
types is not an array of base types.
*/
template<typename T>
class span
{
/* Supporting class types is tricky - the {ptr,len} constructor will allow
derived-to-base conversions. This is NOT desireable because an array of
derived types is not an array of base types. It is possible to handle
this case, implement when/if needed. */
static_assert(!std::is_class<T>(), "no class types are currently allowed");
public:
using value_type = T;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
using pointer = T*;
using const_pointer = const T*;
using reference = T&;
using const_reference = const T&;
using iterator = pointer;
using const_iterator = const_pointer;
constexpr span() noexcept : ptr(nullptr), len(0) {}
constexpr span(std::nullptr_t) noexcept : span() {}
constexpr span(T* const src_ptr, const std::size_t count) noexcept
: ptr(src_ptr), len(count) {}
//! Conversion from C-array. Prevents common bugs with sizeof + arrays.
template<std::size_t N>
constexpr span(T (&src)[N]) noexcept : span(src, N) {}
constexpr span(const span&) noexcept = default;
span& operator=(const span&) noexcept = default;
constexpr iterator begin() const noexcept { return ptr; }
constexpr const_iterator cbegin() const noexcept { return ptr; }
constexpr iterator end() const noexcept { return begin() + size(); }
constexpr const_iterator cend() const noexcept { return cbegin() + size(); }
constexpr bool empty() const noexcept { return size() == 0; }
constexpr pointer data() const noexcept { return ptr; }
constexpr std::size_t size() const noexcept { return len; }
constexpr std::size_t size_bytes() const noexcept { return size() * sizeof(value_type); }
private:
T* ptr;
std::size_t len;
};
//! \return `span<const T::value_type>` from a STL compatible `src`.
template<typename T>
constexpr span<const typename T::value_type> to_span(const T& src)
{
// compiler provides diagnostic if size() is not size_t.
return {src.data(), src.size()};
}
template<typename T>
constexpr bool has_padding() noexcept
{
return !std::is_pod<T>() || alignof(T) != 1;
}
//! \return Cast data from `src` as `span<const std::uint8_t>`.
template<typename T>
span<const std::uint8_t> to_byte_span(const span<const T> src) noexcept
{
static_assert(!has_padding<T>(), "source type may have padding");
return {reinterpret_cast<const std::uint8_t*>(src.data()), src.size_bytes()};
}
//! \return `span<const std::uint8_t>` which represents the bytes at `&src`.
template<typename T>
span<const std::uint8_t> as_byte_span(const T& src) noexcept
{
static_assert(!std::is_empty<T>(), "empty types will not work -> sizeof == 1");
static_assert(!has_padding<T>(), "source type may have padding");
return {reinterpret_cast<const std::uint8_t*>(std::addressof(src)), sizeof(T)};
}
}

View file

@ -45,6 +45,8 @@
#include <boost/uuid/uuid_io.hpp> #include <boost/uuid/uuid_io.hpp>
#include <boost/lexical_cast.hpp> #include <boost/lexical_cast.hpp>
#include <boost/algorithm/string.hpp> #include <boost/algorithm/string.hpp>
#include "hex.h"
#include "span.h"
#include "warnings.h" #include "warnings.h"
@ -114,33 +116,10 @@ namespace string_tools
return false; return false;
} }
} }
//----------------------------------------------------------------------------
template<class CharT>
std::basic_string<CharT> buff_to_hex(const std::basic_string<CharT>& s)
{
using namespace std;
basic_stringstream<CharT> hexStream;
hexStream << hex << noshowbase << setw(2);
for(typename std::basic_string<CharT>::const_iterator it = s.begin(); it != s.end(); it++)
{
hexStream << "0x"<< static_cast<unsigned int>(static_cast<unsigned char>(*it)) << " ";
}
return hexStream.str();
}
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
template<class CharT> inline std::string buff_to_hex_nodelimer(const std::string& src)
std::basic_string<CharT> buff_to_hex_nodelimer(const std::basic_string<CharT>& s)
{ {
using namespace std; return to_hex::string(to_byte_span(to_span(src)));
basic_stringstream<CharT> hexStream;
hexStream << hex << noshowbase;
for(typename std::basic_string<CharT>::const_iterator it = s.begin(); it != s.end(); it++)
{
hexStream << setw(2) << setfill('0') << static_cast<unsigned int>(static_cast<unsigned char>(*it));
}
return hexStream.str();
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
template<class CharT> template<class CharT>
@ -559,9 +538,7 @@ POP_WARNINGS
std::string pod_to_hex(const t_pod_type& s) std::string pod_to_hex(const t_pod_type& s)
{ {
static_assert(std::is_pod<t_pod_type>::value, "expected pod type"); static_assert(std::is_pod<t_pod_type>::value, "expected pod type");
std::string buff; return to_hex::string(as_byte_span(s));
buff.assign(reinterpret_cast<const char*>(&s), sizeof(s));
return buff_to_hex_nodelimer(buff);
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
template<class t_pod_type> template<class t_pod_type>

View file

@ -26,7 +26,7 @@
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
add_library(epee STATIC http_auth.cpp mlog.cpp string_tools.cpp) add_library(epee STATIC hex.cpp http_auth.cpp mlog.cpp string_tools.cpp)
# Build and install libepee if we're building for GUI # Build and install libepee if we're building for GUI
if (BUILD_GUI_DEPS) if (BUILD_GUI_DEPS)
if(IOS) if(IOS)

82
contrib/epee/src/hex.cpp Normal file
View file

@ -0,0 +1,82 @@
// Copyright (c) 2017, The Monero Project
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "hex.h"
#include <iterator>
#include <limits>
#include <ostream>
#include <stdexcept>
namespace epee
{
namespace
{
template<typename T>
void write_hex(T&& out, const span<const std::uint8_t> src)
{
static constexpr const char hex[] = u8"0123456789abcdef";
static_assert(sizeof(hex) == 17, "bad string size");
for (const std::uint8_t byte : src)
{
*out = hex[byte >> 4];
++out;
*out = hex[byte & 0x0F];
++out;
}
}
}
std::string to_hex::string(const span<const std::uint8_t> src)
{
if (std::numeric_limits<std::size_t>::max() / 2 < src.size())
throw std::range_error("hex_view::to_string exceeded maximum size");
std::string out{};
out.resize(src.size() * 2);
buffer_unchecked(std::addressof(out[0]), src);
return out;
}
void to_hex::buffer(std::ostream& out, const span<const std::uint8_t> src)
{
write_hex(std::ostreambuf_iterator<char>{out}, src);
}
void to_hex::formatted(std::ostream& out, const span<const std::uint8_t> src)
{
out.put('<');
buffer(out, src);
out.put('>');
}
void to_hex::buffer_unchecked(char* out, const span<const std::uint8_t> src) noexcept
{
return write_hex(out, src);
}
}

View file

@ -67,6 +67,7 @@
#include <type_traits> #include <type_traits>
#include "crypto/crypto.h" #include "crypto/crypto.h"
#include "hex.h"
#include "md5_l.h" #include "md5_l.h"
#include "string_coding.h" #include "string_coding.h"
@ -104,25 +105,6 @@ namespace
//// Digest Algorithms //// Digest Algorithms
template<std::size_t N>
std::array<char, N * 2> to_hex(const std::array<std::uint8_t, N>& digest) noexcept
{
static constexpr const char alphabet[] = u8"0123456789abcdef";
static_assert(sizeof(alphabet) == 17, "bad alphabet size");
// TODO upgrade (improve performance) of to hex in epee string tools
std::array<char, N * 2> out{{}};
auto current = out.begin();
for (const std::uint8_t byte : digest)
{
*current = alphabet[byte >> 4];
++current;
*current = alphabet[byte & 0x0F];
++current;
}
return out;
}
struct md5_ struct md5_
{ {
static constexpr const boost::string_ref name = ceref(u8"MD5"); static constexpr const boost::string_ref name = ceref(u8"MD5");
@ -156,7 +138,7 @@ namespace
std::array<std::uint8_t, 16> digest{{}}; std::array<std::uint8_t, 16> digest{{}};
md5::MD5Final(digest.data(), std::addressof(ctx)); md5::MD5Final(digest.data(), std::addressof(ctx));
return to_hex(digest); return epee::to_hex::array(digest);
} }
}; };
constexpr const boost::string_ref md5_::name; constexpr const boost::string_ref md5_::name;

View file

@ -44,7 +44,6 @@
#include "serialization/debug_archive.h" #include "serialization/debug_archive.h"
#include "serialization/crypto.h" #include "serialization/crypto.h"
#include "serialization/keyvalue_serialization.h" // eepe named serialization #include "serialization/keyvalue_serialization.h" // eepe named serialization
#include "string_tools.h"
#include "cryptonote_config.h" #include "cryptonote_config.h"
#include "crypto/crypto.h" #include "crypto/crypto.h"
#include "crypto/hash.h" #include "crypto/hash.h"

View file

@ -33,6 +33,8 @@
#include "cryptonote_basic.h" #include "cryptonote_basic.h"
#include "crypto/crypto.h" #include "crypto/crypto.h"
#include "crypto/hash.h" #include "crypto/hash.h"
#include "hex.h"
#include "span.h"
namespace cryptonote { namespace cryptonote {
@ -123,23 +125,28 @@ namespace cryptonote {
bool operator ==(const cryptonote::block& a, const cryptonote::block& b); bool operator ==(const cryptonote::block& a, const cryptonote::block& b);
} }
template <class T>
std::ostream &print256(std::ostream &o, const T &v) {
return o << "<" << epee::string_tools::pod_to_hex(v) << ">";
}
template <class T>
std::ostream &print64(std::ostream &o, const T &v) {
return o << "<" << epee::string_tools::pod_to_hex(v) << ">";
}
bool parse_hash256(const std::string str_hash, crypto::hash& hash); bool parse_hash256(const std::string str_hash, crypto::hash& hash);
namespace crypto { namespace crypto {
inline std::ostream &operator <<(std::ostream &o, const crypto::public_key &v) { return print256(o, v); } inline std::ostream &operator <<(std::ostream &o, const crypto::public_key &v) {
inline std::ostream &operator <<(std::ostream &o, const crypto::secret_key &v) { return print256(o, v); } epee::to_hex::formatted(o, epee::as_byte_span(v)); return o;
inline std::ostream &operator <<(std::ostream &o, const crypto::key_derivation &v) { return print256(o, v); } }
inline std::ostream &operator <<(std::ostream &o, const crypto::key_image &v) { return print256(o, v); } inline std::ostream &operator <<(std::ostream &o, const crypto::secret_key &v) {
inline std::ostream &operator <<(std::ostream &o, const crypto::signature &v) { return print256(o, v); } epee::to_hex::formatted(o, epee::as_byte_span(v)); return o;
inline std::ostream &operator <<(std::ostream &o, const crypto::hash &v) { return print256(o, v); } }
inline std::ostream &operator <<(std::ostream &o, const crypto::hash8 &v) { return print64(o, v); } inline std::ostream &operator <<(std::ostream &o, const crypto::key_derivation &v) {
epee::to_hex::formatted(o, epee::as_byte_span(v)); return o;
}
inline std::ostream &operator <<(std::ostream &o, const crypto::key_image &v) {
epee::to_hex::formatted(o, epee::as_byte_span(v)); return o;
}
inline std::ostream &operator <<(std::ostream &o, const crypto::signature &v) {
epee::to_hex::formatted(o, epee::as_byte_span(v)); return o;
}
inline std::ostream &operator <<(std::ostream &o, const crypto::hash &v) {
epee::to_hex::formatted(o, epee::as_byte_span(v)); return o;
}
inline std::ostream &operator <<(std::ostream &o, const crypto::hash8 &v) {
epee::to_hex::formatted(o, epee::as_byte_span(v)); return o;
}
} }

View file

@ -47,6 +47,8 @@ extern "C" {
#include "crypto/generic-ops.h" #include "crypto/generic-ops.h"
#include "crypto/crypto.h" #include "crypto/crypto.h"
#include "hex.h"
#include "span.h"
#include "serialization/serialization.h" #include "serialization/serialization.h"
#include "serialization/debug_archive.h" #include "serialization/debug_archive.h"
#include "serialization/binary_archive.h" #include "serialization/binary_archive.h"
@ -443,8 +445,9 @@ namespace cryptonote {
static inline bool operator!=(const crypto::secret_key &k0, const rct::key &k1) { return memcmp(&k0, &k1, 32); } static inline bool operator!=(const crypto::secret_key &k0, const rct::key &k1) { return memcmp(&k0, &k1, 32); }
} }
template<typename T> std::ostream &print256(std::ostream &o, const T &v); inline std::ostream &operator <<(std::ostream &o, const rct::key &v) {
inline std::ostream &operator <<(std::ostream &o, const rct::key &v) { return print256(o, v); } epee::to_hex::formatted(o, epee::as_byte_span(v)); return o;
}
BLOB_SERIALIZER(rct::key); BLOB_SERIALIZER(rct::key);

View file

@ -36,6 +36,7 @@ set(unit_tests_sources
chacha8.cpp chacha8.cpp
checkpoints.cpp checkpoints.cpp
command_line.cpp command_line.cpp
crypto.cpp
decompose_amount_into_digits.cpp decompose_amount_into_digits.cpp
dns_resolver.cpp dns_resolver.cpp
epee_boosted_tcp_server.cpp epee_boosted_tcp_server.cpp

View file

@ -0,0 +1,75 @@
// Copyright (c) 2017, The Monero Project
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <cstdint>
#include <gtest/gtest.h>
#include <memory>
#include <sstream>
#include <string>
#include "cryptonote_basic/cryptonote_basic_impl.h"
namespace
{
static constexpr const std::uint8_t source[] = {
0x8b, 0x65, 0x59, 0x70, 0x15, 0x37, 0x99, 0xaf, 0x2a, 0xea, 0xdc, 0x9f, 0xf1, 0xad, 0xd0, 0xea,
0x6c, 0x72, 0x51, 0xd5, 0x41, 0x54, 0xcf, 0xa9, 0x2c, 0x17, 0x3a, 0x0d, 0xd3, 0x9c, 0x1f, 0x94,
0x6c, 0x72, 0x51, 0xd5, 0x41, 0x54, 0xcf, 0xa9, 0x2c, 0x17, 0x3a, 0x0d, 0xd3, 0x9c, 0x1f, 0x94,
0x8b, 0x65, 0x59, 0x70, 0x15, 0x37, 0x99, 0xaf, 0x2a, 0xea, 0xdc, 0x9f, 0xf1, 0xad, 0xd0, 0xea
};
static constexpr const char expected[] =
"8b655970153799af2aeadc9ff1add0ea6c7251d54154cfa92c173a0dd39c1f94"
"6c7251d54154cfa92c173a0dd39c1f948b655970153799af2aeadc9ff1add0ea";
template<typename T>
bool is_formatted()
{
T value{};
static_assert(alignof(T) == 1, "T must have 1 byte alignment");
static_assert(sizeof(T) <= sizeof(source), "T is too large for source");
static_assert(sizeof(T) * 2 <= sizeof(expected), "T is too large for destination");
std::memcpy(std::addressof(value), source, sizeof(T));
std::stringstream out;
out << "BEGIN" << value << "END";
return out.str() == "BEGIN<" + std::string{expected, sizeof(T) * 2} + ">END";
}
}
TEST(Crypto, Ostream)
{
EXPECT_TRUE(is_formatted<crypto::hash8>());
EXPECT_TRUE(is_formatted<crypto::hash>());
EXPECT_TRUE(is_formatted<crypto::public_key>());
EXPECT_TRUE(is_formatted<crypto::secret_key>());
EXPECT_TRUE(is_formatted<crypto::signature>());
EXPECT_TRUE(is_formatted<crypto::key_derivation>());
EXPECT_TRUE(is_formatted<crypto::key_image>());
}

View file

@ -27,18 +27,342 @@
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <array> #include <array>
#include <boost/range/algorithm/equal.hpp>
#include <boost/range/algorithm_ext/iota.hpp>
#include <cstdint>
#include <gtest/gtest.h>
#include <iterator>
#include <string>
#include <sstream>
#include <vector>
#ifdef _WIN32 #ifdef _WIN32
# include <winsock.h> # include <winsock.h>
#else #else
# include <arpa/inet.h> # include <arpa/inet.h>
#endif #endif
#include <cstdint> #include "hex.h"
#include <gtest/gtest.h> #include "span.h"
#include <string>
#include "string_tools.h" #include "string_tools.h"
namespace
{
template<typename Destination, typename Source>
bool can_construct()
{
const unsigned count =
unsigned(std::is_constructible<Destination, Source>()) +
unsigned(std::is_constructible<Destination, Source&>()) +
unsigned(std::is_convertible<Source, Destination>()) +
unsigned(std::is_convertible<Source&, Destination>()) +
unsigned(std::is_assignable<Destination, Source>()) +
unsigned(std::is_assignable<Destination, Source&>());
EXPECT_TRUE(count == 6 || count == 0) <<
"Mismatch on construction results - " << count << " were true";
return count == 6;
}
// This is probably stressing the compiler more than the implementation ...
constexpr const epee::span<const char> test_string("a string");
static_assert(!test_string.empty(), "test failure");
static_assert(test_string.size() == 9, "test failure");
static_assert(test_string.size_bytes() == 9, "test_failure");
static_assert(test_string.begin() == test_string.cbegin(), "test failure");
static_assert(test_string.end() == test_string.cend(), "test failure");
static_assert(test_string.cend() - test_string.cbegin() == 9, "test failure");
static_assert(*test_string.cbegin() == 'a', "test failure");
static_assert(*(test_string.cend() - 2) == 'g', "test failure");
static_assert(
epee::span<const char>(test_string).cbegin() + 3 == test_string.cbegin() + 3,
"test failure"
);
static_assert(epee::span<char>().empty(), "test failure");
static_assert(epee::span<char>(nullptr).empty(), "test failure");
static_assert(epee::span<const char>("foo", 2).size() == 2, "test failure");
std::string std_to_hex(const std::vector<unsigned char>& source)
{
std::stringstream out;
out << std::hex;
for (const unsigned char byte : source)
{
out << std::setw(2) << std::setfill('0') << int(byte);
}
return out.str();
}
std::vector<unsigned char> get_all_bytes()
{
std::vector<unsigned char> out;
out.resize(256);
boost::range::iota(out, 0);
return out;
}
}
TEST(Span, Traits)
{
EXPECT_TRUE((std::is_same<std::size_t, typename epee::span<char>::size_type>()));
EXPECT_TRUE((std::is_same<std::ptrdiff_t, typename epee::span<char>::difference_type>()));
EXPECT_TRUE((std::is_same<char, typename epee::span<char>::value_type>()));
EXPECT_TRUE((std::is_same<char*, typename epee::span<char>::pointer>()));
EXPECT_TRUE((std::is_same<const char*, typename epee::span<char>::const_pointer>()));
EXPECT_TRUE((std::is_same<char*, typename epee::span<char>::iterator>()));
EXPECT_TRUE((std::is_same<const char*, typename epee::span<char>::const_iterator>()));
EXPECT_TRUE((std::is_same<char&, typename epee::span<char>::reference>()));
EXPECT_TRUE((std::is_same<const char&, typename epee::span<char>::const_reference>()));
EXPECT_TRUE((std::is_same<std::size_t, typename epee::span<const char>::size_type>()));
EXPECT_TRUE((std::is_same<std::ptrdiff_t, typename epee::span<const char>::difference_type>()));
EXPECT_TRUE((std::is_same<const char, typename epee::span<const char>::value_type>()));
EXPECT_TRUE((std::is_same<const char*, typename epee::span<const char>::pointer>()));
EXPECT_TRUE((std::is_same<const char*, typename epee::span<const char>::const_pointer>()));
EXPECT_TRUE((std::is_same<const char*, typename epee::span<const char>::iterator>()));
EXPECT_TRUE((std::is_same<const char*, typename epee::span<const char>::const_iterator>()));
EXPECT_TRUE((std::is_same<const char&, typename epee::span<const char>::reference>()));
EXPECT_TRUE((std::is_same<const char&, typename epee::span<const char>::const_reference>()));
}
TEST(Span, MutableConstruction)
{
struct no_conversion{};
EXPECT_TRUE(std::is_constructible<epee::span<char>>());
EXPECT_TRUE((std::is_constructible<epee::span<char>, char*, std::size_t>()));
EXPECT_FALSE((std::is_constructible<epee::span<char>, const char*, std::size_t>()));
EXPECT_FALSE((std::is_constructible<epee::span<char>, unsigned char*, std::size_t>()));
EXPECT_TRUE((can_construct<epee::span<char>, std::nullptr_t>()));
EXPECT_TRUE((can_construct<epee::span<char>, char(&)[1]>()));
EXPECT_FALSE((can_construct<epee::span<char>, std::vector<char>>()));
EXPECT_FALSE((can_construct<epee::span<char>, std::array<char, 1>>()));
EXPECT_FALSE((can_construct<epee::span<char>, std::wstring>()));
EXPECT_FALSE((can_construct<epee::span<char>, const std::vector<char>>()));
EXPECT_FALSE((can_construct<epee::span<char>, std::vector<unsigned char>>()));
EXPECT_FALSE((can_construct<epee::span<char>, const std::array<char, 1>>()));
EXPECT_FALSE((can_construct<epee::span<char>, std::array<unsigned char, 1>>()));
EXPECT_FALSE((can_construct<epee::span<char>, const char[1]>()));
EXPECT_FALSE((can_construct<epee::span<char>, unsigned char[1]>()));
EXPECT_FALSE((can_construct<epee::span<char>, epee::span<const char>>()));
EXPECT_FALSE((can_construct<epee::span<char>, epee::span<unsigned char>>()));
EXPECT_FALSE((can_construct<epee::span<char>, no_conversion>()));
}
TEST(Span, ImmutableConstruction)
{
struct no_conversion{};
EXPECT_TRUE(std::is_constructible<epee::span<const char>>());
EXPECT_TRUE((std::is_constructible<epee::span<const char>, char*, std::size_t>()));
EXPECT_TRUE((std::is_constructible<epee::span<const char>, const char*, std::size_t>()));
EXPECT_FALSE((std::is_constructible<epee::span<const char>, unsigned char*, std::size_t>()));
EXPECT_FALSE((can_construct<epee::span<const char>, std::string>()));
EXPECT_FALSE((can_construct<epee::span<const char>, std::vector<char>>()));
EXPECT_FALSE((can_construct<epee::span<const char>, const std::vector<char>>()));
EXPECT_FALSE((can_construct<epee::span<const char>, std::array<char, 1>>()));
EXPECT_FALSE((can_construct<epee::span<const char>, const std::array<char, 1>>()));
EXPECT_TRUE((can_construct<epee::span<const char>, std::nullptr_t>()));
EXPECT_TRUE((can_construct<epee::span<const char>, char[1]>()));
EXPECT_TRUE((can_construct<epee::span<const char>, const char[1]>()));
EXPECT_TRUE((can_construct<epee::span<const char>, epee::span<const char>>()));
EXPECT_FALSE((can_construct<epee::span<const char>, std::wstring>()));
EXPECT_FALSE((can_construct<epee::span<const char>, std::vector<unsigned char>>()));
EXPECT_FALSE((can_construct<epee::span<const char>, std::array<unsigned char, 1>>()));
EXPECT_FALSE((can_construct<epee::span<const char>, unsigned char[1]>()));
EXPECT_FALSE((can_construct<epee::span<const char>, epee::span<unsigned char>>()));
EXPECT_FALSE((can_construct<epee::span<const char>, no_conversion>()));
}
TEST(Span, NoExcept)
{
EXPECT_TRUE(std::is_nothrow_default_constructible<epee::span<char>>());
EXPECT_TRUE(std::is_nothrow_move_constructible<epee::span<char>>());
EXPECT_TRUE(std::is_nothrow_copy_constructible<epee::span<char>>());
EXPECT_TRUE(std::is_move_assignable<epee::span<char>>());
EXPECT_TRUE(std::is_copy_assignable<epee::span<char>>());
char data[10];
epee::span<char> lvalue(data);
const epee::span<char> clvalue(data);
EXPECT_TRUE(noexcept(epee::span<char>()));
EXPECT_TRUE(noexcept(epee::span<char>(nullptr)));
EXPECT_TRUE(noexcept(epee::span<char>(nullptr, 0)));
EXPECT_TRUE(noexcept(epee::span<char>(data)));
EXPECT_TRUE(noexcept(epee::span<char>(lvalue)));
EXPECT_TRUE(noexcept(epee::span<char>(clvalue)));
// conversion from mutable to immutable not yet implemented
// EXPECT_TRUE(noexcept(epee::span<const char>(lvalue)));
// EXPECT_TRUE(noexcept(epee::span<const char>(clvalue)));
EXPECT_TRUE(noexcept(epee::span<char>(epee::span<char>(lvalue))));
EXPECT_TRUE(noexcept(lvalue = lvalue));
EXPECT_TRUE(noexcept(lvalue = clvalue));
EXPECT_TRUE(noexcept(lvalue = epee::span<char>(lvalue)));
}
TEST(Span, Nullptr)
{
const auto check_empty = [](epee::span<const char> data)
{
EXPECT_TRUE(data.empty());
EXPECT_EQ(data.cbegin(), data.begin());
EXPECT_EQ(data.cend(), data.end());
EXPECT_EQ(data.cend(), data.cbegin());
EXPECT_EQ(0, data.size());
EXPECT_EQ(0, data.size_bytes());
};
check_empty({});
check_empty(nullptr);
}
TEST(Span, Writing)
{
const int expected[] = {-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
std::vector<int> source;
epee::span<int> span;
EXPECT_TRUE(span.empty());
EXPECT_EQ(0, span.size());
EXPECT_EQ(0, span.size_bytes());
source.resize(15);
span = {source.data(), source.size()};
EXPECT_FALSE(span.empty());
EXPECT_EQ(15, span.size());
EXPECT_EQ(15 * 4, span.size_bytes());
boost::range::iota(span, -5);
EXPECT_EQ(span.begin(), span.cbegin());
EXPECT_EQ(span.end(), span.cend());
EXPECT_TRUE(boost::range::equal(expected, source));
EXPECT_TRUE(boost::range::equal(expected, span));
}
TEST(Span, ToByteSpan)
{
const char expected[] = {56, 44, 11, 5};
EXPECT_TRUE(
boost::range::equal(
std::array<std::uint8_t, 4>{{56, 44, 11, 5}},
epee::to_byte_span<char>(expected)
)
);
EXPECT_TRUE(
boost::range::equal(
std::array<char, 4>{{56, 44, 11, 5}},
epee::to_byte_span(epee::span<const char>{expected})
)
);
}
TEST(Span, AsByteSpan)
{
struct some_pod { char value[4]; };
const some_pod immutable {{ 5, 10, 12, 127 }};
EXPECT_TRUE(
boost::range::equal(
std::array<unsigned char, 4>{{5, 10, 12, 127}},
epee::as_byte_span(immutable)
)
);
EXPECT_TRUE(
boost::range::equal(
std::array<std::uint8_t, 3>{{'a', 'y', 0x00}}, epee::as_byte_span("ay")
)
);
}
TEST(ToHex, String)
{
EXPECT_TRUE(epee::to_hex::string(nullptr).empty());
EXPECT_EQ(
std::string{"ffab0100"},
epee::to_hex::string(epee::as_byte_span("\xff\xab\x01"))
);
const std::vector<unsigned char> all_bytes = get_all_bytes();
EXPECT_EQ(
std_to_hex(all_bytes), epee::to_hex::string(epee::to_span(all_bytes))
);
}
TEST(ToHex, Array)
{
EXPECT_EQ(
(std::array<char, 8>{{'f', 'f', 'a', 'b', '0', '1', '0', '0'}}),
(epee::to_hex::array(std::array<unsigned char, 4>{{0xFF, 0xAB, 0x01, 0x00}}))
);
}
TEST(ToHex, Ostream)
{
std::stringstream out;
epee::to_hex::buffer(out, nullptr);
EXPECT_TRUE(out.str().empty());
{
const std::uint8_t source[] = {0xff, 0xab, 0x01, 0x00};
epee::to_hex::buffer(out, source);
}
std::string expected{"ffab0100"};
EXPECT_EQ(expected, out.str());
const std::vector<unsigned char> all_bytes = get_all_bytes();
expected.append(std_to_hex(all_bytes));
epee::to_hex::buffer(out, epee::to_span(all_bytes));
EXPECT_EQ(expected, out.str());
}
TEST(ToHex, Formatted)
{
std::stringstream out;
std::string expected{"<>"};
epee::to_hex::formatted(out, nullptr);
EXPECT_EQ(expected, out.str());
expected.append("<ffab0100>");
epee::to_hex::formatted(out, epee::as_byte_span("\xFF\xAB\x01"));
EXPECT_EQ(expected, out.str());
const std::vector<unsigned char> all_bytes = get_all_bytes();
expected.append("<").append(std_to_hex(all_bytes)).append(">");
epee::to_hex::formatted(out, epee::to_span(all_bytes));
EXPECT_EQ(expected, out.str());
}
TEST(StringTools, BuffToHex)
{
const std::vector<unsigned char> all_bytes = get_all_bytes();
EXPECT_EQ(
std_to_hex(all_bytes),
(epee::string_tools::buff_to_hex_nodelimer(
std::string{reinterpret_cast<const char*>(all_bytes.data()), all_bytes.size()}
))
);
}
TEST(StringTools, PodToHex)
{
struct some_pod { unsigned char data[4]; };
EXPECT_EQ(
std::string{"ffab0100"},
(epee::string_tools::pod_to_hex(some_pod{{0xFF, 0xAB, 0x01, 0x00}}))
);
}
TEST(StringTools, GetIpString) TEST(StringTools, GetIpString)
{ {
EXPECT_EQ( EXPECT_EQ(

View file

@ -32,6 +32,7 @@
#include <cstdint> #include <cstdint>
#include <algorithm> #include <algorithm>
#include <sstream>
#include "ringct/rctTypes.h" #include "ringct/rctTypes.h"
#include "ringct/rctSigs.h" #include "ringct/rctSigs.h"
@ -1048,3 +1049,13 @@ TEST(ringct, reject_gen_non_simple_ver_simple)
rct::rctSig sig = make_sample_rct_sig(NELTS(inputs), inputs, NELTS(outputs), outputs, true); rct::rctSig sig = make_sample_rct_sig(NELTS(inputs), inputs, NELTS(outputs), outputs, true);
ASSERT_FALSE(rct::verRctSimple(sig)); ASSERT_FALSE(rct::verRctSimple(sig));
} }
TEST(ringct, key_ostream)
{
std::stringstream out;
out << "BEGIN" << rct::H << "END";
EXPECT_EQ(
std::string{"BEGIN<8b655970153799af2aeadc9ff1add0ea6c7251d54154cfa92c173a0dd39c1f94>END"},
out.str()
);
}

View file

@ -1000,8 +1000,6 @@ TEST(Serialization, portability_unsigned_tx)
ASSERT_TRUE(tcd.selected_transfers.front() == 2); ASSERT_TRUE(tcd.selected_transfers.front() == 2);
// tcd.extra // tcd.extra
ASSERT_TRUE(tcd.extra.size() == 68); ASSERT_TRUE(tcd.extra.size() == 68);
string tcd_extra_str = epee::string_tools::buff_to_hex(string(reinterpret_cast<char*>(tcd.extra.data()), tcd.extra.size()));
ASSERT_TRUE(tcd_extra_str == "0x2 0x21 0x0 0xf8 0xd 0xbc 0xfc 0xa2 0x2d 0x84 0x1e 0xa0 0x46 0x18 0x7a 0x5b 0x19 0xea 0x4d 0xd1 0xa2 0x8a 0x58 0xa8 0x72 0x9 0xd5 0xdf 0x2 0x30 0x60 0xac 0x9e 0x48 0x84 0x1 0xb2 0xfd 0x5d 0x4e 0x45 0x8b 0xf1 0x28 0xa0 0xc8 0x30 0xd1 0x35 0x4f 0x47 0xb9 0xed 0xc9 0x82 0x8c 0x83 0x37 0x7d 0xb6 0xb5 0xe5 0x3d 0xff 0x64 0xb0 0xde 0x7f ");
// tcd.{unlock_time, use_rct} // tcd.{unlock_time, use_rct}
ASSERT_TRUE(tcd.unlock_time == 0); ASSERT_TRUE(tcd.unlock_time == 0);
ASSERT_TRUE(tcd.use_rct); ASSERT_TRUE(tcd.use_rct);
@ -1157,8 +1155,6 @@ TEST(Serialization, portability_signed_tx)
ASSERT_TRUE(tcd.selected_transfers.front() == 2); ASSERT_TRUE(tcd.selected_transfers.front() == 2);
// ptx.construction_data.extra // ptx.construction_data.extra
ASSERT_TRUE(tcd.extra.size() == 68); ASSERT_TRUE(tcd.extra.size() == 68);
string tcd_extra_str = epee::string_tools::buff_to_hex(string(reinterpret_cast<char*>(tcd.extra.data()), tcd.extra.size()));
ASSERT_TRUE(tcd_extra_str == "0x2 0x21 0x0 0xf8 0xd 0xbc 0xfc 0xa2 0x2d 0x84 0x1e 0xa0 0x46 0x18 0x7a 0x5b 0x19 0xea 0x4d 0xd1 0xa2 0x8a 0x58 0xa8 0x72 0x9 0xd5 0xdf 0x2 0x30 0x60 0xac 0x9e 0x48 0x84 0x1 0xb2 0xfd 0x5d 0x4e 0x45 0x8b 0xf1 0x28 0xa0 0xc8 0x30 0xd1 0x35 0x4f 0x47 0xb9 0xed 0xc9 0x82 0x8c 0x83 0x37 0x7d 0xb6 0xb5 0xe5 0x3d 0xff 0x64 0xb0 0xde 0x7f ");
// ptx.construction_data.{unlock_time, use_rct} // ptx.construction_data.{unlock_time, use_rct}
ASSERT_TRUE(tcd.unlock_time == 0); ASSERT_TRUE(tcd.unlock_time == 0);
ASSERT_TRUE(tcd.use_rct); ASSERT_TRUE(tcd.use_rct);