source: trunk/yat/utility/iterator_traits.h @ 2161

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

updating copyright years

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 8.9 KB
Line 
1#ifndef _theplu_yat_utility_iterator_traits_
2#define _theplu_yat_utility_iterator_traits_
3
4// $Id: iterator_traits.h 2161 2010-01-19 23:59:48Z 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 return unweighted,
86      unless value_type of iterator is DataWeight in which case
87      weighted is returned.
88  */
89  template <class T>
90  struct weighted_iterator_traits
91  {
92  private:
93    typedef typename std::iterator_traits<T>::value_type value;
94  public:
95    /**
96       \return weighted if value_type is DataWeight
97     */
98    typedef typename detail::weighted_iterator_traits_detail<value>::type type;
99  };
100
101
102namespace detail {
103  /**
104     \internal
105
106    Metafunction that works on a pair weighted-unweighted types and
107    return weighted_type. The metafunction is specialized for
108    unweighted unweighted in which case unweighted is returned.
109   */
110  template <class T1, class T2>
111  struct unweighted_type_and {
112    /**
113       default return weighted_iterator_tag
114     */
115    typedef weighted_iterator_tag type;
116  };
117
118  /**
119     \internal
120
121    Specialization that sets type to be unweighted when both arguments
122    are unweighted
123   */
124  template <>
125  struct unweighted_type_and<unweighted_iterator_tag, unweighted_iterator_tag> {
126    /**
127       return unweighted_iterator_tag
128     */
129    typedef unweighted_iterator_tag type;
130  };
131} // namespace detail
132
133  /**
134    struct used to determine if a pair of iterators should be treated
135    as weighted. If both iterators are unweighted, type is set to
136    unweighted else weighted.
137  */
138  template <class T1, class T2>
139  struct weighted_if_any2 {
140  private:
141    typedef typename weighted_iterator_traits<T1>::type w_type1;
142    typedef typename weighted_iterator_traits<T2>::type w_type2;
143  public:
144    /// return unweighted if both are unweighted
145    typedef typename detail::unweighted_type_and<w_type1, w_type2>::type type;
146  };
147
148  /**
149    Same as weighted_iterator_traits2 but for 3 arguments.
150   */
151  template <class T1, class T2, class T3>
152  struct weighted_if_any3 {
153  private:
154    typedef typename weighted_if_any2<T1, T2>::type tmp;
155    typedef typename weighted_iterator_traits<T3>::type w_type3;
156  public:
157    /// return unweighted if all are unweighted
158    typedef typename detail::unweighted_type_and<tmp, w_type3>::type type;
159  };
160
161  namespace detail {
162    /// check (at compile time) that iterator is unweighted.
163    inline void 
164    check_iterator_is_unweighted(utility::unweighted_iterator_tag x){} 
165  } // namespace detail
166
167  /**
168     \brief check (at compile time) that iterator is unweighted.
169
170     This function only compiles if iterator \a iter is unweighted.
171   */
172  template <class Iter>
173  void check_iterator_is_unweighted(Iter iter) 
174  { detail::check_iterator_is_unweighted(typename 
175                                 weighted_iterator_traits<Iter>::type());
176  }
177
178
179namespace detail {
180  /**
181     \internal
182
183     This class is used in iterator_traits to separate different cases.
184
185     This the default implementation that could be used for unweighted
186     iterators.
187   */
188  template <typename Iter, typename T >
189  struct iterator_traits_detail
190  {
191    /**
192       for unweighted data_reference is reference
193    */
194    typedef typename std::iterator_traits<Iter>::reference data_reference;
195
196    /**
197       for unweighted weight_reference is a double
198    */
199    typedef double weight_reference;
200
201    /**
202       Constructor just checking that iterator is unweighted
203    */
204    iterator_traits_detail(void) 
205    { check_iterator_is_unweighted(typename 
206                                   weighted_iterator_traits<Iter>::type());
207    }
208   
209    /**
210       \return * \a iter
211    */
212    data_reference data(Iter iter) const { return *iter; }
213
214    /**
215       \return 1.0
216    */
217    weight_reference weight(Iter iter) const { return 1.0; }
218  };
219
220
221  /**
222     specialization for weighted iterator with reference DataWeight&
223   */
224  template <typename Iter>
225  struct iterator_traits_detail<Iter, DataWeight&> {
226    /**
227       for mutable weighted iterator data_reference is double&
228    */
229    typedef double& data_reference;
230
231    /**
232       for mutable weighted iterator weight_reference is double&
233    */
234    typedef double& weight_reference;
235
236    /**
237       \return reference to data of iterator
238    */
239    data_reference data(Iter iter) const { return (*iter).data(); }
240
241    /**
242       \return reference to weight of iterator
243    */
244    weight_reference weight(Iter iter) const { return (*iter).weight(); }
245  };
246
247
248  /**
249     specialization for weighted iterator with reference const DataWeight&
250   */
251  template <typename Iter>
252  struct iterator_traits_detail<Iter, const DataWeight&> {
253    /**
254       for read-only weighted iterator data_reference is const double&
255    */
256    typedef const double& data_reference;
257
258    /**
259       for read-only weighted iterator data_reference is const double&
260    */
261    typedef const double& weight_reference;
262
263    /**
264       \return const reference to data of iterator
265    */
266    data_reference data(Iter iter) const { return (*iter).data(); }
267
268    /**
269       \return const reference to weight of iterator
270    */
271    weight_reference weight(Iter iter) const { return (*iter).weight(); }
272  };
273
274
275  /**
276     specialization for weighted iterator with reference const DataWeight
277   */
278  template <typename Iter>
279  struct iterator_traits_detail<Iter, const DataWeight> {
280    /**
281       \brief data_reference
282    */
283    typedef const double data_reference;
284
285    /**
286       \brief weight_reference
287    */
288    typedef const double weight_reference;
289
290    /**
291       \return const reference to data of iterator
292    */
293    data_reference data(Iter iter) const { return (*iter).data(); }
294
295    /**
296       \return const reference to weight of iterator
297    */
298    weight_reference weight(Iter iter) const { return (*iter).weight(); }
299  };
300} // namespace detail
301
302  /**
303     The purpose of this class is to allow polymorphism between
304     weighted and unweighted iterators. It allows to access data and
305     weight for both weighted and unweighted iterators.
306
307     This class works for unweighted iterators as well as weighted
308     iterators as long as they have reference type DataWeight& or
309     const DataWeight&.
310
311     For others, such as WeightedIterator for which reference type is
312     a proxy class, this class should be specialized. For adaptors
313     that have an underlying iterator (e.g. StrideIterator), this
314     class should be specialized, so the class also works when the
315     underlying is an iterator that is not covered by this class
316     e.g. WeightedIterator.
317   */ 
318  template <typename Iter>
319  struct iterator_traits {
320  private:
321    typedef typename std::iterator_traits<Iter>::reference reference;
322    typedef detail::iterator_traits_detail<Iter, reference> traits;
323  public:
324    /**
325       data_reference (type returned by data(void) is determined by
326       iterator_traits_detail
327     */
328    typedef typename traits::data_reference data_reference;
329
330    /**
331       data_reference (type returned by data(void) is determined by
332       iterator_traits_detail
333     */
334    typedef typename traits::weight_reference weight_reference;
335
336    /**
337       \return data
338    */
339    data_reference data(Iter iter) const 
340    { return traits().data(iter); }
341
342    /**
343       \return weight
344     */
345    weight_reference weight(Iter iter) const 
346    { return traits().weight(iter); }
347
348  };
349
350
351}}} // of namespace utility, yat, and theplu
352
353#endif
Note: See TracBrowser for help on using the repository browser.