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

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

sort_index: add some compile tests, CONCEPT_ASSERTs, and add docs on requirements the compiler tests revealed.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 6.5 KB
Line 
1#ifndef _theplu_yat_utility_sort_index_
2#define _theplu_yat_utility_sort_index_
3
4// $Id: sort_index.h 3238 2014-05-24 10:27:39Z 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     - \c InputIterator::value_type is
52     <a href=http://www.sgi.com/tech/stl/DefaultConstructible.html>
53     Default Constructible</a> and
54     <a href=http://www.sgi.com/tech/stl/Assignable.html>
55     Assignable</a>
56
57     \since New in yat 0.5. In versions prior 0.13 function was restricted to
58     \forward_iterator with \c value_type convertible to \c double.
59  */
60  template<typename InputIterator>
61  void sort_index(InputIterator first, InputIterator last,
62                  std::vector<size_t>& sort_index);
63
64  /**
65     Same as sort_index(InputIterator, InputIterator,std::vector<size_t>&),
66     but objects are compared with \c comp rather than with \c operator<.
67
68     Type Requirements:
69     - \c InputIterator is a model of \input_iterator
70     - \c Compare is a model of
71     <a href="http://www.sgi.com/tech/stl/StrictWeakOrdering.html">
72     Strict Weak Ordering</a>
73     - \c Compare is
74     <a href="http://www.sgi.com/tech/stl/Assignable.html">
75     Assignable</a>
76     - \c InputIterator::value_type is
77     <a href=http://www.sgi.com/tech/stl/DefaultConstructible.html>
78     Default Constructible</a> and
79     <a href=http://www.sgi.com/tech/stl/Assignable.html>
80     Assignable</a>
81     - \c InputIterator::value_type is convertible to \c Compare's
82       argument type
83
84     \since New in yat 0.13
85   */
86  template<typename InputIterator, class Compare>
87  void sort_index(InputIterator first, InputIterator last,
88                  std::vector<size_t>& sort_index, Compare comp);
89
90
91  /// \cond IGNORE_DOXYGEN
92
93  // private stuff
94  namespace detail {
95
96    template<typename InputIterator, class Compare>
97    void sort_index(InputIterator first, InputIterator last,
98                    std::vector<size_t>& idx, Compare comp,
99                    std::input_iterator_tag);
100
101    // Specialization for random access iterator
102    template<typename RandomAccessIterator, class Compare>
103    void sort_index(RandomAccessIterator first, RandomAccessIterator last,
104                    std::vector<size_t>& idx, Compare comp,
105                    std::random_access_iterator_tag);
106
107
108    template<typename RandomAccessIterator, class Compare>
109    class sort_index_Compare
110    {
111    public:
112      sort_index_Compare(RandomAccessIterator it, Compare comp)
113        : data_(it), compare_(comp) {}
114
115      bool operator()(size_t i, size_t j) const
116      { return compare_(data_[i], data_[j]); }
117
118    private:
119      RandomAccessIterator data_;
120      Compare compare_;
121    };
122
123  } // end of namespace detail
124
125  /// \endcond
126
127
128  //////////////  template implementation ///////////////////////////
129
130  template<typename InputIterator>
131  void sort_index(InputIterator first, InputIterator last,
132                  std::vector<size_t>& idx)
133  {
134    BOOST_CONCEPT_ASSERT((boost::InputIterator<InputIterator>));
135    typedef typename std::iterator_traits<InputIterator>::value_type T;
136    BOOST_CONCEPT_ASSERT((boost::DefaultConstructible<T>));
137    BOOST_CONCEPT_ASSERT((boost::SGIAssignable<T>));
138    BOOST_CONCEPT_ASSERT((boost::LessThanComparable<T>));
139    sort_index(first, last, idx, std::less<T>());
140  }
141
142
143  template<typename InputIterator, class Compare>
144  void sort_index(InputIterator first, InputIterator last,
145                  std::vector<size_t>& idx, Compare comp)
146  {
147    BOOST_CONCEPT_ASSERT((boost::InputIterator<InputIterator>));
148    typedef typename std::iterator_traits<InputIterator> traits;
149    typedef typename std::iterator_traits<InputIterator>::value_type T;
150    BOOST_CONCEPT_ASSERT((boost::DefaultConstructible<T>));
151    BOOST_CONCEPT_ASSERT((boost::SGIAssignable<T>));
152    BOOST_CONCEPT_ASSERT((boost::Assignable<Compare>));
153
154    typedef typename traits::iterator_category category;
155    detail::sort_index(first, last, idx, comp, category());
156  }
157
158
159  // implementation of private functions
160  namespace detail {
161
162    // general implementation. copy range to a std::vector and call
163    // random access version.
164    template<typename InputIterator, class Compare>
165    void sort_index(InputIterator first, InputIterator last,
166                    std::vector<size_t>& idx, Compare comp,
167                    std::input_iterator_tag tag)
168    {
169      typedef typename std::iterator_traits<InputIterator>::value_type T;
170      std::vector<T> vec(first, last);
171      sort_index(vec.begin(), vec.end(), idx, comp,
172                 std::random_access_iterator_tag());
173    }
174
175    // Specialization for random access iterator
176    template<typename RandomAccessIterator, class Compare>
177    void sort_index(RandomAccessIterator first, RandomAccessIterator last,
178                    std::vector<size_t>& idx, Compare comp,
179                    std::random_access_iterator_tag tag)
180    {
181      sort_index_Compare<RandomAccessIterator, Compare> compare(first, comp);
182      // Peter would like to use boost::iota here, but that is only
183      // available in boost v1.50 and newer, which is too recent at
184      // time of writing.
185      size_t n = last-first;
186      idx.clear();
187      idx.reserve(n);
188      for (size_t i=0; i<n; ++i)
189        idx.push_back(i);
190      std::sort(idx.begin(), idx.end(), compare);
191    }
192
193  } // end of namespace detail
194
195}}} // of namespace utility, yat, and theplu
196
197#endif
Note: See TracBrowser for help on using the repository browser.