Skip to content

Commit

Permalink
span: Add std::byte helpers
Browse files Browse the repository at this point in the history
Also, add Span<std::byte> interface to strencondings.
  • Loading branch information
MarcoFalke committed Nov 9, 2021
1 parent fa18038 commit faa3ec2
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 11 deletions.
25 changes: 25 additions & 0 deletions src/span.h
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ class Span
return m_data[m_size - 1];
}
constexpr std::size_t size() const noexcept { return m_size; }
constexpr std::size_t size_bytes() const noexcept { return sizeof(C) * m_size; }
constexpr bool empty() const noexcept { return size() == 0; }
CONSTEXPR_IF_NOT_DEBUG C& operator[](std::size_t pos) const noexcept
{
Expand Down Expand Up @@ -236,11 +237,35 @@ T& SpanPopBack(Span<T>& span)
return back;
}

// From C++20 as_bytes and as_writeable_bytes
template <typename T>
Span<const std::byte> AsBytes(Span<T> s) noexcept
{
return {reinterpret_cast<const std::byte*>(s.data()), s.size_bytes()};
}
template <typename T>
Span<std::byte> AsWritableBytes(Span<T> s) noexcept
{
return {reinterpret_cast<std::byte*>(s.data()), s.size_bytes()};
}

template <typename V>
Span<const std::byte> MakeByteSpan(V&& v) noexcept
{
return AsBytes(MakeSpan(std::forward<V>(v)));
}
template <typename V>
Span<std::byte> MakeWritableByteSpan(V&& v) noexcept
{
return AsWritableBytes(MakeSpan(std::forward<V>(v)));
}

// Helper functions to safely cast to unsigned char pointers.
inline unsigned char* UCharCast(char* c) { return (unsigned char*)c; }
inline unsigned char* UCharCast(unsigned char* c) { return c; }
inline const unsigned char* UCharCast(const char* c) { return (unsigned char*)c; }
inline const unsigned char* UCharCast(const unsigned char* c) { return c; }
inline const unsigned char* UCharCast(const std::byte* c) { return reinterpret_cast<const unsigned char*>(c); }

// Helper function to safely convert a Span to a Span<[const] unsigned char>.
template <typename T> constexpr auto UCharSpanCast(Span<T> s) -> Span<typename std::remove_pointer<decltype(UCharCast(s.data()))>::type> { return {UCharCast(s.data()), s.size()}; }
Expand Down
10 changes: 10 additions & 0 deletions src/test/base64_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,16 @@ BOOST_AUTO_TEST_CASE(base64_testvectors)
BOOST_CHECK_EQUAL(strDec, vstrIn[i]);
}

{
const std::vector<uint8_t> in_u{0xff, 0x01, 0xff};
const std::vector<std::byte> in_b{std::byte{0xff}, std::byte{0x01}, std::byte{0xff}};
const std::string in_s{"\xff\x01\xff"};
const std::string out_exp{"/wH/"};
BOOST_CHECK_EQUAL(EncodeBase64(in_u), out_exp);
BOOST_CHECK_EQUAL(EncodeBase64(in_b), out_exp);
BOOST_CHECK_EQUAL(EncodeBase64(in_s), out_exp);
}

// Decoding strings with embedded NUL characters should fail
bool failure;
(void)DecodeBase64("invalid\0"s, &failure);
Expand Down
23 changes: 18 additions & 5 deletions src/test/util_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -151,12 +151,25 @@ BOOST_AUTO_TEST_CASE(util_HexStr)
HexStr(Span<const unsigned char>(ParseHex_expected, ParseHex_expected)),
"");

std::vector<unsigned char> ParseHex_vec(ParseHex_expected, ParseHex_expected + 5);
{
const std::vector<char> in_s{ParseHex_expected, ParseHex_expected + 5};
const Span<const uint8_t> in_u{MakeUCharSpan(in_s)};
const Span<const std::byte> in_b{MakeByteSpan(in_s)};
const std::string out_exp{"04678afdb0"};

BOOST_CHECK_EQUAL(HexStr(in_u), out_exp);
BOOST_CHECK_EQUAL(HexStr(in_s), out_exp);
BOOST_CHECK_EQUAL(HexStr(in_b), out_exp);
}
}

BOOST_CHECK_EQUAL(
HexStr(ParseHex_vec),
"04678afdb0"
);
BOOST_AUTO_TEST_CASE(span_write_bytes)
{
std::array mut_arr{uint8_t{0xaa}, uint8_t{0xbb}};
const auto mut_bytes{MakeWritableByteSpan(mut_arr)};
mut_bytes[1] = std::byte{0x11};
BOOST_CHECK_EQUAL(mut_arr.at(0), 0xaa);
BOOST_CHECK_EQUAL(mut_arr.at(1), 0x11);
}

BOOST_AUTO_TEST_CASE(util_Join)
Expand Down
5 changes: 0 additions & 5 deletions src/util/strencodings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -138,11 +138,6 @@ std::string EncodeBase64(Span<const unsigned char> input)
return str;
}

std::string EncodeBase64(const std::string& str)
{
return EncodeBase64(MakeUCharSpan(str));
}

std::vector<unsigned char> DecodeBase64(const char* p, bool* pf_invalid)
{
static const int decode64_table[256] =
Expand Down
4 changes: 3 additions & 1 deletion src/util/strencodings.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ bool IsHexNumber(const std::string& str);
std::vector<unsigned char> DecodeBase64(const char* p, bool* pf_invalid = nullptr);
std::string DecodeBase64(const std::string& str, bool* pf_invalid = nullptr);
std::string EncodeBase64(Span<const unsigned char> input);
std::string EncodeBase64(const std::string& str);
inline std::string EncodeBase64(Span<const std::byte> input) { return EncodeBase64(MakeUCharSpan(input)); }
inline std::string EncodeBase64(const std::string& str) { return EncodeBase64(MakeUCharSpan(str)); }
std::vector<unsigned char> DecodeBase32(const char* p, bool* pf_invalid = nullptr);
std::string DecodeBase32(const std::string& str, bool* pf_invalid = nullptr);

Expand Down Expand Up @@ -189,6 +190,7 @@ std::optional<T> ToIntegral(const std::string& str)
*/
std::string HexStr(const Span<const uint8_t> s);
inline std::string HexStr(const Span<const char> s) { return HexStr(MakeUCharSpan(s)); }
inline std::string HexStr(const Span<const std::byte> s) { return HexStr(MakeUCharSpan(s)); }

/**
* Format a paragraph of text to a fixed width, adding spaces for
Expand Down

0 comments on commit faa3ec2

Please sign in to comment.