source: trunk/yat/utility/sort_index.h @ 3285

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

refs #803. Use boost concepts in sort_index. Make requirements more
accurate especially when iterator is random access and value_type
doesn't need to be, e.g., default constructible.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 7.1 KB
Line 
1#ifndef _theplu_yat_utility_sort_index_
2#define _theplu_yat_utility_sort_index_
3
4// $Id: sort_index.h 3285 2014-07-11 10:59:46Z peter $
5
6/*
7  Copyright (C) 2008, 2010, 2014 Peter Johansson
8
9  This file is part of the yat library, http://dev.thep.lu.se/yat
10
11  The yat library is free software; you can redistribute it and/or
12  modify it under the terms of the GNU General Public License as
13  published by the Free Software Foundation; either version 3 of the
14  License, or (at your option) any later version.
15
16  The yat library is distributed in the hope that it will be useful,
17  but WITHOUT ANY WARRANTY; without even the implied warranty of
18  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19  General Public License for more details.
20
21  You should have received a copy of the GNU General Public License
22  along with yat. If not, see <http://www.gnu.org/licenses/>.
23*/
24
25#include <boost/concept_check.hpp>
26#include <boost/iterator/iterator_categories.hpp>
27#include <boost/iterator/iterator_concepts.hpp>
28#include <boost/iterator/iterator_traits.hpp>
29
30#include <algorithm>
31#include <functional>
32#include <iterator>
33#include <vector>
34
35namespace theplu {
36namespace yat {
37namespace utility {
38
39  /**
40     Create a vector \a sort_index containing the indeces of elements
41     in a range [first, last). The elements of \a sort_index give the
42     index of the range element which would have been stored in that
43     position if the range had been sorted in place. The first element
44     of \a sort_index gives the index of the least element in the
45     range, and the last element of \a sort_index gives the index of
46     the greatest element in the range. The function will not affect
47     the range, i.e., ForwardIterator can be read-only.
48
49     Type Requirements:
50     - \c InputIterator is a model of \input_iterator
51     - \c InputIterator::value_type is
52     <a href=http://www.sgi.com/tech/stl/LessThanComparable.html>
53     LessThan Comparable</a>
54     - Either \c InputIterator::value_type is <a
55     href=http://www.sgi.com/tech/stl/DefaultConstructible.html>
56     Default Constructible</a> or \c InputIterator is
57     \random_access_traversal_iterator.
58     - Either \c InputIterator::value_type is
59     <a href=http://www.sgi.com/tech/stl/Assignable.html>
60     Assignable</a> or \c InputIterator is
61     \random_access_traversal_iterator.
62
63     \since New in yat 0.5. In versions prior 0.13 function was restricted to
64     \forward_iterator with \c value_type convertible to \c double.
65  */
66  template<typename InputIterator>
67  void sort_index(InputIterator first, InputIterator last,
68                  std::vector<size_t>& sort_index);
69
70  /**
71     Same as sort_index(InputIterator, InputIterator,std::vector<size_t>&),
72     but objects are compared with \c comp rather than with \c operator<.
73
74     Type Requirements:
75     - \c InputIterator is a model of \input_iterator
76     - Either \c InputIterator::value_type is <a
77     href=http://www.sgi.com/tech/stl/DefaultConstructible.html>
78     Default Constructible</a> or \c InputIterator is
79     \random_access_traversal_iterator.
80     - Either \c InputIterator::value_type is
81     <a href=http://www.sgi.com/tech/stl/Assignable.html>
82     Assignable</a> or \c InputIterator is
83     \random_access_traversal_iterator.
84     - \c Compare is a model of
85     <a href="http://www.sgi.com/tech/stl/StrictWeakOrdering.html">
86     Strict Weak Ordering</a>
87     - \c Compare is
88     <a href="http://www.sgi.com/tech/stl/CopyConstructible.html">
89     Copy Constructible</a>
90     - \c InputIterator::value_type is convertible to \c Compare's
91       argument type
92
93     \since New in yat 0.13
94   */
95  template<typename InputIterator, class Compare>
96  void sort_index(InputIterator first, InputIterator last,
97                  std::vector<size_t>& sort_index, Compare comp);
98
99
100  /// \cond IGNORE_DOXYGEN
101
102  // private stuff
103  namespace detail {
104
105    template<typename InputIterator, class Compare>
106    void sort_index(InputIterator first, InputIterator last,
107                    std::vector<size_t>& idx, Compare comp,
108                    boost::single_pass_traversal_tag);
109
110    // Specialization for random access iterator
111    template<typename RandomAccessIterator, class Compare>
112    void sort_index(RandomAccessIterator first, RandomAccessIterator last,
113                    std::vector<size_t>& idx, Compare comp,
114                    boost::random_access_traversal_tag);
115
116
117    template<typename RandomAccessIterator, class Compare>
118    class sort_index_Compare
119    {
120    public:
121      sort_index_Compare(RandomAccessIterator it, Compare comp)
122        : data_(it), compare_(comp)
123      {
124        using boost_concepts::ReadableIterator;
125        BOOST_CONCEPT_ASSERT((ReadableIterator<RandomAccessIterator>));
126        using boost_concepts::RandomAccessTraversal;
127        BOOST_CONCEPT_ASSERT((RandomAccessTraversal<RandomAccessIterator>));
128        typedef
129          typename boost::iterator_reference<RandomAccessIterator>::type T;
130        BOOST_CONCEPT_ASSERT((boost::BinaryPredicate<Compare, T, T>));
131      }
132
133      bool operator()(size_t i, size_t j) const
134      { return compare_(data_[i], data_[j]); }
135
136    private:
137      RandomAccessIterator data_;
138      Compare compare_;
139    };
140
141  } // end of namespace detail
142
143  /// \endcond
144
145
146  //////////////  template implementation ///////////////////////////
147
148  template<typename InputIterator>
149  void sort_index(InputIterator first, InputIterator last,
150                  std::vector<size_t>& idx)
151  {
152    typedef typename boost::iterator_value<InputIterator>::type T;
153    // we use std::less<T>
154    BOOST_CONCEPT_ASSERT((boost::LessThanComparable<T>));
155    sort_index(first, last, idx, std::less<T>());
156  }
157
158
159  template<typename InputIterator, class Compare>
160  void sort_index(InputIterator first, InputIterator last,
161                  std::vector<size_t>& idx, Compare comp)
162  {
163    BOOST_CONCEPT_ASSERT((boost::InputIterator<InputIterator>));
164    typename boost::iterator_traversal<InputIterator>::type traversal;
165    detail::sort_index(first, last, idx, comp, traversal);
166  }
167
168
169  // implementation of private functions
170  namespace detail {
171
172    // general implementation. copy range to a std::vector and call
173    // random access version.
174    template<typename InputIterator, class Compare>
175    void sort_index(InputIterator first, InputIterator last,
176                    std::vector<size_t>& idx, Compare comp,
177                    boost::single_pass_traversal_tag tag)
178    {
179      typedef typename boost::iterator_value<InputIterator>::type T;
180      // two concepts for vector<T>
181      BOOST_CONCEPT_ASSERT((boost::DefaultConstructible<T>));
182      BOOST_CONCEPT_ASSERT((boost::SGIAssignable<T>));
183      std::vector<T> vec(first, last);
184      sort_index(vec.begin(), vec.end(), idx, comp,
185                 boost::random_access_traversal_tag());
186    }
187
188
189    // Specialization for random access traversal
190    template<typename RandomAccessIterator, class Compare>
191    void sort_index(RandomAccessIterator first, RandomAccessIterator last,
192                    std::vector<size_t>& idx, Compare comp,
193                    boost::random_access_traversal_tag tag)
194    {
195      sort_index_Compare<RandomAccessIterator, Compare> compare(first, comp);
196      // Peter would like to use boost::iota here, but that is only
197      // available in boost v1.50 and newer, which is too recent at
198      // time of writing.
199      size_t n = last-first;
200      idx.clear();
201      idx.reserve(n);
202      for (size_t i=0; i<n; ++i)
203        idx.push_back(i);
204      std::sort(idx.begin(), idx.end(), compare);
205    }
206
207  } // end of namespace detail
208
209}}} // of namespace utility, yat, and theplu
210
211#endif
Note: See TracBrowser for help on using the repository browser.