Skip site navigation (1)Skip section navigation (2)

FreeBSD Manual Pages

  
 
  

home | help
std::ranges::inplace_merge(3) C++ Standard Libarystd::ranges::inplace_merge(3)

NAME
       std::ranges::inplace_merge - std::ranges::inplace_merge

Synopsis
	  Defined in header <algorithm>
	  Call signature
	  template< std::bidirectional_iterator	I, std::sentinel_for<I>
	  S,

		    class  Comp	 =  ranges::less,  class  Proj = std::identity
       (since C++20)
	  >								   (1)
       (constexpr since
	  requires	      std::sortable<I,		 Comp,		 Proj>
       C++26)
	      I	inplace_merge( I first,	I middle, S last,

			       Comp comp = {}, Proj proj = {} );
	  template< ranges::bidirectional_range	R, class Comp =
	  ranges::less,

		    class	 Proj	     =	       std::identity	     >
       (since C++20)
	  requires  std::sortable<ranges::iterator_t<R>, Comp, Proj>	   (2)
       (constexpr since
	  ranges::borrowed_iterator_t<R>
       C++26)
	      inplace_merge( R&& r, ranges::iterator_t<R> middle,

			     Comp comp = {}, Proj proj = {} );

	  Merges two consecutive sorted	ranges [first,	middle)	 and  [middle,
       last) into one
	  sorted range [first, last).

	  A  sequence is said to be sorted with	respect	to the comparator comp
       and projection
	  proj if for any iterator it pointing to the sequence	and  any  non-
       negative	integer	n
	  such	that  it + n is	a valid	iterator pointing to an	element	of the
       sequence,
	  std::invoke(comp, std::invoke(proj, *(it  +  n)),  std::invoke(proj,
       *it))) evaluates
	  to false.

	  This	merge function is stable, which	means that for equivalent ele-
       ments in	the
	  original two ranges, the elements from the first  range  (preserving
       their original
	  order)  precede the elements from the	second range (preserving their
       original	order).

	  1) Elements are compared using the given binary comparison  function
       comp and
	  projection  object  proj, and	the ranges must	be sorted with respect
       to the same.
	  2) Same as (1), but uses r as	the range,  as	if  using  ranges::be-
       gin(r) as first,	and
	  ranges::end(r) as last.

	  The  function-like  entities	described  on this page	are niebloids,
       that is:

	    * Explicit template	argument lists cannot be specified when	 call-
       ing any of them.
	    * None of them are visible to argument-dependent lookup.
	    *  When  any of them are found by normal unqualified lookup	as the
       name to the left
	      of the function-call operator, argument-dependent	lookup is  in-
       hibited.

	  In  practice,	 they  may be implemented as function objects, or with
       special compiler
	  extensions.

Parameters
	  first	 - the beginning of the	first sorted range
	  middle - the end of the first	range and the beginning	of the	second
       range
	  last	 - the end of the second sorted	range
	  r	 - the range of	elements to merge inplace
	  comp	 - comparison to apply to the projected	elements
	  proj	 - projection to apply to the elements in the range

Return value
	  An iterator equal to last.

Complexity
	  Exactly  N  1	comparisons, if	additional memory buffer is available,
       where N =
	  ranges::distance(first, last). Otherwise, \(\scriptsize
	  \mathcal{O}(N\cdot\log{(N)})\)(N*log(N)) comparisons.	 Additionally,
       twice as	many
	  projections as comparisons in	both cases.

Notes
	  This	function attempts to allocate a	temporary buffer. If the allo-
       cation fails, the
	  less efficient algorithm is chosen.

		Feature-test macro	  Value	 Std	     Feature
	  __cpp_lib_constexpr_algorithms 202306L     constexpr stable sorting

Possible implementation
	  This implementation only shows the slower algorithm used when	no ad-
       ditional	memory
	  is available.	See also the implementation in MSVC STL	and libstdc++.

       struct inplace_merge_fn {
	   template<std::bidirectional_iterator	I, std::sentinel_for<I>	S,
		    class Comp = ranges::less, class Proj = std::identity>
	   requires std::sortable<I, Comp, Proj>
	   constexpr I operator()(I first, I middle, S last, Comp comp	=  {},
       Proj proj = {}) const
	   {
	       I last_it = ranges::next(middle,	last);
	       inplace_merge_slow(first, middle, last_it,
				  ranges::distance(first, middle),
				  ranges::distance(middle, last_it),
				  std::ref(comp), std::ref(proj));
	       return last_it;
	   }

	   template<ranges::bidirectional_range	R, class Comp =	ranges::less,
		    class Proj = std::identity>
	   requires std::sortable<ranges::iterator_t<R>, Comp, Proj>
	   constexpr ranges::borrowed_iterator_t<R>
	       operator()(R&& r, ranges::iterator_t<R> middle,
			  Comp comp = {}, Proj proj = {}) const
	   {
	       return	    (*this)(ranges::begin(r),	    std::move(middle),
       ranges::end(r),
			      std::move(comp), std::move(proj));
	   }

       private:
	   template<class I, class Comp, class Proj>
	   static constexpr void inplace_merge_slow(I first, I middle, I last,
						    std::iter_difference_t<I>
       n1,
						    std::iter_difference_t<I>
       n2,
						    Comp comp, Proj proj)
	   {
	       if (n1 == 0 || n2 == 0)
		   return;
	       if (n1 +	n2 == 2	&& comp(proj(*middle), proj(*first)))
	       {
		   ranges::iter_swap(first, middle);
		   return;
	       }

	       I cut1 =	first, cut2 = middle;
	       std::iter_difference_t<I> d1{}, d2{};

	       if (n1 >	n2)
	       {
		   d1 =	n1 / 2;
		   ranges::advance(cut1, d1);
		   cut2	= ranges::lower_bound(middle, last, *cut1,
					      std::ref(comp), std::ref(proj));
		   d2 =	ranges::distance(middle, cut2);
	       }
	       else
	       {
		   d2 =	n2 / 2;
		   ranges::advance(cut2, d2);
		   cut1	= ranges::upper_bound(first, middle, *cut2,
					      std::ref(comp), std::ref(proj));
		   d1 =	ranges::distance(first,	cut1);
	       }

	       I new_middle = ranges::rotate(cut1, middle, cut2);
	       inplace_merge_slow(first, cut1, new_middle, d1, d2,
				  std::ref(comp), std::ref(proj));
	       inplace_merge_slow(new_middle, cut2, last, n1 - d1, n2 -	d2,
				  std::ref(comp), std::ref(proj));
	   } };

       inline constexpr	inplace_merge_fn inplace_merge {};

Example
       // Run this code

	#include <algorithm>
	#include <complex>
	#include <functional>
	#include <iostream>
	#include <iterator>
	#include <vector>

	void print(auto	const& v, auto const& rem, int middle =	-1)
	{
	    for	(int i{}; auto n : v)
		std::cout << (i++ == middle ? "	" : "")	<< n <<	' ';
	    std::cout << rem <<	'\n';
	}

	template<std::random_access_iterator I,	std::sentinel_for<I> S>
	requires std::sortable<I>
	void merge_sort(I first, S last)
	{
	    if (last - first > 1)
	    {
		I middle{first + (last - first)	/ 2};
		merge_sort(first, middle);
		merge_sort(middle, last);
		std::ranges::inplace_merge(first, middle, last);
	    }
	}

	int main()
	{
	    // custom merge-sort demo
	    std::vector	v{8, 2,	0, 4, 9, 8, 1, 7, 3};
	    print(v, ":	before sort");
	    merge_sort(v.begin(), v.end());
	    print(v, ":	after sort\n");

	    // merging with comparison function	object and projection
	    using CI = std::complex<int>;
	    std::vector<CI> r{{0,1}, {0,2}, {0,3}, {1,1}, {1,2}};
	    const auto middle{std::ranges::next(r.begin(), 3)};
	    auto comp{std::ranges::less{}};
	    auto proj{[](CI z) { return	z.imag(); }};

	    print(r, ":	before merge", middle -	r.begin());
	    std::ranges::inplace_merge(r, middle, comp,	proj);
	    print(r, ":	after merge");
	}

Output:
	8 2 0 4	9 8 1 7	3 : before sort
	0 1 2 3	4 7 8 8	9 : after sort

	(0,1) (0,2) (0,3)  (1,1) (1,2) : before	merge
	(0,1) (1,1) (0,2) (1,2)	(0,3) :	after merge

See also
	  ranges::merge	    merges two sorted ranges
	  (C++20)	    (niebloid)
	  ranges::set_union computes the union of two sets
	  (C++20)	    (niebloid)
	  ranges::is_sorted checks whether a range is  sorted  into  ascending
       order
	  (C++20)	    (niebloid)
	  ranges::sort	    sorts a range into ascending order
	  (C++20)	    (niebloid)
	  inplace_merge	    merges two ordered ranges in-place
			    (function template)

http://cppreference.com		  2024.06.10	 std::ranges::inplace_merge(3)

Want to link to this manual page? Use this URL:
<https://man.freebsd.org/cgi/man.cgi?query=std::ranges::inplace_merge&sektion=3&manpath=FreeBSD+Ports+15.1.quarterly>

home | help