123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401 |
- //----------------------------------------------------------------------------
- /// @file range.hpp
- /// @brief Define a range [first, last), and the associated operations
- ///
- /// @author Copyright (c) 2016 Francisco José Tapia ([email protected] )\n
- /// Distributed under the Boost Software License, Version 1.0.\n
- /// ( See accompanyingfile LICENSE_1_0.txt or copy at
- /// http://www.boost.org/LICENSE_1_0.txt )
- /// @version 0.1
- ///
- /// @remarks
- //-----------------------------------------------------------------------------
- #ifndef __BOOST_SORT_PARALLEL_DETAIL_UTIL_RANGE_HPP
- #define __BOOST_SORT_PARALLEL_DETAIL_UTIL_RANGE_HPP
- #include <ciso646>
- #include <cassert>
- #include <functional>
- #include <memory>
- #include <vector>
- #include <boost/sort/common/util/algorithm.hpp>
- #include <boost/sort/common/util/merge.hpp>
- #include <boost/sort/common/util/traits.hpp>
- namespace boost
- {
- namespace sort
- {
- namespace common
- {
- ///---------------------------------------------------------------------------
- /// @struct range
- /// @brief this represent a range between two iterators
- /// @remarks
- //----------------------------------------------------------------------------
- template <class Iter_t>
- struct range
- {
- Iter_t first, last;
- //
- //------------------------------------------------------------------------
- // function : range
- /// @brief empty constructor
- //------------------------------------------------------------------------
- range(void) { };
- //
- //------------------------------------------------------------------------
- // function : range
- /// @brief constructor with two parameters
- /// @param frs : iterator to the first element
- /// @param lst : iterator to the last element
- //-----------------------------------------------------------------------
- range(const Iter_t &frs, const Iter_t &lst): first(frs), last(lst) { };
- //
- //-----------------------------------------------------------------------
- // function : empty
- /// @brief indicate if the range is empty
- /// @return true : empty false : not empty
- //-----------------------------------------------------------------------
- bool empty(void) const { return (first == last); };
- //
- //-----------------------------------------------------------------------
- // function : not_empty
- /// @brief indicate if the range is not empty
- /// @return true : not empty false : empty
- //-----------------------------------------------------------------------
- bool not_empty(void) const {return (first != last); };
- //
- //-----------------------------------------------------------------------
- // function : valid
- /// @brief Indicate if the range is well constructed, and valid
- /// @return true : valid, false : not valid
- //-----------------------------------------------------------------------
- bool valid(void) const { return ((last - first) >= 0); };
- //
- //-----------------------------------------------------------------------
- // function : size
- /// @brief return the size of the range
- /// @return size
- //-----------------------------------------------------------------------
- size_t size(void) const { return (last - first); };
- //
- //------------------------------------------------------------------------
- // function : front
- /// @brief return an iterator to the first element of the range
- /// @return iterator
- //-----------------------------------------------------------------------
- Iter_t front(void) const { return first; };
- //
- //-------------------------------------------------------------------------
- // function : back
- /// @brief return an iterator to the last element of the range
- /// @return iterator
- //-------------------------------------------------------------------------
- Iter_t back(void) const {return (last - 1); };
- };
- //
- //-----------------------------------------------------------------------------
- // function : concat
- /// @brief concatenate two contiguous ranges
- /// @param it1 : first range
- /// @param it2 : second range
- /// @return range resulting of the concatenation
- //-----------------------------------------------------------------------------
- template<class Iter_t>
- inline range<Iter_t> concat(const range<Iter_t> &it1, const range<Iter_t> &it2)
- {
- return range<Iter_t>(it1.first, it2.last);
- }
- ;
- //
- //-----------------------------------------------------------------------------
- // function : move_forward
- /// @brief Move initialized objets from the range src to dest
- /// @param dest : range where move the objects
- /// @param src : range from where move the objects
- /// @return range with the objects moved and the size adjusted
- //-----------------------------------------------------------------------------
- template <class Iter1_t, class Iter2_t>
- inline range<Iter2_t> move_forward(const range<Iter2_t> &dest,
- const range<Iter1_t> &src)
- {
- assert(dest.size() >= src.size());
- Iter2_t it_aux = util::move_forward(dest.first, src.first, src.last);
- return range<Iter2_t>(dest.first, it_aux);
- };
- //
- //-----------------------------------------------------------------------------
- // function : move_backward
- /// @brief Move initialized objets from the range src to dest
- /// @param dest : range where move the objects
- /// @param src : range from where move the objects
- /// @return range with the objects moved and the size adjusted
- //-----------------------------------------------------------------------------
- template <class Iter1_t, class Iter2_t>
- inline range<Iter2_t> move_backward(const range<Iter2_t> &dest,
- const range<Iter1_t> &src)
- {
- assert(dest.size() >= src.size());
- Iter2_t it_aux = util::move_backward(dest.first + src.size(), src.first,
- src.last);
- return range<Iter2_t>(dest.first, dest.src.size());
- };
- //-----------------------------------------------------------------------------
- // function : uninit_move
- /// @brief Move uninitialized objets from the range src creating them in dest
- ///
- /// @param dest : range where move and create the objects
- /// @param src : range from where move the objects
- /// @return range with the objects moved and the size adjusted
- //-----------------------------------------------------------------------------
- template<class Iter_t, class Value_t = util::value_iter<Iter_t> >
- inline range<Value_t*> move_construct(const range<Value_t*> &dest,
- const range<Iter_t> &src)
- {
- Value_t *ptr_aux = util::move_construct(dest.first, src.first, src.last);
- return range<Value_t*>(dest.first, ptr_aux);
- };
- //
- //-----------------------------------------------------------------------------
- // function : destroy
- /// @brief destroy a range of objects
- /// @param rng : range to destroy
- //-----------------------------------------------------------------------------
- template<class Iter_t>
- inline void destroy(range<Iter_t> rng)
- {
- util::destroy(rng.first, rng.last);
- };
- //
- //-----------------------------------------------------------------------------
- // function : initialize
- /// @brief initialize a range of objects with the object val moving across them
- /// @param rng : range of elements not initialized
- /// @param val : object used for the initialization
- /// @return range initialized
- //-----------------------------------------------------------------------------
- template<class Iter_t, class Value_t = util::value_iter<Iter_t> >
- inline range<Iter_t> initialize(const range<Iter_t> &rng, Value_t &val)
- {
- util::initialize(rng.first, rng.last, val);
- return rng;
- };
- //
- //-----------------------------------------------------------------------------
- // function : is_mergeable
- /// @brief : indicate if two ranges have a possible merge
- /// @param src1 : first range
- /// @param src2 : second range
- /// @param comp : object for to compare elements
- /// @return true : they can be merged
- /// false : they can't be merged
- //-----------------------------------------------------------------------------
- template<class Iter1_t, class Iter2_t, class Compare>
- inline bool is_mergeable(const range<Iter1_t> &src1, const range<Iter2_t> &src2,
- Compare comp)
- {
- //------------------------------------------------------------------------
- // Metaprogramming
- //------------------------------------------------------------------------
- typedef util::value_iter<Iter1_t> type1;
- typedef util::value_iter<Iter2_t> type2;
- static_assert (std::is_same< type1, type2 >::value,
- "Incompatible iterators\n");
- //------------------------------------------------------------------------
- // Code
- //------------------------------------------------------------------------
- return comp(*(src2.front()), *(src1.back()));
- };
- //
- //-----------------------------------------------------------------------------
- // function : is_mergeable_stable
- /// @brief : indicate if two ranges have a possible merge
- /// @param src1 : first range
- /// @param src2 : second range
- /// @param comp : object for to compare elements
- /// @return true : they can be merged
- /// false : they can't be merged
- //-----------------------------------------------------------------------------
- template<class Iter1_t, class Iter2_t, class Compare>
- inline bool is_mergeable_stable(const range<Iter1_t> &src1,
- const range<Iter2_t> &src2, Compare comp)
- {
- //------------------------------------------------------------------------
- // Metaprogramming
- //------------------------------------------------------------------------
- typedef util::value_iter<Iter1_t> type1;
- typedef util::value_iter<Iter2_t> type2;
- static_assert (std::is_same< type1, type2 >::value,
- "Incompatible iterators\n");
- //------------------------------------------------------------------------
- // Code
- //------------------------------------------------------------------------
- return not comp(*(src1.back()), *(src2.front()));
- };
- //
- //-----------------------------------------------------------------------------
- // function : merge
- /// @brief Merge two contiguous ranges src1 and src2, and put the result in
- /// the range dest, returning the range merged
- ///
- /// @param dest : range where locate the lements merged. the size of dest
- /// must be greater or equal than the sum of the sizes of
- /// src1 and src2
- /// @param src1 : first range to merge
- /// @param src2 : second range to merge
- /// @param comp : comparison object
- /// @return range with the elements merged and the size adjusted
- //-----------------------------------------------------------------------------
- template<class Iter1_t, class Iter2_t, class Iter3_t, class Compare>
- inline range<Iter3_t> merge(const range<Iter3_t> &dest,
- const range<Iter1_t> &src1,
- const range<Iter2_t> &src2, Compare comp)
- {
- Iter3_t it_aux = util::merge(src1.first, src1.last, src2.first, src2.last,
- dest.first, comp);
- return range<Iter3_t>(dest.first, it_aux);
- };
- //-----------------------------------------------------------------------------
- // function : merge_construct
- /// @brief Merge two contiguous uninitialized ranges src1 and src2, and create
- /// and move the result in the uninitialized range dest, returning the
- /// range merged
- //
- /// @param dest : range where locate the elements merged. the size of dest
- /// must be greater or equal than the sum of the sizes of
- /// src1 and src2. Initially is uninitialize memory
- /// @param src1 : first range to merge
- /// @param src2 : second range to merge
- /// @param comp : comparison object
- /// @return range with the elements merged and the size adjusted
- //-----------------------------------------------------------------------------
- template<class Iter1_t, class Iter2_t, class Value_t, class Compare>
- inline range<Value_t *> merge_construct(const range<Value_t *> &dest,
- const range<Iter1_t> &src1,
- const range<Iter2_t> &src2,
- Compare comp)
- {
- Value_t * ptr_aux = util::merge_construct(src1.first, src1.last, src2.first,
- src2.last, dest.first, comp);
- return range<Value_t*>(dest.first, ptr_aux);
- };
- //
- //---------------------------------------------------------------------------
- // function : half_merge
- /// @brief : Merge two initialized buffers. The first buffer is in a separate
- /// memory
- //
- /// @param dest : range where finish the two buffers merged
- /// @param src1 : first range to merge in a separate memory
- /// @param src2 : second range to merge, in the final part of the
- /// range where deposit the final results
- /// @param comp : object for compare two elements of the type pointed
- /// by the Iter1_t and Iter2_t
- /// @return : range with the two buffers merged
- //---------------------------------------------------------------------------
- template<class Iter1_t, class Iter2_t, class Compare>
- inline range<Iter2_t> merge_half(const range<Iter2_t> &dest,
- const range<Iter1_t> &src1,
- const range<Iter2_t> &src2, Compare comp)
- {
- Iter2_t it_aux = util::merge_half(src1.first, src1.last, src2.first,
- src2.last, dest.first, comp);
- return range<Iter2_t>(dest.first, it_aux);
- };
- //
- //-----------------------------------------------------------------------------
- // function : merge_uncontiguous
- /// @brief : merge two non contiguous ranges src1, src2, using the range
- /// aux as auxiliary memory. The results are in the original ranges
- //
- /// @param src1 : first range to merge
- /// @param src2 : second range to merge
- /// @param aux : auxiliary range used in the merge
- /// @param comp : object for to compare elements
- /// @return true : not changes done, false : changes in the buffers
- //-----------------------------------------------------------------------------
- template<class Iter1_t, class Iter2_t, class Iter3_t, class Compare>
- inline bool merge_uncontiguous(const range<Iter1_t> &src1,
- const range<Iter2_t> &src2,
- const range<Iter3_t> &aux, Compare comp)
- {
- return util::merge_uncontiguous(src1.first, src1.last, src2.first,
- src2.last, aux.first, comp);
- };
- //
- //-----------------------------------------------------------------------------
- // function : merge_contiguous
- /// @brief : merge two contiguous ranges ( src1, src2) using buf as
- /// auxiliary memory. The results are in the same ranges
- /// @param src1 : first range to merge
- /// @param src1 : second range to merge
- /// @param buf : auxiliary memory used in the merge
- /// @param comp : object for to compare elements
- /// @return true : not changes done, false : changes in the buffers
- //-----------------------------------------------------------------------------
- template<class Iter1_t, class Iter2_t, class Compare>
- inline range<Iter1_t> merge_contiguous(const range<Iter1_t> &src1,
- const range<Iter1_t> &src2,
- const range<Iter2_t> &buf, Compare comp)
- {
- util::merge_contiguous(src1.first, src1.last, src2.last, buf.first, comp);
- return concat(src1, src2);
- };
- //
- //-----------------------------------------------------------------------------
- // function : merge_flow
- /// @brief : merge two ranges, as part of a merge the ranges in a list. This
- /// function reduce the number of movements compared with inplace_merge
- /// when you need to merge a sequence of ranges.
- /// This function merge the ranges rbuf and rng2, and the results
- /// are in rng1 and rbuf
- //
- /// @param rng1 : range where locate the first elements of the merge
- /// @param rbuf : range which provide the first elements, and where store
- /// the last results of the merge
- /// @param rng2 : range which provide the last elements to merge
- /// @param comp : object for to compare elements
- /// @return true : not changes done, false : changes in the buffers
- //-----------------------------------------------------------------------------
- template<class Iter1_t, class Iter2_t, class Compare>
- static void merge_flow(range<Iter1_t> rng1, range<Iter2_t> rbuf,
- range<Iter1_t> rng2, Compare cmp)
- {
- //-------------------------------------------------------------------------
- // Metaprogramming
- //-------------------------------------------------------------------------
- typedef util::value_iter<Iter1_t> type1;
- typedef util::value_iter<Iter2_t> type2;
- static_assert (std::is_same< type1, type2 >::value,
- "Incompatible iterators\n");
- //-------------------------------------------------------------------------
- // Code
- //-------------------------------------------------------------------------
- range<Iter2_t> rbx(rbuf);
- range<Iter1_t> rx1(rng1), rx2(rng2);
- assert(rbx.size() == rx1.size() and rx1.size() == rx2.size());
- while (rx1.first != rx1.last)
- {
- *(rx1.first++) = (cmp(*rbx.first, *rx2.first)) ?
- std::move(*(rbx.first++)):
- std::move(*(rx2.first++));
- };
- if (rx2.first == rx2.last) return;
- if (rbx.first == rbx.last) move_forward(rbuf, rng2);
- else merge_half(rbuf, rx2, rbx, cmp);
- };
- //****************************************************************************
- };// End namespace common
- };// End namespace sort
- };// End namespace boost
- //****************************************************************************
- //
- #endif
|