Bolt  1.3
C++ template library with support for OpenCL
iterator_adaptor.h
1 // (C) Copyright David Abrahams 2002.
2 // (C) Copyright Jeremy Siek 2002.
3 // (C) Copyright Thomas Witt 2002.
4 /***************************************************************************
5 * © 2012,2014 Advanced Micro Devices, Inc. All rights reserved.
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 
19 ***************************************************************************/
20 
21 // Distributed under the Boost Software License, Version 1.0. (See
22 // accompanying file BOOST_LICENSE_1_0.txt or copy at
23 // http://www.boost.org/LICENSE_1_0.txt)
24 
25 #ifndef BOLT_ITERATOR_ADAPTOR_H
26 #define BOLT_ITERATOR_ADAPTOR_H
27 
28 #include <type_traits>
29 #include <bolt/cl/detail/type_traits.h>
30 #include <bolt/cl/iterator/iterator_facade.h>
31 #include <bolt/cl/iterator/iterator_categories.h>
32 #include <bolt/cl/iterator/facade_iterator_category.h>
33 namespace bolt
34 {
35 namespace cl
36 {
37  // Used as a default template argument internally, merely to
38  // indicate "use the default", this can also be passed by users
39  // explicitly in order to specify that the default should be used.
40  struct use_default;
41 
42 //# ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
43 // // the incompleteness of use_default causes massive problems for
44 // // is_convertible (naturally). This workaround is fortunately not
45 // // needed for vc6/vc7.
46 // template<class To>
47 // struct is_convertible<use_default,To>
48 // : mpl::false_ {};
49 //# endif
50 
51  namespace detail
52  {
53 
54  //
55  // Result type used in enable_if_convertible meta function.
56  // This can be an incomplete type, as only pointers to
57  // enable_if_convertible< ... >::type are used.
58  // We could have used void for this, but conversion to
59  // void* is just to easy.
60  //
61  struct enable_type;
62  }
63 
64 
65  //
66  // enable_if for use in adapted iterators constructors.
67  //
68  // In order to provide interoperability between adapted constant and
69  // mutable iterators, adapted iterators will usually provide templated
70  // conversion constructors of the following form
71  //
72  // template <class BaseIterator>
73  // class adapted_iterator :
74  // public iterator_adaptor< adapted_iterator<Iterator>, Iterator >
75  // {
76  // public:
77  //
78  // ...
79  //
80  // template <class OtherIterator>
81  // adapted_iterator(
82  // OtherIterator const& it
83  // , typename enable_if_convertible<OtherIterator, Iterator>::type* = 0);
84  //
85  // ...
86  // };
87  //
88  // enable_if_convertible is used to remove those overloads from the overload
89  // set that cannot be instantiated. For all practical purposes only overloads
90  // for constant/mutable interaction will remain. This has the advantage that
91  // meta functions like boost::is_convertible do not return false positives,
92  // as they can only look at the signature of the conversion constructor
93  // and not at the actual instantiation.
94  //
95  // enable_if_interoperable can be safely used in user code. It falls back to
96  // always enabled for compilers that don't support enable_if or is_convertible.
97  // There is no need for compiler specific workarounds in user code.
98  //
99  // The operators implementation relies on boost::is_convertible not returning
100  // false positives for user/library defined iterator types. See comments
101  // on operator implementation for consequences.
102  //
103 
104 //# if BOOST_WORKAROUND(BOOST_MSVC, <= 1300)
105 //
106 // template<typename From, typename To>
107 // struct enable_if_convertible
108 // {
109 // typedef typename mpl::if_<
110 // mpl::or_<
111 // is_same<From,To>
112 // , is_convertible<From, To>
113 // >
114 // , boost::detail::enable_type
115 // , int&
116 // >::type type;
117 // };
118 //
119 //# elif defined(BOOST_NO_IS_CONVERTIBLE) || defined(BOOST_NO_SFINAE)
120 //
121 // template <class From, class To>
122 // struct enable_if_convertible
123 // {
124 // typedef boost::detail::enable_type type;
125 // };
126 //
127 //# elif BOOST_WORKAROUND(_MSC_FULL_VER, BOOST_TESTED_AT(13102292)) && BOOST_MSVC > 1300
128 //
129 // // For some reason vc7.1 needs us to "cut off" instantiation
130 // // of is_convertible in a few cases.
131 // template<typename From, typename To>
132 // struct enable_if_convertible
133 // : iterators::enable_if<
134 // mpl::or_<
135 // is_same<From,To>
136 // , is_convertible<From, To>
137 // >
138 // , boost::detail::enable_type
139 // >
140 // {};
141 //
142 //# else
143 //
144  template<typename From, typename To>
146  : std::enable_if<
147  std::is_convertible<From, To>::value
148  , bolt::cl::detail::enable_type
149  >
150  {};
151 //
152 //# endif
153 
154  //
155  // Default template argument handling for iterator_adaptor
156  //
157  namespace detail
158  {
159  // If T is use_default, return the result of invoking
160  // DefaultNullaryFn, otherwise return T.
161  template <class T, class DefaultNullaryFn>
163  : bolt::cl::detail::eval_if<
164  bolt::cl::detail::is_same<T, use_default>
165  , DefaultNullaryFn
166  , bolt::cl::detail::identity_<T>
167  >
168  {
169  };
170 
171  // A metafunction which computes an iterator_adaptor's base class,
172  // a specialization of iterator_facade.
173  template <
174  class Derived
175  , class Base
176  , class Value
177  , class Traversal
178  , class Reference
179  , class Difference
180  >
182  {
183  typedef iterator_facade<
184  Derived
185  //TODO - Replace bolt::cl with std namespace.
188  Value
189  , bolt::cl::detail::eval_if<
190  std::is_same<Reference,use_default>
192  , std::remove_reference<Reference>
193  >
194  >::type
196 // , typename boost::detail::ia_dflt_help<
197 // Value, iterator_value<Base>
198 // >::type
199 //# endif
200 //
202  Traversal
204  >::type
205 
207  Reference
208  , bolt::cl::detail::eval_if<
209  std::is_same<Value,use_default>
211  , bolt::cl::detail::add_reference<Value>
212  >
213  >::type
214 
217  >::type
218  >
219  type;
220  };
221  }// namespace detail
222 
223  //
224  // Iterator Adaptor
225  //
226  // The parameter ordering changed slightly with respect to former
227  // versions of iterator_adaptor The idea is that when the user needs
228  // to fiddle with the reference type it is highly likely that the
229  // iterator category has to be adjusted as well. Any of the
230  // following four template arguments may be ommitted or explicitly
231  // replaced by use_default.
232  //
233  // Value - if supplied, the value_type of the resulting iterator, unless
234  // const. If const, a conforming compiler strips constness for the
235  // value_type. If not supplied, iterator_traits<Base>::value_type is used
236  //
237  // Category - the traversal category of the resulting iterator. If not
238  // supplied, iterator_traversal<Base>::type is used.
239  //
240  // Reference - the reference type of the resulting iterator, and in
241  // particular, the result type of operator*(). If not supplied but
242  // Value is supplied, Value& is used. Otherwise
243  // iterator_traits<Base>::reference is used.
244  //
245  // Difference - the difference_type of the resulting iterator. If not
246  // supplied, iterator_traits<Base>::difference_type is used.
247  //
248  template <
249  class Derived
250  , class Base
251  , class Value = use_default
252  , class Traversal = use_default
253  , class Reference = use_default
254  , class Difference = use_default
255  >
258  Derived, Base, Value, Traversal, Reference, Difference
259  >::type
260  {
261  friend class bolt::cl::iterator_core_access;
262 
263  protected:
265  Derived, Base, Value, Traversal, Reference, Difference
266  >::type super_t;
267  public:
268  iterator_adaptor() {}
269 
270  explicit iterator_adaptor(Base const &iter)
271  : m_iterator(iter)
272  {
273  }
274 
275  typedef Base base_type;
276 
277  Base const& base() const
278  { return m_iterator; }
279 
280  protected:
281  // for convenience in derived classes
283 
284  //
285  // lvalue access to the Base object for Derived
286  //
287  Base const& base_reference() const
288  { return m_iterator; }
289 
290  Base& base_reference()
291  { return m_iterator; }
292 
293  private:
294  //
295  // Core iterator interface for iterator_facade. This is private
296  // to prevent temptation for Derived classes to use it, which
297  // will often result in an error. Derived classes should use
298  // base_reference(), above, to get direct access to m_iterator.
299  //
300  typename super_t::reference dereference() const
301  { return *m_iterator; }
302 
303  template <
304  class OtherDerived, class OtherIterator, class V, class C, class R, class D
305  >
307  {
308  return m_iterator == x.base();
309  }
310 
311  void advance(typename super_t::difference_type n)
312  {
313  m_iterator += (int)n;
314  }
315 
316  void increment() { ++m_iterator; }
317 
318  void decrement() { --m_iterator; }
319 
320  template <
321  class OtherDerived, class OtherIterator, class V, class C, class R, class D
322  >
323  typename super_t::difference_type distance_to(
325  {
326  return y.base() - m_iterator;
327  }
328 
329  private: // data members
330  Base m_iterator;
331  };
332 } // namespace cl
333 } // namespace bolt
334 
335 
336 
337 #endif // BOLT_ITERATOR_ADAPTOR_H