std::ranges::ends_with() algorithm
- od C++20
- Simplified
- Detailed
// (1)constexpr bool ends_with( I1 first1, S1 last1, I2 first2, S2 last2, Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {} );// (2)constexpr bool ends_with( R1&& r1, R2&& r2, Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {} );
The type of arguments are generic and have the following constraints:
I1
,I2
-std::input_iterator
S1
,S2
-std::sentinel_for<I1>
,std::sentinel_for<I2>
Pred
- (none)Proj1
,Proj2
- (none)- (2) -
R1
,R2
-std::ranges::input_range
The Pred
template argumenth as a default type of ranges::equal_to
for all overloads.
The Proj1
and Proj2
template arguments have a default type of std::identity
for all overloads.
Additionally, each overload has the following constraints:
- (1):
(forward_iterator<I1> || sized_sentinel_for<S1, I1>)&& (forward_iterator<I2> || sized_sentinel_for<S2, I2>)&& indirectly_comparable<I1, I2, Pred, Proj1, Proj2>`
- (2):
(ranges::forward_range<R1> || ranges::sized_range<R1>)&& (ranges::forward_range<R2> || ranges::sized_range<R2>)&& std::indirectly_comparable<ranges::iterator_t<R1>, ranges::iterator_t<R2>, Pred, Proj1, Proj2>
(The std::
namespace was ommitted here for readability)
// (1)template< std::input_iterator I1, std::sentinel_for<I1> S1, std::input_iterator I2, std::sentinel_for<I2> S2, class Pred = ranges::equal_to, class Proj1 = std::identity, class Proj2 = std::identity> requires (std::forward_iterator<I1> || std::sized_sentinel_for<S1, I1>) && (std::forward_iterator<I2> || std::sized_sentinel_for<S2, I2>) && std::indirectly_comparable<I1, I2, Pred, Proj1, Proj2>constexpr bool ends_with( I1 first1, S1 last1, I2 first2, S2 last2, Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {} );// (2)template< ranges::input_range R1, ranges::input_range R2, class Pred = ranges::equal_to, class Proj1 = std::identity, class Proj2 = std::identity> requires (ranges::forward_range<R1> || ranges::sized_range<R1>) && (ranges::forward_range<R2> || ranges::sized_range<R2>) && std::indirectly_comparable<ranges::iterator_t<R1>, ranges::iterator_t<R2>, Pred, Proj1, Proj2>constexpr bool ends_with( R1&& r1, R2&& r2, Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {} );
Checks whether the second range matches the suffix of the first range.
-
(1) Comparison is done by applying the binary predicate
pred
to elements in two ranges projected byproj1
andproj2
respectively. -
(2) Same as (1), but uses
r1
as the first source range andr2
as the second source range, as if usingranges::begin(r1)
asfirst1
,ranges::end(r1)
aslast1
,ranges::begin(r2)
asfirst2
, andranges::end(r2)
aslast2
.
The function-like entities described on this page are niebloids.
Parameters
first1 last1 | The range of elements to examine. |
r1 | The range of elements to examine. |
first2 last2 | The range of elements to be used as suffix. |
r2 | The range of elements to be used as suffix. |
pred | Binary predicate to compare the elements with. |
proj1 | Projection to apply to the elements in the first range. |
proj2 | Projection to apply to the elements in the second range. |
Return value
true
if the second range matches the prefix of the first range, false
otherwise.
More specifically:
Let N1
and N2
denote the size of ranges [first1
; last1
) and [first2
; last2
) respectively.
- If
N1 < N2
, returnsfalse
. - Otherwise, if every element in the range [
first2
;last2
) is equal to the corresponding element in [first1 + N1 - N2
;last1
) (compared usingpred
after projections), returnstrue
.
Complexity
At most min(N1, N2)
applications of the predicate and both projections. The predicate and both projections are not applied if N1 < N2
If both N1
and N2
can be calculated in constant time (i.e. both iterator-sentinel type pairs model sized_sentinel_for
, or both range types model sized_range
) and N1 < N2
, the time complexity is constant.
Exceptions
(none)
Possible implementation
ends_with(1) and starts_with(2)
struct ends_with_fn{ template<std::input_iterator I1, std::sentinel_for<I1> S1, std::input_iterator I2, std::sentinel_for<I2> S2, class Pred = ranges::equal_to, class Proj1 = std::identity, class Proj2 = std::identity> requires (std::forward_iterator<I1> || std::sized_sentinel_for<S1, I1>) && (std::forward_iterator<I2> || std::sized_sentinel_for<S2, I2>) && std::indirectly_comparable<I1, I2, Pred, Proj1, Proj2> constexpr bool operator()(I1 first1, S1 last1, I2 first2, S2 last2, Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {}) const { const auto n1 = ranges::distance(first1, last1); const auto n2 = ranges::distance(first2, last2); if (n1 < n2) return false; ranges::advance(first1, n1 - n2); return ranges::equal(std::move(first1), std::move(last1), std::move(first2), std::move(last2), std::move(pred), std::move(proj1), std::move(proj2)); } template<ranges::input_range R1, ranges::input_range R2, class Pred = ranges::equal_to, class Proj1 = std::identity, class Proj2 = std::identity> requires (ranges::forward_range<R1> || ranges::sized_range<R1>) && (ranges::forward_range<R2> || ranges::sized_range<R2>) && std::indirectly_comparable<ranges::iterator_t<R1>, ranges::iterator_t<R2>, Pred, Proj1, Proj2> constexpr bool operator()(R1&& r1, R2&& r2, Pred pred = {}, Proj1 proj1 = {}, Proj2 proj2 = {}) const { return (*this)(ranges::begin(r1), ranges::end(r1), ranges::begin(r2), ranges::end(r2), std::move(pred), std::move(proj1), std::move(proj2)); }};inline constexpr ends_with_fn ends_with {};
Examples
#include <algorithm>#include <array>#include <iostream>int main(){ std::cout << std::boolalpha << std::ranges::ends_with("static_cast", "cast") << '\n' << std::ranges::ends_with("const_cast", "cast") << '\n' << std::ranges::ends_with("reinterpret_cast", "cast") << '\n' << std::ranges::ends_with("dynamic_cast", "cast") << '\n' << std::ranges::ends_with("move", "cast") << '\n' << std::ranges::ends_with("move_if_noexcept", "cast") << '\n' << std::ranges::ends_with("forward", "cast") << '\n'; static_assert( ! std::ranges::ends_with("as_const", "cast") and !! std::ranges::ends_with("bit_cast", "cast") and ! std::ranges::ends_with("to_underlying", "cast") and !! std::ranges::ends_with(std::array {1,2,3,4}, std::array {3,4}) and ! std::ranges::ends_with(std::array {1,2,3,4}, std::array {4,5}) );}
truetruetruetruefalsefalsefalse
Hover to see the original license.