//---------------------------------------------------------------------------- /// @file flat_stable_sort.hpp /// @brief Flat stable sort algorithm /// /// @author Copyright (c) 2017 Francisco José Tapia (fjtapia@gmail.com )\n /// Distributed under the Boost Software License, Version 1.0.\n /// ( See accompanying file LICENSE_1_0.txt or copy at /// http://www.boost.org/LICENSE_1_0.txt ) /// @version 0.1 /// /// @remarks //----------------------------------------------------------------------------- #ifndef __BOOST_SORT_FLAT_STABLE_SORT_HPP #define __BOOST_SORT_FLAT_STABLE_SORT_HPP #include #include #include #include #include #include #include #include #include #include #include #include #include namespace boost { namespace sort { namespace flat_internal { namespace bsc = boost::sort::common; namespace bscu = boost::sort::common::util; //--------------------------------------------------------------------------- /// @struct flat_stable_sort /// @brief This class implement s stable sort algorithm with 1 thread, with /// an auxiliary memory of N/2 elements //---------------------------------------------------------------------------- template , uint32_t Power2 = 10> class flat_stable_sort: public bsc::merge_block { //------------------------------------------------------------------------ // DEFINITIONS AND CONSTANTS //------------------------------------------------------------------------ typedef bsc::merge_block merge_block_t; //------------------------------------------------------------------------- // D E F I N I T I O N S //------------------------------------------------------------------------- typedef typename merge_block_t::value_t value_t; typedef typename merge_block_t::range_pos range_pos; typedef typename merge_block_t::range_it range_it; typedef typename merge_block_t::range_buf range_buf; typedef typename merge_block_t::it_index it_index; typedef typename merge_block_t::circular_t circular_t; //------------------------------------------------------------------------ // CONSTANTS //------------------------------------------------------------------------ using merge_block_t::BLOCK_SIZE; using merge_block_t::LOG_BLOCK; using merge_block_t::index; using merge_block_t::cmp; using merge_block_t::ptr_circ; using merge_block_t::get_range; using merge_block_t::get_group_range; using merge_block_t::merge_range_pos; using merge_block_t::move_range_pos_backward; using merge_block_t::rearrange_with_index; public: //------------------------------------------------------------------------ // PUBLIC FUNCTIONS //------------------------------------------------------------------------- flat_stable_sort(Iter_t first, Iter_t last, Compare comp, circular_t *ptr_circ) : merge_block_t(first, last, comp, ptr_circ) { divide(index.begin(), index.end()); rearrange_with_index(); }; flat_stable_sort(Iter_t first, Iter_t last, Compare comp = Compare()) : flat_stable_sort(first, last, comp, nullptr) { }; void divide(it_index itx_first, it_index itx_last); void sort_small(it_index itx_first, it_index itx_last); bool is_sorted_forward(it_index itx_first, it_index itx_last); bool is_sorted_backward(it_index itx_first, it_index itx_last); }; //---------------------------------------------------------------------------- // End of class flat_stable_sort //---------------------------------------------------------------------------- // //------------------------------------------------------------------------ // function : /// @brief : /// @param Pos : /// @return //------------------------------------------------------------------------ template void flat_stable_sort ::divide(it_index itx_first, it_index itx_last) { size_t nblock = size_t(itx_last - itx_first); if (nblock < 5) { sort_small(itx_first, itx_last); return; }; if ( nblock > 7) { if (is_sorted_forward(itx_first, itx_last)) return; if (is_sorted_backward(itx_first, itx_last)) return; }; size_t nblock1 = (nblock + 1) >> 1; divide(itx_first, itx_first + nblock1); divide(itx_first + nblock1, itx_last); merge_range_pos(itx_first, itx_first + nblock1, itx_last); }; // //------------------------------------------------------------------------ // function : sort_small /// @brief : /// @param /// @param /// @param //------------------------------------------------------------------------ template void flat_stable_sort ::sort_small(it_index itx_first, it_index itx_last) { size_t nblock = size_t(itx_last - itx_first); assert(nblock > 0 and nblock < 5); value_t *paux = ptr_circ->get_buffer(); range_it rng_data = get_group_range(*itx_first, nblock); if (nblock < 3) { range_buf rng_aux(paux, paux + rng_data.size()); range_sort_data(rng_data, rng_aux, cmp); return; }; //-------------------------------------------------------------------- // division of range_data in two ranges for be sorted and merged //-------------------------------------------------------------------- size_t nblock1 = (nblock + 1) >> 1; range_it rng_data1 = get_group_range(*itx_first, nblock1); range_it rng_data2(rng_data1.last, rng_data.last); range_buf rng_aux1(paux, paux + rng_data1.size()); range_buf rng_aux2(paux, paux + rng_data2.size()); range_sort_data(rng_data2, rng_aux2, cmp); range_sort_buffer(rng_data1, rng_aux1, cmp); merge_half(rng_data, rng_aux1, rng_data2, cmp); }; // //------------------------------------------------------------------------ // function : is_sorted_forward /// @brief : return if the data are ordered, /// @param itx_first : iterator to the first block in the index /// @param itx_last : iterator to the last block in the index /// @return : true : the data are ordered false : not ordered //------------------------------------------------------------------------ template bool flat_stable_sort ::is_sorted_forward(it_index itx_first, it_index itx_last) { size_t nblock = size_t(itx_last - itx_first); range_it rng = get_group_range(*itx_first, nblock); size_t nelem = rng.size(); size_t min_process = (std::max)(BLOCK_SIZE, (nelem >> 3)); size_t nsorted1 = bsc::number_stable_sorted_forward (rng.first, rng.last, min_process, cmp); if (nsorted1 == nelem) return true; if (nsorted1 == 0) return false; size_t nsorted2 = nelem - nsorted1; Iter_t itaux = rng.first + nsorted1; if (nsorted2 <= (BLOCK_SIZE << 1)) { flat_stable_sort(itaux, rng.last, cmp, ptr_circ); bscu::insert_sorted(rng.first, itaux, rng.last, cmp, ptr_circ->get_buffer()); } else { // Adjust the size of the sorted data to a number of blocks size_t mask = ~(BLOCK_SIZE - 1); size_t nsorted1_adjust = nsorted1 & mask; flat_stable_sort(rng.first + nsorted1_adjust, rng.last, cmp, ptr_circ); size_t nblock1 = nsorted1_adjust >> Power2; merge_range_pos(itx_first, itx_first + nblock1, itx_last); }; return true; }; // //------------------------------------------------------------------------ // function : is_sorted_backward /// @brief : return if the data are ordered, /// @param itx_first : iterator to the first block in the index /// @param itx_last : iterator to the last block in the index /// @return : true : the data are ordered false : not ordered //------------------------------------------------------------------------ template bool flat_stable_sort ::is_sorted_backward(it_index itx_first, it_index itx_last) { size_t nblock = size_t(itx_last - itx_first); range_it rng = get_group_range(*itx_first, nblock); size_t nelem = rng.size(); size_t min_process = (std::max)(BLOCK_SIZE, (nelem >> 3)); size_t nsorted2 = bsc::number_stable_sorted_backward(rng.first, rng.last, min_process, cmp); if (nsorted2 == nelem) return true; if (nsorted2 == 0 ) return false; Iter_t itaux = rng.last - nsorted2; size_t nsorted1 = nelem - nsorted2; if (nsorted1 <= (BLOCK_SIZE << 1)) { flat_stable_sort(rng.first, itaux, cmp, ptr_circ); bscu::insert_sorted_backward(rng.first, itaux, rng.last, cmp, ptr_circ->get_buffer()); } else { // Adjust the size of nsorted2 for to be a number of blocks size_t nblock1 = (nsorted1 + BLOCK_SIZE - 1) >> Power2; size_t nsorted1_adjust = (nblock1 << Power2); flat_stable_sort(rng.first, rng.first + nsorted1_adjust, cmp, ptr_circ); merge_range_pos(itx_first, itx_first + nblock1, itx_last); }; return true; }; //**************************************************************************** };// End namespace flat_internal //**************************************************************************** // namespace bscu = boost::sort::common::util; namespace flat = boost::sort::flat_internal; // ///--------------------------------------------------------------------------- // function flat_stable_sort /// @brief This class is select the block size in the block_indirect_sort /// algorithm depending of the type and size of the data to sort /// //---------------------------------------------------------------------------- template , bscu::enable_if_string > * = nullptr> inline void flat_stable_sort (Iter_t first, Iter_t last, Compare cmp = Compare()) { flat::flat_stable_sort (first, last, cmp); }; template struct block_size_fss { static constexpr const uint32_t BitsSize = (Size == 0) ? 0 : (Size > 128) ? 7 : bscu::tmsb[Size - 1]; static constexpr const uint32_t sz[10] = { 10, 10, 10, 9, 8, 7, 6, 6 }; static constexpr const uint32_t data = sz[BitsSize]; }; // ///--------------------------------------------------------------------------- // function flat_stable_sort /// @brief This class is select the block size in the flat_stable_sort /// algorithm depending of the type and size of the data to sort /// //---------------------------------------------------------------------------- template , bscu::enable_if_not_string >* = nullptr> inline void flat_stable_sort (Iter_t first, Iter_t last, Compare cmp = Compare()) { flat::flat_stable_sort )>::data> (first, last, cmp); }; template > inline void indirect_flat_stable_sort (Iter_t first, Iter_t last, Compare comp = Compare()) { typedef typename std::vector::iterator itx_iter; typedef common::less_ptr_no_null itx_comp; common::indirect_sort ( flat_stable_sort, first, last, comp); }; //**************************************************************************** };// End namespace sort };// End namepspace boost //**************************************************************************** // #endif