boost/poly_collection/detail/iterator_impl.hpp
/* Copyright 2016-2021 Joaquin M Lopez Munoz.
* Distributed under 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)
*
* See http://www.boost.org/libs/poly_collection for library home page.
*/
#ifndef BOOST_POLY_COLLECTION_DETAIL_ITERATOR_IMPL_HPP
#define BOOST_POLY_COLLECTION_DETAIL_ITERATOR_IMPL_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/detail/workaround.hpp>
#include <boost/iterator/iterator_adaptor.hpp>
#include <boost/iterator/iterator_facade.hpp>
#include <boost/poly_collection/detail/is_constructible.hpp>
#include <boost/poly_collection/detail/iterator_traits.hpp>
#include <type_traits>
#include <typeinfo>
namespace boost{
namespace poly_collection{
namespace detail{
/* Implementations of poly_collection::[const_][local_[base_]]iterator moved
* out of class to allow for use in deduced contexts.
*/
template<typename PolyCollection,bool Const>
using iterator_impl_value_type=typename std::conditional<
Const,
const typename PolyCollection::value_type,
typename PolyCollection::value_type
>::type;
template<typename PolyCollection,bool Const>
class iterator_impl:
public boost::iterator_facade<
iterator_impl<PolyCollection,Const>,
iterator_impl_value_type<PolyCollection,Const>,
boost::forward_traversal_tag
>
{
using segment_type=typename PolyCollection::segment_type;
using const_segment_base_iterator=
typename PolyCollection::const_segment_base_iterator;
using const_segment_base_sentinel=
typename PolyCollection::const_segment_base_sentinel;
using const_segment_map_iterator=
typename PolyCollection::const_segment_map_iterator;
public:
using value_type=iterator_impl_value_type<PolyCollection,Const>;
private:
iterator_impl(
const_segment_map_iterator mapit,
const_segment_map_iterator mapend)noexcept:
mapit{mapit},mapend{mapend}
{
next_segment_position();
}
iterator_impl(
const_segment_map_iterator mapit_,const_segment_map_iterator mapend_,
const_segment_base_iterator segpos_)noexcept:
mapit{mapit_},mapend{mapend_},segpos{segpos_}
{
if(mapit!=mapend&&segpos==sentinel()){
++mapit;
next_segment_position();
}
}
public:
iterator_impl()=default;
iterator_impl(const iterator_impl&)=default;
iterator_impl& operator=(const iterator_impl&)=default;
template<bool Const2,typename std::enable_if<!Const2>::type* =nullptr>
iterator_impl(const iterator_impl<PolyCollection,Const2>& x):
mapit{x.mapit},mapend{x.mapend},segpos{x.segpos}{}
private:
template<typename,bool>
friend class iterator_impl;
friend PolyCollection;
friend class boost::iterator_core_access;
template<typename>
friend struct iterator_traits;
value_type& dereference()const noexcept
{return const_cast<value_type&>(*segpos);}
bool equal(const iterator_impl& x)const noexcept{return segpos==x.segpos;}
void increment()noexcept
{
if(++segpos==sentinel()){
++mapit;
next_segment_position();
}
}
void next_segment_position()noexcept
{
for(;mapit!=mapend;++mapit){
segpos=segment().begin();
if(segpos!=sentinel())return;
}
segpos=nullptr;
}
segment_type& segment()noexcept
{return const_cast<segment_type&>(mapit->second);}
const segment_type& segment()const noexcept{return mapit->second;}
const_segment_base_sentinel sentinel()const noexcept
{return segment().sentinel();}
const_segment_map_iterator mapit,mapend;
const_segment_base_iterator segpos;
};
template<typename PolyCollection,bool Const>
struct poly_collection_of<iterator_impl<PolyCollection,Const>>
{
using type=PolyCollection;
};
template<typename PolyCollection,typename BaseIterator>
class local_iterator_impl:
public boost::iterator_adaptor<
local_iterator_impl<PolyCollection,BaseIterator>,
BaseIterator
>
{
using segment_type=typename PolyCollection::segment_type;
using segment_base_iterator=typename PolyCollection::segment_base_iterator;
using const_segment_map_iterator=
typename PolyCollection::const_segment_map_iterator;
#if BOOST_WORKAROUND(BOOST_GCC_VERSION,>=90300)&&\
BOOST_WORKAROUND(BOOST_GCC_VERSION,<100300)
/* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95888 */
public:
#else
private:
#endif
template<typename Iterator>
local_iterator_impl(
const_segment_map_iterator mapit,
Iterator it):
local_iterator_impl::iterator_adaptor_{BaseIterator(it)},
mapit{mapit}
{}
public:
using base_iterator=BaseIterator;
local_iterator_impl()=default;
local_iterator_impl(const local_iterator_impl&)=default;
local_iterator_impl& operator=(const local_iterator_impl&)=default;
template<
typename BaseIterator2,
typename std::enable_if<
std::is_convertible<BaseIterator2,BaseIterator>::value
>::type* =nullptr
>
local_iterator_impl(
const local_iterator_impl<PolyCollection,BaseIterator2>& x):
local_iterator_impl::iterator_adaptor_{x.base()},
mapit{x.mapit}{}
template<
typename BaseIterator2,
typename std::enable_if<
!std::is_convertible<BaseIterator2,BaseIterator>::value&&
is_constructible<BaseIterator,BaseIterator2>::value
>::type* =nullptr
>
explicit local_iterator_impl(
const local_iterator_impl<PolyCollection,BaseIterator2>& x):
local_iterator_impl::iterator_adaptor_{BaseIterator(x.base())},
mapit{x.mapit}{}
template<
typename BaseIterator2,
typename std::enable_if<
!is_constructible<BaseIterator,BaseIterator2>::value&&
is_constructible<BaseIterator,segment_base_iterator>::value&&
is_constructible<BaseIterator2,segment_base_iterator>::value
>::type* =nullptr
>
explicit local_iterator_impl(
const local_iterator_impl<PolyCollection,BaseIterator2>& x):
local_iterator_impl::iterator_adaptor_{
base_iterator_from(x.segment(),x.base())},
mapit{x.mapit}{}
/* define [] to avoid Boost.Iterator operator_brackets_proxy mess */
template<typename DifferenceType>
typename std::iterator_traits<BaseIterator>::reference
operator[](DifferenceType n)const{return *(*this+n);}
private:
template<typename,typename>
friend class local_iterator_impl;
friend PolyCollection;
template<typename>
friend struct iterator_traits;
template<typename BaseIterator2>
static BaseIterator base_iterator_from(
const segment_type& s,BaseIterator2 it)
{
segment_base_iterator bit=s.begin();
return BaseIterator{bit+(it-static_cast<BaseIterator2>(bit))};
}
base_iterator base()const noexcept
{return local_iterator_impl::iterator_adaptor_::base();}
const std::type_info& type_info()const{return *mapit->first;}
segment_type& segment()noexcept
{return const_cast<segment_type&>(mapit->second);}
const segment_type& segment()const noexcept{return mapit->second;}
const_segment_map_iterator mapit;
};
template<typename PolyCollection,typename BaseIterator>
struct poly_collection_of<local_iterator_impl<PolyCollection,BaseIterator>>
{
using type=PolyCollection;
};
} /* namespace poly_collection::detail */
} /* namespace poly_collection */
} /* namespace boost */
#endif