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

Last change on this file since 3188 was 3188, checked in by Peter, 9 years ago

merge patch release 0.11.2

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 11.0 KB
Line 
1#ifndef _theplu_yat_utility_iterator_traits_
2#define _theplu_yat_utility_iterator_traits_
3
4// $Id: iterator_traits.h 3188 2014-03-25 10:24:29Z 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, 2011, 2014 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/mpl/logical.hpp>
30#include <boost/type_traits/is_const.hpp>
31#include <boost/type_traits/is_convertible.hpp>
32#include <boost/type_traits/is_same.hpp>
33#include <boost/type_traits/remove_reference.hpp>
34#include <boost/utility/enable_if.hpp>
35
36#include <iterator>
37
38namespace theplu {
39namespace yat {
40namespace utility {
41
42  /**
43    Struct to be used to make compile-time decision that Iterator is
44    unweighted, which is the default.
45   */ 
46  struct unweighted_iterator_tag {};
47   
48  /**
49    Struct to be used to make compile-time decision that Iterator is
50    weighted. Some algorithms come also in a weighted version and
51    this tag could be used to decide on using them (rather than
52    the corresponding unweighted algorithm).
53   */ 
54  struct weighted_iterator_tag {};
55
56
57/// \cond IGNORE_DOXYGEN
58
59namespace detail {
60  /**
61     \internal
62
63     used in weighted_iterator_traits
64  */
65  template <typename T, typename Enable = void>
66  struct weighted_iterator_traits_detail {
67    /**
68       default is a iterator unweighted
69    */
70    typedef unweighted_iterator_tag type;
71  }; 
72
73  /**
74      \internal
75
76      specialization for iterators with value type convertible to DataWeight
77  */
78  template <typename T>
79  struct weighted_iterator_traits_detail<T, typename boost::enable_if<typename boost::is_convertible<T, DataWeight> >::type > {
80    /**
81       Iterators with value type convertible to DataWeight is weighted
82     */
83    typedef weighted_iterator_tag type;
84  }; 
85
86} // namespace detail
87
88/// \endcond
89
90
91  /**
92      Metafunction to decide whether an Iterator is weighted or
93      non-weighted. This (default) implementation returns
94      unweighted_iterator_tag, unless value_type of Iterator is
95      convertible to DataWeight in which case weighted_iterator_tag is
96      returned.
97  */
98  template <class Iterator>
99  struct weighted_iterator_traits
100  {
101  private:
102    typedef typename std::iterator_traits<Iterator>::value_type value;
103  public:
104    /**
105       \return weighted_iterator_tag if Iterator::value_type is
106       convertible to DataWeight
107     */
108    typedef typename detail::weighted_iterator_traits_detail<value>::type type;
109  };
110
111
112/// \cond IGNORE_DOXYGEN
113namespace detail {
114  /**
115     \internal
116
117    Metafunction that works on a pair weighted-unweighted types and
118    return weighted_type. The metafunction is specialized for
119    unweighted unweighted in which case unweighted is returned.
120   */
121  template <class T1, class T2>
122  struct unweighted_type_and {
123    /**
124       default return weighted_iterator_tag
125     */
126    typedef weighted_iterator_tag type;
127  };
128
129  /**
130     \internal
131
132    Specialization that sets type to be unweighted when both arguments
133    are unweighted
134   */
135  template <>
136  struct unweighted_type_and<unweighted_iterator_tag, unweighted_iterator_tag> {
137    /**
138       return unweighted_iterator_tag
139     */
140    typedef unweighted_iterator_tag type;
141  };
142} // namespace detail
143
144/// \endcond
145
146
147  /**
148    struct used to determine if a pair of iterators should be treated
149    as weighted. If both iterators are unweighted, type is set to
150    unweighted else weighted.
151  */
152  template <class T1, class T2>
153  struct weighted_if_any2 {
154  private:
155    typedef typename weighted_iterator_traits<T1>::type w_type1;
156    typedef typename weighted_iterator_traits<T2>::type w_type2;
157  public:
158    /// return unweighted if both are unweighted
159    typedef typename detail::unweighted_type_and<w_type1, w_type2>::type type;
160  };
161
162  /**
163    Same as weighted_iterator_traits2 but for 3 arguments.
164   */
165  template <class T1, class T2, class T3>
166  struct weighted_if_any3 {
167  private:
168    typedef typename weighted_if_any2<T1, T2>::type tmp;
169    typedef typename weighted_iterator_traits<T3>::type w_type3;
170  public:
171    /// return unweighted if all are unweighted
172    typedef typename detail::unweighted_type_and<tmp, w_type3>::type type;
173  };
174
175  /// \cond IGNORE_DOXYGEN
176  namespace detail {
177    /**
178        \internal
179
180        check (at compile time) that iterator is unweighted.
181    */
182    inline void 
183    check_iterator_is_unweighted(utility::unweighted_iterator_tag x){} 
184  } // namespace detail
185
186  /// \endcond
187
188  /**
189     \brief check (at compile time) that iterator is unweighted.
190
191     This function only compiles if iterator \a iter is unweighted.
192   */
193  template <class Iter>
194  void check_iterator_is_unweighted(Iter iter) 
195  { detail::check_iterator_is_unweighted(typename 
196                                 weighted_iterator_traits<Iter>::type());
197  }
198
199
200/// \cond IGNORE_DOXYGEN
201namespace detail {
202
203  /**
204     \internal
205
206     The following block of code is used to detect if weighted
207     iterators have functions 'double& data(void)' or if they only
208     have the const version.
209     
210     The technique used is taken from http://www.martinecker.com/wiki/
211   */
212  typedef char yes;
213  /**
214     \internal
215
216     This type (no) and type yes have different sizes and are used to
217     differentiate between the two cases.
218   */
219  typedef char (&no)[2];
220  /**
221     \internal
222
223     Overloaded function with template below. If there exists a
224     function that returns double& that will used and otherwise
225     overloaded template below will be used. This implementation and
226     template return different types to differentiate the two cases.
227   */
228  yes has_mutable(double&);
229  /**
230     \internal
231
232     Function used in iter_has_mutable_data and
233     iter_has_mutable_weight. The default case is used if function
234     called (e.g. data() does not return double&.
235   */
236  template<typename T>
237  no has_mutable(const T&);
238
239  /**
240     \internal
241
242     Struct to check if iterator has mutable data. *Iter must have a
243     function data(). If that function returns double& value is
244     true.
245   */
246  template <class Iter>
247  struct iter_has_mutable_data
248  {
249    /// instance of Iter
250    static Iter iter;
251    /// true if *iter has a function data() that returns double&
252    static const bool value = 
253      sizeof(has_mutable((*iter).data())) == sizeof(yes);
254  };
255
256
257  /**
258     \internal
259
260     Struct to check if iterator has mutable data. *Iter must have a
261     function data(). If that function returns double& value is
262     true.
263   */
264  template <class Iter>
265  struct iter_has_mutable_weight
266  {
267    /// instance of Iter
268    static Iter iter;
269    /// true if *iter has a function weight() that returns double&
270    static const bool value = 
271      sizeof(has_mutable((*iter).weight())) == sizeof(yes);
272  };
273
274
275  /**
276     \internal
277
278     Convenience meta-function. The struct is-a boost::true_type if
279     Iter is a weighted iterator
280
281     The purpose of the struct is to be used in boost::mpl, for
282     example, in boost::mpl::and_.
283
284     \see weighted_iterator_traits
285   */
286  template<typename Iter>
287  struct is_weighted 
288    : public boost::is_same<weighted_iterator_tag
289                            , typename weighted_iterator_traits<Iter>::type> 
290  {};
291
292  /**
293     \internal
294
295     same is_weighted but negated
296   */
297  template<typename Iter>
298  struct is_unweighted 
299    : public boost::is_same<unweighted_iterator_tag
300                            , typename weighted_iterator_traits<Iter>::type> 
301  {};
302
303
304  /**
305     \internal
306
307     Default implementation of iterator_traits_detail. Is supposed to
308     be used for unweighted iterators. Weighted iterators use
309     specialization below.
310   */
311  template <typename Iter, typename Enable = void>
312  struct iterator_traits_detail {
313    /**
314       for unweighted data_reference is reference
315    */
316    typedef typename std::iterator_traits<Iter>::reference data_reference;
317
318    /**
319       for unweighted weight_reference is a double
320    */
321    typedef const double weight_reference;
322
323    /**
324       \return * \a iter
325    */
326    data_reference data(Iter iter) const { return *iter; }
327
328    /**
329       \return 1.0
330    */
331    weight_reference weight(Iter iter) const { return 1.0; }
332  };
333
334  /**
335     \internal
336     Metafunction that returns double& if true and const double otherwise
337   */
338  template<bool>
339  struct mutable_reference {
340    /// return const double if bool is false
341    typedef const double type;
342  };
343
344  /**
345     \internal
346     Specialization that returns double& in true case
347  */
348  template<>
349  struct mutable_reference<true> {
350    /// return double& if bool is false
351    typedef double& type;
352  };
353
354
355  /**
356     \internal
357
358     Specialization for weighted iterators
359   */
360  // we need remove_reference because is_const seems to not work on const&
361  template <typename Iter>
362  struct iterator_traits_detail<Iter, 
363                         typename boost::enable_if<is_weighted<Iter> >::type >
364  {
365    /**
366       data_reference is double& for mutable iterators and const
367       double otherwise
368    */
369    typedef 
370    typename mutable_reference<iter_has_mutable_data<Iter>::value>::type
371    data_reference;
372
373    /**
374       weight_reference is double& for mutable iterators and const
375       double otherwise
376    */
377    typedef 
378    typename mutable_reference<iter_has_mutable_weight<Iter>::value>::type
379    weight_reference;
380
381    /**
382       return data of \a iter
383    */
384    data_reference data(Iter iter) const { return (*iter).data(); }
385
386    /**
387       return weight of \a iter
388    */
389    weight_reference weight(Iter iter) const { return (*iter).weight(); }
390  };
391
392} // namespace detail
393
394/// \endcond
395
396
397  /**
398     The purpose of this class is to allow polymorphism between
399     weighted and unweighted iterators. It allows to access data and
400     weight for both weighted and unweighted iterators.
401
402     For weighted iterators this class requires that *Iter has
403     functions data(void) and weight(void).
404   */ 
405  template <typename Iter>
406  struct iterator_traits {
407  private:
408    typedef detail::iterator_traits_detail<Iter> traits;
409  public:
410    /**
411       For unweighted iterator, data_reference is the same as
412       std::iterator_traits<Iter>::reference, i.e., the data if the
413       iterator is the same as *Iter.
414
415       For weighted iterators, data_reference is double& if *Iter has
416       a function double& data(void). Otherwise data_reference is
417       const double.
418     */
419    typedef typename traits::data_reference data_reference;
420
421    /**
422       For unweighted iterator, weight_reference is const double since
423       the weight is always implicitly 1.0 and not mutable.
424
425       For weighted iterators, weight_reference is double& if *Iter has
426       a function double& weight(void). Otherwise weight_reference is
427       const double.
428     */
429    typedef typename traits::weight_reference weight_reference;
430
431    /**
432       \return data of iterator \a iter
433    */
434    data_reference data(Iter iter) const 
435    { return traits().data(iter); }
436
437    /**
438       \return weight of iterator \a iter
439     */
440    weight_reference weight(Iter iter) const 
441    { return traits().weight(iter); }
442
443  };
444
445}}} // of namespace utility, yat, and theplu
446
447#endif
Note: See TracBrowser for help on using the repository browser.