Skip to content
This repository was archived by the owner on Apr 8, 2026. It is now read-only.

Commit 613889b

Browse files
authored
C++: Fix basic_string<unsigned char> (#712)
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>`.
1 parent 7e3a944 commit 613889b

4 files changed

Lines changed: 94 additions & 13 deletions

File tree

include/evmc/bytes.hpp

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
// EVMC: Ethereum Client-VM Connector API.
2+
// Copyright 2024 The EVMC Authors.
3+
// Licensed under the Apache License, Version 2.0.
4+
#pragma once
5+
6+
#include <algorithm>
7+
#include <cstring>
8+
#include <string>
9+
#include <string_view>
10+
11+
namespace evmc
12+
{
13+
/// The char traits for byte-like types.
14+
///
15+
/// See: https://en.cppreference.com/w/cpp/string/char_traits.
16+
template <typename T>
17+
struct byte_traits : std::char_traits<char>
18+
{
19+
static_assert(sizeof(T) == 1, "type must be a byte");
20+
21+
using char_type = T; ///< The byte type.
22+
23+
/// Assigns c2 to c1.
24+
static constexpr void assign(char_type& c1, const char_type& c2) { c1 = c2; }
25+
26+
/// Assigns value to each byte in [ptr, ptr+count).
27+
static constexpr char_type* assign(char_type* ptr, std::size_t count, char_type value)
28+
{
29+
std::fill_n(ptr, count, value);
30+
return ptr;
31+
}
32+
33+
/// Returns true if bytes are equal.
34+
static constexpr bool eq(char_type a, char_type b) { return a == b; }
35+
36+
/// Returns true if byte a is less than byte b.
37+
static constexpr bool lt(char_type a, char_type b) { return a < b; }
38+
39+
/// Copies count bytes from src to dest. Performs correctly even if ranges overlap.
40+
static constexpr char_type* move(char_type* dest, const char_type* src, std::size_t count)
41+
{
42+
if (dest < src)
43+
std::copy_n(src, count, dest);
44+
else if (src < dest)
45+
std::copy_backward(src, src + count, dest + count);
46+
return dest;
47+
}
48+
49+
/// Copies count bytes from src to dest. The ranges must not overlap.
50+
static constexpr char_type* copy(char_type* dest, const char_type* src, std::size_t count)
51+
{
52+
std::copy_n(src, count, dest);
53+
return dest;
54+
}
55+
56+
/// Compares lexicographically the bytes in two ranges of equal length.
57+
static constexpr int compare(const char_type* a, const char_type* b, std::size_t count)
58+
{
59+
for (; count != 0; --count, ++a, ++b)
60+
{
61+
if (lt(*a, *b))
62+
return -1;
63+
if (lt(*b, *a))
64+
return 1;
65+
}
66+
return 0;
67+
}
68+
69+
/// Returns the length of a null-terminated byte string.
70+
// TODO: Not constexpr
71+
static std::size_t length(const char_type* s)
72+
{
73+
return std::strlen(reinterpret_cast<const char*>(s));
74+
}
75+
76+
/// Finds the value in the range of bytes and returns the pointer to the first occurrence
77+
/// or nullptr if not found.
78+
static constexpr const char_type* find(const char_type* s,
79+
std::size_t count,
80+
const char_type& value)
81+
{
82+
const auto end = s + count;
83+
const auto p = std::find(s, end, value);
84+
return p != end ? p : nullptr;
85+
}
86+
};
87+
88+
/// String of unsigned chars representing bytes.
89+
using bytes = std::basic_string<unsigned char, byte_traits<unsigned char>>;
90+
91+
/// String view of unsigned chars representing bytes.
92+
using bytes_view = std::basic_string_view<unsigned char, byte_traits<unsigned char>>;
93+
} // namespace evmc

include/evmc/evmc.hpp

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,6 @@ static_assert(EVMC_LATEST_STABLE_REVISION <= EVMC_MAX_REVISION,
2020
/// @ingroup cpp
2121
namespace evmc
2222
{
23-
/// String view of uint8_t chars.
24-
using bytes_view = std::basic_string_view<uint8_t>;
25-
2623
/// The big-endian 160-bit hash suitable for keeping an Ethereum address.
2724
///
2825
/// This type wraps C ::evmc_address to make sure objects of this type are always initialized.

include/evmc/hex.hpp

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// Licensed under the Apache License, Version 2.0.
44
#pragma once
55

6+
#include <evmc/bytes.hpp>
67
#include <evmc/filter_iterator.hpp>
78
#include <cstdint>
89
#include <optional>
@@ -11,13 +12,6 @@
1112

1213
namespace evmc
1314
{
14-
/// String of uint8_t chars.
15-
using bytes = std::basic_string<uint8_t>;
16-
17-
/// String view of uint8_t chars.
18-
using bytes_view = std::basic_string_view<uint8_t>;
19-
20-
2115
/// Encode a byte to a hex string.
2216
inline std::string hex(uint8_t b) noexcept
2317
{

include/evmc/mocked_host.hpp

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,6 @@
1212

1313
namespace evmc
1414
{
15-
/// The string of bytes.
16-
using bytes = std::basic_string<uint8_t>;
17-
1815
/// Extended value (with original value and access flag) for account storage.
1916
struct StorageValue
2017
{

0 commit comments

Comments
 (0)