diff --git a/include/boost/geometry/iterators/base.hpp b/include/boost/geometry/iterators/base.hpp index af794955e..d3ee72235 100644 --- a/include/boost/geometry/iterators/base.hpp +++ b/include/boost/geometry/iterators/base.hpp @@ -18,11 +18,16 @@ namespace boost { namespace geometry { namespace detail { namespace iterators { -template -struct iterator_base : - public boost::iterator_adaptor +template +< + typename DerivedClass, + typename Iterator, + typename TraversalFlag = boost::bidirectional_traversal_tag +> +struct iterator_base + : public boost::iterator_adaptor < - T, + DerivedClass, Iterator, boost::use_default, typename boost::mpl::if_ @@ -32,7 +37,7 @@ struct iterator_base : typename boost::iterator_traversal::type, boost::random_access_traversal_tag >, - boost::bidirectional_traversal_tag, + TraversalFlag, boost::use_default >::type > diff --git a/include/boost/geometry/iterators/closing_iterator.hpp b/include/boost/geometry/iterators/closing_iterator.hpp new file mode 100644 index 000000000..26b7f4d78 --- /dev/null +++ b/include/boost/geometry/iterators/closing_iterator.hpp @@ -0,0 +1,98 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) +// +// Copyright Barend Gehrels 2010, Geodan, Amsterdam, the Netherlands. +// 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) + +#ifndef BOOST_GEOMETRY_ITERATORS_CLOSING_ITERATOR_HPP +#define BOOST_GEOMETRY_ITERATORS_CLOSING_ITERATOR_HPP + +#include +#include +#include +#include + +#include + + +namespace boost { namespace geometry +{ + +/*! + \brief Iterator which iterates through a range, but adds first element at end of the range + \tparam Range range on which this class is based on + \ingroup iterators + \note Use with "closing_iterator or "closing_iterator + to get non-const / const behaviour + \note This class is normally used from "closeable_view" if Close==true +*/ +template +struct closing_iterator + : public detail::iterators::iterator_base + < + closing_iterator, + typename boost::range_iterator::type, + boost::forward_traversal_tag + > +{ + friend class boost::iterator_core_access; + + explicit inline closing_iterator(Range& range) + : m_range(range) + , m_beyond(false) + , m_end(boost::end(m_range)) + { + this->base_reference() = boost::begin(m_range); + } + + // Constructor to indicate the end of a range + explicit inline closing_iterator(Range& range, bool) + : m_range(range) + , m_beyond(true) + , m_end(boost::end(m_range)) + { + this->base_reference() = m_end; + } + + //inline bool equal(closing_iterator const& other) const + inline bool operator==(closing_iterator const& other) const + { + return this->base() == other->base() + && this->m_beyond == other->m_beyond; + } + + +private: + + inline void increment() + { + if (m_beyond) + { + this->base_reference() = m_end; + } + else if (this->base() != m_end) + { + (this->base_reference())++; + + if (this->base() == m_end) + { + // Now beyond last position -> set to "begin" again + // and set flag "beyond" such that next increment + // will finish traversal + this->base_reference() = boost::begin(m_range); + m_beyond = true; + } + } + } + + Range& m_range; + bool m_beyond; + typename boost::range_iterator::type m_end; +}; + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ITERATORS_CLOSING_ITERATOR_HPP diff --git a/include/boost/geometry/util/closeable_view.hpp b/include/boost/geometry/util/closeable_view.hpp new file mode 100644 index 000000000..be5c5378c --- /dev/null +++ b/include/boost/geometry/util/closeable_view.hpp @@ -0,0 +1,74 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) +// +// Copyright Barend Gehrels 2010, Geodan, Amsterdam, the Netherlands. +// 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) + +#ifndef BOOST_GEOMETRY_UTIL_CLOSEABLE_VIEW_HPP +#define BOOST_GEOMETRY_UTIL_CLOSEABLE_VIEW_HPP + + +#include + +#include +#include +#include +#include + + +namespace boost { namespace geometry +{ + + + +template +struct closeable_view {}; + + + +template +struct closeable_view +{ + closeable_view(Range& r) + : m_range(r) + {} + + typedef typename boost::range_iterator::type const_iterator; + typedef typename boost::range_iterator::type iterator; + + const_iterator begin() const { return boost::begin(m_range); } + const_iterator end() const { return boost::end(m_range); } + + iterator begin() { return boost::begin(m_range); } + iterator end() { return boost::end(m_range); } +private : + Range& m_range; +}; + + +template +struct closeable_view +{ + closeable_view(Range& r) + : m_range(r) + {} + + + typedef closing_iterator iterator; + typedef closing_iterator const_iterator; + + const_iterator begin() const { return const_iterator(m_range); } + const_iterator end() const { return const_iterator(m_range, true); } + + iterator begin() { return iterator(m_range); } + iterator end() { return iterator(m_range, true); } +private : + Range& m_range; +}; + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_UTIL_CLOSEABLE_VIEW_HPP diff --git a/test/iterators/Jamfile.v2 b/test/iterators/Jamfile.v2 index 551ab3d2a..4034a738d 100644 --- a/test/iterators/Jamfile.v2 +++ b/test/iterators/Jamfile.v2 @@ -9,6 +9,7 @@ test-suite ggl-iterators : [ run circular_iterator.cpp ] + [ run closing_iterator.cpp ] [ run ever_circling_iterator.cpp ] [ run segment_iterator.cpp ] ; diff --git a/test/iterators/closing_iterator.cpp b/test/iterators/closing_iterator.cpp new file mode 100644 index 000000000..2b5b762fe --- /dev/null +++ b/test/iterators/closing_iterator.cpp @@ -0,0 +1,90 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) test file +// +// Copyright Barend Gehrels 2007-2009, Geodan, Amsterdam, the Netherlands +// Copyright Bruno Lalande 2008, 2009 +// 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) + +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include + + + + + + + +template +void test_geometry(std::string const& wkt) +{ + Geometry geometry; + boost::geometry::read_wkt(wkt, geometry); + typedef boost::geometry::closing_iterator closing_iterator; + + + // 1. Test normal behaviour + { + closing_iterator it(geometry); + closing_iterator end(geometry, true); + + std::ostringstream out; + for (; it != end; ++it) + { + out << " " << boost::geometry::get<0>(*it) << boost::geometry::get<1>(*it); + } + BOOST_CHECK_EQUAL(out.str(), " 11 14 44 41 11"); + + // All the following does NOT compile, and should NOT, + // 1) Because it is forward only: + //it--; + //--it; + // 2) Because it is not random access: + //it += 2; + //it = boost::begin(geometry); + } + + + // 2: check copy behaviour + { + typedef typename boost::range_iterator::type normal_iterator; + Geometry copy; + + std::copy( + closing_iterator(geometry), + closing_iterator(geometry, true), + std::back_inserter(copy)); + + std::ostringstream out; + for (normal_iterator cit = boost::begin(copy); cit != boost::end(copy); ++cit) + { + out << " " << boost::geometry::get<0>(*cit) << boost::geometry::get<1>(*cit); + } + BOOST_CHECK_EQUAL(out.str(), " 11 14 44 41 11"); + } +} + + +template +void test_all() +{ + test_geometry >("POLYGON((1 1,1 4,4 4,4 1))"); +} + + +int test_main(int, char* []) +{ + test_all(); + + return 0; +} diff --git a/test/iterators/closing_iterator.vcproj b/test/iterators/closing_iterator.vcproj new file mode 100644 index 000000000..e11dc14ef --- /dev/null +++ b/test/iterators/closing_iterator.vcproj @@ -0,0 +1,178 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/iterators/iterators.sln b/test/iterators/iterators.sln index b0ed018d3..bf0642533 100644 --- a/test/iterators/iterators.sln +++ b/test/iterators/iterators.sln @@ -8,6 +8,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "segment_iterator", "segment EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ggl_headers", "..\ggl_headers.vcproj", "{B3B37654-5AB4-49F3-A1D3-DFDE73EA5E1A}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "closing_iterator", "closing_iterator.vcproj", "{04C31A2D-BE88-4FDB-AFFE-EFDFFA9D9C39}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -30,6 +32,10 @@ Global {B3B37654-5AB4-49F3-A1D3-DFDE73EA5E1A}.Debug|Win32.Build.0 = Debug|Win32 {B3B37654-5AB4-49F3-A1D3-DFDE73EA5E1A}.Release|Win32.ActiveCfg = Release|Win32 {B3B37654-5AB4-49F3-A1D3-DFDE73EA5E1A}.Release|Win32.Build.0 = Release|Win32 + {04C31A2D-BE88-4FDB-AFFE-EFDFFA9D9C39}.Debug|Win32.ActiveCfg = Debug|Win32 + {04C31A2D-BE88-4FDB-AFFE-EFDFFA9D9C39}.Debug|Win32.Build.0 = Debug|Win32 + {04C31A2D-BE88-4FDB-AFFE-EFDFFA9D9C39}.Release|Win32.ActiveCfg = Release|Win32 + {04C31A2D-BE88-4FDB-AFFE-EFDFFA9D9C39}.Release|Win32.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/test/util/Jamfile.v2 b/test/util/Jamfile.v2 index ffcd79450..1fc000c14 100644 --- a/test/util/Jamfile.v2 +++ b/test/util/Jamfile.v2 @@ -12,4 +12,7 @@ test-suite ggl-util [ run for_each_coordinate.cpp ] [ run select_most_precise.cpp ] [ run write_dsv.cpp ] + [ run reversible_view.cpp ] + [ run closeable_view.cpp ] + [ run reversible_closeable.cpp ] ; diff --git a/test/util/as_range.vcproj b/test/util/as_range.vcproj index 14f90cf90..cc96fd53b 100644 --- a/test/util/as_range.vcproj +++ b/test/util/as_range.vcproj @@ -46,6 +46,7 @@ ExceptionHandling="2" RuntimeLibrary="1" UsePrecompiledHeader="0" + DebugInformationFormat="1" /> +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include + + +template +void test_optionally_closing(Range const& range, std::string const& expected) +{ + typedef boost::geometry::closeable_view view_type; + typedef typename boost::range_iterator::type iterator; + + view_type view(range); + + bool first = true; + std::ostringstream out; + iterator end = boost::end(view); + for (iterator it = boost::begin(view); it != end; ++it, first = false) + { + out << (first ? "" : " ") << boost::geometry::dsv(*it); + } + BOOST_CHECK_EQUAL(out.str(), expected); +} + + +template +void test_geometry(std::string const& wkt, + std::string const& expected_false, + std::string const& expected_true) +{ + namespace bg = boost::geometry; + Geometry geo; + bg::read_wkt(wkt, geo); + + test_optionally_closing(geo, expected_false); + test_optionally_closing(geo, expected_true); +} + + +template +void test_all() +{ + test_geometry >( + "POLYGON((1 1,1 4,4 4,4 1))", + "(1, 1) (1, 4) (4, 4) (4, 1)", + "(1, 1) (1, 4) (4, 4) (4, 1) (1, 1)"); +} + + +int test_main(int, char* []) +{ + namespace bg = boost::geometry; + test_all(); + test_all >(); + test_all >(); + + return 0; +} diff --git a/test/util/closeable_view.vcproj b/test/util/closeable_view.vcproj new file mode 100644 index 000000000..204e1ac30 --- /dev/null +++ b/test/util/closeable_view.vcproj @@ -0,0 +1,176 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/util/copy.vcproj b/test/util/copy.vcproj index e18b96aea..4829b7208 100644 --- a/test/util/copy.vcproj +++ b/test/util/copy.vcproj @@ -46,6 +46,7 @@ ExceptionHandling="2" RuntimeLibrary="1" UsePrecompiledHeader="0" + DebugInformationFormat="1" /> +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include +#include + + +template +void test_option(Range const& range, std::string const& expected) +{ + typedef typename boost::range_iterator::type iterator; + + View view(range); + + bool first = true; + std::ostringstream out; + iterator end = boost::end(view); + for (iterator it = boost::begin(view); it != end; ++it, first = false) + { + out << (first ? "" : " ") << boost::geometry::dsv(*it); + } + BOOST_CHECK_EQUAL(out.str(), expected); +} + +template +void test_close_reverse(Range const& range, std::string const& expected) +{ + namespace bg = boost::geometry; + test_option + < + bg::closeable_view + < + bg::reversible_view const, + Close + > + >(range, expected); +} + +/* + +This should NOT compile, or at least not instantiate +Use the code as above, so reversible_view should be nested inside closeable_view + +template +void test_reverse_close(Range const& range, std::string const& expected) +{ + namespace bg = boost::geometry; + test_option + < + bg::reversible_view + < + bg::closeable_view const, + Direction + > + >(range, expected); +} +*/ + +template +< + boost::geometry::iterate_direction Direction1, + boost::geometry::iterate_direction Direction2, + typename Range +> +void test_reverse_reverse(Range const& range, std::string const& expected) +{ + namespace bg = boost::geometry; + test_option + < + bg::reversible_view + < + bg::reversible_view const, + Direction1 + > + >(range, expected); +} + +template +< + bool Close1, + bool Close2, + typename Range +> +void test_close_close(Range const& range, std::string const& expected) +{ + namespace bg = boost::geometry; + test_option + < + bg::closeable_view + < + bg::closeable_view const, + Close1 + > + >(range, expected); +} + + +template +void test_geometry(std::string const& wkt, + std::string const& expected_1, + std::string const& expected_2, + std::string const& expected_3, + std::string const& expected_4, + std::string const& expected_cc + ) +{ + namespace bg = boost::geometry; + Geometry geo; + bg::read_wkt(wkt, geo); + + test_close_reverse(geo, expected_1); + test_close_reverse(geo, expected_2); + test_close_reverse(geo, expected_3); + test_close_reverse(geo, expected_4); + + /* + This should NOT compile on purpose + Because the closing_iterator can only be used forward + test_reverse_close(geo, expected_1); + test_reverse_close(geo, expected_2); + test_reverse_close(geo, expected_3); + test_reverse_close(geo, expected_4); + */ + + test_reverse_reverse(geo, expected_1); + test_reverse_reverse(geo, expected_1); + + test_close_close(geo, expected_1); + test_close_close(geo, expected_2); + test_close_close(geo, expected_2); + + // Does not compile - no assignment operator + // Ranges basically support nesting, but the closing iterator does not. + // It is not necessary for the closing iterator to do so. + + //test_close_close(geo, expected_cc); +} + + +template +void test_all() +{ + test_geometry >( + "POLYGON((1 1,1 4,4 4,4 1))", + "(1, 1) (1, 4) (4, 4) (4, 1)", + "(1, 1) (1, 4) (4, 4) (4, 1) (1, 1)", + "(4, 1) (4, 4) (1, 4) (1, 1)", + "(4, 1) (4, 4) (1, 4) (1, 1) (4, 1)", + "(1, 1) (1, 4) (4, 4) (4, 1) (1, 1) (1, 1)" // closed twice, not used + ); +} + + +int test_main(int, char* []) +{ + namespace bg = boost::geometry; + test_all(); + test_all >(); + test_all >(); + + return 0; +} diff --git a/test/util/reversible_closeable.vcproj b/test/util/reversible_closeable.vcproj new file mode 100644 index 000000000..b2a3846b1 --- /dev/null +++ b/test/util/reversible_closeable.vcproj @@ -0,0 +1,176 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/util/reversible_view.vcproj b/test/util/reversible_view.vcproj index 0f43b2725..f81885210 100644 --- a/test/util/reversible_view.vcproj +++ b/test/util/reversible_view.vcproj @@ -47,6 +47,7 @@ RuntimeLibrary="1" UsePrecompiledHeader="0" WarningLevel="3" + DebugInformationFormat="1" />