From 7e8f7611d18017ea2415baa8245838fd8ffc0429 Mon Sep 17 00:00:00 2001 From: Barry Revzin Date: Wed, 19 Jun 2019 08:11:23 -0500 Subject: [PATCH 1/5] Adding view::remove_when. --- include/range/v3/view/remove_when.hpp | 183 ++++++++++++++++++++++++++ include/range/v3/view/split_when.hpp | 19 +-- include/range/v3/view/when_common.hpp | 44 +++++++ test/view/CMakeLists.txt | 1 + test/view/remove_when.cpp | 40 ++++++ 5 files changed, 271 insertions(+), 16 deletions(-) create mode 100644 include/range/v3/view/remove_when.hpp create mode 100644 include/range/v3/view/when_common.hpp create mode 100644 test/view/remove_when.cpp diff --git a/include/range/v3/view/remove_when.hpp b/include/range/v3/view/remove_when.hpp new file mode 100644 index 0000000000..5f18374fba --- /dev/null +++ b/include/range/v3/view/remove_when.hpp @@ -0,0 +1,183 @@ +/// \file +// Range v3 library +// +// Copyright Eric Niebler 2013-present +// +// Use, modification and distribution is subject to the +// Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// Project home: https://github.com/ericniebler/range-v3 +// + +#ifndef RANGES_V3_VIEW_REMOVE_WHEN_HPP +#define RANGES_V3_VIEW_REMOVE_WHEN_HPP + +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +RANGES_DISABLE_WARNINGS + +namespace ranges +{ + /// \addtogroup group-views + /// @{ + template + struct RANGES_EMPTY_BASES remove_when_view + : view_adaptor, Rng, + is_finite::value ? finite : range_cardinality::value> + , private box> + { + remove_when_view() = default; + constexpr remove_when_view(Rng rng, Pred pred) + : remove_when_view::view_adaptor{detail::move(rng)} + , remove_when_view::box(detail::move(pred)) + {} + + private: + friend range_access; + bool zero_; + + struct adaptor : adaptor_base + { + adaptor() = default; + constexpr adaptor(remove_when_view & rng) noexcept + : rng_(&rng) + {} + static constexpr iterator_t begin(remove_when_view & rng) + { + return *rng.begin_; + } + constexpr void next(iterator_t & it) const + { + RANGES_ASSERT(it != ranges::end(rng_->base())); + rng_->satisfy_forward(++it); + } + void advance() = delete; + void distance_to() = delete; + + private: + remove_when_view * rng_; + }; + constexpr adaptor begin_adaptor() + { + cache_begin(); + return {*this}; + } + constexpr adaptor end_adaptor() + { + return {*this}; + } + + constexpr void satisfy_forward(iterator_t & it) + { + if(zero_) + { + // if the last match consumed zero elements, we already bumped the + // position so can stop here. + zero_ = false; + return; + } + + auto const last = ranges::end(this->base()); + auto & pred = this->remove_when_view::box::get(); + if(it != last) + { + auto p = invoke(pred, it, last); + if(p.first) + { + zero_ = (it == p.second); + it = p.second; + } + } + } + + constexpr void cache_begin() + { + if(begin_) + return; + auto it = ranges::begin(this->base()); + zero_ = false; + satisfy_forward(it); + begin_.emplace(std::move(it)); + } + + detail::non_propagating_cache> begin_; + }; + +#if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17 + CPP_template(typename Rng, typename Pred)(requires CopyConstructible) + remove_when_view(Rng &&, Pred) + ->remove_when_view, Pred>; +#endif + + namespace view + { + /// Given a source range, unary predicate, and optional projection, + /// present a view of the elements that do not satisfy the predicate. + struct remove_when_fn + { + private: + friend view_access; + template + static auto bind(remove_when_fn remove_when, Pred && pred) + { + return make_pipeable(std::bind( + remove_when, std::placeholders::_1, static_cast(pred))); + } + + public: + template + constexpr auto operator()(Rng && rng, Pred pred) const + -> CPP_ret(remove_when_view, detail::predicate_pred>)( // + requires ViewableRange && InputRange && Predicate< + Pred const &, range_reference_t> && CopyConstructible) + { + return {all(static_cast(rng)), + detail::predicate_pred{std::move(pred)}}; + } + template + auto operator()(Rng && rng, Fun fun) const -> CPP_ret( + remove_when_view, Fun>)( // + requires ViewableRange && ForwardRange && + Invocable, sentinel_t> && + Invocable, iterator_t> && + CopyConstructible && ConvertibleTo< + invoke_result_t, sentinel_t>, + std::pair>>) + { + return {all(static_cast(rng)), std::move(fun)}; + } + }; + + /// \relates remove_when_fn + /// \ingroup group-views + RANGES_INLINE_VARIABLE(view, remove_when) + } // namespace view + /// @} +} // namespace ranges + +RANGES_RE_ENABLE_WARNINGS + +#include +RANGES_SATISFY_BOOST_RANGE(::ranges::remove_when_view) + +#endif diff --git a/include/range/v3/view/split_when.hpp b/include/range/v3/view/split_when.hpp index 7a66987979..8aa754839c 100644 --- a/include/range/v3/view/split_when.hpp +++ b/include/range/v3/view/split_when.hpp @@ -21,7 +21,6 @@ #include -#include #include #include #include @@ -35,6 +34,7 @@ #include #include #include +#include namespace ranges { @@ -168,19 +168,6 @@ namespace ranges return make_pipeable( std::bind(split_when, std::placeholders::_1, bind_forward(t))); } - template - struct predicate_pred - { - semiregular_t pred_; - - template - auto operator()(I cur, S end) const -> CPP_ret(std::pair)( // - requires Sentinel) - { - auto where = ranges::find_if_not(cur, end, std::ref(pred_)); - return {cur != where, where}; - } - }; public: template @@ -197,12 +184,12 @@ namespace ranges } template auto operator()(Rng && rng, Fun fun) const - -> CPP_ret(split_when_view, predicate_pred>)( // + -> CPP_ret(split_when_view, detail::predicate_pred>)( // requires ViewableRange && ForwardRange && Predicate< Fun const &, range_reference_t> && CopyConstructible) { return {all(static_cast(rng)), - predicate_pred{std::move(fun)}}; + detail::predicate_pred{std::move(fun)}}; } }; diff --git a/include/range/v3/view/when_common.hpp b/include/range/v3/view/when_common.hpp new file mode 100644 index 0000000000..c3ec449e5c --- /dev/null +++ b/include/range/v3/view/when_common.hpp @@ -0,0 +1,44 @@ +/// \file +// Range v3 library +// +// Copyright Eric Niebler 2013-present +// +// Use, modification and distribution is subject to the +// Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// Project home: https://github.com/ericniebler/range-v3 +// + +#ifndef RANGES_V3_VIEW_WHEN_COMMON_HPP +#define RANGES_V3_VIEW_WHEN_COMMON_HPP + +#include +#include +#include + +namespace ranges +{ + namespace view + { + namespace detail + { + template + struct predicate_pred + { + semiregular_t pred_; + + template + auto operator()(I cur, S end) const -> CPP_ret(std::pair)( // + requires Sentinel) + { + auto where = ranges::find_if_not(cur, end, std::ref(pred_)); + return {cur != where, where}; + } + }; + } // namespace detail + } // namespace view +} // namespace ranges + +#endif \ No newline at end of file diff --git a/test/view/CMakeLists.txt b/test/view/CMakeLists.txt index 2cb7b7d8c0..f0b82760c7 100644 --- a/test/view/CMakeLists.txt +++ b/test/view/CMakeLists.txt @@ -39,6 +39,7 @@ rv3_add_test(test.view.partial_sum view.partial_sum partial_sum.cpp) rv3_add_test(test.view.repeat view.repeat repeat.cpp) rv3_add_test(test.view.remove view.remove remove.cpp) rv3_add_test(test.view.remove_if view.remove_if remove_if.cpp) +rv3_add_test(test.view.remove_when view.remove_when remove_when.cpp) rv3_add_test(test.view.replace view.replace replace.cpp) rv3_add_test(test.view.replace_if view.replace_if replace_if.cpp) rv3_add_test(test.view.reverse view.reverse reverse.cpp) diff --git a/test/view/remove_when.cpp b/test/view/remove_when.cpp new file mode 100644 index 0000000000..60923135cd --- /dev/null +++ b/test/view/remove_when.cpp @@ -0,0 +1,40 @@ +// Range v3 library +// +// Copyright Eric Niebler 2014-present +// +// Use, modification and distribution is subject to the +// Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// Project home: https://github.com/ericniebler/range-v3 + +#include +#include + +#include +#include + +#include "../simple_test.hpp" +#include "../test_utils.hpp" + +int main() +{ + using namespace ranges; + + // a simple predicate behaves just like a worse remove_if + std::string str = "The quick brown fox"; + auto rng0 = view::remove_when(str, [](char c) { return c == ' '; }); + ::check_equal(rng0, std::string("Thequickbrownfox")); + + // a silly predicate that actually doesn't remove anything + std::list lst = {1, 2, 3, 4, 5}; + auto rng1 = + view::remove_when(lst, [](auto i, auto) { return std::make_pair(true, i); }); + ::check_equal(rng1, {1, 2, 3, 4, 5}); + + // remove 3s and what's after 3 + auto rng2 = view::remove_when( + lst, [](auto i, auto) { return std::make_pair(*i == 3, next(i, 2)); }); + ::check_equal(rng2, {1, 2, 5}); +} \ No newline at end of file From b0dc5ba76ac79ea6e2261ea123b4ead4703cb548 Mon Sep 17 00:00:00 2001 From: Barry Revzin Date: Wed, 19 Jun 2019 08:21:24 -0500 Subject: [PATCH 2/5] Adding missing newline. --- include/range/v3/view/when_common.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/range/v3/view/when_common.hpp b/include/range/v3/view/when_common.hpp index c3ec449e5c..4511345e14 100644 --- a/include/range/v3/view/when_common.hpp +++ b/include/range/v3/view/when_common.hpp @@ -41,4 +41,5 @@ namespace ranges } // namespace view } // namespace ranges -#endif \ No newline at end of file +#endif + From dfb84e7655ad1a566640395fd8359cb913a3852a Mon Sep 17 00:00:00 2001 From: Barry Revzin Date: Wed, 19 Jun 2019 09:58:39 -0500 Subject: [PATCH 3/5] Fixing detail namespace --- include/range/v3/view/when_common.hpp | 29 ++++++++++++--------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/include/range/v3/view/when_common.hpp b/include/range/v3/view/when_common.hpp index 4511345e14..4eb2e925e2 100644 --- a/include/range/v3/view/when_common.hpp +++ b/include/range/v3/view/when_common.hpp @@ -20,25 +20,22 @@ namespace ranges { - namespace view + namespace detail { - namespace detail + template + struct predicate_pred { - template - struct predicate_pred - { - semiregular_t pred_; + semiregular_t pred_; - template - auto operator()(I cur, S end) const -> CPP_ret(std::pair)( // - requires Sentinel) - { - auto where = ranges::find_if_not(cur, end, std::ref(pred_)); - return {cur != where, where}; - } - }; - } // namespace detail - } // namespace view + template + auto operator()(I cur, S end) const -> CPP_ret(std::pair)( // + requires Sentinel) + { + auto where = ranges::find_if_not(cur, end, std::ref(pred_)); + return {cur != where, where}; + } + }; + } // namespace detail } // namespace ranges #endif From a90291ad06d78faf5469f97debf6dfab65e48b79 Mon Sep 17 00:00:00 2001 From: Barry Revzin Date: Wed, 19 Jun 2019 11:34:21 -0500 Subject: [PATCH 4/5] Adding missing newline here too. --- test/view/remove_when.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/view/remove_when.cpp b/test/view/remove_when.cpp index 60923135cd..6646f80827 100644 --- a/test/view/remove_when.cpp +++ b/test/view/remove_when.cpp @@ -37,4 +37,4 @@ int main() auto rng2 = view::remove_when( lst, [](auto i, auto) { return std::make_pair(*i == 3, next(i, 2)); }); ::check_equal(rng2, {1, 2, 5}); -} \ No newline at end of file +} From eff8c8c415d7e8d11461e28969c0f3982686896d Mon Sep 17 00:00:00 2001 From: Barry Revzin Date: Wed, 19 Jun 2019 20:19:33 -0500 Subject: [PATCH 5/5] PR review comments. --- doc/index.md | 2 + .../delimiter_specifier.hpp} | 8 ++-- include/range/v3/view/remove_when.hpp | 42 +++++++++---------- include/range/v3/view/split_when.hpp | 6 +-- test/view/remove_when.cpp | 2 +- 5 files changed, 30 insertions(+), 30 deletions(-) rename include/range/v3/{view/when_common.hpp => detail/delimiter_specifier.hpp} (84%) diff --git a/doc/index.md b/doc/index.md index b247b3dad9..5f56d9bc33 100644 --- a/doc/index.md +++ b/doc/index.md @@ -733,6 +733,8 @@ provides, and a blurb about how each is intended to be used.
Given a source range and a value, filter out those elements that do not equal value.
\link ranges::view::remove_if_fn `view::remove_if`\endlink
Given a source range and a unary predicate, filter out those elements that do not satisfy the predicate. (For users of Boost.Range, this is like the `filter` adaptor with the predicate negated.)
+
\link ranges::view::remove_when_fn `view::remove_when`\endlink
+
Given a source range and a delimiter specifier, filter out those elements specified by the delimiter specifier. The delimiter specifier can be a predicate or a function. The predicate should take a single argument of the range's reference type and return `true` if and only if the element is part of a delimiter. The function should accept an iterator and sentinel indicating the current position and end of the source range and return `std::make_pair(true, iterator_past_the_delimiter)` if the current position is a boundary; otherwise `std::make_pair(false, ignored_iterator_value)`.
\link ranges::view::repeat_fn `view::repeat`\endlink
Given a value, create a range that is that value repeated infinitely.
\link ranges::view::repeat_n_fn `view::repeat_n`\endlink
diff --git a/include/range/v3/view/when_common.hpp b/include/range/v3/detail/delimiter_specifier.hpp similarity index 84% rename from include/range/v3/view/when_common.hpp rename to include/range/v3/detail/delimiter_specifier.hpp index 4eb2e925e2..7ef0c0ad81 100644 --- a/include/range/v3/view/when_common.hpp +++ b/include/range/v3/detail/delimiter_specifier.hpp @@ -1,7 +1,7 @@ /// \file // Range v3 library // -// Copyright Eric Niebler 2013-present +// Copyright Barry Revzin 2019-present // // Use, modification and distribution is subject to the // Boost Software License, Version 1.0. (See accompanying @@ -11,8 +11,8 @@ // Project home: https://github.com/ericniebler/range-v3 // -#ifndef RANGES_V3_VIEW_WHEN_COMMON_HPP -#define RANGES_V3_VIEW_WHEN_COMMON_HPP +#ifndef RANGES_V3_DETAIL_DELIMITER_SPECIFIER_HPP +#define RANGES_V3_DETAIL_DELIMITER_SPECIFIER_HPP #include #include @@ -23,7 +23,7 @@ namespace ranges namespace detail { template - struct predicate_pred + struct delimiter_specifier { semiregular_t pred_; diff --git a/include/range/v3/view/remove_when.hpp b/include/range/v3/view/remove_when.hpp index 5f18374fba..26c8d5c481 100644 --- a/include/range/v3/view/remove_when.hpp +++ b/include/range/v3/view/remove_when.hpp @@ -1,7 +1,7 @@ /// \file // Range v3 library // -// Copyright Eric Niebler 2013-present +// Copyright Barry Revzin 2019-present // // Use, modification and distribution is subject to the // Boost Software License, Version 1.0. (See accompanying @@ -32,7 +32,7 @@ #include #include #include -#include +#include RANGES_DISABLE_WARNINGS @@ -40,16 +40,16 @@ namespace ranges { /// \addtogroup group-views /// @{ - template + template struct RANGES_EMPTY_BASES remove_when_view - : view_adaptor, Rng, + : view_adaptor, Rng, is_finite::value ? finite : range_cardinality::value> - , private box> + , private box> { remove_when_view() = default; - constexpr remove_when_view(Rng rng, Pred pred) + constexpr remove_when_view(Rng rng, Fun fun) : remove_when_view::view_adaptor{detail::move(rng)} - , remove_when_view::box(detail::move(pred)) + , remove_when_view::box(detail::move(fun)) {} private: @@ -98,10 +98,10 @@ namespace ranges } auto const last = ranges::end(this->base()); - auto & pred = this->remove_when_view::box::get(); + auto & fun = this->remove_when_view::box::get(); if(it != last) { - auto p = invoke(pred, it, last); + auto p = invoke(fun, it, last); if(p.first) { zero_ = (it == p.second); @@ -124,35 +124,33 @@ namespace ranges }; #if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17 - CPP_template(typename Rng, typename Pred)(requires CopyConstructible) - remove_when_view(Rng &&, Pred) - ->remove_when_view, Pred>; + CPP_template(typename Rng, typename Fun)(requires CopyConstructible) + remove_when_view(Rng &&, Fun) + ->remove_when_view, Fun>; #endif namespace view { - /// Given a source range, unary predicate, and optional projection, - /// present a view of the elements that do not satisfy the predicate. struct remove_when_fn { private: friend view_access; - template - static auto bind(remove_when_fn remove_when, Pred && pred) + template + static auto bind(remove_when_fn remove_when, Fun && fun) { return make_pipeable(std::bind( - remove_when, std::placeholders::_1, static_cast(pred))); + remove_when, std::placeholders::_1, static_cast(fun))); } public: - template - constexpr auto operator()(Rng && rng, Pred pred) const - -> CPP_ret(remove_when_view, detail::predicate_pred>)( // + template + constexpr auto operator()(Rng && rng, Fun fun) const + -> CPP_ret(remove_when_view, detail::delimiter_specifier>)( // requires ViewableRange && InputRange && Predicate< - Pred const &, range_reference_t> && CopyConstructible) + Fun const &, range_reference_t> && CopyConstructible) { return {all(static_cast(rng)), - detail::predicate_pred{std::move(pred)}}; + detail::delimiter_specifier{std::move(fun)}}; } template auto operator()(Rng && rng, Fun fun) const -> CPP_ret( diff --git a/include/range/v3/view/split_when.hpp b/include/range/v3/view/split_when.hpp index 8aa754839c..d9090faadc 100644 --- a/include/range/v3/view/split_when.hpp +++ b/include/range/v3/view/split_when.hpp @@ -34,7 +34,7 @@ #include #include #include -#include +#include namespace ranges { @@ -184,12 +184,12 @@ namespace ranges } template auto operator()(Rng && rng, Fun fun) const - -> CPP_ret(split_when_view, detail::predicate_pred>)( // + -> CPP_ret(split_when_view, detail::delimiter_specifier>)( // requires ViewableRange && ForwardRange && Predicate< Fun const &, range_reference_t> && CopyConstructible) { return {all(static_cast(rng)), - detail::predicate_pred{std::move(fun)}}; + detail::delimiter_specifier{std::move(fun)}}; } }; diff --git a/test/view/remove_when.cpp b/test/view/remove_when.cpp index 6646f80827..5812ae7a5f 100644 --- a/test/view/remove_when.cpp +++ b/test/view/remove_when.cpp @@ -1,6 +1,6 @@ // Range v3 library // -// Copyright Eric Niebler 2014-present +// Copyright Barry Revzin 2019-present // // Use, modification and distribution is subject to the // Boost Software License, Version 1.0. (See accompanying