source: branches/0.6-stable/yat/utility/iterator_traits.h @ 2164

Last change on this file since 2164 was 2164, checked in by Peter, 12 years ago

improved docs. refs #604

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 9.0 KB
Line 
1#ifndef _theplu_yat_utility_iterator_traits_
2#define _theplu_yat_utility_iterator_traits_
3
4// $Id: iterator_traits.h 2164 2010-01-20 05:01:55Z peter $
5
6/*
7  Copyright (C) 2007 Jari Häkkinen, Peter Johansson
8  Copyright (C) 2008 Jari Häkkinen, Peter Johansson, Markus Ringnér
9  Copyright (C) 2010 Peter Johansson
10
11  This file is part of the yat library, http://dev.thep.lu.se/yat
12
13  The yat library is free software; you can redistribute it and/or
14  modify it under the terms of the GNU General Public License as
15  published by the Free Software Foundation; either version 3 of the
16  License, or (at your option) any later version.
17
18  The yat library is distributed in the hope that it will be useful,
19  but WITHOUT ANY WARRANTY; without even the implied warranty of
20  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21  General Public License for more details.
22
23  You should have received a copy of the GNU General Public License
24  along with yat. If not, see <http://www.gnu.org/licenses/>.
25*/
26
27#include "DataWeight.h"
28
29#include <boost/type_traits/is_convertible.hpp>
30#include <boost/utility/enable_if.hpp>
31
32#include <iterator>
33
34namespace theplu {
35namespace yat {
36namespace utility {
37
38  /**
39    Struct to be used to make compile-time decision that Iterator is
40    unweighted, which is the default.
41   */ 
42  struct unweighted_iterator_tag {};
43   
44  /**
45    Struct to be used to make compile-time decision that Iterator is
46    weighted. Some algorithms come also in a weighted version and
47    this tag could be used to decide on using them (rather than
48    the corresponding unweighted algorithm).
49   */ 
50  struct weighted_iterator_tag {};
51
52
53namespace detail {
54  /**
55     \internal
56
57     used in weighted_iterator_traits
58  */
59  template <typename T, typename Enable = void>
60  struct weighted_iterator_traits_detail {
61    /**
62       default is a iterator unweighted
63    */
64    typedef unweighted_iterator_tag type;
65  }; 
66
67  /**
68      \internal
69
70      specialization for iterators with value type DataWeight
71  */
72  template <typename T>
73  struct weighted_iterator_traits_detail<T, typename boost::enable_if<typename boost::is_convertible<T, DataWeight>::type>::type > {
74    /**
75       Iterators with value type DataWeight is weighted
76     */
77    typedef weighted_iterator_tag type;
78  }; 
79
80} // namespace detail
81
82
83  /**
84      Metafunction to decide whether an Iterator is weighted or
85      non-weighted. This (default) implementation returns
86      unweighted_iterator_tag, unless \t value_type of Iterator is
87      convertible to DataWeight in which case weighted_iterator_tag is
88      returned.
89  */
90  template <class Iterator>
91  struct weighted_iterator_traits
92  {
93  private:
94    typedef typename std::iterator_traits<T>::value_type value;
95  public:
96    /**
97       \return weighted if value_type is DataWeight
98     */
99    typedef typename detail::weighted_iterator_traits_detail<value>::type type;
100  };
101
102
103namespace detail {
104  /**
105     \internal
106
107    Metafunction that works on a pair weighted-unweighted types and
108    return weighted_type. The metafunction is specialized for
109    unweighted unweighted in which case unweighted is returned.
110   */
111  template <class T1, class T2>
112  struct unweighted_type_and {
113    /**
114       default return weighted_iterator_tag
115     */
116    typedef weighted_iterator_tag type;
117  };
118
119  /**
120     \internal
121
122    Specialization that sets type to be unweighted when both arguments
123    are unweighted
124   */
125  template <>
126  struct unweighted_type_and<unweighted_iterator_tag, unweighted_iterator_tag> {
127    /**
128       return unweighted_iterator_tag
129     */
130    typedef unweighted_iterator_tag type;
131  };
132} // namespace detail
133
134  /**
135    struct used to determine if a pair of iterators should be treated
136    as weighted. If both iterators are unweighted, type is set to
137    unweighted else weighted.
138  */
139  template <class T1, class T2>
140  struct weighted_if_any2 {
141  private:
142    typedef typename weighted_iterator_traits<T1>::type w_type1;
143    typedef typename weighted_iterator_traits<T2>::type w_type2;
144  public:
145    /// return unweighted if both are unweighted
146    typedef typename detail::unweighted_type_and<w_type1, w_type2>::type type;
147  };
148
149  /**
150    Same as weighted_iterator_traits2 but for 3 arguments.
151   */
152  template <class T1, class T2, class T3>
153  struct weighted_if_any3 {
154  private:
155    typedef typename weighted_if_any2<T1, T2>::type tmp;
156    typedef typename weighted_iterator_traits<T3>::type w_type3;
157  public:
158    /// return unweighted if all are unweighted
159    typedef typename detail::unweighted_type_and<tmp, w_type3>::type type;
160  };
161
162  namespace detail {
163    /// check (at compile time) that iterator is unweighted.
164    inline void 
165    check_iterator_is_unweighted(utility::unweighted_iterator_tag x){} 
166  } // namespace detail
167
168  /**
169     \brief check (at compile time) that iterator is unweighted.
170
171     This function only compiles if iterator \a iter is unweighted.
172   */
173  template <class Iter>
174  void check_iterator_is_unweighted(Iter iter) 
175  { detail::check_iterator_is_unweighted(typename 
176                                 weighted_iterator_traits<Iter>::type());
177  }
178
179
180namespace detail {
181  /**
182     \internal
183
184     This class is used in iterator_traits to separate different cases.
185
186     This the default implementation that could be used for unweighted
187     iterators.
188   */
189  template <typename Iter, typename T >
190  struct iterator_traits_detail
191  {
192    /**
193       for unweighted data_reference is reference
194    */
195    typedef typename std::iterator_traits<Iter>::reference data_reference;
196
197    /**
198       for unweighted weight_reference is a double
199    */
200    typedef double weight_reference;
201
202    /**
203       Constructor just checking that iterator is unweighted
204    */
205    iterator_traits_detail(void) 
206    { check_iterator_is_unweighted(typename 
207                                   weighted_iterator_traits<Iter>::type());
208    }
209   
210    /**
211       \return * \a iter
212    */
213    data_reference data(Iter iter) const { return *iter; }
214
215    /**
216       \return 1.0
217    */
218    weight_reference weight(Iter iter) const { return 1.0; }
219  };
220
221
222  /**
223     specialization for weighted iterator with reference DataWeight&
224   */
225  template <typename Iter>
226  struct iterator_traits_detail<Iter, DataWeight&> {
227    /**
228       for mutable weighted iterator data_reference is double&
229    */
230    typedef double& data_reference;
231
232    /**
233       for mutable weighted iterator weight_reference is double&
234    */
235    typedef double& weight_reference;
236
237    /**
238       \return reference to data of iterator
239    */
240    data_reference data(Iter iter) const { return (*iter).data(); }
241
242    /**
243       \return reference to weight of iterator
244    */
245    weight_reference weight(Iter iter) const { return (*iter).weight(); }
246  };
247
248
249  /**
250     specialization for weighted iterator with reference const DataWeight&
251   */
252  template <typename Iter>
253  struct iterator_traits_detail<Iter, const DataWeight&> {
254    /**
255       for read-only weighted iterator data_reference is const double&
256    */
257    typedef const double& data_reference;
258
259    /**
260       for read-only weighted iterator data_reference is const double&
261    */
262    typedef const double& weight_reference;
263
264    /**
265       \return const reference to data of iterator
266    */
267    data_reference data(Iter iter) const { return (*iter).data(); }
268
269    /**
270       \return const reference to weight of iterator
271    */
272    weight_reference weight(Iter iter) const { return (*iter).weight(); }
273  };
274
275
276  /**
277     specialization for weighted iterator with reference const DataWeight
278   */
279  template <typename Iter>
280  struct iterator_traits_detail<Iter, const DataWeight> {
281    /**
282       \brief data_reference
283    */
284    typedef const double data_reference;
285
286    /**
287       \brief weight_reference
288    */
289    typedef const double weight_reference;
290
291    /**
292       \return const reference to data of iterator
293    */
294    data_reference data(Iter iter) const { return (*iter).data(); }
295
296    /**
297       \return const reference to weight of iterator
298    */
299    weight_reference weight(Iter iter) const { return (*iter).weight(); }
300  };
301} // namespace detail
302
303  /**
304     The purpose of this class is to allow polymorphism between
305     weighted and unweighted iterators. It allows to access data and
306     weight for both weighted and unweighted iterators.
307
308     This class works for unweighted iterators as well as weighted
309     iterators as long as they have reference type DataWeight& or
310     const DataWeight&.
311
312     For others, such as WeightedIterator for which reference type is
313     a proxy class, this class should be specialized. For adaptors
314     that have an underlying iterator (e.g. StrideIterator), this
315     class should be specialized, so the class also works when the
316     underlying is an iterator that is not covered by this class
317     e.g. WeightedIterator.
318   */ 
319  template <typename Iter>
320  struct iterator_traits {
321  private:
322    typedef typename std::iterator_traits<Iter>::reference reference;
323    typedef detail::iterator_traits_detail<Iter, reference> traits;
324  public:
325    /**
326       data_reference (type returned by data(void) is determined by
327       iterator_traits_detail
328     */
329    typedef typename traits::data_reference data_reference;
330
331    /**
332       data_reference (type returned by data(void) is determined by
333       iterator_traits_detail
334     */
335    typedef typename traits::weight_reference weight_reference;
336
337    /**
338       \return data
339    */
340    data_reference data(Iter iter) const 
341    { return traits().data(iter); }
342
343    /**
344       \return weight
345     */
346    weight_reference weight(Iter iter) const 
347    { return traits().weight(iter); }
348
349  };
350
351
352}}} // of namespace utility, yat, and theplu
353
354#endif
Note: See TracBrowser for help on using the repository browser.