[ Web Proxy ]
URL:
Viewing: https://en.cppreference.com/cpp/algorithm/ranges/unique_copy [Back]  [Original]

std::ranges::unique_copy, std::ranges::unique_copy_result - cppreference.com
cppreference.com
Namespaces
Variants

std::ranges::unique_copy, std::ranges::unique_copy_result

From cppreference.com
 
 
Algorithm library
Constrained algorithms and algorithms on ranges (C++20)
Constrained algorithms, e.g. ranges::copy, ranges::sort, ...
Non-modifying sequence operations    
Batch operations
(C++17)
Search operations
Modifying sequence operations
Copy operations
(C++11)
(C++11)
Swap operations
Transformation operations
Generation operations
Removing operations
Order-changing operations
(until C++17)(C++11)
(C++20)(C++20)
Sampling operations
(C++17)

Sorting and related operations
Partitioning operations
(C++11)    

Sorting operations
Binary search operations
(on partitioned ranges)
Set operations (on sorted ranges)
Merge operations (on sorted ranges)
Heap operations
Minimum/maximum operations
(C++11)
(C++17)
Lexicographical comparison operations
Permutation operations


 
Constrained algorithms
All names in this menu belong to namespace std::ranges
Non-modifying sequence operations
Fold operations (Helper templates)
Modifying sequence operations
Partitioning operations
Sorting operations
Binary search operations (on sorted ranges)
       
       
Set operations (on sorted ranges)
Heap operations
Minimum/maximum operations
       
       
Permutation operations
Specialized <memory> algorithms
Return types
 
Defined in header <algorithm>
Call signature
template< std::input_iterator I, std::sentinel_for<I> S,
          std::weakly_incrementable O, class Proj = std::identity,
          std::indirect_equivalence_relation<std::projected<I, Proj>>
              C = ranges::equal_to >
    requires std::indirectly_copyable<I, O> &&
             (std::forward_iterator<I> ||
              (std::input_iterator<O> &&
               std::same_as<std::iter_value_t<I>, std::iter_value_t<O>>) ||
              std::indirectly_copyable_storable<I, O>)
constexpr ranges::unique_copy_result<I, O>
    unique_copy( I first, S last, O d_first, C comp = {}, Proj proj = {} );
(1) (since C++20)
template< ranges::input_range R, std::weakly_incrementable O,
          class Proj = std::identity,
          std::indirect_equivalence_relation
              <std::projected<ranges::iterator_t<R>, Proj>>
              C = ranges::equal_to >
    requires std::indirectly_copyable<ranges::iterator_t<R>, O> &&
             (std::forward_iterator<ranges::iterator_t<R>> ||
              (std::input_iterator<O> &&
               std::same_as<ranges::range_value_t<R>, std::iter_value_t<O>>) ||
              std::indirectly_copyable_storable<ranges::iterator_t<R>, O>)
constexpr ranges::unique_copy_result<ranges::borrowed_iterator_t<R>, O>
    unique_copy( R&& r, O d_first, C comp = {}, Proj proj = {} );
(2) (since C++20)
template< /*execution-policy*/ Ep,
          std::random_access_iterator I, std::sized_sentinel_for<I> S,
          std::random_access_iterator O, std::sized_sentinel_for<O> OutS,
          class Proj = std::identity,
          std::indirect_equivalence_relation<std::projected<I, Proj>>
              C = ranges::equal_to >
    requires std::indirectly_copyable<I, O>
ranges::unique_copy_result<I, O>
    unique_copy( Ep&& policy, I first, S last, O d_first, OutS d_last,
                 C comp = {}, Proj proj = {} );
(3) (since C++26)
template< /*execution-policy*/ Ep,
          /*sized-random-access-range*/ R,
          /*sized-random-access-range*/ OutR,
          class Proj = std::identity,
          std::indirect_equivalence_relation
              <std::projected<ranges::iterator_t<R>, Proj>>
              C = ranges::equal_to >
    requires std::indirectly_copyable<ranges::iterator_t<R>,
                                      ranges::iterator_t<OutR>>
ranges::unique_copy_result<ranges::borrowed_iterator_t<R>,
                           ranges::borrowed_iterator_t<OutR>>
    unique_copy( Ep&& policy, R&& r, OutR&& d_r, C comp = {}, Proj proj = {});
(4) (since C++26)
Helper types
template< class I, class O >
using unique_copy_result = ranges::in_out_result<I, O>;
(5) (since C++20)

For the definition of /*execution-policy*/, see this page; for the definition of /*sized-random-access-range*/, see this page.

Copies elements from the source range [firstlast) or r to the destination range. For each group of consecutive equivalent elements (projected by proj), only the first element is copied.

1,2) The destination range begins at d_first.
3,4) Same as (1,2), but executed according to policy. If the destination range is exhausted before reaching the end of the source range, the remaining elements in the source range will not be copied.
3) The destination range is [d_firstd_last).
4) The destination range is d_r.

If the source and destination ranges overlap, the behavior is undefined.

The function-like entities described on this page are algorithm function objects (informally known as niebloids), that is:

Parameters

first, last - the iterator-sentinel pair defining the source range
r - the source range
d_first - the beginning of the destination range
d_last - the sentinel of the destination range
d_r - the destination range
comp - the predicate to be applied to the (projected) elements
proj - the projection to be applied to the elements in the source range
policy - the execution policy to use

Return value

A ranges::unique_copy_result object where:

  • The data member in holds the past-the-end iterator of the source range.
3,4) If the destination range is exhausted before reaching the end of the source range and there are full groups of consecutive equivalent elements in the remaining elements (projected by proj), in holds an iterator to the first element of first such group instead.
  • The data member out holds an iterator past the last copy-assigned element in the destination range, or an iterator to the beginning of the destination range if no element is copied.

Complexity

Given \(\scriptsize N\)N as ranges::distance(first, last) or ranges::distance(r):

1,2) Exactly \(\scriptsize \max(0,N-1)\)max(0,N-1) applications of comp, and at most twice as many applications of proj.
3,4) \(\scriptsize \mathcal{O}(N)\)(N) applications of comp, and at most twice as many applications of proj.

Exceptions

3,4) During the execution process:
  • If the temporary memory resources required for parallelization are not available, std::bad_alloc is thrown.
  • If an uncaught exception is thrown while accessing objects via an algorithm argument, the behavior is determined by the execution policy (for standard policies, std::terminate is invoked).

Possible implementation

See also the implementations in libstdc++ and MSVC STL (and third-party libraries: cmcstl2, NanoRange, and range-v3).

struct unique_copy_fn
{
    template<std::input_iterator I, std::sentinel_for<I> S,
             std::weakly_incrementable O, class Proj = std::identity,
             std::indirect_equivalence_relation
                 <std::projected<I, Proj>> C = ranges::equal_to>
        requires std::indirectly_copyable<I, O> &&
                 (std::forward_iterator<I> ||
                  (std::input_iterator<O> &&
                   std::same_as<std::iter_value_t<I>, std::iter_value_t<O>>) ||
                  std::indirectly_copyable_storable<I, O>)
    constexpr ranges::unique_copy_result<I, O>
        operator()(I first, S last, O result, C comp = {}, Proj proj = {}) const
    {
        if (!(first == last))
        {
            std::iter_value_t<I> value = *first;
            *result = value;
            ++result;
            while (!(++first == last))
            {
                auto&& value2 = *first;
                if (!std::invoke(comp, std::invoke(proj, value2),
                        std::invoke(proj, value)))
                {
                    value = std::forward<decltype(value2)>(value2);
                    *result = value;
                    ++result;
                }
            }
        }
        
        return {std::move(first), std::move(result)};
    }
    
    template<ranges::input_range R,
             std::weakly_incrementable O, class Proj = std::identity,
             std::indirect_equivalence_relation
                 <std::projected<ranges::iterator_t<R>, Proj>> C = ranges::equal_to>
        requires std::indirectly_copyable<ranges::iterator_t<R>, O> &&
                 (std::forward_iterator<ranges::iterator_t<R>> ||
                  (std::input_iterator<O> &&
                   std::same_as<ranges::range_value_t<R>, std::iter_value_t<O>>) ||
                  std::indirectly_copyable_storable<ranges::iterator_t<R>, O>)
    constexpr ranges::unique_copy_result<ranges::borrowed_iterator_t<R>, O>
        operator()(R&& r, O result, C comp = {}, Proj proj = {}) const
    {
        return (*this)(ranges::begin(r), ranges::end(r),
                       std::move(result), std::move(comp), std::move(proj));
    }
    
    template<ranges::forward_range R,
             std::weakly_incrementable O, class Proj = std::identity,
             std::indirect_equivalence_relation
                 <std::projected<ranges::iterator_t<R>, Proj>> C = ranges::equal_to>
        requires std::indirectly_copyable<ranges::iterator_t<R>, O> &&
                 (std::forward_iterator<ranges::iterator_t<R>> ||
                  (std::input_iterator<O> &&
                   std::same_as<ranges::range_value_t<R>, std::iter_value_t<O>>) ||
                  std::indirectly_copyable_storable<ranges::iterator_t<R>, O>)
    constexpr ranges::unique_copy_result<ranges::borrowed_iterator_t<R>, O>
        operator()(R&& r, O result, C comp = {}, Proj proj = {}) const
    {
        return (*this)(ranges::begin(r),
                       ranges::next(ranges::begin(r), ranges::end(r)),
                       std::move(result), std::move(comp), std::move(proj));
    }
};

inline constexpr unique_copy_fn unique_copy{};

Example

#include <algorithm>
#include <cmath>
#include <iostream>
#include <iterator>
#include <list>
#include <string>
#include <type_traits>

void print(const auto& rem, const auto& v)
{
    using V = std::remove_cvref_t<decltype(v)>;
    constexpr bool sep{std::is_same_v<typename V::value_type, int>};
    std::cout << rem << std::showpos;
    for (const auto& e : v)
        std::cout << e << (sep ? " " : "");
    std::cout << '\n';
}

int main()
{
    std::string s1{"The      string    with many       spaces!"};
    print("s1: ", s1);
    
    std::string s2;
    std::ranges::unique_copy
    (
        s1.begin(), s1.end(), std::back_inserter(s2),
        [](char c1, char c2) { return c1 == ' ' && c2 == ' '; }
    );
    print("s2: ", s2);
    
    const auto v1 = {-1, +1, +2, -2, -3, +3, -3};
    print("v1: ", v1);
    std::list<int> v2;
    std::ranges::unique_copy
    (
        v1, std::back_inserter(v2),
        {}, // default comparator std::ranges::equal_to
        [](int x) { return std::abs(x); } // projection
    );
    print("v2: ", v2);
}

Output:

s1: The      string    with many       spaces!
s2: The string with many spaces!
v1: -1 +1 +2 -2 -3 +3 -3 
v2: -1 +2 -3

See also

creates a copy of some range of elements that contains no consecutive duplicates
(function template) [edit]
removes consecutive duplicate elements in a range
(algorithm function object)[edit]
copies a range of elements to a new location
(algorithm function object)[edit]
finds the first two adjacent items that are equal (or satisfy a given predicate)
(algorithm function object)[edit]

Web Proxy Viewer  |  New URL  |  Original Page