1// (C) Copyright Jeremy Siek 2002.
2// Distributed under the Boost Software License, Version 1.0. (See
3// accompanying file LICENSE_1_0.txt or copy at
4// http://www.boost.org/LICENSE_1_0.txt)
5
6#ifndef BOOST_ITERATOR_CATEGORIES_HPP
7# define BOOST_ITERATOR_CATEGORIES_HPP
8
9# include <boost/config.hpp>
10# include <boost/iterator/detail/config_def.hpp>
11
12# include <boost/detail/workaround.hpp>
13
14# include <boost/mpl/eval_if.hpp>
15# include <boost/mpl/identity.hpp>
16# include <boost/mpl/placeholders.hpp>
17# include <boost/mpl/aux_/lambda_support.hpp>
18
19# include <boost/type_traits/is_convertible.hpp>
20
21# include <boost/static_assert.hpp>
22
23#include <iterator>
24
25namespace boost {
26namespace iterators {
27
28//
29// Traversal Categories
30//
31
32struct no_traversal_tag {};
33
34struct incrementable_traversal_tag
35 : no_traversal_tag
36{
37// incrementable_traversal_tag() {}
38// incrementable_traversal_tag(std::output_iterator_tag const&) {};
39};
40
41struct single_pass_traversal_tag
42 : incrementable_traversal_tag
43{
44// single_pass_traversal_tag() {}
45// single_pass_traversal_tag(std::input_iterator_tag const&) {};
46};
47
48struct forward_traversal_tag
49 : single_pass_traversal_tag
50{
51// forward_traversal_tag() {}
52// forward_traversal_tag(std::forward_iterator_tag const&) {};
53};
54
55struct bidirectional_traversal_tag
56 : forward_traversal_tag
57{
58// bidirectional_traversal_tag() {};
59// bidirectional_traversal_tag(std::bidirectional_iterator_tag const&) {};
60};
61
62struct random_access_traversal_tag
63 : bidirectional_traversal_tag
64{
65// random_access_traversal_tag() {};
66// random_access_traversal_tag(std::random_access_iterator_tag const&) {};
67};
68
69namespace detail
70{
71 //
72 // Convert a "strictly old-style" iterator category to a traversal
73 // tag. This is broken out into a separate metafunction to reduce
74 // the cost of instantiating iterator_category_to_traversal, below,
75 // for new-style types.
76 //
77 template <class Cat>
78 struct old_category_to_traversal
79 : mpl::eval_if<
80 is_convertible<Cat,std::random_access_iterator_tag>
81 , mpl::identity<random_access_traversal_tag>
82 , mpl::eval_if<
83 is_convertible<Cat,std::bidirectional_iterator_tag>
84 , mpl::identity<bidirectional_traversal_tag>
85 , mpl::eval_if<
86 is_convertible<Cat,std::forward_iterator_tag>
87 , mpl::identity<forward_traversal_tag>
88 , mpl::eval_if<
89 is_convertible<Cat,std::input_iterator_tag>
90 , mpl::identity<single_pass_traversal_tag>
91 , mpl::eval_if<
92 is_convertible<Cat,std::output_iterator_tag>
93 , mpl::identity<incrementable_traversal_tag>
94 , void
95 >
96 >
97 >
98 >
99 >
100 {};
101
102} // namespace detail
103
104//
105// Convert an iterator category into a traversal tag
106//
107template <class Cat>
108struct iterator_category_to_traversal
109 : mpl::eval_if< // if already convertible to a traversal tag, we're done.
110 is_convertible<Cat,incrementable_traversal_tag>
111 , mpl::identity<Cat>
112 , boost::iterators::detail::old_category_to_traversal<Cat>
113 >
114{};
115
116// Trait to get an iterator's traversal category
117template <class Iterator = mpl::_1>
118struct iterator_traversal
119 : iterator_category_to_traversal<
120 typename std::iterator_traits<Iterator>::iterator_category
121 >
122{};
123
124# ifdef BOOST_MPL_CFG_NO_FULL_LAMBDA_SUPPORT
125// Hack because BOOST_MPL_AUX_LAMBDA_SUPPORT doesn't seem to work
126// out well. Instantiating the nested apply template also
127// requires instantiating iterator_traits on the
128// placeholder. Instead we just specialize it as a metafunction
129// class.
130template <>
131struct iterator_traversal<mpl::_1>
132{
133 template <class T>
134 struct apply : iterator_traversal<T>
135 {};
136};
137template <>
138struct iterator_traversal<mpl::_>
139 : iterator_traversal<mpl::_1>
140{};
141# endif
142
143//
144// Convert an iterator traversal to one of the traversal tags.
145//
146template <class Traversal>
147struct pure_traversal_tag
148 : mpl::eval_if<
149 is_convertible<Traversal,random_access_traversal_tag>
150 , mpl::identity<random_access_traversal_tag>
151 , mpl::eval_if<
152 is_convertible<Traversal,bidirectional_traversal_tag>
153 , mpl::identity<bidirectional_traversal_tag>
154 , mpl::eval_if<
155 is_convertible<Traversal,forward_traversal_tag>
156 , mpl::identity<forward_traversal_tag>
157 , mpl::eval_if<
158 is_convertible<Traversal,single_pass_traversal_tag>
159 , mpl::identity<single_pass_traversal_tag>
160 , mpl::eval_if<
161 is_convertible<Traversal,incrementable_traversal_tag>
162 , mpl::identity<incrementable_traversal_tag>
163 , void
164 >
165 >
166 >
167 >
168 >
169{
170};
171
172//
173// Trait to retrieve one of the iterator traversal tags from the iterator category or traversal.
174//
175template <class Iterator = mpl::_1>
176struct pure_iterator_traversal
177 : pure_traversal_tag<typename iterator_traversal<Iterator>::type>
178{};
179
180# ifdef BOOST_MPL_CFG_NO_FULL_LAMBDA_SUPPORT
181template <>
182struct pure_iterator_traversal<mpl::_1>
183{
184 template <class T>
185 struct apply : pure_iterator_traversal<T>
186 {};
187};
188template <>
189struct pure_iterator_traversal<mpl::_>
190 : pure_iterator_traversal<mpl::_1>
191{};
192# endif
193
194} // namespace iterators
195
196using iterators::no_traversal_tag;
197using iterators::incrementable_traversal_tag;
198using iterators::single_pass_traversal_tag;
199using iterators::forward_traversal_tag;
200using iterators::bidirectional_traversal_tag;
201using iterators::random_access_traversal_tag;
202using iterators::iterator_category_to_traversal;
203using iterators::iterator_traversal;
204
205// This import is needed for backward compatibility with Boost.Range:
206// boost/range/detail/demote_iterator_traversal_tag.hpp
207// It should be removed when that header is fixed.
208namespace detail {
209using iterators::pure_traversal_tag;
210} // namespace detail
211
212} // namespace boost
213
214#include <boost/iterator/detail/config_undef.hpp>
215
216#endif // BOOST_ITERATOR_CATEGORIES_HPP
217