////////////////////////////////////////////////////////////////////////////// // // (C) Copyright Ion Gaztanaga 2017-2018. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // // See http://www.boost.org/libs/move for documentation. // ////////////////////////////////////////////////////////////////////////////// //! \file #ifndef BOOST_MOVE_DETAIL_HEAP_SORT_HPP #define BOOST_MOVE_DETAIL_HEAP_SORT_HPP #ifndef BOOST_CONFIG_HPP # include #endif # #if defined(BOOST_HAS_PRAGMA_ONCE) # pragma once #endif #include #include #include #include #include #include #if defined(BOOST_CLANG) || (defined(BOOST_GCC) && (BOOST_GCC >= 40600)) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wsign-conversion" #endif namespace boost { namespace movelib{ template class heap_sort_helper { typedef typename boost::movelib::iter_size::type size_type; typedef typename boost::movelib::iterator_traits::value_type value_type; static void adjust_heap(RandomAccessIterator first, size_type hole_index, size_type const len, value_type &value, Compare comp) { size_type const top_index = hole_index; size_type second_child = size_type(2u*(hole_index + 1u)); while (second_child < len) { if (comp(*(first + second_child), *(first + size_type(second_child - 1u)))) second_child--; *(first + hole_index) = boost::move(*(first + second_child)); hole_index = second_child; second_child = size_type(2u * (second_child + 1u)); } if (second_child == len) { *(first + hole_index) = boost::move(*(first + size_type(second_child - 1u))); hole_index = size_type(second_child - 1); } { //push_heap-like ending size_type parent = size_type((hole_index - 1u) / 2u); while (hole_index > top_index && comp(*(first + parent), value)) { *(first + hole_index) = boost::move(*(first + parent)); hole_index = parent; parent = size_type((hole_index - 1u) / 2u); } *(first + hole_index) = boost::move(value); } } static void make_heap(RandomAccessIterator first, RandomAccessIterator last, Compare comp) { size_type const len = size_type(last - first); if (len > 1) { size_type parent = size_type(len/2u - 1u); do { value_type v(boost::move(*(first + parent))); adjust_heap(first, parent, len, v, comp); }while (parent--); } } static void sort_heap(RandomAccessIterator first, RandomAccessIterator last, Compare comp) { size_type len = size_type(last - first); while (len > 1) { //move biggest to the safe zone --last; value_type v(boost::move(*last)); *last = boost::move(*first); adjust_heap(first, size_type(0), --len, v, comp); } } public: static void sort(RandomAccessIterator first, RandomAccessIterator last, Compare comp) { make_heap(first, last, comp); sort_heap(first, last, comp); assert(boost::movelib::is_sorted(first, last, comp)); } }; template inline void heap_sort(RandomAccessIterator first, RandomAccessIterator last, Compare comp) { heap_sort_helper::sort(first, last, comp); } }} //namespace boost { namespace movelib{ #if defined(BOOST_CLANG) || (defined(BOOST_GCC) && (BOOST_GCC >= 40600)) #pragma GCC diagnostic pop #endif #include #endif //#ifndef BOOST_MOVE_DETAIL_HEAP_SORT_HPP