Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:35:32

0001 // Boost.Geometry
0002 
0003 // Copyright (c) 2021-2023, Oracle and/or its affiliates.
0004 // Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
0005 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
0006 
0007 // Licensed under the Boost Software License version 1.0.
0008 // http://www.boost.org/users/license.html
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 // msvc and clang-win
0019 #include <intrin.h>
0020 #endif
0021 
0022 namespace boost { namespace geometry { namespace index { namespace detail
0023 {
0024 
0025 // Resources:
0026 // https://en.wikipedia.org/wiki/Min-max_heap
0027 // http://akira.ruc.dk/~keld/teaching/algoritmedesign_f03/Artikler/02/Atkinson86.pdf
0028 // https://probablydance.com/2020/08/31/on-modern-hardware-the-min-max-heap-beats-a-binary-heap/
0029 // https://stackoverflow.com/questions/6531543/efficient-implementation-of-binary-heaps
0030 // https://stackoverflow.com/questions/994593/how-to-do-an-integer-log2-in-c
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 // TODO: In C++20 use std::bit_width()
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 //template <typename T>
0055 //inline int level(T i)
0056 //{
0057 //    using std::log2;
0058 //    return int(log2(i + 1));
0059 //}
0060 
0061 #ifdef _MSC_VER // msvc and clang-win
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 // Only available in gcc-10 and clang-10
0086 //#elif defined(__has_builtin) && __has_builtin(__builtin_clzl) && __has_builtin(__builtin_clzll)
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 // min/max functions only differ in the order of arguments in comp
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; // grandparent index
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; // parent index
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; // back index
0194     val_t<It> val = std::move(*(first + c));
0195     if (level(c) % 2 == 0) // is min level
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 //template <typename Call, typename It, typename Compare>
0216 //inline diff_t<It> pick_descendant(It first, diff_t<It> f, diff_t<It> l, Compare comp)
0217 //{
0218 //    diff_t<It> m = f;
0219 //    for (++f; f != l; ++f)
0220 //    {
0221 //        if (Call()(comp, *(first + f), *(first + m)))
0222 //        {
0223 //            m = f;
0224 //        }
0225 //    }
0226 //    return m;
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) // grandparent of 4 grandchildren is possible
0233     {
0234         diff_t<It> const last_g = (size - 3) >> 2; // grandparent of the element behind back
0235         while (p < last_g) // p is grandparent of 4 grandchildren
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)) // at least one child
0259     {
0260         diff_t<It> const l = 2 * p + 1;
0261         diff_t<It> m = l; // left child
0262         if (size >= 3 && p <= ((size - 3) >> 1)) // at least two children
0263         {
0264             // m = left child
0265             diff_t<It> m2 = l + 1; // right child
0266             if (size >= 4 && p <= ((size - 4) >> 2)) // at least two children and one grandchild
0267             {
0268                 diff_t<It> const ll = 2 * l + 1;
0269                 m = ll; // left most grandchild
0270                 // m2 = right child
0271                 if (size >= 5 && p <= ((size - 5) >> 2)) // at least two children and two grandchildren
0272                 {
0273                     m = Call()(comp, *(first + ll), *(first + ll + 1)) ? ll : (ll + 1); // greater of the left grandchildren
0274                     // m2 = right child
0275                     if (size >= 6 && p <= ((size - 6) >> 2)) // at least two children and three grandchildren
0276                     {
0277                         // m = greater of the left grandchildren
0278                         m2 = ll + 2; // third grandchild
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)) // is p grandparent of m
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     // Ignore the last element
0321     --size;
0322 
0323     diff_t<It> p = el - first;
0324     if (level(p) % 2 == 0) // is min level
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) // is min level
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 } // namespace minmax_heap_detail
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 }}}} // namespace boost::geometry::index::detail
0520 
0521 #endif // BOOST_GEOMETRY_INDEX_DETAIL_MINMAX_HEAP_HPP