Improve C++ helpers

This commit is contained in:
Paweł Bylica 2018-09-08 16:08:37 +02:00
parent da9c03ffb5
commit 5c8e64915a
No known key found for this signature in database
GPG Key ID: 7A0C037434FE77EF
5 changed files with 60 additions and 22 deletions

View File

@ -7,8 +7,8 @@
#include "example_host.h" #include "example_host.h"
#include <evmc/helpers.hpp>
#include <evmc/helpers.h> #include <evmc/helpers.h>
#include <evmc/helpers.hpp>
#include <map> #include <map>

View File

@ -10,6 +10,8 @@
* These are convenient for languages where invoking function pointers * These are convenient for languages where invoking function pointers
* is "ugly" or impossible (such as Go). * is "ugly" or impossible (such as Go).
* *
* It also contains helpers (overloaded operators) for using EVMC types effectively in C++.
*
* @defgroup helpers EVMC Helpers * @defgroup helpers EVMC Helpers
* @{ * @{
*/ */

View File

@ -4,11 +4,10 @@
*/ */
/** /**
* EVMC C++ helpers * @file
* A collection of helpers (overloaded operators) for using EVMC types effectively in C++.
* *
* A collection of helpers (overloaded operators) for using EVMC effectively in C++. * @addtogroup helpers
*
* @defgroup cpphelpers EVMC C++ helpers
* @{ * @{
*/ */
#pragma once #pragma once
@ -19,31 +18,31 @@
#include <functional> #include <functional>
/// The comparator for std::map<evmc_address, ...>. /// The comparator for std::map<evmc_address, ...>.
bool operator<(const evmc_address& a, const evmc_address& b) inline bool operator<(const evmc_address& a, const evmc_address& b)
{ {
return std::memcmp(a.bytes, b.bytes, sizeof(a)) < 0; return std::memcmp(a.bytes, b.bytes, sizeof(a.bytes)) < 0;
} }
/// The comparator for std::map<evmc_bytes32, ...>. /// The comparator for std::map<evmc_bytes32, ...>.
bool operator<(const evmc_bytes32& a, const evmc_bytes32& b) inline bool operator<(const evmc_bytes32& a, const evmc_bytes32& b)
{ {
return std::memcmp(a.bytes, b.bytes, sizeof(a)) < 0; return std::memcmp(a.bytes, b.bytes, sizeof(a.bytes)) < 0;
} }
/// The comparator for equality. /// The comparator for equality.
bool operator==(const evmc_address& a, const evmc_address& b) inline bool operator==(const evmc_address& a, const evmc_address& b)
{ {
return std::memcmp(a.bytes, b.bytes, sizeof(a)) == 0; return std::memcmp(a.bytes, b.bytes, sizeof(a.bytes)) == 0;
} }
/// The comparator for equality. /// The comparator for equality.
bool operator==(const evmc_bytes32& a, const evmc_bytes32& b) inline bool operator==(const evmc_bytes32& a, const evmc_bytes32& b)
{ {
return std::memcmp(a.bytes, b.bytes, sizeof(a)) == 0; return std::memcmp(a.bytes, b.bytes, sizeof(a.bytes)) == 0;
} }
/// FNV1a hash function with 64-bit result. /// FNV1a hash function with 64-bit result.
static inline uint64_t fnv1a_64(const uint8_t* ptr, size_t len) inline uint64_t fnv1a_64(const uint8_t* ptr, size_t len)
{ {
constexpr uint64_t prime = 1099511628211ULL; constexpr uint64_t prime = 1099511628211ULL;
constexpr uint64_t offset_basis = 14695981039346656037ULL; constexpr uint64_t offset_basis = 14695981039346656037ULL;
@ -57,20 +56,27 @@ static inline uint64_t fnv1a_64(const uint8_t* ptr, size_t len)
return ret; return ret;
} }
static_assert(sizeof(size_t) == sizeof(uint64_t), "size_t is not 64-bit wide");
namespace std namespace std
{ {
/// Hash operator template needed for std::ordered_set and others using hashes. /// Hash operator template specialization for evmc_address needed for unordered containers.
template <>
struct hash<evmc_address>
{
/// Hash operator using FNV1a.
std::enable_if<sizeof(size_t) == 8, std::size_t>::type operator()(const evmc_address& s) const
noexcept
{
return fnv1a_64(s.bytes, sizeof(s.bytes));
}
};
/// Hash operator template needed for std::unordered_set and others using hashes.
template <> template <>
struct hash<evmc_bytes32> struct hash<evmc_bytes32>
{ {
/// The argument type.
typedef evmc_bytes32 argument_type;
/// The result type.
typedef std::size_t result_type;
/// Hash operator using FNV1a. /// Hash operator using FNV1a.
result_type operator()(argument_type const& s) const noexcept std::enable_if<sizeof(size_t) == 8, std::size_t>::type operator()(const evmc_bytes32& s) const
noexcept
{ {
return fnv1a_64(s.bytes, sizeof(s.bytes)); return fnv1a_64(s.bytes, sizeof(s.bytes));
} }

View File

@ -39,6 +39,7 @@ add_custom_command(
add_executable( add_executable(
evmc-test evmc-test
test_helpers.cpp
test_instructions.cpp test_instructions.cpp
test_loader.cpp test_loader.cpp
) )

View File

@ -0,0 +1,29 @@
// EVMC: Ethereum Client-VM Connector API.
// Copyright 2018 The EVMC Authors.
// Licensed under the Apache License, Version 2.0. See the LICENSE file.
#include <evmc/helpers.hpp>
#include <gtest/gtest.h>
#include <map>
#include <unordered_map>
TEST(helpers, maps)
{
std::map<evmc_address, bool> addresses;
addresses[{}] = true;
ASSERT_EQ(addresses.size(), 1);
std::unordered_map<evmc_address, bool> unordered_addresses;
unordered_addresses.emplace(*addresses.begin());
EXPECT_EQ(unordered_addresses.size(), 1);
std::map<evmc_bytes32, bool> storage;
storage[{}] = true;
ASSERT_EQ(storage.size(), 1);
std::unordered_map<evmc_bytes32, bool> unordered_storage;
unordered_storage.emplace(*storage.begin());
EXPECT_EQ(unordered_storage.size(), 1);
}