Skip to content

Commit

Permalink
Merge pull request #474 from ethereum/cpp-operators
Browse files Browse the repository at this point in the history
cpp: Add all comparison operators for address and bytes32
  • Loading branch information
chfast authored Dec 5, 2019
2 parents ef5a2c1 + cb1e4c1 commit 0faf6d1
Show file tree
Hide file tree
Showing 3 changed files with 152 additions and 57 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ and this project adheres to [Semantic Versioning].

- Added Java bindings.
[#455](https://github.com/ethereum/evmc/pull/455)
- The C++ EVMC basic types `address` and `bytes32` have all the comparison operators supported.
[#474](https://github.com/ethereum/evmc/pull/474)


## [7.1.0] — 2019-11-29
Expand Down
49 changes: 42 additions & 7 deletions include/evmc/evmc.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ using uint256be = bytes32;
/// Loads 64 bits / 8 bytes of data from the given @p bytes array in big-endian order.
constexpr inline uint64_t load64be(const uint8_t* bytes) noexcept
{
// TODO: Report bug in clang incorrectly optimizing this with AVX2 enabled.
return (uint64_t{bytes[0]} << 56) | (uint64_t{bytes[1]} << 48) | (uint64_t{bytes[2]} << 40) |
(uint64_t{bytes[3]} << 32) | (uint64_t{bytes[4]} << 24) | (uint64_t{bytes[5]} << 16) |
(uint64_t{bytes[6]} << 8) | uint64_t{bytes[7]};
Expand All @@ -76,7 +75,7 @@ constexpr inline uint64_t fnv1a_by64(uint64_t h, uint64_t x) noexcept
} // namespace fnv


/// The "equal" comparison operator for the evmc::address type.
/// The "equal to" comparison operator for the evmc::address type.
constexpr bool operator==(const address& a, const address& b) noexcept
{
// TODO: Report bug in clang keeping unnecessary bswap.
Expand All @@ -85,13 +84,13 @@ constexpr bool operator==(const address& a, const address& b) noexcept
load32be(&a.bytes[16]) == load32be(&b.bytes[16]);
}

/// The "not equal" comparison operator for the evmc::address type.
/// The "not equal to" comparison operator for the evmc::address type.
constexpr bool operator!=(const address& a, const address& b) noexcept
{
return !(a == b);
}

/// The "less" comparison operator for the evmc::address type.
/// The "less than" comparison operator for the evmc::address type.
constexpr bool operator<(const address& a, const address& b) noexcept
{
return load64be(&a.bytes[0]) < load64be(&b.bytes[0]) ||
Expand All @@ -101,7 +100,25 @@ constexpr bool operator<(const address& a, const address& b) noexcept
load32be(&a.bytes[16]) < load32be(&b.bytes[16]));
}

/// The "equal" comparison operator for the evmc::bytes32 type.
/// The "greater than" comparison operator for the evmc::address type.
constexpr bool operator>(const address& a, const address& b) noexcept
{
return b < a;
}

/// The "less than or equal to" comparison operator for the evmc::address type.
constexpr bool operator<=(const address& a, const address& b) noexcept
{
return !(b < a);
}

/// The "greater than or equal to" comparison operator for the evmc::address type.
constexpr bool operator>=(const address& a, const address& b) noexcept
{
return !(a < b);
}

/// The "equal to" comparison operator for the evmc::bytes32 type.
constexpr bool operator==(const bytes32& a, const bytes32& b) noexcept
{
return load64be(&a.bytes[0]) == load64be(&b.bytes[0]) &&
Expand All @@ -110,13 +127,13 @@ constexpr bool operator==(const bytes32& a, const bytes32& b) noexcept
load64be(&a.bytes[24]) == load64be(&b.bytes[24]);
}

/// The "not equal" comparison operator for the evmc::bytes32 type.
/// The "not equal to" comparison operator for the evmc::bytes32 type.
constexpr bool operator!=(const bytes32& a, const bytes32& b) noexcept
{
return !(a == b);
}

/// The "less" comparison operator for the evmc::bytes32 type.
/// The "less than" comparison operator for the evmc::bytes32 type.
constexpr bool operator<(const bytes32& a, const bytes32& b) noexcept
{
return load64be(&a.bytes[0]) < load64be(&b.bytes[0]) ||
Expand All @@ -128,6 +145,24 @@ constexpr bool operator<(const bytes32& a, const bytes32& b) noexcept
load64be(&a.bytes[24]) < load64be(&b.bytes[24]));
}

/// The "greater than" comparison operator for the evmc::bytes32 type.
constexpr bool operator>(const bytes32& a, const bytes32& b) noexcept
{
return b < a;
}

/// The "less than or equal to" comparison operator for the evmc::bytes32 type.
constexpr bool operator<=(const bytes32& a, const bytes32& b) noexcept
{
return !(b < a);
}

/// The "greater than or equal to" comparison operator for the evmc::bytes32 type.
constexpr bool operator>=(const bytes32& a, const bytes32& b) noexcept
{
return !(a < b);
}

/// Checks if the given address is the zero address.
constexpr inline bool is_zero(const address& a) noexcept
{
Expand Down
158 changes: 108 additions & 50 deletions test/unittests/cpp_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -155,9 +155,79 @@ TEST(cpp, std_maps)
EXPECT_FALSE(unordered_storage.begin()->first);
}

enum relation
{
equal,
less,
greater
};

/// Compares x and y using all comparison operators (also with reversed argument order)
/// and validates results against the expected relation: eq: x == y, less: x < y.
template <typename T>
static void expect_cmp(const T& x, const T& y, relation expected)
{
switch (expected)
{
case equal:
EXPECT_TRUE(x == y);
EXPECT_FALSE(x != y);
EXPECT_FALSE(x < y);
EXPECT_TRUE(x <= y);
EXPECT_FALSE(x > y);
EXPECT_TRUE(x >= y);

EXPECT_TRUE(y == x);
EXPECT_FALSE(y != x);
EXPECT_FALSE(y < x);
EXPECT_TRUE(y <= x);
EXPECT_FALSE(y > x);
EXPECT_TRUE(y >= x);
break;
case less:
EXPECT_FALSE(x == y);
EXPECT_TRUE(x != y);
EXPECT_TRUE(x < y);
EXPECT_TRUE(x <= y);
EXPECT_FALSE(x > y);
EXPECT_FALSE(x >= y);

EXPECT_FALSE(y == x);
EXPECT_TRUE(y != x);
EXPECT_FALSE(y < x);
EXPECT_FALSE(y <= x);
EXPECT_TRUE(y > x);
EXPECT_TRUE(y >= x);
break;
case greater:
EXPECT_FALSE(x == y);
EXPECT_TRUE(x != y);
EXPECT_FALSE(x < y);
EXPECT_FALSE(x <= y);
EXPECT_TRUE(x > y);
EXPECT_TRUE(x >= y);

EXPECT_FALSE(y == x);
EXPECT_TRUE(y != x);
EXPECT_TRUE(y < x);
EXPECT_TRUE(y <= x);
EXPECT_FALSE(y > x);
EXPECT_FALSE(y >= x);
break;
}
}

TEST(cpp, address_comparison)
{
const auto zero = evmc::address{};
auto max = evmc::address{};
std::fill_n(max.bytes, sizeof(max), uint8_t{0xff});

expect_cmp(zero, zero, equal);
expect_cmp(max, max, equal);
expect_cmp(zero, max, less);
expect_cmp(max, zero, greater);

for (size_t i = 0; i < sizeof(evmc::address); ++i)
{
auto t = evmc::address{};
Expand All @@ -167,37 +237,35 @@ TEST(cpp, address_comparison)
auto f = evmc::address{};
f.bytes[i] = 0xff;

EXPECT_TRUE(zero < t);
EXPECT_TRUE(zero < u);
EXPECT_TRUE(zero < f);
EXPECT_TRUE(zero != t);
EXPECT_TRUE(zero != u);
EXPECT_TRUE(zero != f);

EXPECT_TRUE(t < u);
EXPECT_TRUE(t < f);
EXPECT_TRUE(u < f);

EXPECT_FALSE(u < t);
EXPECT_FALSE(f < t);
EXPECT_FALSE(f < u);

EXPECT_TRUE(t != u);
EXPECT_TRUE(t != f);
EXPECT_TRUE(u != t);
EXPECT_TRUE(u != f);
EXPECT_TRUE(f != t);
EXPECT_TRUE(f != u);

EXPECT_TRUE(t == t);
EXPECT_TRUE(u == u);
EXPECT_TRUE(f == f);
expect_cmp(zero, t, less);
expect_cmp(zero, u, less);
expect_cmp(zero, f, less);

expect_cmp(t, max, less);
expect_cmp(u, max, less);
expect_cmp(f, max, less);

expect_cmp(t, u, less);
expect_cmp(t, f, less);
expect_cmp(u, f, less);

expect_cmp(t, t, equal);
expect_cmp(u, u, equal);
expect_cmp(f, f, equal);
}
}

TEST(cpp, bytes32_comparison)
{
const auto zero = evmc::bytes32{};
auto max = evmc::bytes32{};
std::fill_n(max.bytes, sizeof(max), uint8_t{0xff});

expect_cmp(zero, zero, equal);
expect_cmp(max, max, equal);
expect_cmp(zero, max, less);
expect_cmp(max, zero, greater);

for (size_t i = 0; i < sizeof(evmc::bytes32); ++i)
{
auto t = evmc::bytes32{};
Expand All @@ -207,31 +275,21 @@ TEST(cpp, bytes32_comparison)
auto f = evmc::bytes32{};
f.bytes[i] = 0xff;

EXPECT_TRUE(zero < t);
EXPECT_TRUE(zero < u);
EXPECT_TRUE(zero < f);
EXPECT_TRUE(zero != t);
EXPECT_TRUE(zero != u);
EXPECT_TRUE(zero != f);

EXPECT_TRUE(t < u);
EXPECT_TRUE(t < f);
EXPECT_TRUE(u < f);

EXPECT_FALSE(u < t);
EXPECT_FALSE(f < t);
EXPECT_FALSE(f < u);

EXPECT_TRUE(t != u);
EXPECT_TRUE(t != f);
EXPECT_TRUE(u != t);
EXPECT_TRUE(u != f);
EXPECT_TRUE(f != t);
EXPECT_TRUE(f != u);

EXPECT_TRUE(t == t);
EXPECT_TRUE(u == u);
EXPECT_TRUE(f == f);
expect_cmp(zero, t, less);
expect_cmp(zero, u, less);
expect_cmp(zero, f, less);

expect_cmp(t, max, less);
expect_cmp(u, max, less);
expect_cmp(f, max, less);

expect_cmp(t, u, less);
expect_cmp(t, f, less);
expect_cmp(u, f, less);

expect_cmp(t, t, equal);
expect_cmp(u, u, equal);
expect_cmp(f, f, equal);
}
}

Expand Down

0 comments on commit 0faf6d1

Please sign in to comment.