-
Notifications
You must be signed in to change notification settings - Fork 274
Add support for containers of move only typed values to range. #3586
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
f010ebf
181becf
16bc92f
81e4a93
a6832e3
0b73746
bbc2016
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -48,7 +48,7 @@ class map_iteratort | |
PRECONDITION(underlying != underlying_end); | ||
++underlying; | ||
if(underlying != underlying_end) | ||
current = util_make_unique<outputt>((*f)(*underlying)); | ||
current = std::make_shared<outputt>((*f)(*underlying)); | ||
return *this; | ||
} | ||
|
||
|
@@ -60,6 +60,16 @@ class map_iteratort | |
return tmp; | ||
} | ||
|
||
value_type &operator*() | ||
{ | ||
return *current.get(); | ||
} | ||
|
||
value_type *operator->() | ||
{ | ||
return &(*current.get()); | ||
} | ||
|
||
const value_type &operator*() const | ||
{ | ||
return *current.get(); | ||
|
@@ -80,16 +90,7 @@ class map_iteratort | |
f(std::move(f)) | ||
{ | ||
if(this->underlying != this->underlying_end) | ||
current = util_make_unique<outputt>((*this->f)(*this->underlying)); | ||
} | ||
|
||
map_iteratort(const map_iteratort &other) | ||
: underlying(other.underlying), | ||
underlying_end(other.underlying_end), | ||
f(other.f) | ||
{ | ||
if(other.current != nullptr) | ||
current = util_make_unique<outputt>(*other.current.get()); | ||
current = std::make_shared<outputt>((*this->f)(*this->underlying)); | ||
} | ||
|
||
private: | ||
|
@@ -101,7 +102,7 @@ class map_iteratort | |
|
||
/// Stores the result of \c f at the current position of the iterator. | ||
/// Equals nullptr if the iterator reached \c underlying_end. | ||
std::unique_ptr<outputt> current = nullptr; | ||
std::shared_ptr<outputt> current = nullptr; | ||
}; | ||
|
||
/// Iterator which only stops at elements for which some given function \c f is | ||
|
@@ -142,6 +143,16 @@ class filter_iteratort | |
return tmp; | ||
} | ||
|
||
value_type &operator*() | ||
{ | ||
return *underlying; | ||
} | ||
|
||
value_type *operator->() | ||
{ | ||
return &(*underlying); | ||
} | ||
|
||
const value_type &operator*() const | ||
{ | ||
return *underlying; | ||
|
@@ -234,6 +245,20 @@ struct concat_iteratort | |
return tmp; | ||
} | ||
|
||
value_type &operator*() | ||
thk123 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
{ | ||
if(first_begin == first_end) | ||
return *second_begin; | ||
return *first_begin; | ||
} | ||
|
||
value_type *operator->() | ||
{ | ||
if(first_begin == first_end) | ||
return &(*second_begin); | ||
return &(*first_begin); | ||
} | ||
|
||
const value_type &operator*() const | ||
{ | ||
if(first_begin == first_end) | ||
|
@@ -302,7 +327,11 @@ struct ranget final | |
} | ||
|
||
/// The type of elements contained in the resulting range is deduced from the | ||
/// return type of \p `f`. | ||
/// return type of `f`. | ||
/// Please note that the parameter to `f` must be a const reference. This is | ||
/// a limitation of the current implementation. This means that you can't move | ||
/// a value through `f`. `f` may take a move-only typed parameter by const | ||
/// reference. 'f' may also construct and return a move-only typed value. | ||
template <typename functiont> | ||
auto map(functiont &&f) -> ranget<map_iteratort< | ||
iteratort, | ||
|
@@ -357,12 +386,11 @@ ranget<iteratort> make_range(iteratort begin, iteratort end) | |
return ranget<iteratort>(begin, end); | ||
} | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Comment on the commit message: s/in oder/in order/ |
||
template < | ||
typename containert, | ||
typename iteratort = typename containert::const_iterator> | ||
ranget<iteratort> make_range(const containert &container) | ||
template <typename containert> | ||
auto make_range(containert &container) -> ranget<decltype(container.begin())> | ||
{ | ||
return ranget<iteratort>(container.begin(), container.end()); | ||
return ranget<decltype(container.begin())>( | ||
container.begin(), container.end()); | ||
} | ||
|
||
#endif // CPROVER_UTIL_RANGE_H |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -65,3 +65,121 @@ SCENARIO("range tests", "[core][util][range]") | |
} | ||
} | ||
} | ||
|
||
class move_onlyt | ||
{ | ||
public: | ||
move_onlyt(move_onlyt &&) = default; | ||
move_onlyt &operator=(move_onlyt &&) = default; | ||
move_onlyt(const move_onlyt &) = delete; | ||
move_onlyt &operator=(const move_onlyt &) = delete; | ||
|
||
explicit move_onlyt(int value) : value{value} {}; | ||
thk123 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
int value = 0; | ||
}; | ||
|
||
bool is_odd(const move_onlyt &move_only) | ||
{ | ||
return move_only.value % 2 != 0; | ||
} | ||
|
||
const auto add = [](int left) { | ||
return [=](const move_onlyt &right) { return left + right.value; }; | ||
}; | ||
|
||
SCENARIO( | ||
"Range tests, with collections of move only typed values.", | ||
"[core][util][range]") | ||
{ | ||
GIVEN("A vector of move only typed values.") | ||
{ | ||
std::vector<move_onlyt> input; | ||
for(int i = 1; i <= 10; ++i) | ||
input.emplace_back(i); | ||
THEN("Values from a range of made from the vector can be moved.") | ||
{ | ||
auto input_range = make_range(input); | ||
move_onlyt destination{std::move(*input_range.begin())}; | ||
REQUIRE(destination.value == 1); | ||
} | ||
THEN("A range of made from the vector can be filtered.") | ||
{ | ||
auto odds_filter = make_range(input).filter(is_odd); | ||
std::size_t total = 0; | ||
for(const auto &move_only : odds_filter) | ||
total += 1; | ||
REQUIRE(total == 5); | ||
auto iterator = odds_filter.begin(); | ||
REQUIRE((iterator++)->value == 1); | ||
REQUIRE((iterator++)->value == 3); | ||
REQUIRE((iterator++)->value == 5); | ||
REQUIRE((iterator++)->value == 7); | ||
REQUIRE((iterator++)->value == 9); | ||
} | ||
THEN("Values from a filtered range made from the vector can be moved.") | ||
{ | ||
std::vector<move_onlyt> odds; | ||
for(move_onlyt &odd : make_range(input).filter(is_odd)) | ||
odds.emplace_back(std::move(odd)); | ||
|
||
REQUIRE(odds.size() == 5); | ||
REQUIRE(odds[0].value == 1); | ||
REQUIRE(odds[1].value == 3); | ||
REQUIRE(odds[2].value == 5); | ||
REQUIRE(odds[3].value == 7); | ||
REQUIRE(odds[4].value == 9); | ||
} | ||
THEN("Map can be applied to a range of move only typed values.") | ||
{ | ||
std::vector<int> results; | ||
for(int result : make_range(input).map(add(1))) | ||
results.push_back(result); | ||
|
||
const std::vector<int> expected_results{2, 3, 4, 5, 6, 7, 8, 9, 10, 11}; | ||
REQUIRE(results == expected_results); | ||
} | ||
} | ||
GIVEN("Two vectors containing move only types values.") | ||
{ | ||
std::vector<move_onlyt> input1; | ||
for(int i = 1; i <= 3; ++i) | ||
input1.emplace_back(i); | ||
std::vector<move_onlyt> input2; | ||
for(int i = 7; i <= 9; ++i) | ||
input2.emplace_back(i); | ||
|
||
THEN("Values from concatenated ranges made from the vector can be moved.") | ||
{ | ||
std::vector<move_onlyt> both_inputs; | ||
for(move_onlyt &input : make_range(input1).concat(make_range(input2))) | ||
both_inputs.emplace_back(std::move(input)); | ||
|
||
REQUIRE(both_inputs.size() == 6); | ||
REQUIRE(both_inputs[0].value == 1); | ||
REQUIRE(both_inputs[1].value == 2); | ||
REQUIRE(both_inputs[2].value == 3); | ||
REQUIRE(both_inputs[3].value == 7); | ||
REQUIRE(both_inputs[4].value == 8); | ||
REQUIRE(both_inputs[5].value == 9); | ||
} | ||
} | ||
GIVEN("A const vector of ints.") | ||
{ | ||
const std::vector<int> input{1, 2, 3, 4, 5}; | ||
|
||
THEN("The vector can be mapped into a range of move-only types") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If it works - you should add a test that maps from a move only type to a regular type, and one that moves the same type through the map There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The test which "maps from a move only type to a regular type" already exists. As we discussed, you missed it when reviewing. The |
||
{ | ||
std::vector<move_onlyt> results; | ||
const auto make_move_only = [](int i) { return move_onlyt{i}; }; | ||
for(auto &incremented : make_range(input).map(make_move_only)) | ||
results.emplace_back(std::move(incremented)); | ||
|
||
REQUIRE(results.size() == 5); | ||
REQUIRE(results[0].value == 1); | ||
REQUIRE(results[1].value == 2); | ||
REQUIRE(results[2].value == 3); | ||
REQUIRE(results[3].value == 4); | ||
REQUIRE(results[4].value == 5); | ||
} | ||
} | ||
} |
Uh oh!
There was an error while loading. Please reload this page.