//---------------------------------------------------------------------------- /// @file backbone.hpp /// @brief This file constains the class backbone, which is part of the /// block_indirect_sort algorithm /// /// @author Copyright (c) 2016 Francisco Jose 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_PARALLEL_DETAIL_BACKBONE_HPP #define __BOOST_SORT_PARALLEL_DETAIL_BACKBONE_HPP #include #include #include #include #include #include #include #include #include namespace boost { namespace sort { namespace blk_detail { //--------------------------------------------------------------------------- // USING SENTENCES //--------------------------------------------------------------------------- namespace bsc = boost::sort::common; namespace bscu = bsc::util; using bsc::stack_cnc; using bsc::range; ///--------------------------------------------------------------------------- /// @struct backbone /// @brief This contains all the information shared betwen the classes of the /// block indirect sort algorithm //---------------------------------------------------------------------------- template < uint32_t Block_size, class Iter_t, class Compare > struct backbone { //------------------------------------------------------------------------- // D E F I N I T I O N S //------------------------------------------------------------------------- typedef typename std::iterator_traits< Iter_t >::value_type value_t; typedef std::atomic< uint32_t > atomic_t; typedef range< size_t > range_pos; typedef range< Iter_t > range_it; typedef range< value_t * > range_buf; typedef std::function< void(void) > function_t; typedef block< Block_size, Iter_t > block_t; //------------------------------------------------------------------------ // V A R I A B L E S //------------------------------------------------------------------------ // range with all the element to sort range< Iter_t > global_range; // index vector of block_pos elements std::vector< block_pos > index; // Number of elements to sort size_t nelem; // Number of blocks to sort size_t nblock; // Number of elements in the last block (tail) size_t ntail; // object for to compare two elements Compare cmp; // range of elements of the last block (tail) range_it range_tail; // thread local varible. It is a pointer to the buffer static thread_local value_t *buf; // concurrent stack where store the function_t elements stack_cnc< function_t > works; // global indicator of error bool error; // //------------------------------------------------------------------------ // F U N C T I O N S //------------------------------------------------------------------------ backbone (Iter_t first, Iter_t last, Compare comp); //------------------------------------------------------------------------ // function : get_block /// @brief obtain the block in the position pos /// @param pos : position of the range /// @return block required //------------------------------------------------------------------------ block_t get_block (size_t pos) const { return block_t (global_range.first + (pos * Block_size)); }; //------------------------------------------------------------------------- // function : get_range /// @brief obtain the range in the position pos /// @param pos : position of the range /// @return range required //------------------------------------------------------------------------- range_it get_range (size_t pos) const { Iter_t it1 = global_range.first + (pos * Block_size); Iter_t it2 = (pos == (nblock - 1)) ? global_range.last : it1 + Block_size; return range_it (it1, it2); }; //------------------------------------------------------------------------- // function : get_range_buf /// @brief obtain the auxiliary buffer of the thread //------------------------------------------------------------------------- range_buf get_range_buf ( ) const { return range_buf (buf, buf + Block_size); }; //------------------------------------------------------------------------- // function : exec /// @brief Initialize the thread local buffer with the ptr_buf pointer, /// and begin with the execution of the functions stored in works // /// @param ptr_buf : Pointer to the memory assigned to the thread_local /// buffer /// @param counter : atomic counter for to invoke to the exec function /// with only 1 parameter //------------------------------------------------------------------------- void exec (value_t *ptr_buf, atomic_t &counter) { buf = ptr_buf; exec (counter); }; void exec (atomic_t &counter); //--------------------------------------------------------------------------- }; // end struct backbone //--------------------------------------------------------------------------- // //############################################################################ // ## // ## // N O N I N L I N E F U N C T I O N S ## // ## // ## //############################################################################ // // initialization of the thread_local pointer to the auxiliary buffer template < uint32_t Block_size, class Iter_t, class Compare > thread_local typename std::iterator_traits< Iter_t > ::value_type *backbone< Block_size, Iter_t, Compare >::buf = nullptr; //------------------------------------------------------------------------ // function : backbone /// @brief constructor of the class // /// @param first : iterator to the first element of the range to sort /// @param last : iterator after the last element to the range to sort /// @param comp : object for to compare two elements pointed by Iter_t /// iterators //------------------------------------------------------------------------ template < uint32_t Block_size, class Iter_t, class Compare > backbone< Block_size, Iter_t, Compare > ::backbone (Iter_t first, Iter_t last, Compare comp) : global_range (first, last), cmp (comp), error (false) { assert ((last - first) >= 0); if (first == last) return; // nothing to do nelem = size_t (last - first); nblock = (nelem + Block_size - 1) / Block_size; ntail = (nelem % Block_size); index.reserve (nblock + 1); for (size_t i = 0; i < nblock; ++i) index.emplace_back (block_pos (i)); range_tail.first = (ntail == 0) ? last : (first + ((nblock - 1) * Block_size)); range_tail.last = last; }; // //------------------------------------------------------------------------- // function : exec /// @brief execute the function_t stored in works, until counter is zero // /// @param counter : atomic counter. When 0 exits the function //------------------------------------------------------------------------- template < uint32_t Block_size, class Iter_t, class Compare > void backbone< Block_size, Iter_t, Compare >::exec (atomic_t &counter) { function_t func_exec; while (bscu::atomic_read (counter) != 0) { if (works.pop_move_back (func_exec)) func_exec ( ); else std::this_thread::yield ( ); }; }; // //**************************************************************************** }; // End namespace blk_detail }; // End namespace sort }; // End namespace boost //**************************************************************************** #endif