Merge pull request #4791 from romainbrenguier/feature/range-zip

Add ranget::zip method
This commit is contained in:
Romain Brenguier 2019-06-17 13:45:32 +01:00 committed by GitHub
commit 1ea4a764ca
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 164 additions and 4 deletions

View File

@ -398,21 +398,20 @@ void goto_symext::symex_assign_from_struct(
const auto &components = to_struct_type(ns.follow(lhs.type())).components();
PRECONDITION(rhs.operands().size() == components.size());
for(std::size_t i = 0; i < components.size(); ++i)
for(const auto &comp_rhs : make_range(components).zip(rhs.operands()))
{
const auto &comp = components[i];
const auto &comp = comp_rhs.first;
const exprt lhs_field = state.field_sensitivity.apply(
ns, state, member_exprt{lhs, comp.get_name(), comp.type()}, true);
INVARIANT(
lhs_field.id() == ID_symbol,
"member of symbol should be susceptible to field-sensitivity");
const exprt &rhs_field = rhs.operands()[i];
symex_assign_symbol(
state,
to_ssa_expr(lhs_field),
full_lhs,
rhs_field,
comp_rhs.second,
guard,
assignment_type);
}

View File

@ -265,6 +265,90 @@ private:
second_iteratort second_begin;
};
/// Zip two ranges to make a range of pairs.
/// On increment, both iterators are incremented.
/// Ends when the two ranges reach their ends.
/// Invariants are checking that one does not end before the other.
template <typename first_iteratort, typename second_iteratort>
struct zip_iteratort
{
public:
using difference_type = typename first_iteratort::difference_type;
using value_type = std::pair<
typename first_iteratort::value_type,
typename second_iteratort::value_type>;
using pointer = value_type *;
using reference = value_type &;
using iterator_category = std::forward_iterator_tag;
bool operator==(const zip_iteratort &other) const
{
return first_begin == other.first_begin && first_end == other.first_end &&
second_begin == other.second_begin && second_end == other.second_end;
}
bool operator!=(const zip_iteratort &other) const
{
return !(*this == other);
}
/// Preincrement operator
zip_iteratort &operator++()
{
PRECONDITION(first_begin != first_end && second_begin != second_end);
++first_begin;
++second_begin;
INVARIANT(
(first_begin == first_end) == (second_begin == second_end),
"Zipped ranges should have the same size");
current = first_begin != first_end
? std::make_shared<value_type>(*first_begin, *second_begin)
: nullptr;
return *this;
}
/// Postincrement operator
const zip_iteratort operator++(int)
{
zip_iteratort tmp(first_begin, first_end, second_begin, second_end);
this->operator++();
return tmp;
}
reference operator*() const
{
PRECONDITION(current != nullptr);
return *current;
}
pointer operator->() const
{
return current.get();
}
zip_iteratort(
first_iteratort _first_begin,
first_iteratort _first_end,
second_iteratort _second_begin,
second_iteratort _second_end)
: first_begin(std::move(_first_begin)),
first_end(std::move(_first_end)),
second_begin(std::move(_second_begin)),
second_end(std::move(_second_end))
{
PRECONDITION((first_begin == first_end) == (second_begin == second_end));
if(first_begin != first_end)
current = util_make_unique<value_type>(*first_begin, *second_begin);
}
private:
first_iteratort first_begin;
first_iteratort first_end;
second_iteratort second_begin;
second_iteratort second_end;
std::shared_ptr<value_type> current = nullptr;
};
/// A range is a pair of a begin and an end iterators.
/// The class provides useful methods such as map, filter and concat which only
/// manipulate iterators and thus don't have to create instances of heavy data
@ -337,6 +421,26 @@ public:
concat_begin, concat_end);
}
template <typename other_iteratort>
ranget<zip_iteratort<iteratort, other_iteratort>>
zip(ranget<other_iteratort> other)
{
auto zip_begin = zip_iteratort<iteratort, other_iteratort>(
begin(), end(), other.begin(), other.end());
auto zip_end = zip_iteratort<iteratort, other_iteratort>(
end(), end(), other.end(), other.end());
return ranget<zip_iteratort<iteratort, other_iteratort>>(
zip_begin, zip_end);
}
template <typename containert>
auto zip(containert &container)
-> ranget<zip_iteratort<iteratort, decltype(container.begin())>>
{
return zip(
ranget<decltype(container.begin())>{container.begin(), container.end()});
}
bool empty() const
{
return begin_value == end_value;

View File

@ -6,6 +6,7 @@ Author: Romain Brenguier, romain.brenguier@diffblue.com
\*******************************************************************/
#include <list>
#include <vector>
#include <testing-utils/use_catch.h>
@ -188,6 +189,62 @@ SCENARIO("range tests", "[core][util][range]")
REQUIRE(input2 == expected_result2);
}
}
GIVEN("A vectors of int and a list of strings.")
{
std::vector<int> int_vector{1, 2};
std::list<std::string> string_list{"foo", "bar"};
WHEN("We zip the vector and the list")
{
auto range = make_range(int_vector).zip(string_list);
REQUIRE(!range.empty());
THEN("First pair is (1, foo)")
{
const std::pair<int, std::string> first_pair = *range.begin();
REQUIRE(first_pair.first == 1);
REQUIRE(first_pair.second == "foo");
}
range = std::move(range).drop(1);
THEN("Second pair is (2, bar)")
{
const std::pair<int, std::string> second_pair = *range.begin();
REQUIRE(second_pair.first == 2);
REQUIRE(second_pair.second == "bar");
}
range = std::move(range).drop(1);
THEN("Range is empty")
{
REQUIRE(range.empty());
}
}
}
GIVEN("A constant vectors of int and a list of strings.")
{
const std::vector<int> int_vector{41, 27};
const std::list<std::string> string_list{"boo", "far"};
WHEN("We zip the vector and the list")
{
auto range = make_range(int_vector).zip(string_list);
REQUIRE(!range.empty());
THEN("First pair is (1, foo)")
{
const std::pair<int, std::string> first_pair = *range.begin();
REQUIRE(first_pair.first == 41);
REQUIRE(first_pair.second == "boo");
}
range = std::move(range).drop(1);
THEN("Second pair is (2, bar)")
{
const std::pair<int, std::string> second_pair = *range.begin();
REQUIRE(second_pair.first == 27);
REQUIRE(second_pair.second == "far");
}
range = std::move(range).drop(1);
THEN("Range is empty")
{
REQUIRE(range.empty());
}
}
}
}
class move_onlyt