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

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

re-write sort_index so it's not limited to ranges of double but work on any value_type than is less than comparable. Also provide a variant that takes a compare functor, similarly to std::sort

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 5.6 KB
Line 
1#ifndef _theplu_yat_utility_sort_index_
2#define _theplu_yat_utility_sort_index_
3
4// $Id: sort_index.h 3237 2014-05-24 05:49:24Z 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
27#include <algorithm>
28#include <functional>
29#include <iterator>
30#include <vector>
31
32namespace theplu {
33namespace yat {
34namespace utility {
35
36  /**
37     Create a vector \a sort_index containing the indeces of elements
38     in a range [first, last). The elements of \a sort_index give the
39     index of the range element which would have been stored in that
40     position if the range had been sorted in place. The first element
41     of \a sort_index gives the index of the least element in the
42     range, and the last element of \a sort_index gives the index of
43     the greatest element in the range. The function will not affect
44     the range, i.e., ForwardIterator can be read-only.
45
46     Type Requirements:
47     - \c InputIterator is a model of \input_iterator
48     - \c InputIterator::value_type is
49     <a href=http://www.sgi.com/tech/stl/LessThanComparable.html>
50     LessThan Comparable</a>
51
52     \since New in yat 0.5. In versions prior 0.13 function was restricted to
53     \forward_iterator and \c value_type of \c double.
54  */
55  template<typename InputIterator>
56  void sort_index(InputIterator first, InputIterator last,
57                  std::vector<size_t>& sort_index);
58
59  /**
60     Same as sort_index(InputIterator, InputIterator,std::vector<size_t>&),
61     but objects are compared with \c comp rather than with \c operator<.
62
63     Type Requirements:
64     - \c InputIterator is a model of \input_iterator
65     - \c Compare is a model of
66     <a href="http://www.sgi.com/tech/stl/StrictWeakOrdering.html">
67     Strict Weak Ordering</a>
68     - \c InputIterator::value_type is convertible to \c Compare's
69       argument type
70
71     \since New in yat 0.13
72   */
73  template<typename InputIterator, class Compare>
74  void sort_index(InputIterator first, InputIterator last,
75                  std::vector<size_t>& sort_index, Compare comp);
76
77
78  /// \cond IGNORE_DOXYGEN
79
80  // private stuff
81  namespace detail {
82
83    template<typename InputIterator, class Compare>
84    void sort_index(InputIterator first, InputIterator last,
85                    std::vector<size_t>& idx, Compare comp,
86                    std::input_iterator_tag);
87
88    // Specialization for random access iterator
89    template<typename RandomAccessIterator, class Compare>
90    void sort_index(RandomAccessIterator first, RandomAccessIterator last,
91                    std::vector<size_t>& idx, Compare comp,
92                    std::random_access_iterator_tag);
93
94
95    template<typename RandomAccessIterator, class Compare>
96    class sort_index_Compare
97    {
98    public:
99      sort_index_Compare(RandomAccessIterator it, Compare comp)
100        : data_(it), compare_(comp) {}
101
102      bool operator()(size_t i, size_t j) const
103      { return compare_(data_[i], data_[j]); }
104
105    private:
106      RandomAccessIterator data_;
107      Compare compare_;
108    };
109
110  } // end of namespace detail
111
112  /// \endcond
113
114
115  //////////////  template implementation ///////////////////////////
116
117  template<typename InputIterator>
118  void sort_index(InputIterator first, InputIterator last,
119                  std::vector<size_t>& idx)
120  {
121    BOOST_CONCEPT_ASSERT((boost::InputIterator<InputIterator>));
122    typedef typename std::iterator_traits<InputIterator>::value_type T;
123    BOOST_CONCEPT_ASSERT((boost::LessThanComparable<T>));
124    sort_index(first, last, idx, std::less<T>());
125  }
126
127
128  template<typename InputIterator, class Compare>
129  void sort_index(InputIterator first, InputIterator last,
130                  std::vector<size_t>& idx, Compare comp)
131  {
132    BOOST_CONCEPT_ASSERT((boost::InputIterator<InputIterator>));
133   
134    typedef typename std::iterator_traits<InputIterator> traits;
135    typedef typename traits::iterator_category category;
136    detail::sort_index(first, last, idx, comp, category());
137  }
138
139
140  // implementation of private functions
141  namespace detail {
142
143    // general implementation. copy range to a std::vector and call
144    // random access version.
145    template<typename InputIterator, class Compare>
146    void sort_index(InputIterator first, InputIterator last,
147                    std::vector<size_t>& idx, Compare comp,
148                    std::input_iterator_tag tag)
149    {
150      typedef typename std::iterator_traits<InputIterator>::value_type T;
151      std::vector<T> vec(first, last);
152      sort_index(vec.begin(), vec.end(), idx, comp,
153                 std::random_access_iterator_tag());
154    }
155
156    // Specialization for random access iterator
157    template<typename RandomAccessIterator, class Compare>
158    void sort_index(RandomAccessIterator first, RandomAccessIterator last,
159                    std::vector<size_t>& idx, Compare comp,
160                    std::random_access_iterator_tag tag)
161    {
162      sort_index_Compare<RandomAccessIterator, Compare> compare(first, comp);
163      // Peter would like to use boost::iota here, but that is only
164      // available in boost v1.50 and newer, which is too recent at
165      // time of writing.
166      size_t n = last-first;
167      idx.clear();
168      idx.reserve(n);
169      for (size_t i=0; i<n; ++i)
170        idx.push_back(i);
171      std::sort(idx.begin(), idx.end(), compare);
172    }
173
174  } // end of namespace detail
175
176}}} // of namespace utility, yat, and theplu
177
178#endif
Note: See TracBrowser for help on using the repository browser.