// Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2014, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Licensed under the Boost Software License version 1.0. // http://www.boost.org/users/license.html #ifndef BOOST_GEOMETRY_ITERATORS_FLATTEN_ITERATOR_HPP #define BOOST_GEOMETRY_ITERATORS_FLATTEN_ITERATOR_HPP #include #include #include #include #include #include namespace boost { namespace geometry { template < typename OuterIterator, typename InnerIterator, typename Value, typename AccessInnerBegin, typename AccessInnerEnd, typename Reference = Value& > class flatten_iterator : public boost::iterator_facade < flatten_iterator < OuterIterator, InnerIterator, Value, AccessInnerBegin, AccessInnerEnd, Reference >, Value, boost::bidirectional_traversal_tag, Reference > { private: OuterIterator m_outer_it, m_outer_end; InnerIterator m_inner_it; public: typedef OuterIterator outer_iterator_type; typedef InnerIterator inner_iterator_type; // default constructor flatten_iterator() {} // for begin flatten_iterator(OuterIterator outer_it, OuterIterator outer_end) : m_outer_it(outer_it), m_outer_end(outer_end) { advance_through_empty(); } // for end flatten_iterator(OuterIterator outer_end) : m_outer_it(outer_end), m_outer_end(outer_end) {} template < typename OtherOuterIterator, typename OtherInnerIterator, typename OtherValue, typename OtherAccessInnerBegin, typename OtherAccessInnerEnd, typename OtherReference > flatten_iterator(flatten_iterator < OtherOuterIterator, OtherInnerIterator, OtherValue, OtherAccessInnerBegin, OtherAccessInnerEnd, OtherReference > const& other) : m_outer_it(other.m_outer_it), m_outer_end(other.m_outer_end), m_inner_it(other.m_inner_it) { static const bool are_conv = boost::is_convertible < OtherOuterIterator, OuterIterator >::value && boost::is_convertible < OtherInnerIterator, InnerIterator >::value; BOOST_MPL_ASSERT_MSG((are_conv), NOT_CONVERTIBLE, (types)); } flatten_iterator& operator=(flatten_iterator const& other) { m_outer_it = other.m_outer_it; m_outer_end = other.m_outer_end; // avoid assigning an iterator having singular value if ( other.m_outer_it != other.m_outer_end ) { m_inner_it = other.m_inner_it; } return *this; } private: friend class boost::iterator_core_access; template < typename Outer, typename Inner, typename V, typename InnerBegin, typename InnerEnd, typename R > friend class flatten_iterator; static inline bool empty(OuterIterator outer_it) { return AccessInnerBegin::apply(*outer_it) == AccessInnerEnd::apply(*outer_it); } inline void advance_through_empty() { while ( m_outer_it != m_outer_end && empty(m_outer_it) ) { ++m_outer_it; } if ( m_outer_it != m_outer_end ) { m_inner_it = AccessInnerBegin::apply(*m_outer_it); } } inline Reference dereference() const { BOOST_GEOMETRY_ASSERT( m_outer_it != m_outer_end ); BOOST_GEOMETRY_ASSERT( m_inner_it != AccessInnerEnd::apply(*m_outer_it) ); return *m_inner_it; } template < typename OtherOuterIterator, typename OtherInnerIterator, typename OtherValue, typename OtherAccessInnerBegin, typename OtherAccessInnerEnd, typename OtherReference > inline bool equal(flatten_iterator < OtherOuterIterator, OtherInnerIterator, OtherValue, OtherAccessInnerBegin, OtherAccessInnerEnd, OtherReference > const& other) const { if ( m_outer_it != other.m_outer_it ) { return false; } if ( m_outer_it == m_outer_end ) { return true; } return m_inner_it == other.m_inner_it; } inline void increment() { BOOST_GEOMETRY_ASSERT( m_outer_it != m_outer_end ); BOOST_GEOMETRY_ASSERT( m_inner_it != AccessInnerEnd::apply(*m_outer_it) ); ++m_inner_it; if ( m_inner_it == AccessInnerEnd::apply(*m_outer_it) ) { ++m_outer_it; advance_through_empty(); } } inline void decrement() { if ( m_outer_it == m_outer_end || m_inner_it == AccessInnerBegin::apply(*m_outer_it) ) { do { --m_outer_it; } while ( empty(m_outer_it) ); m_inner_it = AccessInnerEnd::apply(*m_outer_it); } --m_inner_it; } }; }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ITERATORS_FLATTEN_ITERATOR_HPP