Skip to content

Commit

Permalink
refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
chfast committed Jun 1, 2022
1 parent d3be582 commit 83aef6d
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 17 deletions.
9 changes: 3 additions & 6 deletions test/unittests/skip_space_iterator_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,12 @@ namespace
std::string remove_space(std::string_view in)
{
// Copy input to additional buffer. This helps with out-of-buffer reads detection by sanitizers.
const auto in_buffer = std::make_unique<char[]>(in.size());
const auto begin = in_buffer.get();
const auto end = begin + in.size();
std::copy(in.begin(), in.end(), begin);
const std::vector in_buffer(in.begin(), in.end());

// Filter the input.
std::string out;
std::copy(skip_space_iterator{begin, end}, skip_space_iterator{end, end},
std::back_inserter(out));
std::copy(skip_space_iterator{in_buffer.begin(), in_buffer.end()},
skip_space_iterator{in_buffer.end(), in_buffer.end()}, std::back_inserter(out));
return out;
}
} // namespace
Expand Down
50 changes: 39 additions & 11 deletions tools/evmc/skip_space_iterator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,23 @@ inline constexpr bool isspace(char ch) noexcept
return ch == ' ' || (static_cast<unsigned>(ch) - '\t') < 5;
}

/// The input filter iterator which skips whitespace characters from the base input iterator.
template <typename BaseIterator>
struct skip_space_iterator
inline constexpr bool is_not_space(char ch) noexcept
{
return !isspace(ch);
}

/// The filter iterator adaptor creates a view of an iterator range in which some elements of the
/// range are skipped. A predicate function controls which elements are skipped. When the predicate
/// is applied to an element, if it returns true then the element is retained and if it returns
/// false then the element is skipped over. When skipping over elements, it is necessary for the
/// filter adaptor to know when to stop so as to avoid going past the end of the underlying range.
/// A filter iterator is therefore constructed with pair of iterators indicating the range of
/// elements in the unfiltered sequence to be traversed.
///
/// Similar to boost::filter_iterator.
template <typename BaseIterator,
bool predicate(typename std::iterator_traits<BaseIterator>::value_type) noexcept>
struct filter_iterator
{
using difference_type = typename std::iterator_traits<BaseIterator>::difference_type;
using value_type = typename std::iterator_traits<BaseIterator>::value_type;
Expand All @@ -29,32 +43,46 @@ struct skip_space_iterator
BaseIterator base_end;
value_type value;

constexpr void forward_to_next_value()
constexpr void forward_to_next_value() noexcept
{
for (; base != base_end; ++base)
{
value = *base;
if (isspace(value) == 0)
if (predicate(value))
break;
}
}

public:
constexpr skip_space_iterator(BaseIterator it, BaseIterator end) noexcept
: base{it}, base_end{end}
constexpr filter_iterator(BaseIterator it, BaseIterator end) noexcept : base{it}, base_end{end}
{
forward_to_next_value();
}

constexpr auto operator*() { return value; }
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;
}

constexpr void operator++()
constexpr void operator++() noexcept
{
++base;
forward_to_next_value();
}

constexpr bool operator!=(const skip_space_iterator& o) { return base != o.base; }
constexpr bool operator==(const skip_space_iterator& o) { return base == o.base; }
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 input filter iterator which skips whitespace characters from the base input iterator.
template <typename BaseIterator>
struct skip_space_iterator : filter_iterator<BaseIterator, is_not_space>
{
using filter_iterator<BaseIterator, is_not_space>::filter_iterator;
};

template <typename BaseIterator>
skip_space_iterator(BaseIterator, BaseIterator) -> skip_space_iterator<BaseIterator>;
} // namespace evmc

0 comments on commit 83aef6d

Please sign in to comment.