File indexing completed on 2025-01-18 09:35:32
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #ifndef BOOST_GEOMETRY_INDEX_DETAIL_MINMAX_HEAP_HPP
0011 #define BOOST_GEOMETRY_INDEX_DETAIL_MINMAX_HEAP_HPP
0012
0013 #include <iterator>
0014 #include <limits.h>
0015 #include <type_traits>
0016 #include <utility>
0017
0018 #ifdef _MSC_VER
0019 #include <intrin.h>
0020 #endif
0021
0022 namespace boost { namespace geometry { namespace index { namespace detail
0023 {
0024
0025
0026
0027
0028
0029
0030
0031
0032 namespace minmax_heap_detail
0033 {
0034
0035 template <typename T>
0036 using bitsize = std::integral_constant<std::size_t, sizeof(T) * CHAR_BIT>;
0037
0038 template <typename It>
0039 using diff_t = typename std::iterator_traits<It>::difference_type;
0040 template <typename It>
0041 using val_t = typename std::iterator_traits<It>::value_type;
0042
0043
0044
0045 template <typename T, std::enable_if_t<!std::is_integral<T>::value || (bitsize<T>::value != 32 && bitsize<T>::value != 64), int> = 0>
0046 inline int level(T i)
0047 {
0048 ++i;
0049 int r = 0;
0050 while (i >>= 1) { ++r; }
0051 return r;
0052 }
0053
0054
0055
0056
0057
0058
0059
0060
0061 #ifdef _MSC_VER
0062
0063 template <typename T, std::enable_if_t<std::is_integral<T>::value && bitsize<T>::value == 32, int> = 0>
0064 inline int level(T i)
0065 {
0066 unsigned long r = 0;
0067 _BitScanReverse(&r, (unsigned long)(i + 1));
0068 return int(r);
0069 }
0070
0071 template <typename T, std::enable_if_t<std::is_integral<T>::value && bitsize<T>::value == 64, int> = 0>
0072 inline int level(T i)
0073 {
0074 unsigned long r = 0;
0075 #ifdef _WIN64
0076 _BitScanReverse64(&r, (unsigned long long)(i + 1));
0077 #else
0078 if (_BitScanReverse(&r, (unsigned long)((i + 1) >> 32))) { r += 32; }
0079 else { _BitScanReverse(&r, (unsigned long)(i + 1)); }
0080 #endif
0081 return int(r);
0082 }
0083
0084 #elif defined(__clang__) || defined(__GNUC__)
0085
0086
0087
0088 template <typename T, std::enable_if_t<std::is_integral<T>::value && bitsize<T>::value == 32, int> = 0>
0089 inline int level(T i)
0090 {
0091 return 31 - __builtin_clzl((unsigned long)(i + 1));
0092 }
0093
0094 template <typename T, std::enable_if_t<std::is_integral<T>::value && bitsize<T>::value == 64, int> = 0>
0095 inline int level(T i)
0096 {
0097 return 63 - __builtin_clzll((unsigned long long)(i + 1));
0098 }
0099
0100 #else
0101
0102 template <typename T, std::enable_if_t<std::is_integral<T>::value && bitsize<T>::value == 32, int> = 0>
0103 inline int level(T i)
0104 {
0105 ++i;
0106 int r = 0;
0107 if (i >= 65536) { r += 16; i >>= 16; }
0108 if (i >= 256) { r += 8; i >>= 8; }
0109 if (i >= 16) { r += 4; i >>= 4; }
0110 if (i >= 4) { r += 2; i >>= 2; }
0111 if (i >= 2) { r += 1; i >>= 1; }
0112 return r;
0113 }
0114
0115 template <typename T, std::enable_if_t<std::is_integral<T>::value && bitsize<T>::value == 64, int> = 0>
0116 inline int level(T i)
0117 {
0118 ++i;
0119 int r = 0;
0120 if (i >= 4294967296ll) { r += 32; i >>= 32; }
0121 if (i >= 65536ll) { r += 16; i >>= 16; }
0122 if (i >= 256ll) { r += 8; i >>= 8; }
0123 if (i >= 16ll) { r += 4; i >>= 4; }
0124 if (i >= 4ll) { r += 2; i >>= 2; }
0125 if (i >= 2ll) { r += 1; i >>= 1; }
0126 return r;
0127 }
0128
0129 #endif
0130
0131
0132
0133 struct min_call
0134 {
0135 template <typename Compare, typename T1, typename T2>
0136 bool operator()(Compare&& comp, T1 const& v1, T2 const& v2) const
0137 {
0138 return comp(v1, v2);
0139 }
0140 };
0141
0142 struct max_call
0143 {
0144 template <typename Compare, typename T1, typename T2>
0145 bool operator()(Compare&& comp, T1 const& v1, T2 const& v2) const
0146 {
0147 return comp(v2, v1);
0148 }
0149 };
0150
0151
0152 template <typename Call, typename It, typename Compare>
0153 inline void push_heap2(It first, diff_t<It> c, val_t<It> val, Compare comp)
0154 {
0155 while (c > 2)
0156 {
0157 diff_t<It> const g = (c - 3) >> 2;
0158 if (! Call()(comp, val, *(first + g)))
0159 {
0160 break;
0161 }
0162 *(first + c) = std::move(*(first + g));
0163 c = g;
0164 }
0165
0166 *(first + c) = std::move(val);
0167 }
0168
0169 template <typename MinCall, typename MaxCall, typename It, typename Compare>
0170 inline void push_heap1(It first, diff_t<It> c, val_t<It> val, Compare comp)
0171 {
0172 diff_t<It> const p = (c - 1) >> 1;
0173 if (MinCall()(comp, *(first + p), val))
0174 {
0175 *(first + c) = std::move(*(first + p));
0176 return push_heap2<MaxCall>(first, p, std::move(val), comp);
0177 }
0178 else
0179 {
0180 return push_heap2<MinCall>(first, c, std::move(val), comp);
0181 }
0182 }
0183
0184 template <typename MinCall, typename MaxCall, typename It, typename Compare>
0185 inline void push_heap(It first, It last, Compare comp)
0186 {
0187 diff_t<It> const size = last - first;
0188 if (size < 2)
0189 {
0190 return;
0191 }
0192
0193 diff_t<It> c = size - 1;
0194 val_t<It> val = std::move(*(first + c));
0195 if (level(c) % 2 == 0)
0196 {
0197 push_heap1<MinCall, MaxCall>(first, c, std::move(val), comp);
0198 }
0199 else
0200 {
0201 push_heap1<MaxCall, MinCall>(first, c, std::move(val), comp);
0202 }
0203 }
0204
0205
0206 template <typename Call, typename It, typename Compare>
0207 inline diff_t<It> pick_grandchild4(It first, diff_t<It> f, Compare comp)
0208 {
0209 It it = first + f;
0210 diff_t<It> m1 = Call()(comp, *(it), *(it + 1)) ? f : f + 1;
0211 diff_t<It> m2 = Call()(comp, *(it + 2), *(it + 3)) ? f + 2 : f + 3;
0212 return Call()(comp, *(first + m1), *(first + m2)) ? m1 : m2;
0213 }
0214
0215
0216
0217
0218
0219
0220
0221
0222
0223
0224
0225
0226
0227
0228
0229 template <typename Call, typename It, typename Compare>
0230 inline void pop_heap1(It first, diff_t<It> p, diff_t<It> size, val_t<It> val, Compare comp)
0231 {
0232 if (size >= 7)
0233 {
0234 diff_t<It> const last_g = (size - 3) >> 2;
0235 while (p < last_g)
0236 {
0237 diff_t<It> const ll = 4 * p + 3;
0238 diff_t<It> const m = pick_grandchild4<Call>(first, ll, comp);
0239
0240 if (! Call()(comp, *(first + m), val))
0241 {
0242 break;
0243 }
0244
0245 *(first + p) = std::move(*(first + m));
0246
0247 diff_t<It> par = (m - 1) >> 1;
0248 if (Call()(comp, *(first + par), val))
0249 {
0250 using std::swap;
0251 swap(*(first + par), val);
0252 }
0253
0254 p = m;
0255 }
0256 }
0257
0258 if (size >= 2 && p <= ((size - 2) >> 1))
0259 {
0260 diff_t<It> const l = 2 * p + 1;
0261 diff_t<It> m = l;
0262 if (size >= 3 && p <= ((size - 3) >> 1))
0263 {
0264
0265 diff_t<It> m2 = l + 1;
0266 if (size >= 4 && p <= ((size - 4) >> 2))
0267 {
0268 diff_t<It> const ll = 2 * l + 1;
0269 m = ll;
0270
0271 if (size >= 5 && p <= ((size - 5) >> 2))
0272 {
0273 m = Call()(comp, *(first + ll), *(first + ll + 1)) ? ll : (ll + 1);
0274
0275 if (size >= 6 && p <= ((size - 6) >> 2))
0276 {
0277
0278 m2 = ll + 2;
0279 }
0280 }
0281 }
0282
0283 m = Call()(comp, *(first + m), *(first + m2)) ? m : m2;
0284 }
0285
0286 if (Call()(comp, *(first + m), val))
0287 {
0288 *(first + p) = std::move(*(first + m));
0289
0290 if (m >= 3 && p <= ((m - 3) >> 2))
0291 {
0292 diff_t<It> par = (m - 1) >> 1;
0293 if (Call()(comp, *(first + par), val))
0294 {
0295 using std::swap;
0296 swap(*(first + par), val);
0297 }
0298 }
0299
0300 p = m;
0301 }
0302 }
0303
0304 *(first + p) = std::move(val);
0305 }
0306
0307 template <typename MinCall, typename MaxCall, typename It, typename Compare>
0308 inline void pop_heap(It first, It el, It last, Compare comp)
0309 {
0310 diff_t<It> size = last - first;
0311 if (size < 2)
0312 {
0313 return;
0314 }
0315
0316 --last;
0317 val_t<It> val = std::move(*last);
0318 *last = std::move(*el);
0319
0320
0321 --size;
0322
0323 diff_t<It> p = el - first;
0324 if (level(p) % 2 == 0)
0325 {
0326 pop_heap1<MinCall>(first, p, size, std::move(val), comp);
0327 }
0328 else
0329 {
0330 pop_heap1<MaxCall>(first, p, size, std::move(val), comp);
0331 }
0332 }
0333
0334 template <typename MinCall, typename MaxCall, typename It, typename Compare>
0335 inline void make_heap(It first, It last, Compare comp)
0336 {
0337 diff_t<It> size = last - first;
0338 diff_t<It> p = size / 2;
0339 if (p <= 0)
0340 {
0341 return;
0342 }
0343
0344 int level_p = level(p - 1);
0345 diff_t<It> level_f = (diff_t<It>(1) << level_p) - 1;
0346 while (p > 0)
0347 {
0348 --p;
0349 val_t<It> val = std::move(*(first + p));
0350 if (level_p % 2 == 0)
0351 {
0352 pop_heap1<MinCall>(first, p, size, std::move(val), comp);
0353 }
0354 else
0355 {
0356 pop_heap1<MaxCall>(first, p, size, std::move(val), comp);
0357 }
0358
0359 if (p == level_f)
0360 {
0361 --level_p;
0362 level_f >>= 1;
0363 }
0364 }
0365 }
0366
0367 template <typename Call, typename It, typename Compare>
0368 inline bool is_heap(It first, It last, Compare comp)
0369 {
0370 diff_t<It> const size = last - first;
0371 diff_t<It> pow2 = 4;
0372 bool is_min_level = false;
0373 for (diff_t<It> i = 1; i < size; ++i)
0374 {
0375 if (i == pow2 - 1)
0376 {
0377 pow2 *= 2;
0378 is_min_level = ! is_min_level;
0379 }
0380
0381 diff_t<It> const p = (i - 1) >> 1;
0382 if (is_min_level)
0383 {
0384 if (Call()(comp, *(first + p), *(first + i)))
0385 {
0386 return false;
0387 }
0388 }
0389 else
0390 {
0391 if (Call()(comp, *(first + i), *(first + p)))
0392 {
0393 return false;
0394 }
0395 }
0396
0397 if (i >= 3)
0398 {
0399 diff_t<It> const g = (p - 1) >> 1;
0400 if (is_min_level)
0401 {
0402 if (Call()(comp, *(first + i), *(first + g)))
0403 {
0404 return false;
0405 }
0406 }
0407 else
0408 {
0409 if (Call()(comp, *(first + g), *(first + i)))
0410 {
0411 return false;
0412 }
0413 }
0414 }
0415 }
0416 return true;
0417 }
0418
0419 template <typename Call, typename It, typename Compare>
0420 inline It bottom_heap(It first, It last, Compare comp)
0421 {
0422 diff_t<It> const size = last - first;
0423 return size <= 1 ? first :
0424 size == 2 ? (first + 1) :
0425 Call()(comp, *(first + 1), *(first + 2)) ? (first + 2) : (first + 1);
0426 }
0427
0428 }
0429
0430
0431 template <typename It, typename Compare>
0432 inline void push_minmax_heap(It first, It last, Compare comp)
0433 {
0434 using namespace minmax_heap_detail;
0435 minmax_heap_detail::push_heap<min_call, max_call>(first, last, comp);
0436 }
0437
0438 template <typename It>
0439 inline void push_minmax_heap(It first, It last)
0440 {
0441 using namespace minmax_heap_detail;
0442 minmax_heap_detail::push_heap<min_call, max_call>(first, last, std::less<>());
0443 }
0444
0445 template <typename It, typename Compare>
0446 inline void pop_top_minmax_heap(It first, It last, Compare comp)
0447 {
0448 using namespace minmax_heap_detail;
0449 pop_heap<min_call, max_call>(first, first, last, comp);
0450 }
0451
0452 template <typename It>
0453 inline void pop_top_minmax_heap(It first, It last)
0454 {
0455 using namespace minmax_heap_detail;
0456 pop_heap<min_call, max_call>(first, first, last, std::less<>());
0457 }
0458
0459 template <typename It, typename Compare>
0460 inline void pop_bottom_minmax_heap(It first, It last, Compare comp)
0461 {
0462 using namespace minmax_heap_detail;
0463 It bottom = minmax_heap_detail::bottom_heap<min_call>(first, last, comp);
0464 pop_heap<min_call, max_call>(first, bottom, last, comp);
0465 }
0466
0467 template <typename It>
0468 inline void pop_bottom_minmax_heap(It first, It last)
0469 {
0470 using namespace minmax_heap_detail;
0471 auto&& comp = std::less<>();
0472 It bottom = minmax_heap_detail::bottom_heap<min_call>(first, last, comp);
0473 pop_heap<min_call, max_call>(first, bottom, last, comp);
0474 }
0475
0476 template <typename It, typename Compare>
0477 inline void make_minmax_heap(It first, It last, Compare comp)
0478 {
0479 using namespace minmax_heap_detail;
0480 return minmax_heap_detail::make_heap<min_call, max_call>(first, last, comp);
0481 }
0482
0483 template <typename It>
0484 inline void make_minmax_heap(It first, It last)
0485 {
0486 using namespace minmax_heap_detail;
0487 return minmax_heap_detail::make_heap<min_call, max_call>(first, last, std::less<>());
0488 }
0489
0490 template <typename It, typename Compare>
0491 inline bool is_minmax_heap(It first, It last, Compare comp)
0492 {
0493 using namespace minmax_heap_detail;
0494 return minmax_heap_detail::is_heap<min_call>(first, last, comp);
0495 }
0496
0497 template <typename It>
0498 inline bool is_minmax_heap(It first, It last)
0499 {
0500 using namespace minmax_heap_detail;
0501 return minmax_heap_detail::is_heap<min_call>(first, last, std::less<>());
0502 }
0503
0504 template <typename It, typename Compare>
0505 inline decltype(auto) bottom_minmax_heap(It first, It last, Compare comp)
0506 {
0507 using namespace minmax_heap_detail;
0508 return *minmax_heap_detail::bottom_heap<min_call>(first, last, comp);
0509 }
0510
0511 template <typename It>
0512 inline decltype(auto) bottom_minmax_heap(It first, It last)
0513 {
0514 using namespace minmax_heap_detail;
0515 return *minmax_heap_detail::bottom_heap<min_call>(first, last, std::less<>());
0516 }
0517
0518
0519 }}}}
0520
0521 #endif