Skip to content

Commit

Permalink
[libc++] [P2848R0] Implement is_uniqued
Browse files Browse the repository at this point in the history
  • Loading branch information
Quuxplusone committed Apr 22, 2023
1 parent cbe3761 commit 490536e
Show file tree
Hide file tree
Showing 25 changed files with 477 additions and 16 deletions.
2 changes: 2 additions & 0 deletions libcxx/include/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ set(files
__algorithm/is_permutation.h
__algorithm/is_sorted.h
__algorithm/is_sorted_until.h
__algorithm/is_uniqued.h
__algorithm/iter_swap.h
__algorithm/iterator_operations.h
__algorithm/lexicographical_compare.h
Expand Down Expand Up @@ -102,6 +103,7 @@ set(files
__algorithm/ranges_is_permutation.h
__algorithm/ranges_is_sorted.h
__algorithm/ranges_is_sorted_until.h
__algorithm/ranges_is_uniqued.h
__algorithm/ranges_iterator_concept.h
__algorithm/ranges_lexicographical_compare.h
__algorithm/ranges_lower_bound.h
Expand Down
43 changes: 43 additions & 0 deletions libcxx/include/__algorithm/is_uniqued.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef _LIBCPP___ALGORITHM_IS_UNIQUED_H
#define _LIBCPP___ALGORITHM_IS_UNIQUED_H

#include <__algorithm/comp.h>
#include <__algorithm/adjacent_find.h>
#include <__config>
#include <__iterator/iterator_traits.h>

#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif

_LIBCPP_BEGIN_NAMESPACE_STD

template <class _ForwardIterator, class _BinaryPredicate>
_LIBCPP_NODISCARD_EXT inline
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
bool
is_uniqued(_ForwardIterator __first, _ForwardIterator __last, _BinaryPredicate __pred)
{
return std::__adjacent_find(__first, __last, __pred) == __last;
}

template<class _ForwardIterator>
_LIBCPP_NODISCARD_EXT inline
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
bool
is_uniqued(_ForwardIterator __first, _ForwardIterator __last)
{
return std::__adjacent_find(__first, __last, __equal_to()) == __last;
}

_LIBCPP_END_NAMESPACE_STD

#endif // _LIBCPP___ALGORITHM_IS_UNIQUED_H
31 changes: 15 additions & 16 deletions libcxx/include/__algorithm/ranges_adjacent_find.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,30 +29,29 @@
_LIBCPP_BEGIN_NAMESPACE_STD

namespace ranges {
namespace __adjacent_find {
struct __fn {

template <class _Iter, class _Sent, class _Proj, class _Pred>
_LIBCPP_HIDE_FROM_ABI constexpr static
_Iter __adjacent_find_impl(_Iter __first, _Sent __last, _Pred& __pred, _Proj& __proj) {
if (__first == __last)
template <class _Iter, class _Sent, class _Proj, class _Pred>
_LIBCPP_HIDE_FROM_ABI constexpr
_Iter __adjacent_find_impl(_Iter __first, _Sent __last, _Pred& __pred, _Proj& __proj) {
if (__first == __last)
return __first;
auto __i = __first;
while (++__i != __last) {
if (std::invoke(__pred, std::invoke(__proj, *__first), std::invoke(__proj, *__i)))
return __first;

auto __i = __first;
while (++__i != __last) {
if (std::invoke(__pred, std::invoke(__proj, *__first), std::invoke(__proj, *__i)))
return __first;
__first = __i;
}
return __i;
__first = __i;
}
return __i;
}

namespace __adjacent_find {
struct __fn {
template <forward_iterator _Iter, sentinel_for<_Iter> _Sent,
class _Proj = identity,
indirect_binary_predicate<projected<_Iter, _Proj>, projected<_Iter, _Proj>> _Pred = ranges::equal_to>
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr
_Iter operator()(_Iter __first, _Sent __last, _Pred __pred = {}, _Proj __proj = {}) const {
return __adjacent_find_impl(std::move(__first), std::move(__last), __pred, __proj);
return ranges::__adjacent_find_impl(std::move(__first), std::move(__last), __pred, __proj);
}

template <forward_range _Range,
Expand All @@ -61,7 +60,7 @@ struct __fn {
projected<iterator_t<_Range>, _Proj>> _Pred = ranges::equal_to>
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr
borrowed_iterator_t<_Range> operator()(_Range&& __range, _Pred __pred = {}, _Proj __proj = {}) const {
return __adjacent_find_impl(ranges::begin(__range), ranges::end(__range), __pred, __proj);
return ranges::__adjacent_find_impl(ranges::begin(__range), ranges::end(__range), __pred, __proj);
}
};
} // namespace __adjacent_find
Expand Down
63 changes: 63 additions & 0 deletions libcxx/include/__algorithm/ranges_is_uniqued.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef _LIBCPP__ALGORITHM_RANGES_IS_UNIQUED_H
#define _LIBCPP__ALGORITHM_RANGES_IS_UNIQUED_H

#include <__algorithm/ranges_adjacent_find.h>
#include <__config>
#include <__functional/identity.h>
#include <__functional/ranges_operations.h>
#include <__iterator/concepts.h>
#include <__iterator/projected.h>
#include <__ranges/access.h>
#include <__ranges/concepts.h>
#include <__utility/move.h>

#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif

#if _LIBCPP_STD_VER >= 20

_LIBCPP_BEGIN_NAMESPACE_STD

namespace ranges {
namespace __is_uniqued {
struct __fn {
template <forward_iterator _Iter, sentinel_for<_Iter> _Sent,
class _Proj = identity,
indirect_binary_predicate<projected<_Iter, _Proj>,
projected<_Iter, _Proj>> _Pred = ranges::equal_to>
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr
bool operator()(_Iter __first, _Sent __last, _Pred __pred = {}, _Proj __proj = {}) const {
return ranges::__adjacent_find_impl(std::move(__first), __last, __pred, __proj) == __last;
}

template <forward_range _Range,
class _Proj = identity,
indirect_binary_predicate<projected<iterator_t<_Range>, _Proj>,
projected<iterator_t<_Range>, _Proj>> _Pred = ranges::equal_to>
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr
bool operator()(_Range&& __range, _Pred __pred = {}, _Proj __proj = {}) const {
auto __last = ranges::end(__range);
return ranges::__adjacent_find_impl(ranges::begin(__range), __last, __pred, __proj) == __last;
}
};
} // namespace __is_uniqued

inline namespace __cpo {
inline constexpr auto is_uniqued = __is_uniqued::__fn{};
} // namespace __cpo
} // namespace ranges

_LIBCPP_END_NAMESPACE_STD

#endif // _LIBCPP_STD_VER >= 20

#endif // _LIBCPP__ALGORITHM_RANGES_IS_UNIQUED_H
2 changes: 2 additions & 0 deletions libcxx/include/algorithm
Original file line number Diff line number Diff line change
Expand Up @@ -1762,6 +1762,7 @@ template <class BidirectionalIterator, class Compare>
#include <__algorithm/is_permutation.h>
#include <__algorithm/is_sorted.h>
#include <__algorithm/is_sorted_until.h>
#include <__algorithm/is_uniqued.h>
#include <__algorithm/iter_swap.h>
#include <__algorithm/lexicographical_compare.h>
#include <__algorithm/lexicographical_compare_three_way.h>
Expand Down Expand Up @@ -1821,6 +1822,7 @@ template <class BidirectionalIterator, class Compare>
#include <__algorithm/ranges_is_permutation.h>
#include <__algorithm/ranges_is_sorted.h>
#include <__algorithm/ranges_is_sorted_until.h>
#include <__algorithm/ranges_is_uniqued.h>
#include <__algorithm/ranges_lexicographical_compare.h>
#include <__algorithm/ranges_lower_bound.h>
#include <__algorithm/ranges_make_heap.h>
Expand Down
5 changes: 5 additions & 0 deletions libcxx/include/module.modulemap.in
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,7 @@ module std [system] {
module is_permutation { private header "__algorithm/is_permutation.h" }
module is_sorted { private header "__algorithm/is_sorted.h" }
module is_sorted_until { private header "__algorithm/is_sorted_until.h" }
module is_uniqued { private header "__algorithm/is_uniqued.h" }
module iter_swap { private header "__algorithm/iter_swap.h" }
module iterator_operations {
private header "__algorithm/iterator_operations.h"
Expand Down Expand Up @@ -398,6 +399,10 @@ module std [system] {
private header "__algorithm/ranges_is_sorted_until.h"
export functional.__functional.ranges_operations
}
module ranges_is_uniqued {
private header "__algorithm/ranges_is_uniqued.h"
export functional.__functional.ranges_operations
}
module ranges_iterator_concept { private header "__algorithm/ranges_iterator_concept.h" }
module ranges_lexicographical_compare {
private header "__algorithm/ranges_lexicographical_compare.h"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,8 @@ constexpr bool all_the_algorithms()
(void)std::ranges::is_sorted(a, Less(&copies)); assert(copies == 0);
(void)std::ranges::is_sorted_until(first, last, Less(&copies)); assert(copies == 0);
(void)std::ranges::is_sorted_until(a, Less(&copies)); assert(copies == 0);
(void)std::ranges::is_uniqued(first, last, Equal(&copies)); assert(copies == 0);
(void)std::ranges::is_uniqued(a, Equal(&copies)); assert(copies == 0);
if (!std::is_constant_evaluated()) { (void)std::ranges::inplace_merge(first, mid, last, Less(&copies)); assert(copies == 0); }
if (!std::is_constant_evaluated()) { (void)std::ranges::inplace_merge(a, mid, Less(&copies)); assert(copies == 0); }
(void)std::ranges::lexicographical_compare(first, last, first2, last2, Less(&copies)); assert(copies == 0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,8 @@ constexpr bool all_the_algorithms()
(void)std::ranges::is_sorted(a, Less(), Proj(&copies)); assert(copies == 0);
(void)std::ranges::is_sorted_until(first, last, Less(), Proj(&copies)); assert(copies == 0);
(void)std::ranges::is_sorted_until(a, Less(), Proj(&copies)); assert(copies == 0);
(void)std::ranges::is_uniqued(first, last, Equal(), Proj(&copies)); assert(copies == 0);
(void)std::ranges::is_uniqued(a, Equal(), Proj(&copies)); assert(copies == 0);
if (!std::is_constant_evaluated()) { (void)std::ranges::inplace_merge(first, mid, last, Less(), Proj(&copies)); assert(copies == 0); }
if (!std::is_constant_evaluated()) { (void)std::ranges::inplace_merge(a, mid, Less(), Proj(&copies)); assert(copies == 0); }
(void)std::ranges::lexicographical_compare(first, last, first2, last2, Less(), Proj(&copies), Proj(&copies)); assert(copies == 0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ TEST_CONSTEXPR_CXX20 bool all_the_algorithms()
#endif
(void)std::is_sorted(first, last, Less<T>(&copies)); assert(copies == 0);
(void)std::is_sorted_until(first, last, Less<T>(&copies)); assert(copies == 0);
(void)std::is_uniqued(first, last, Equal<T>(&copies)); assert(copies == 0);
if (!TEST_IS_CONSTANT_EVALUATED) { (void)std::inplace_merge(first, mid, last, Less<T>(&copies)); assert(copies == 0); }
(void)std::lexicographical_compare(first, last, first2, last2, Less<T>(&copies)); assert(copies == 0);
#if TEST_STD_VER > 17
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,8 @@ void test() {
(void) std::is_sorted_until(it, it, pred);
(void) std::is_sorted(it, it);
(void) std::is_sorted(it, it, pred);
(void) std::is_uniqued(it, it);
(void) std::is_uniqued(it, it, pred);
(void) std::lexicographical_compare(it, it, it, it);
(void) std::lexicographical_compare(it, it, it, it, pred);
#if TEST_STD_VER > 17
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ void test_algorithms() {
std::is_sorted_until(std::begin(arr), std::end(arr), std::greater<int>());
std::is_sorted(std::begin(arr), std::end(arr));
std::is_sorted(std::begin(arr), std::end(arr), std::greater<int>());
std::is_uniqued(std::begin(arr), std::end(arr));
std::is_uniqued(std::begin(arr), std::end(arr), std::equal_to<int>());
std::lexicographical_compare(std::begin(arr), std::end(arr), std::begin(arr),
std::end(arr));
std::lexicographical_compare(std::begin(arr), std::end(arr), std::begin(arr),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,12 @@ void test_algorithms() {
// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
std::is_sorted(std::begin(arr), std::end(arr), std::greater<int>());

// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
std::is_uniqued(std::begin(arr), std::end(arr));

// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
std::is_uniqued(std::begin(arr), std::end(arr), std::equal_to<int>());

// expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}}
std::lexicographical_compare(std::begin(arr), std::end(arr), std::begin(arr),
std::end(arr));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ void test() {
std::ranges::is_sorted_until(iter, iter);
std::ranges::is_sorted(range);
std::ranges::is_sorted(iter, iter);
std::ranges::is_uniqued(range);
std::ranges::is_uniqued(iter, iter);
std::ranges::lexicographical_compare(range, range);
std::ranges::lexicographical_compare(iter, iter, iter, iter);
std::ranges::lower_bound(range, 1);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ void test() {
std::ranges::is_sorted_until(iter, iter); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
std::ranges::is_sorted(range); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
std::ranges::is_sorted(iter, iter); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
std::ranges::is_uniqued(range); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
std::ranges::is_uniqued(iter, iter); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
std::ranges::lexicographical_compare(range, range); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
std::ranges::lexicographical_compare(iter, iter, iter, iter); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
std::ranges::lower_bound(range, 1); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
Expand Down
2 changes: 2 additions & 0 deletions libcxx/test/libcxx/private_headers.verify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ END-SCRIPT
#include <__algorithm/is_permutation.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/is_permutation.h'}}
#include <__algorithm/is_sorted.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/is_sorted.h'}}
#include <__algorithm/is_sorted_until.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/is_sorted_until.h'}}
#include <__algorithm/is_uniqued.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/is_uniqued.h'}}
#include <__algorithm/iter_swap.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/iter_swap.h'}}
#include <__algorithm/iterator_operations.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/iterator_operations.h'}}
#include <__algorithm/lexicographical_compare.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/lexicographical_compare.h'}}
Expand Down Expand Up @@ -139,6 +140,7 @@ END-SCRIPT
#include <__algorithm/ranges_is_permutation.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_is_permutation.h'}}
#include <__algorithm/ranges_is_sorted.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_is_sorted.h'}}
#include <__algorithm/ranges_is_sorted_until.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_is_sorted_until.h'}}
#include <__algorithm/ranges_is_uniqued.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_is_uniqued.h'}}
#include <__algorithm/ranges_iterator_concept.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_iterator_concept.h'}}
#include <__algorithm/ranges_lexicographical_compare.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_lexicographical_compare.h'}}
#include <__algorithm/ranges_lower_bound.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_lower_bound.h'}}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

// <algorithm>

// template<ForwardIterator Iter>
// constexpr bool is_uniqued(Iter first, Iter last);

#include <algorithm>
#include <cassert>

#include "test_macros.h"
#include "test_iterators.h"

TEST_CONSTEXPR_CXX20 bool test_constexpr() {
int ia[] = {0, 1, 2, 2, 0, 1, 2, 3};
int ib[] = {0, 1, 2, 7, 0, 1, 2, 3};
assert(std::is_uniqued(ia, ia + 8) == false);
assert(std::is_uniqued(ib, ib + 8) == true);
return true;
}

int main(int, char**)
{
{
int ia[] = {0, 1, 2, 2, 0, 1, 2, 3};
assert(!std::is_uniqued(ia, ia + 8));
assert(std::is_uniqued(ia, ia + 3));
assert(!std::is_uniqued(ia, ia + 4));
assert(std::is_uniqued(ia, ia));
assert(!std::is_uniqued(ia + 2, ia + 8));
assert(std::is_uniqued(ia + 3, ia + 8));
}
{
using It = forward_iterator<const int*>;
int ia[] = {0, 1, 2, 2, 0, 1, 2, 3};
assert(!std::is_uniqued(It(ia), It(ia + 8)));
assert(std::is_uniqued(It(ia), It(ia + 3)));
assert(!std::is_uniqued(It(ia), It(ia + 4)));
assert(std::is_uniqued(It(ia), It(ia)));
assert(!std::is_uniqued(It(ia + 2), It(ia + 8)));
assert(std::is_uniqued(It(ia + 3), It(ia + 8)));
}

test_constexpr();
#if TEST_STD_VER >= 20
static_assert(test_constexpr());
#endif

return 0;
}
Loading

0 comments on commit 490536e

Please sign in to comment.