summaryrefslogtreecommitdiff
path: root/src/swapping_sort.icc
blob: 30c703a6a95f2b723c47647946a413a6ccc8b15a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
/* Sorting objects for which copies cost more than swaps.  -*- C++ -*-
   Copyright (C) 2001-2010 Roberto Bagnara <bagnara@cs.unipr.it>
   Copyright (C) 2010-2011 BUGSENG srl (http://bugseng.com)

This file is part of the Parma Polyhedra Library (PPL).

The PPL is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 3 of the License, or (at your
option) any later version.

The PPL is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307, USA.

For the most up-to-date information see the Parma Polyhedra Library
site: http://www.cs.unipr.it/ppl/ . */

#ifndef PPL_swapping_sort_icc
#define PPL_swapping_sort_icc 1

#include <vector>
#include <algorithm>

namespace {

template <typename RA_Container, typename Compare>
struct Indirect_Sort_Compare {
  typedef typename RA_Container::size_type size_type;

  Indirect_Sort_Compare(const RA_Container& cont,
                        size_type base = 0,
                        Compare comp = Compare())
    : container(cont), base_index(base), compare(comp) {
  }

  bool operator()(size_type i, size_type j) const {
    return compare(container[base_index + i], container[base_index + j]);
  }

  const RA_Container& container;
  const size_type base_index;
  const Compare compare;
}; // struct Indirect_Sort_Compare

template <typename RA_Container>
struct Indirect_Unique_Compare {
  typedef typename RA_Container::size_type size_type;

  Indirect_Unique_Compare(const RA_Container& cont, size_type base = 0)
    : container(cont), base_index(base) {
  }

  bool operator()(size_type i, size_type j) const {
    return container[base_index + i] == container[base_index + j];
  }

  const RA_Container& container;
  const size_type base_index;
}; // struct Indirect_Unique_Compare

template <typename RA_Container>
struct Indirect_Swapper {
  typedef typename RA_Container::size_type size_type;

  Indirect_Swapper(RA_Container& cont, size_type base = 0)
    : container(cont), base_index(base) {
  }

  void operator()(size_type i, size_type j) const {
    std::swap(container[base_index + i], container[base_index + j]);
  }

  RA_Container& container;
  const size_type base_index;
}; // struct Indirect_Swapper

template <typename RA_Container1, typename RA_Container2>
struct Indirect_Swapper2 {
  typedef typename RA_Container1::size_type size_type;

  Indirect_Swapper2(RA_Container1& cont1, RA_Container2& cont2)
    : container1(cont1), container2(cont2) {
  }

  void operator()(size_type i, size_type j) const {
    std::swap(container1[i], container1[j]);
    std::swap(container2[i], container2[j]);
  }

  RA_Container1& container1;
  RA_Container2& container2;
}; // struct Indirect_Swapper2

template <typename Sort_Comparer, typename Unique_Comparer, typename Swapper>
typename Sort_Comparer::size_type
indirect_sort_and_unique(typename Sort_Comparer::size_type num_elems,
                         Sort_Comparer sort_cmp,
                         Unique_Comparer unique_cmp,
                         Swapper indirect_swap) {
  typedef typename Sort_Comparer::size_type index_type;
  // `iv' is a vector of indices for the portion of rows to be sorted.
  PPL_ASSERT(num_elems >= 2);
  std::vector<index_type> iv;
  iv.reserve(num_elems);
  for (index_type i = 0, i_end = num_elems; i != i_end; ++i)
    iv.push_back(i);

  typedef typename std::vector<index_type>::iterator Iter;
  const Iter iv_begin = iv.begin();
  Iter iv_end = iv.end();

  // Sort `iv' by comparing the rows indexed by its elements.
  std::sort(iv_begin, iv_end, sort_cmp);

  // Swap the indexed rows according to `iv':
  // for each index `i', the element that should be placed in
  // position dst = i is the one placed in position src = iv[i].
  for (index_type i = num_elems; i-- > 0; ) {
    if (i != iv[i]) {
      index_type dst = i;
      index_type src = iv[i];
      do {
        indirect_swap(src, dst);
        iv[dst] = dst;
        dst = src;
        src = iv[dst];
      } while (i != src);
      iv[dst] = dst;
    }
  }

  // Restore `iv' indices to 0 .. num_elems-1 for the call to unique.
  for (index_type i = num_elems; i-- > 0; )
    iv[i] = i;

  // Unique `iv' by comparing the rows indexed by its elements.
  iv_end = std::unique(iv_begin, iv_end, unique_cmp);

  const index_type num_sorted = iv_end - iv_begin;
  const index_type num_duplicates = num_elems - num_sorted;
  if (num_duplicates == 0)
    return 0;

  // There were duplicates: swap the rows according to `iv'.
  index_type dst = 0;
  while (dst < num_sorted && dst == iv[dst])
    ++dst;
  if (dst == num_sorted)
    return num_duplicates;
  do {
    const index_type src = iv[dst];
    indirect_swap(src, dst);
    ++dst;
  }
  while (dst < num_sorted);
  return num_duplicates;
}

} // namespace

#endif // !defined(PPL_swapping_sort_icc)