From 2fc1a3fe8f7e3d1919353f2c988d8aef2f90fda2 Mon Sep 17 00:00:00 2001 From: Adam Wulkiewicz Date: Fri, 4 Jun 2021 00:02:59 +0200 Subject: [PATCH] Add support for ranges passed by rvalue in range utilities. This allows to pass temporary ranges and proxies without the need to explicitly create variables. --- .../detail/disjoint/linear_segment_or_box.hpp | 10 +- include/boost/geometry/io/wkt/read.hpp | 6 +- include/boost/geometry/util/range.hpp | 221 +++++++------- test/util/range.cpp | 270 ++++++++++++------ 4 files changed, 287 insertions(+), 220 deletions(-) diff --git a/include/boost/geometry/algorithms/detail/disjoint/linear_segment_or_box.hpp b/include/boost/geometry/algorithms/detail/disjoint/linear_segment_or_box.hpp index 1999f10f3..110798034 100644 --- a/include/boost/geometry/algorithms/detail/disjoint/linear_segment_or_box.hpp +++ b/include/boost/geometry/algorithms/detail/disjoint/linear_segment_or_box.hpp @@ -5,8 +5,8 @@ // Copyright (c) 2009-2014 Mateusz Loskot, London, UK. // Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland. -// This file was modified by Oracle on 2013-2020. -// Modifications copyright (c) 2013-2020, Oracle and/or its affiliates. +// This file was modified by Oracle on 2013-2021. +// Modifications copyright (c) 2013-2021, Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle @@ -104,7 +104,7 @@ struct disjoint_range_segment_or_box point_type const > range_segment; - view_type view(range); + view_type const view(range); const size_type count = ::boost::size(view); @@ -117,9 +117,7 @@ struct disjoint_range_segment_or_box return disjoint_point_segment_or_box < SegmentOrBox - >::apply(geometry::range::front(view), - segment_or_box, - strategy); + >::apply(range::front(view), segment_or_box, strategy); } else { diff --git a/include/boost/geometry/io/wkt/read.hpp b/include/boost/geometry/io/wkt/read.hpp index ad620efc8..ccfb4352c 100644 --- a/include/boost/geometry/io/wkt/read.hpp +++ b/include/boost/geometry/io/wkt/read.hpp @@ -442,11 +442,7 @@ struct polygon_parser { typename ring_type::type ring; appender::apply(it, end, wkt, ring); - // This may be a proxy range and push_back needs lvalue - // TODO: Support rvalue ranges in util/range.hpp - typename traits::interior_mutable_type::type - rings = geometry::interior_rings(poly); - range::push_back(rings, std::move(ring)); + range::push_back(geometry::interior_rings(poly), std::move(ring)); } if (it != end && *it == ",") diff --git a/include/boost/geometry/util/range.hpp b/include/boost/geometry/util/range.hpp index 89d5c7720..445636dd0 100644 --- a/include/boost/geometry/util/range.hpp +++ b/include/boost/geometry/util/range.hpp @@ -1,15 +1,13 @@ -// Boost.Geometry (aka GGL, Generic Geometry Library) +// Boost.Geometry // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // This file was modified by Oracle on 2013-2021. // Modifications copyright (c) 2013-2021 Oracle and/or its affiliates. - // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle -// 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) +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html #ifndef BOOST_GEOMETRY_UTIL_RANGE_HPP #define BOOST_GEOMETRY_UTIL_RANGE_HPP @@ -29,7 +27,6 @@ #include #include #include -#include #include #include #include @@ -75,37 +72,16 @@ struct is_range : is_range_impl {}; +template +using enable_if_mutable_t = std::enable_if_t + < + (! std::is_const>::value), + T + >; -// NOTE: For SinglePassRanges pos could iterate over all elements until the i-th element was met. - -template -struct pos -{ - typedef typename boost::range_iterator::type iterator; - typedef typename boost::range_size::type size_type; - typedef typename boost::range_difference::type difference_type; - - static inline iterator apply(RandomAccessRange & rng, size_type i) - { - BOOST_RANGE_CONCEPT_ASSERT(( boost::RandomAccessRangeConcept )); - return boost::begin(rng) + static_cast(i); - } -}; } // namespace detail -/*! -\brief Short utility to conveniently return an iterator of a RandomAccessRange. -\ingroup utility -*/ -template -inline typename boost::range_iterator::type -pos(RandomAccessRange const& rng, - typename boost::range_size::type i) -{ - BOOST_GEOMETRY_ASSERT(i <= boost::size(rng)); - return detail::pos::apply(rng, i); -} /*! \brief Short utility to conveniently return an iterator of a RandomAccessRange. @@ -113,24 +89,13 @@ pos(RandomAccessRange const& rng, */ template inline typename boost::range_iterator::type -pos(RandomAccessRange & rng, +pos(RandomAccessRange && rng, typename boost::range_size::type i) { + BOOST_RANGE_CONCEPT_ASSERT((boost::RandomAccessRangeConcept)); BOOST_GEOMETRY_ASSERT(i <= boost::size(rng)); - return detail::pos::apply(rng, i); -} - -/*! -\brief Short utility to conveniently return an element of a RandomAccessRange. -\ingroup utility -*/ -template -inline typename boost::range_reference::type -at(RandomAccessRange const& rng, - typename boost::range_size::type i) -{ - BOOST_GEOMETRY_ASSERT(i < boost::size(rng)); - return * detail::pos::apply(rng, i); + return boost::begin(rng) + + static_cast::type>(i); } /*! @@ -139,23 +104,10 @@ at(RandomAccessRange const& rng, */ template inline typename boost::range_reference::type -at(RandomAccessRange & rng, +at(RandomAccessRange && rng, typename boost::range_size::type i) { - BOOST_GEOMETRY_ASSERT(i < boost::size(rng)); - return * detail::pos::apply(rng, i); -} - -/*! -\brief Short utility to conveniently return the front element of a Range. -\ingroup utility -*/ -template -inline typename boost::range_reference::type -front(Range const& rng) -{ - BOOST_GEOMETRY_ASSERT(!boost::empty(rng)); - return *boost::begin(rng); + return *pos(rng, i); } /*! @@ -164,38 +116,24 @@ front(Range const& rng) */ template inline typename boost::range_reference::type -front(Range & rng) +front(Range && rng) { BOOST_GEOMETRY_ASSERT(!boost::empty(rng)); return *boost::begin(rng); } -// NOTE: For SinglePassRanges back() could iterate over all elements until the last element is met. - -/*! -\brief Short utility to conveniently return the back element of a BidirectionalRange. -\ingroup utility -*/ -template -inline typename boost::range_reference::type -back(BidirectionalRange const& rng) -{ - BOOST_RANGE_CONCEPT_ASSERT(( boost::BidirectionalRangeConcept )); - BOOST_GEOMETRY_ASSERT(!boost::empty(rng)); - return *(boost::rbegin(rng)); -} - /*! \brief Short utility to conveniently return the back element of a BidirectionalRange. \ingroup utility */ template inline typename boost::range_reference::type -back(BidirectionalRange & rng) +back(BidirectionalRange && rng) { BOOST_RANGE_CONCEPT_ASSERT((boost::BidirectionalRangeConcept)); BOOST_GEOMETRY_ASSERT(!boost::empty(rng)); - return *(boost::rbegin(rng)); + auto it = boost::end(rng); + return *(--it); } @@ -204,11 +142,17 @@ back(BidirectionalRange & rng) It uses traits::clear<>. \ingroup utility */ -template -inline void clear(Range & rng) +template +< + typename Range, + detail::enable_if_mutable_t = 0 +> +inline void clear(Range && rng) { - // NOTE: this trait is probably not needed since it could be implemented using resize() - geometry::traits::clear::apply(rng); + geometry::traits::clear + < + std::remove_reference_t + >::apply(rng); } /*! @@ -216,11 +160,18 @@ inline void clear(Range & rng) It uses boost::geometry::traits::push_back<>. \ingroup utility */ -template -inline void push_back(Range & rng, +template +< + typename Range, + detail::enable_if_mutable_t = 0 +> +inline void push_back(Range && rng, typename boost::range_value::type const& value) { - geometry::traits::push_back::apply(rng, value); + geometry::traits::push_back + < + std::remove_reference_t + >::apply(rng, value); } /*! @@ -228,11 +179,18 @@ inline void push_back(Range & rng, It uses boost::geometry::traits::push_back<>. \ingroup utility */ -template -inline void push_back(Range & rng, +template +< + typename Range, + detail::enable_if_mutable_t = 0 +> +inline void push_back(Range && rng, typename boost::range_value::type && value) { - geometry::traits::push_back::apply(rng, std::move(value)); + geometry::traits::push_back + < + std::remove_reference_t + >::apply(rng, std::move(value)); } /*! @@ -240,10 +198,18 @@ inline void push_back(Range & rng, It uses boost::geometry::traits::emplace_back<>. \ingroup utility */ -template -inline void emplace_back(Range & rng, Args&&... args) +template +< + typename Range, + typename ...Args, + detail::enable_if_mutable_t = 0 +> +inline void emplace_back(Range && rng, Args &&... args) { - geometry::traits::emplace_back::apply(rng, std::forward(args)...); + geometry::traits::emplace_back + < + std::remove_reference_t + >::apply(rng, std::forward(args)...); } /*! @@ -251,11 +217,18 @@ inline void emplace_back(Range & rng, Args&&... args) It uses boost::geometry::traits::resize<>. \ingroup utility */ -template -inline void resize(Range & rng, +template +< + typename Range, + detail::enable_if_mutable_t = 0 +> +inline void resize(Range && rng, typename boost::range_size::type new_size) { - geometry::traits::resize::apply(rng, new_size); + geometry::traits::resize + < + std::remove_reference_t + >::apply(rng, new_size); } /*! @@ -263,8 +236,12 @@ inline void resize(Range & rng, It uses resize(). \ingroup utility */ -template -inline void pop_back(Range & rng) +template +< + typename Range, + detail::enable_if_mutable_t = 0 +> +inline void pop_back(Range && rng) { BOOST_GEOMETRY_ASSERT(!boost::empty(rng)); range::resize(rng, boost::size(rng) - 1); @@ -272,12 +249,16 @@ inline void pop_back(Range & rng) /*! \brief Short utility to conveniently remove an element from a mutable range. - It uses std::copy() and resize(). Version taking mutable iterators. + It uses std::move() and resize(). Version taking mutable iterators. \ingroup utility */ -template +template +< + typename Range, + detail::enable_if_mutable_t = 0 +> inline typename boost::range_iterator::type -erase(Range & rng, +erase(Range && rng, typename boost::range_iterator::type it) { BOOST_GEOMETRY_ASSERT(!boost::empty(rng)); @@ -304,13 +285,17 @@ erase(Range & rng, /*! \brief Short utility to conveniently remove an element from a mutable range. - It uses std::copy() and resize(). Version taking non-mutable iterators. + It uses std::move() and resize(). Version taking non-mutable iterators. \ingroup utility */ -template +template +< + typename Range, + detail::enable_if_mutable_t = 0 +> inline typename boost::range_iterator::type -erase(Range & rng, - typename boost::range_iterator::type cit) +erase(Range && rng, + typename boost::range_iterator const>::type cit) { BOOST_RANGE_CONCEPT_ASSERT(( boost::RandomAccessRangeConcept )); @@ -323,12 +308,16 @@ erase(Range & rng, /*! \brief Short utility to conveniently remove a range of elements from a mutable range. - It uses std::copy() and resize(). Version taking mutable iterators. + It uses std::move() and resize(). Version taking mutable iterators. \ingroup utility */ -template +template +< + typename Range, + detail::enable_if_mutable_t = 0 +> inline typename boost::range_iterator::type -erase(Range & rng, +erase(Range && rng, typename boost::range_iterator::type first, typename boost::range_iterator::type last) { @@ -361,14 +350,18 @@ erase(Range & rng, /*! \brief Short utility to conveniently remove a range of elements from a mutable range. - It uses std::copy() and resize(). Version taking non-mutable iterators. + It uses std::move() and resize(). Version taking non-mutable iterators. \ingroup utility */ -template +template +< + typename Range, + detail::enable_if_mutable_t = 0 +> inline typename boost::range_iterator::type -erase(Range & rng, - typename boost::range_iterator::type cfirst, - typename boost::range_iterator::type clast) +erase(Range && rng, + typename boost::range_iterator const>::type cfirst, + typename boost::range_iterator const>::type clast) { BOOST_RANGE_CONCEPT_ASSERT(( boost::RandomAccessRangeConcept )); diff --git a/test/util/range.cpp b/test/util/range.cpp index 05a5e2f85..6f0bbba67 100644 --- a/test/util/range.cpp +++ b/test/util/range.cpp @@ -5,10 +5,8 @@ // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle -// 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) - +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html #include @@ -21,57 +19,15 @@ namespace bgt { -template -struct beginner +struct NonCopyable { - template - typename boost::range_iterator::type - operator()(Range & rng) - { - return boost::begin(rng); - } -}; -template <> -struct beginner -{ - template - typename boost::range_iterator::type - operator()(Range & rng) - { - return boost::const_begin(rng); - } -}; - -template -struct ender -{ - template - typename boost::range_iterator::type - operator()(Range & rng) - { - return boost::end(rng); - } -}; -template <> -struct ender -{ - template - typename boost::range_iterator::type - operator()(Range & rng) - { - return boost::const_end(rng); - } -}; - -struct NonMovable -{ - NonMovable(int ii = 0) : i(ii) {} - NonMovable(NonMovable const& ii) : i(ii.i) {} - NonMovable & operator=(NonMovable const& ii) { i = ii.i; return *this; } - bool operator==(NonMovable const& ii) const { return i == ii.i; } + NonCopyable(int ii = 0) : i(ii) {} + NonCopyable(NonCopyable && ii) : i(ii.i) {} + NonCopyable & operator=(NonCopyable && ii) { i = ii.i; return *this; } + bool operator==(NonCopyable const& ii) const { return i == ii.i; } int i; - NonMovable(NonMovable && ii) = delete; - NonMovable & operator=(NonMovable && ii) = delete; + NonCopyable(NonCopyable const& ii) = delete; + NonCopyable & operator=(NonCopyable const& ii) = delete; }; struct CopyableAndMovable @@ -85,45 +41,154 @@ struct CopyableAndMovable CopyableAndMovable & operator=(CopyableAndMovable && ii) { i = std::move(ii.i); return *this; } }; +template +struct proxy +{ + using iterator = typename boost::range_iterator::type; + using const_iterator = typename boost::range_iterator::type; + + explicit proxy(Container & container) : m_ptr(&container) {} + template + void push_back(T&& v) { m_ptr->push_back(std::forward(v)); } + template + void emplace_back(Ts&&... vs) { m_ptr->emplace_back(std::forward(vs)...); } + void clear() { m_ptr->clear(); } + void resize(size_t n) { m_ptr->resize(n); } + + iterator begin() { return m_ptr->begin(); } + const_iterator begin() const { return m_ptr->begin(); } + iterator end() { return m_ptr->end(); } + const_iterator end() const { return m_ptr->end(); } + +private: + Container * m_ptr; +}; + +template +bgt::proxy make_proxy(Container & container) +{ + return bgt::proxy(container); +} + } // namespace bgt namespace bgr = bg::range; -template -void test_all() +template +void fill(std::vector & v, int n) { - bgt::beginner begin; - bgt::ender end; - - std::vector v; - for (int i = 0 ; i < 20 ; ++i) + for (int i = 0; i < n; ++i) { bgr::push_back(v, i); } +} - for (int i = 0 ; i < 20 ; ++i) - { - BOOST_CHECK(bgr::at(v, i) == i); - } +template +void test_push_emplace(std::vector & v) +{ + bgr::push_back(v, 0); + bgr::push_back(bgt::make_proxy(v), 1); + bgr::emplace_back(v, 2); + bgr::emplace_back(bgt::make_proxy(v), 3); + typename std::vector::value_type val = 4; + bgr::push_back(v, std::move(val)); + val = 5; + bgr::push_back(bgt::make_proxy(v), std::move(val)); + val = 6; + bgr::emplace_back(v, std::move(val)); + val = 7; + bgr::emplace_back(bgt::make_proxy(v), std::move(val)); + + for (int i = (int)v.size(); i < 20; ++i) { - std::vector w; - std::copy(v.begin(), v.end(), bgr::back_inserter(w)); - BOOST_CHECK(v.size() == w.size() && std::equal(v.begin(), v.end(), w.begin())); + bgr::push_back(v, i); } +} + +template +void test_at_front_back(std::vector const& v) +{ + BOOST_CHECK(bgr::at(v, 1) == 1); + BOOST_CHECK(bgr::at(bgt::make_proxy(v), 2) == 2); + BOOST_CHECK(bgr::at(std::make_pair(v.begin(), v.end()), 3) == 3); BOOST_CHECK(bgr::front(v) == 0); - BOOST_CHECK(bgr::back(v) == 19); + BOOST_CHECK(bgr::front(bgt::make_proxy(v)) == 0); + BOOST_CHECK(bgr::front(std::make_pair(v.begin(), v.end())) == 0); + BOOST_CHECK(bgr::back(v) == 19); + BOOST_CHECK(bgr::back(bgt::make_proxy(v)) == 19); + BOOST_CHECK(bgr::back(std::make_pair(v.begin(), v.end())) == 19); +} + +template +void test_at_front_back(std::vector & v) +{ + bgr::at(v, 1) = 101; + bgr::at(bgt::make_proxy(v), 2) = 102; + bgr::at(std::make_pair(v.begin(), v.end()), 3) = 103; + + BOOST_CHECK(bgr::at(v, 1) == 101); + BOOST_CHECK(bgr::at(bgt::make_proxy(v), 2) == 102); + BOOST_CHECK(bgr::at(std::make_pair(v.begin(), v.end()), 3) == 103); + + bgr::at(v, 1) = 1; + bgr::at(bgt::make_proxy(v), 2) = 2; + bgr::at(std::make_pair(v.begin(), v.end()), 3) = 3; + + bgr::front(v) = 100; + BOOST_CHECK(bgr::front(v) == 100); + bgr::front(bgt::make_proxy(v)) = 200; + BOOST_CHECK(bgr::front(v) == 200); + bgr::front(std::make_pair(v.begin(), v.end())) = 0; + BOOST_CHECK(bgr::front(v) == 0); + + bgr::back(v) = 119; + BOOST_CHECK(bgr::back(v) == 119); + bgr::back(bgt::make_proxy(v)) = 219; + BOOST_CHECK(bgr::back(v) == 219); + bgr::back(std::make_pair(v.begin(), v.end())) = 19; + BOOST_CHECK(bgr::back(v) == 19); +} + +template +void test_clear(std::vector & v) +{ + std::vector w; + std::copy(v.begin(), v.end(), bgr::back_inserter(w)); + BOOST_CHECK(w.size() == 20 && std::equal(v.begin(), v.end(), w.begin())); + bgr::clear(w); + BOOST_CHECK(w.size() == 0); + w = v; + BOOST_CHECK(w.size() == 20); + bgr::clear(bgt::make_proxy(w)); + BOOST_CHECK(w.size() == 0); +} + +void test_clear(std::vector & ) +{} + +template +void test_resize_pop(std::vector & v) +{ BOOST_CHECK(boost::size(v) == 20); // [0,19] - bgr::resize(v, 15); - BOOST_CHECK(boost::size(v) == 15); // [0,14] - BOOST_CHECK(bgr::back(v) == 14); + bgr::resize(v, 18); + BOOST_CHECK(boost::size(v) == 18); // [0,17] + bgr::resize(bgt::make_proxy(v), 16); + BOOST_CHECK(boost::size(v) == 16); // [0,15] + BOOST_CHECK(bgr::back(v) == 15); bgr::pop_back(v); + BOOST_CHECK(boost::size(v) == 15); // [0,14] + bgr::pop_back(bgt::make_proxy(v)); BOOST_CHECK(boost::size(v) == 14); // [0,13] BOOST_CHECK(bgr::back(v) == 13); - +} + +template +void test_erase(std::vector & v, Begin begin, End end) +{ typename std::vector::iterator it = bgr::erase(v, end(v) - 1); BOOST_CHECK(boost::size(v) == 13); // [0,12] @@ -135,14 +200,14 @@ void test_all() BOOST_CHECK(bgr::back(v) == 9); BOOST_CHECK(it == end(v)); - it = bgr::erase(v, begin(v) + 2); + it = bgr::erase(bgt::make_proxy(v), begin(v) + 2); BOOST_CHECK(boost::size(v) == 9); // {0,1,3..9} BOOST_CHECK(bgr::at(v, 1) == 1); BOOST_CHECK(bgr::at(v, 2) == 3); BOOST_CHECK(bgr::back(v) == 9); BOOST_CHECK(it == bgr::pos(v, 2)); - it = bgr::erase(v, begin(v) + 2, begin(v) + 2); + it = bgr::erase(bgt::make_proxy(v), begin(v) + 2, begin(v) + 2); BOOST_CHECK(boost::size(v) == 9); // {0,1,3..9} BOOST_CHECK(bgr::at(v, 1) == 1); BOOST_CHECK(bgr::at(v, 2) == 3); @@ -175,6 +240,38 @@ void test_all() BOOST_CHECK(it == end(v)); } +template +void test_erase(std::vector & , Begin , End ) +{} + +template +void test_all() +{ + std::vector v; + + test_push_emplace(v); + + BOOST_CHECK(boost::size(v) == 20); + + test_at_front_back(v); + test_at_front_back(const_cast const&>(v)); + + test_clear(v); + + test_resize_pop(v); + + int n = (int)v.size(); + + test_erase(v, [](auto & rng) { return boost::begin(rng); }, + [](auto & rng) { return boost::end(rng); }); + + bgr::clear(v); + fill(v, n); + + test_erase(v, [](auto & rng) { return boost::const_begin(rng); }, + [](auto & rng) { return boost::const_end(rng); }); +} + void test_detail() { int arr[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; @@ -186,18 +283,6 @@ void test_detail() BOOST_CHECK(boost::size(v) == 10); bgr::erase(v, v.begin() + 1); BOOST_CHECK(boost::size(v) == 9); - - bgt::NonMovable * arr2[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - bgt::NonMovable foo; - arr2[1] = &foo; - std::move(arr2 + 1, arr2 + 10, arr2); - BOOST_CHECK(arr2[0] == &foo); - - std::vector v2(10, (bgt::NonMovable*)NULL); - std::move(v2.begin() + 1, v2.begin() + 10, v2.begin()); - BOOST_CHECK(boost::size(v2) == 10); - bgr::erase(v2, v2.begin() + 1); - BOOST_CHECK(boost::size(v2) == 9); } template @@ -218,17 +303,12 @@ void test_pointers() int test_main(int, char* []) { - test_all(); - test_all(); - // Storing non-movable elements in a std::vector is not possible in some implementations of STD lib -#ifdef BOOST_GEOMETRY_TEST_NONMOVABLE_ELEMENTS - test_all(); - test_all(); -#endif - test_all(); - test_all(); + test_all(); + test_all(); + test_all(); test_detail(); + test_pointers(); test_pointers();