File indexing completed on 2025-01-18 09:40:51
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038 #ifndef BOOST_MOVE_ALGO_PDQSORT_HPP
0039 #define BOOST_MOVE_ALGO_PDQSORT_HPP
0040
0041 #ifndef BOOST_CONFIG_HPP
0042 # include <boost/config.hpp>
0043 #endif
0044 #
0045 #if defined(BOOST_HAS_PRAGMA_ONCE)
0046 # pragma once
0047 #endif
0048
0049 #include <boost/move/detail/config_begin.hpp>
0050
0051 #include <boost/move/detail/workaround.hpp>
0052 #include <boost/move/utility_core.hpp>
0053 #include <boost/move/algo/detail/insertion_sort.hpp>
0054 #include <boost/move/algo/detail/heap_sort.hpp>
0055 #include <boost/move/detail/iterator_traits.hpp>
0056
0057 #include <boost/move/adl_move_swap.hpp>
0058 #include <cstddef>
0059
0060 #if defined(BOOST_CLANG) || (defined(BOOST_GCC) && (BOOST_GCC >= 40600))
0061 #pragma GCC diagnostic push
0062 #pragma GCC diagnostic ignored "-Wsign-conversion"
0063 #endif
0064
0065 namespace boost {
0066 namespace movelib {
0067
0068 namespace pdqsort_detail {
0069
0070
0071 template<class T1, class T2>
0072 struct pair
0073 {
0074 pair()
0075 {}
0076
0077 pair(const T1 &t1, const T2 &t2)
0078 : first(t1), second(t2)
0079 {}
0080
0081 T1 first;
0082 T2 second;
0083 };
0084
0085 enum {
0086
0087 insertion_sort_threshold = 24,
0088
0089
0090 ninther_threshold = 128,
0091
0092
0093
0094 partial_insertion_sort_limit = 8,
0095
0096
0097 block_size = 64,
0098
0099
0100 cacheline_size = 64
0101
0102 };
0103
0104
0105 template<class Unsigned>
0106 Unsigned log2(Unsigned n) {
0107 Unsigned log = 0;
0108 while (n >>= 1) ++log;
0109 return log;
0110 }
0111
0112
0113
0114
0115 template<class Iter, class Compare>
0116 inline bool partial_insertion_sort(Iter begin, Iter end, Compare comp) {
0117 typedef typename boost::movelib::iterator_traits<Iter>::value_type T;
0118 typedef typename boost::movelib:: iter_size<Iter>::type size_type;
0119 if (begin == end) return true;
0120
0121 size_type limit = 0;
0122 for (Iter cur = begin + 1; cur != end; ++cur) {
0123 if (limit > partial_insertion_sort_limit) return false;
0124
0125 Iter sift = cur;
0126 Iter sift_1 = cur - 1;
0127
0128
0129 if (comp(*sift, *sift_1)) {
0130 T tmp = boost::move(*sift);
0131
0132 do { *sift-- = boost::move(*sift_1); }
0133 while (sift != begin && comp(tmp, *--sift_1));
0134
0135 *sift = boost::move(tmp);
0136 limit += size_type(cur - sift);
0137 }
0138 }
0139
0140 return true;
0141 }
0142
0143 template<class Iter, class Compare>
0144 inline void sort2(Iter a, Iter b, Compare comp) {
0145 if (comp(*b, *a)) boost::adl_move_iter_swap(a, b);
0146 }
0147
0148
0149 template<class Iter, class Compare>
0150 inline void sort3(Iter a, Iter b, Iter c, Compare comp) {
0151 sort2(a, b, comp);
0152 sort2(b, c, comp);
0153 sort2(a, b, comp);
0154 }
0155
0156
0157
0158
0159
0160
0161 template<class Iter, class Compare>
0162 pdqsort_detail::pair<Iter, bool> partition_right(Iter begin, Iter end, Compare comp) {
0163 typedef typename boost::movelib::iterator_traits<Iter>::value_type T;
0164
0165
0166 T pivot(boost::move(*begin));
0167
0168 Iter first = begin;
0169 Iter last = end;
0170
0171
0172
0173 while (comp(*++first, pivot));
0174
0175
0176
0177 if (first - 1 == begin) while (first < last && !comp(*--last, pivot));
0178 else while ( !comp(*--last, pivot));
0179
0180
0181
0182 bool already_partitioned = first >= last;
0183
0184
0185
0186
0187 while (first < last) {
0188 boost::adl_move_iter_swap(first, last);
0189 while (comp(*++first, pivot));
0190 while (!comp(*--last, pivot));
0191 }
0192
0193
0194 Iter pivot_pos = first - 1;
0195 if(begin != pivot_pos)
0196 *begin = boost::move(*pivot_pos);
0197 *pivot_pos = boost::move(pivot);
0198
0199 return pdqsort_detail::pair<Iter, bool>(pivot_pos, already_partitioned);
0200 }
0201
0202
0203
0204
0205
0206 template<class Iter, class Compare>
0207 inline Iter partition_left(Iter begin, Iter end, Compare comp) {
0208 typedef typename boost::movelib::iterator_traits<Iter>::value_type T;
0209
0210 T pivot(boost::move(*begin));
0211 Iter first = begin;
0212 Iter last = end;
0213
0214 while (comp(pivot, *--last));
0215
0216 if (last + 1 == end) while (first < last && !comp(pivot, *++first));
0217 else while ( !comp(pivot, *++first));
0218
0219 while (first < last) {
0220 boost::adl_move_iter_swap(first, last);
0221 while (comp(pivot, *--last));
0222 while (!comp(pivot, *++first));
0223 }
0224
0225 Iter pivot_pos = last;
0226 *begin = boost::move(*pivot_pos);
0227 *pivot_pos = boost::move(pivot);
0228
0229 return pivot_pos;
0230 }
0231
0232
0233 template<class Iter, class Compare>
0234 void pdqsort_loop( Iter begin, Iter end, Compare comp
0235 , typename boost::movelib:: iter_size<Iter>::type bad_allowed
0236 , bool leftmost = true)
0237 {
0238 typedef typename boost::movelib:: iter_size<Iter>::type size_type;
0239
0240
0241 while (true) {
0242 size_type size = size_type(end - begin);
0243
0244
0245 if (size < insertion_sort_threshold) {
0246 insertion_sort(begin, end, comp);
0247 return;
0248 }
0249
0250
0251 size_type s2 = size / 2;
0252 if (size > ninther_threshold) {
0253 sort3(begin, begin + s2, end - 1, comp);
0254 sort3(begin + 1, begin + (s2 - 1), end - 2, comp);
0255 sort3(begin + 2, begin + (s2 + 1), end - 3, comp);
0256 sort3(begin + (s2 - 1), begin + s2, begin + (s2 + 1), comp);
0257 boost::adl_move_iter_swap(begin, begin + s2);
0258 } else sort3(begin + s2, begin, end - 1, comp);
0259
0260
0261
0262
0263
0264
0265 if (!leftmost && !comp(*(begin - 1), *begin)) {
0266 begin = partition_left(begin, end, comp) + 1;
0267 continue;
0268 }
0269
0270
0271 pdqsort_detail::pair<Iter, bool> part_result = partition_right(begin, end, comp);
0272 Iter pivot_pos = part_result.first;
0273 bool already_partitioned = part_result.second;
0274
0275
0276 size_type l_size = size_type(pivot_pos - begin);
0277 size_type r_size = size_type(end - (pivot_pos + 1));
0278 bool highly_unbalanced = l_size < size / 8 || r_size < size / 8;
0279
0280
0281 if (highly_unbalanced) {
0282
0283 if (--bad_allowed == 0) {
0284 boost::movelib::heap_sort(begin, end, comp);
0285 return;
0286 }
0287
0288 if (l_size >= insertion_sort_threshold) {
0289 boost::adl_move_iter_swap(begin, begin + l_size / 4);
0290 boost::adl_move_iter_swap(pivot_pos - 1, pivot_pos - l_size / 4);
0291
0292 if (l_size > ninther_threshold) {
0293 boost::adl_move_iter_swap(begin + 1, begin + (l_size / 4 + 1));
0294 boost::adl_move_iter_swap(begin + 2, begin + (l_size / 4 + 2));
0295 boost::adl_move_iter_swap(pivot_pos - 2, pivot_pos - (l_size / 4 + 1));
0296 boost::adl_move_iter_swap(pivot_pos - 3, pivot_pos - (l_size / 4 + 2));
0297 }
0298 }
0299
0300 if (r_size >= insertion_sort_threshold) {
0301 boost::adl_move_iter_swap(pivot_pos + 1, pivot_pos + (1 + r_size / 4));
0302 boost::adl_move_iter_swap(end - 1, end - r_size / 4);
0303
0304 if (r_size > ninther_threshold) {
0305 boost::adl_move_iter_swap(pivot_pos + 2, pivot_pos + (2 + r_size / 4));
0306 boost::adl_move_iter_swap(pivot_pos + 3, pivot_pos + (3 + r_size / 4));
0307 boost::adl_move_iter_swap(end - 2, end - (1 + r_size / 4));
0308 boost::adl_move_iter_swap(end - 3, end - (2 + r_size / 4));
0309 }
0310 }
0311 } else {
0312
0313
0314 if (already_partitioned && partial_insertion_sort(begin, pivot_pos, comp)
0315 && partial_insertion_sort(pivot_pos + 1, end, comp)) return;
0316 }
0317
0318
0319
0320 pdqsort_loop<Iter, Compare>(begin, pivot_pos, comp, bad_allowed, leftmost);
0321 begin = pivot_pos + 1;
0322 leftmost = false;
0323 }
0324 }
0325 }
0326
0327
0328 template<class Iter, class Compare>
0329 void pdqsort(Iter begin, Iter end, Compare comp)
0330 {
0331 if (begin == end) return;
0332 typedef typename boost::movelib:: iter_size<Iter>::type size_type;
0333 pdqsort_detail::pdqsort_loop<Iter, Compare>(begin, end, comp, pdqsort_detail::log2(size_type(end - begin)));
0334 }
0335
0336 }
0337 }
0338
0339 #if defined(BOOST_CLANG) || (defined(BOOST_GCC) && (BOOST_GCC >= 40600))
0340 #pragma GCC diagnostic pop
0341 #endif
0342
0343 #include <boost/move/detail/config_end.hpp>
0344
0345 #endif