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

Last change on this file since 1591 was 1591, checked in by Peter, 13 years ago

fixes #447

Moved some (internal) functions and clases to namespace
theplu::yat::utility::detail. Did not move the stuff to another file
though, because unexpected problems with cyclic dependency.

Currently the namespace theplu::yat::utility::detail is not documented
(doc/namespace.doxygen), which implies that functionality is excluded
from documentation.

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