Merge pull request #4791 from romainbrenguier/feature/range-zip
Add ranget::zip method
This commit is contained in:
commit
1ea4a764ca
|
@ -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);
|
||||
}
|
||||
|
|
104
src/util/range.h
104
src/util/range.h
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue