Skip to content

Commit

Permalink
Merge pull request #654 from ethereum/hex_spaced
Browse files Browse the repository at this point in the history
hex: Add from_spaced_hex()
  • Loading branch information
chfast authored Jun 3, 2022
2 parents f4d9b41 + b2b0879 commit 586d2c9
Show file tree
Hide file tree
Showing 7 changed files with 55 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ inline constexpr bool isspace(char ch) noexcept
return ch == ' ' || (static_cast<unsigned>(ch) - '\t') < 5;
}

/// Checks if a character is not a white space.
inline constexpr bool is_not_space(char ch) noexcept
{
return !isspace(ch);
Expand All @@ -32,10 +33,19 @@ template <typename BaseIterator,
bool predicate(typename std::iterator_traits<BaseIterator>::value_type) noexcept>
struct filter_iterator
{
/// The iterator difference type.
using difference_type = typename std::iterator_traits<BaseIterator>::difference_type;

/// The iterator value type.
using value_type = typename std::iterator_traits<BaseIterator>::value_type;

/// The iterator pointer type.
using pointer = typename std::iterator_traits<BaseIterator>::pointer;

/// The iterator reference type.
using reference = typename std::iterator_traits<BaseIterator>::reference;

/// The iterator category.
using iterator_category = std::input_iterator_tag;

private:
Expand All @@ -54,26 +64,32 @@ struct filter_iterator
}

public:
/// The constructor of the base iterator pair.
constexpr filter_iterator(BaseIterator it, BaseIterator end) noexcept : base{it}, base_end{end}
{
forward_to_next_value();
}

/// The dereference operator.
constexpr auto operator*() noexcept
{
// We should not read from an input base iterator twice. So the only read is in
// forward_to_next_value() and here we return the cached value.
return value;
}

/// The increment operator.
constexpr void operator++() noexcept
{
++base;
forward_to_next_value();
}

constexpr bool operator!=(const filter_iterator& o) noexcept { return base != o.base; }
constexpr bool operator==(const filter_iterator& o) noexcept { return base == o.base; }
/// The equality operator.
constexpr bool operator==(const filter_iterator& o) const noexcept { return base == o.base; }

/// The inequality operator.
constexpr bool operator!=(const filter_iterator& o) const noexcept { return base != o.base; }
};

/// The input filter iterator which skips whitespace characters from the base input iterator.
Expand All @@ -83,6 +99,7 @@ struct skip_space_iterator : filter_iterator<BaseIterator, is_not_space>
using filter_iterator<BaseIterator, is_not_space>::filter_iterator;
};

/// Class template argument deduction guide.
template <typename BaseIterator>
skip_space_iterator(BaseIterator, BaseIterator) -> skip_space_iterator<BaseIterator>;
} // namespace evmc
24 changes: 22 additions & 2 deletions include/evmc/hex.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
// Licensed under the Apache License, Version 2.0.
#pragma once

#include <evmc/filter_iterator.hpp>
#include <cstdint>
#include <iterator>
#include <optional>
#include <string>
#include <string_view>
Expand Down Expand Up @@ -104,7 +104,6 @@ inline bool validate_hex(std::string_view hex) noexcept
///
/// In case the input is invalid the returned value is std::nullopt.
/// This can happen if a non-hex digit or odd number of digits is encountered.
/// Whitespace in the input is ignored.
inline std::optional<bytes> from_hex(std::string_view hex)
{
bytes bs;
Expand Down Expand Up @@ -135,4 +134,25 @@ constexpr std::optional<T> from_hex(std::string_view s) noexcept
return {};
return r;
}

/// Decodes hex encoded string to bytes. The whitespace in the input is ignored.
///
/// In case the input is invalid the returned value is std::nullopt.
/// This can happen if a non-hex digit or odd number of digits is encountered.
/// The whitespace (as defined by std::isspace) in the input is ignored.
template <typename InputIterator>
std::optional<bytes> from_spaced_hex(InputIterator begin, InputIterator end) noexcept
{
bytes bs;
if (!from_hex(skip_space_iterator{begin, end}, skip_space_iterator{end, end},
std::back_inserter(bs)))
return {};
return bs;
}

/// @copydoc from_spaced_hex
inline std::optional<bytes> from_spaced_hex(std::string_view hex) noexcept
{
return from_spaced_hex(hex.begin(), hex.end());
}
} // namespace evmc
2 changes: 2 additions & 0 deletions test/compilation/compilation_test.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <evmc/mocked_host.hpp>
#include <evmc/utils.h>
#include <evmc/hex.hpp>
#include <evmc/filter_iterator.hpp>

// Include again to check if headers have proper include guards.
#include <evmc/evmc.h>
Expand All @@ -22,3 +23,4 @@
#include <evmc/mocked_host.hpp>
#include <evmc/utils.h>
#include <evmc/hex.hpp>
#include <evmc/filter_iterator.hpp>
2 changes: 1 addition & 1 deletion test/unittests/filter_iterator_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Copyright 2022 The EVMC Authors.
// Licensed under the Apache License, Version 2.0.

#include <tools/evmc/filter_iterator.hpp>
#include <evmc/filter_iterator.hpp>
#include <gtest/gtest.h>
#include <cctype>

Expand Down
20 changes: 5 additions & 15 deletions test/unittests/hex_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
// Licensed under the Apache License, Version 2.0.

#include <evmc/hex.hpp>
#include <tools/evmc/filter_iterator.hpp>
#include <gtest/gtest.h>

using namespace evmc;
Expand Down Expand Up @@ -82,21 +81,12 @@ TEST(hex, validate_hex)
EXPECT_FALSE(validate_hex("WXYZ"));
}

TEST(hex, from_hex_skip_space)
TEST(hex, from_spaced_hex)
{
// Combine from_hex with skip_space_iterator.
static constexpr auto from_hex_skip_space = [](std::string_view hex) {
bytes out;
const auto status =
from_hex(skip_space_iterator{hex.begin(), hex.end()},
skip_space_iterator{hex.end(), hex.end()}, std::back_inserter(out));
EXPECT_TRUE(status);
return out;
};
EXPECT_EQ(from_hex_skip_space("0x010203"), (bytes{0x01, 0x02, 0x03}));
EXPECT_EQ(from_hex_skip_space("0x 010203 "), (bytes{0x01, 0x02, 0x03}));
EXPECT_EQ(from_hex_skip_space(" 0 x 0 1 0 2 0 3 "), (bytes{0x01, 0x02, 0x03}));
EXPECT_EQ(from_hex_skip_space("\f 0\r x 0 1\t 0 2 \v0 3 \n"), (bytes{0x01, 0x02, 0x03}));
EXPECT_EQ(from_spaced_hex("0x010203"), (bytes{0x01, 0x02, 0x03}));
EXPECT_EQ(from_spaced_hex("0x 010203 "), (bytes{0x01, 0x02, 0x03}));
EXPECT_EQ(from_spaced_hex(" 0 x 0 1 0 2 0 3 "), (bytes{0x01, 0x02, 0x03}));
EXPECT_EQ(from_spaced_hex("\f 0\r x 0 1\t 0 2 \v0 3 \n"), (bytes{0x01, 0x02, 0x03}));
}

TEST(hex, from_hex_to_custom_type)
Expand Down
2 changes: 1 addition & 1 deletion tools/evmc/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
hunter_add_package(CLI11)
find_package(CLI11 REQUIRED)

add_executable(evmc-tool main.cpp filter_iterator.hpp)
add_executable(evmc-tool main.cpp)
add_executable(evmc::tool ALIAS evmc-tool)
set_target_properties(evmc-tool PROPERTIES OUTPUT_NAME evmc)
set_source_files_properties(main.cpp PROPERTIES
Expand Down
13 changes: 5 additions & 8 deletions tools/evmc/main.cpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
// EVMC: Ethereum Client-VM Connector API.
// Copyright 2019-2020 The EVMC Authors.
// Copyright 2019 The EVMC Authors.
// Licensed under the Apache License, Version 2.0.

#include "filter_iterator.hpp"
#include <CLI/CLI.hpp>
#include <evmc/hex.hpp>
#include <evmc/loader.h>
Expand All @@ -20,13 +19,11 @@ evmc::bytes load_from_hex(const std::string& str)
{
const auto path = str.substr(1);
std::ifstream file{path};
const std::istreambuf_iterator<char> file_begin{file};
const std::istreambuf_iterator<char> file_end;
evmc::bytes out;
if (!evmc::from_hex(evmc::skip_space_iterator{file_begin, file_end},
evmc::skip_space_iterator{file_end, file_end}, std::back_inserter(out)))
auto out = evmc::from_spaced_hex(std::istreambuf_iterator<char>{file},
std::istreambuf_iterator<char>{});
if (!out)
throw std::invalid_argument{"invalid hex in " + path};
return out;
return out.value();
}

return evmc::from_hex(str).value(); // Should be validated already.
Expand Down

0 comments on commit 586d2c9

Please sign in to comment.