Skip to content

Commit

Permalink
Implement ranges::advance (#546)
Browse files Browse the repository at this point in the history
* Implement `ranges::advance`

* [skip-tests] Address review feedback
  • Loading branch information
miscco authored Oct 25, 2023
1 parent 61a3b29 commit 8e89bde
Show file tree
Hide file tree
Showing 15 changed files with 1,385 additions and 109 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,55 +23,62 @@
#include <cuda/std/iterator>
#include <cuda/std/cassert>


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

template <class It>
__host__ __device__
void
test(It i, typename cuda::std::iterator_traits<It>::difference_type n, It x)
template <class Distance, class It>
__host__ __device__ TEST_CONSTEXPR_CXX14
void check_advance(It it, Distance n, It result)
{
cuda::std::advance(i, n);
assert(i == x);
static_assert(cuda::std::is_same<decltype(cuda::std::advance(it, n)), void>::value, "");
cuda::std::advance(it, n);
assert(it == result);
}

#if TEST_STD_VER > 14
template <class It>
__host__ __device__
constexpr bool
constepxr_test(It i, typename cuda::std::iterator_traits<It>::difference_type n, It x)
__host__ __device__ TEST_CONSTEXPR_CXX14 bool tests()
{
cuda::std::advance(i, n);
return i == x;
}
#endif
const char* s = "1234567890";

int main(int, char**)
{
// Check with iterator_traits::difference_type
{
const char* s = "1234567890";
test(cpp17_input_iterator<const char*>(s), 10, cpp17_input_iterator<const char*>(s+10));
test(forward_iterator<const char*>(s), 10, forward_iterator<const char*>(s+10));
test(bidirectional_iterator<const char*>(s+5), 5, bidirectional_iterator<const char*>(s+10));
test(bidirectional_iterator<const char*>(s+5), -5, bidirectional_iterator<const char*>(s));
test(random_access_iterator<const char*>(s+5), 5, random_access_iterator<const char*>(s+10));
test(random_access_iterator<const char*>(s+5), -5, random_access_iterator<const char*>(s));
test(s+5, 5, s+10);
test(s+5, -5, s);
typedef cuda::std::iterator_traits<const char*>::difference_type Distance;
check_advance<Distance>(cpp17_input_iterator<const char*>(s), 10, cpp17_input_iterator<const char*>(s+10));
check_advance<Distance>(forward_iterator<const char*>(s), 10, forward_iterator<const char*>(s+10));
check_advance<Distance>(bidirectional_iterator<const char*>(s+5), 5, bidirectional_iterator<const char*>(s+10));
check_advance<Distance>(bidirectional_iterator<const char*>(s+5), -5, bidirectional_iterator<const char*>(s));
check_advance<Distance>(random_access_iterator<const char*>(s+5), 5, random_access_iterator<const char*>(s+10));
check_advance<Distance>(random_access_iterator<const char*>(s+5), -5, random_access_iterator<const char*>(s));
check_advance<Distance>(s+5, 5, s+10);
check_advance<Distance>(s+5, -5, s);
}
#if TEST_STD_VER > 14

// Also check with other distance types
{
constexpr const char* s = "1234567890";
static_assert( constepxr_test(cpp17_input_iterator<const char*>(s), 10, cpp17_input_iterator<const char*>(s+10)), "" );
static_assert( constepxr_test(forward_iterator<const char*>(s), 10, forward_iterator<const char*>(s+10)), "" );
static_assert( constepxr_test(bidirectional_iterator<const char*>(s+5), 5, bidirectional_iterator<const char*>(s+10)), "" );
static_assert( constepxr_test(bidirectional_iterator<const char*>(s+5), -5, bidirectional_iterator<const char*>(s)), "" );
static_assert( constepxr_test(random_access_iterator<const char*>(s+5), 5, random_access_iterator<const char*>(s+10)), "" );
static_assert( constepxr_test(random_access_iterator<const char*>(s+5), -5, random_access_iterator<const char*>(s)), "" );
static_assert( constepxr_test(s+5, 5, s+10), "" );
static_assert( constepxr_test(s+5, -5, s), "" );
typedef int Distance;
check_advance<Distance>(cpp17_input_iterator<const char*>(s), 10, cpp17_input_iterator<const char*>(s+10));
check_advance<Distance>(forward_iterator<const char*>(s), 10, forward_iterator<const char*>(s+10));
check_advance<Distance>(bidirectional_iterator<const char*>(s), 10, bidirectional_iterator<const char*>(s+10));
check_advance<Distance>(random_access_iterator<const char*>(s), 10, random_access_iterator<const char*>(s+10));
}
#endif

return 0;
// Check with unsigned distance types to catch signedness-change issues
{
typedef cuda::std::size_t Distance;
check_advance<Distance>(cpp17_input_iterator<const char*>(s), 10u, cpp17_input_iterator<const char*>(s+10));
check_advance<Distance>(forward_iterator<const char*>(s), 10u, forward_iterator<const char*>(s+10));
check_advance<Distance>(bidirectional_iterator<const char*>(s), 10u, bidirectional_iterator<const char*>(s+10));
check_advance<Distance>(random_access_iterator<const char*>(s), 10u, random_access_iterator<const char*>(s+10));
}

return true;
}

int main(int, char**)
{
tests();
#if TEST_STD_VER > 14
static_assert(tests(), "");
#endif
return 0;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//===----------------------------------------------------------------------===//
//
// 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
// SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES.
//
//===----------------------------------------------------------------------===//

// UNSUPPORTED: c++03, c++11, c++14
// UNSUPPORTED: nvrtc
// UNSUPPORTED: msvc-19.16

// ranges::advance
// Make sure we're SFINAE-friendly when the template argument constraints are not met.

#include <cuda/std/iterator>

class not_incrementable{};

__host__ __device__ void proper_constraints() {
not_incrementable p{};
cuda::std::ranges::advance(p, 5); // expected-error {{no matching function for call}}
cuda::std::ranges::advance(p, p); // expected-error {{no matching function for call}}
cuda::std::ranges::advance(p, 5, p); // expected-error {{no matching function for call}}
}

int main(int, char**) {
return 0;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
//===----------------------------------------------------------------------===//
//
// 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
// SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES.
//
//===----------------------------------------------------------------------===//

// UNSUPPORTED: c++03, c++11, c++14
// UNSUPPORTED: msvc-19.16

// ranges::advance(it, n)

#include <cuda/std/iterator>

#include <cuda/std/cassert>

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

struct Abs {
template<class T>
__host__ __device__ constexpr T operator()(T x) const noexcept { return x < 0 ? -x : x; };
};

template <bool Count, typename It>
__host__ __device__ constexpr void check(int* first, cuda::std::iter_difference_t<It> n, int* expected) {
using Difference = cuda::std::iter_difference_t<It>;
Difference const M = (expected - first); // expected travel distance (which may be negative)
Abs abs{};
unused(abs);
unused(M);

{
It it(first);
cuda::std::ranges::advance(it, n);
assert(base(it) == expected);
ASSERT_SAME_TYPE(decltype(cuda::std::ranges::advance(it, n)), void);
}

// Count operations
if constexpr (Count) {
auto it = stride_counting_iterator(It(first));
cuda::std::ranges::advance(it, n);
if constexpr (cuda::std::random_access_iterator<It>) {
assert(it.stride_count() <= 1);
} else {
assert(it.stride_count() == abs(M));
}
}
}

__host__ __device__ constexpr bool test() {
int range[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};

// Check advancing forward
for (int n = 0; n != 10; ++n) {
check<false, cpp17_input_iterator<int*>>( range, n, range+n);
check<false, cpp20_input_iterator<int*>>( range, n, range+n);
check<true, forward_iterator<int*>>( range, n, range+n);
check<true, bidirectional_iterator<int*>>(range, n, range+n);
check<true, random_access_iterator<int*>>(range, n, range+n);
check<true, contiguous_iterator<int*>>( range, n, range+n);
check<true, int*>( range, n, range+n);
check<true, cpp17_output_iterator<int*> >(range, n, range+n);
}

// Check advancing backward
for (int n = 0; n != 10; ++n) {
check<true, bidirectional_iterator<int*>>(range+9, -n, range+9 - n);
check<true, random_access_iterator<int*>>(range+9, -n, range+9 - n);
check<true, contiguous_iterator<int*>>( range+9, -n, range+9 - n);
check<true, int*>( range+9, -n, range+9 - n);
}

return true;
}

int main(int, char**) {
assert(test());
static_assert(test());
return 0;
}
Loading

0 comments on commit 8e89bde

Please sign in to comment.