Skip to content

Commit

Permalink
C++: Fix basic_string<unsigned char> (#712)
Browse files Browse the repository at this point in the history
The `std::basic_string<unsigned char>` is not standard compliant because
it relies on non-standard specialization `std::char_traits<unsigned
char>`.

The later has been deprecated in libc++ and will be removed in version
19.

Define our own traits `byte_traits<unsigned char>` and define the types
for storing bytes as:
`std::basic_string<unsigned char, byte_traits<unsigned char>`.
  • Loading branch information
chfast authored May 24, 2024
1 parent 7e3a944 commit 613889b
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 13 deletions.
93 changes: 93 additions & 0 deletions include/evmc/bytes.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
// EVMC: Ethereum Client-VM Connector API.
// Copyright 2024 The EVMC Authors.
// Licensed under the Apache License, Version 2.0.
#pragma once

#include <algorithm>
#include <cstring>
#include <string>
#include <string_view>

namespace evmc
{
/// The char traits for byte-like types.
///
/// See: https://en.cppreference.com/w/cpp/string/char_traits.
template <typename T>
struct byte_traits : std::char_traits<char>
{
static_assert(sizeof(T) == 1, "type must be a byte");

using char_type = T; ///< The byte type.

/// Assigns c2 to c1.
static constexpr void assign(char_type& c1, const char_type& c2) { c1 = c2; }

/// Assigns value to each byte in [ptr, ptr+count).
static constexpr char_type* assign(char_type* ptr, std::size_t count, char_type value)
{
std::fill_n(ptr, count, value);
return ptr;
}

/// Returns true if bytes are equal.
static constexpr bool eq(char_type a, char_type b) { return a == b; }

/// Returns true if byte a is less than byte b.
static constexpr bool lt(char_type a, char_type b) { return a < b; }

/// Copies count bytes from src to dest. Performs correctly even if ranges overlap.
static constexpr char_type* move(char_type* dest, const char_type* src, std::size_t count)
{
if (dest < src)
std::copy_n(src, count, dest);
else if (src < dest)
std::copy_backward(src, src + count, dest + count);
return dest;
}

/// Copies count bytes from src to dest. The ranges must not overlap.
static constexpr char_type* copy(char_type* dest, const char_type* src, std::size_t count)
{
std::copy_n(src, count, dest);
return dest;
}

/// Compares lexicographically the bytes in two ranges of equal length.
static constexpr int compare(const char_type* a, const char_type* b, std::size_t count)
{
for (; count != 0; --count, ++a, ++b)
{
if (lt(*a, *b))
return -1;
if (lt(*b, *a))
return 1;
}
return 0;
}

/// Returns the length of a null-terminated byte string.
// TODO: Not constexpr
static std::size_t length(const char_type* s)
{
return std::strlen(reinterpret_cast<const char*>(s));
}

/// Finds the value in the range of bytes and returns the pointer to the first occurrence
/// or nullptr if not found.
static constexpr const char_type* find(const char_type* s,
std::size_t count,
const char_type& value)
{
const auto end = s + count;
const auto p = std::find(s, end, value);
return p != end ? p : nullptr;
}
};

/// String of unsigned chars representing bytes.
using bytes = std::basic_string<unsigned char, byte_traits<unsigned char>>;

/// String view of unsigned chars representing bytes.
using bytes_view = std::basic_string_view<unsigned char, byte_traits<unsigned char>>;
} // namespace evmc
3 changes: 0 additions & 3 deletions include/evmc/evmc.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,6 @@ static_assert(EVMC_LATEST_STABLE_REVISION <= EVMC_MAX_REVISION,
/// @ingroup cpp
namespace evmc
{
/// String view of uint8_t chars.
using bytes_view = std::basic_string_view<uint8_t>;

/// The big-endian 160-bit hash suitable for keeping an Ethereum address.
///
/// This type wraps C ::evmc_address to make sure objects of this type are always initialized.
Expand Down
8 changes: 1 addition & 7 deletions include/evmc/hex.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// Licensed under the Apache License, Version 2.0.
#pragma once

#include <evmc/bytes.hpp>
#include <evmc/filter_iterator.hpp>
#include <cstdint>
#include <optional>
Expand All @@ -11,13 +12,6 @@

namespace evmc
{
/// String of uint8_t chars.
using bytes = std::basic_string<uint8_t>;

/// String view of uint8_t chars.
using bytes_view = std::basic_string_view<uint8_t>;


/// Encode a byte to a hex string.
inline std::string hex(uint8_t b) noexcept
{
Expand Down
3 changes: 0 additions & 3 deletions include/evmc/mocked_host.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,6 @@

namespace evmc
{
/// The string of bytes.
using bytes = std::basic_string<uint8_t>;

/// Extended value (with original value and access flag) for account storage.
struct StorageValue
{
Expand Down

0 comments on commit 613889b

Please sign in to comment.