Skip to content

Commit

Permalink
Implement move_sentinel (#496)
Browse files Browse the repository at this point in the history
  • Loading branch information
miscco committed Sep 28, 2023
1 parent 94b358b commit 8deec58
Show file tree
Hide file tree
Showing 20 changed files with 1,183 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
//===----------------------------------------------------------------------===//
//
// 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

// <cuda/std/iterator>

// move_sentinel

// template<class S2>
// requires assignable_from<S&, const S2&>
// constexpr move_sentinel& operator=(const move_sentinel<S2>& s);

#include <cuda/std/iterator>
#include <cuda/std/cassert>
#include <cuda/std/concepts>

#include "test_macros.h"

struct NonAssignable {
__host__ __device__ NonAssignable& operator=(int i);
};
static_assert(cuda::std::semiregular<NonAssignable>);
static_assert(cuda::std::is_assignable_v<NonAssignable, int>);
static_assert(!cuda::std::assignable_from<NonAssignable, int>);

__host__ __device__ TEST_CONSTEXPR_CXX17 bool test()
{
// Assigning from an lvalue.
{
cuda::std::move_sentinel<int> m(42);
cuda::std::move_sentinel<long> m2;
m2 = m;
assert(m2.base() == 42L);
}

// Assigning from an rvalue.
{
cuda::std::move_sentinel<long> m2;
m2 = cuda::std::move_sentinel<int>(43);
assert(m2.base() == 43L);
}

// SFINAE checks.
{
static_assert( cuda::std::is_assignable_v<cuda::std::move_sentinel<int>, cuda::std::move_sentinel<long>>);
static_assert(!cuda::std::is_assignable_v<cuda::std::move_sentinel<int*>, cuda::std::move_sentinel<const int*>>);
static_assert( cuda::std::is_assignable_v<cuda::std::move_sentinel<const int*>, cuda::std::move_sentinel<int*>>);
static_assert(!cuda::std::is_assignable_v<cuda::std::move_sentinel<NonAssignable>, cuda::std::move_sentinel<int>>);
}
return true;
}

int main(int, char**)
{
test();
static_assert(test());

return 0;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
//===----------------------------------------------------------------------===//
//
// 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

// <cuda/std/iterator>

// move_sentinel

// constexpr S base() const;

#include <cuda/std/iterator>

#include <cuda/std/cassert>
#include <cuda/std/utility>

#include "test_macros.h"

__host__ __device__ constexpr bool test()
{
// The sentinel type is a value.
{
auto m = cuda::std::move_sentinel<int>(42);
const auto& cm = m;
assert(m.base() == 42);
assert(cm.base() == 42);
assert(cuda::std::move(m).base() == 42);
assert(cuda::std::move(cm).base() == 42);
ASSERT_SAME_TYPE(decltype(m.base()), int);
ASSERT_SAME_TYPE(decltype(cm.base()), int);
ASSERT_SAME_TYPE(decltype(cuda::std::move(m).base()), int);
ASSERT_SAME_TYPE(decltype(cuda::std::move(cm).base()), int);
}

// The sentinel type is a pointer.
{
int a[] = {1, 2, 3};
auto m = cuda::std::move_sentinel<const int*>(a);
const auto& cm = m;
assert(m.base() == a);
assert(cm.base() == a);
assert(cuda::std::move(m).base() == a);
assert(cuda::std::move(cm).base() == a);
ASSERT_SAME_TYPE(decltype(m.base()), const int*);
ASSERT_SAME_TYPE(decltype(cm.base()), const int*);
ASSERT_SAME_TYPE(decltype(cuda::std::move(m).base()), const int*);
ASSERT_SAME_TYPE(decltype(cuda::std::move(cm).base()), const int*);
}
return true;
}

int main(int, char**)
{
test();
static_assert(test());

return 0;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
//===----------------------------------------------------------------------===//
//
// 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
// XFAIL: c++17, c++20

// <cuda/std/iterator>

// template<semiregular S>
// class move_sentinel;
#include <cuda/std/concepts>
#include <cuda/std/iterator>

#include "test_iterators.h"

__host__ __device__ void test()
{
// Pointer.
{
using It = int*;
static_assert( cuda::std::sentinel_for<cuda::std::move_sentinel<It>, cuda::std::move_iterator<It>>);
static_assert( cuda::std::sized_sentinel_for<cuda::std::move_sentinel<It>, cuda::std::move_iterator<It>>);
static_assert( cuda::std::sentinel_for<cuda::std::move_sentinel<sentinel_wrapper<It>>, cuda::std::move_iterator<It>>);
static_assert(!cuda::std::sized_sentinel_for<cuda::std::move_sentinel<sentinel_wrapper<It>>, cuda::std::move_iterator<It>>);
static_assert( cuda::std::sentinel_for<cuda::std::move_sentinel<sized_sentinel<It>>, cuda::std::move_iterator<It>>);
static_assert( cuda::std::sized_sentinel_for<cuda::std::move_sentinel<sized_sentinel<It>>, cuda::std::move_iterator<It>>);
}

// `Cpp17InputIterator`.
{
using It = cpp17_input_iterator<int*>;
static_assert( cuda::std::sentinel_for<cuda::std::move_sentinel<sentinel_wrapper<It>>, cuda::std::move_iterator<It>>);
static_assert(!cuda::std::sized_sentinel_for<cuda::std::move_sentinel<sentinel_wrapper<It>>, cuda::std::move_iterator<It>>);
static_assert( cuda::std::sentinel_for<cuda::std::move_sentinel<sized_sentinel<It>>, cuda::std::move_iterator<It>>);
static_assert( cuda::std::sized_sentinel_for<cuda::std::move_sentinel<sized_sentinel<It>>, cuda::std::move_iterator<It>>);
}

// `cuda::std::input_iterator`.
{
using It = cpp20_input_iterator<int*>;
static_assert( cuda::std::sentinel_for<cuda::std::move_sentinel<sentinel_wrapper<It>>, cuda::std::move_iterator<It>>);
static_assert(!cuda::std::sized_sentinel_for<cuda::std::move_sentinel<sentinel_wrapper<It>>, cuda::std::move_iterator<It>>);
static_assert( cuda::std::sentinel_for<cuda::std::move_sentinel<sized_sentinel<It>>, cuda::std::move_iterator<It>>);
static_assert( cuda::std::sized_sentinel_for<cuda::std::move_sentinel<sized_sentinel<It>>, cuda::std::move_iterator<It>>);
}

// `cuda::std::forward_iterator`.
{
using It = forward_iterator<int*>;
static_assert( cuda::std::sentinel_for<cuda::std::move_sentinel<It>, cuda::std::move_iterator<It>>);
static_assert(!cuda::std::sized_sentinel_for<cuda::std::move_sentinel<It>, cuda::std::move_iterator<It>>);
static_assert( cuda::std::sentinel_for<cuda::std::move_sentinel<sentinel_wrapper<It>>, cuda::std::move_iterator<It>>);
static_assert(!cuda::std::sized_sentinel_for<cuda::std::move_sentinel<sentinel_wrapper<It>>, cuda::std::move_iterator<It>>);
static_assert( cuda::std::sentinel_for<cuda::std::move_sentinel<sized_sentinel<It>>, cuda::std::move_iterator<It>>);
static_assert( cuda::std::sized_sentinel_for<cuda::std::move_sentinel<sized_sentinel<It>>, cuda::std::move_iterator<It>>);
}

// `cuda::std::bidirectional_iterator`.
{
using It = bidirectional_iterator<int*>;
static_assert( cuda::std::sentinel_for<cuda::std::move_sentinel<It>, cuda::std::move_iterator<It>>);
static_assert(!cuda::std::sized_sentinel_for<cuda::std::move_sentinel<It>, cuda::std::move_iterator<It>>);
static_assert( cuda::std::sentinel_for<cuda::std::move_sentinel<sentinel_wrapper<It>>, cuda::std::move_iterator<It>>);
static_assert(!cuda::std::sized_sentinel_for<cuda::std::move_sentinel<sentinel_wrapper<It>>, cuda::std::move_iterator<It>>);
static_assert( cuda::std::sentinel_for<cuda::std::move_sentinel<sized_sentinel<It>>, cuda::std::move_iterator<It>>);
static_assert( cuda::std::sized_sentinel_for<cuda::std::move_sentinel<sized_sentinel<It>>, cuda::std::move_iterator<It>>);
}

// `cuda::std::random_access_iterator`.
{
using It = random_access_iterator<int*>;
static_assert( cuda::std::sentinel_for<cuda::std::move_sentinel<It>, cuda::std::move_iterator<It>>);
static_assert( cuda::std::sized_sentinel_for<cuda::std::move_sentinel<It>, cuda::std::move_iterator<It>>);
static_assert( cuda::std::sentinel_for<cuda::std::move_sentinel<sentinel_wrapper<It>>, cuda::std::move_iterator<It>>);
static_assert(!cuda::std::sized_sentinel_for<cuda::std::move_sentinel<sentinel_wrapper<It>>, cuda::std::move_iterator<It>>);
static_assert( cuda::std::sentinel_for<cuda::std::move_sentinel<sized_sentinel<It>>, cuda::std::move_iterator<It>>);
static_assert( cuda::std::sized_sentinel_for<cuda::std::move_sentinel<sized_sentinel<It>>, cuda::std::move_iterator<It>>);
}

// `cuda::std::contiguous_iterator`.
{
using It = contiguous_iterator<int*>;
static_assert( cuda::std::sentinel_for<cuda::std::move_sentinel<It>, cuda::std::move_iterator<It>>);
static_assert( cuda::std::sized_sentinel_for<cuda::std::move_sentinel<It>, cuda::std::move_iterator<It>>);
static_assert( cuda::std::sentinel_for<cuda::std::move_sentinel<sentinel_wrapper<It>>, cuda::std::move_iterator<It>>);
static_assert(!cuda::std::sized_sentinel_for<cuda::std::move_sentinel<sentinel_wrapper<It>>, cuda::std::move_iterator<It>>);
static_assert( cuda::std::sentinel_for<cuda::std::move_sentinel<sized_sentinel<It>>, cuda::std::move_iterator<It>>);
static_assert( cuda::std::sized_sentinel_for<cuda::std::move_sentinel<sized_sentinel<It>>, cuda::std::move_iterator<It>>);
}

#ifndef TEST_HAS_NO_SPACESHIP_OPERATOR
// `cuda::std::contiguous_iterator` with the spaceship operator.
{
using It = three_way_contiguous_iterator<int*>;
static_assert( cuda::std::sentinel_for<cuda::std::move_sentinel<It>, cuda::std::move_iterator<It>>);
static_assert( cuda::std::sized_sentinel_for<cuda::std::move_sentinel<It>, cuda::std::move_iterator<It>>);
static_assert( cuda::std::sentinel_for<cuda::std::move_sentinel<sentinel_wrapper<It>>, cuda::std::move_iterator<It>>);
static_assert(!cuda::std::sized_sentinel_for<cuda::std::move_sentinel<sentinel_wrapper<It>>, cuda::std::move_iterator<It>>);
static_assert( cuda::std::sentinel_for<cuda::std::move_sentinel<sized_sentinel<It>>, cuda::std::move_iterator<It>>);
static_assert( cuda::std::sized_sentinel_for<cuda::std::move_sentinel<sized_sentinel<It>>, cuda::std::move_iterator<It>>);
}
#endif
}

int main(int, char**)
{
return 0;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
//===----------------------------------------------------------------------===//
//
// 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

// <cuda/std/iterator>

// template<semiregular S>
// class move_sentinel;

#include <cuda/std/iterator>

template<class T, class = void>
constexpr bool HasMoveSentinel = false;

template<class T>
constexpr bool HasMoveSentinel<T, cuda::std::void_t<typename cuda::std::move_sentinel<T>>> = true;

struct Semiregular {};

struct NotSemiregular {
__host__ __device__ NotSemiregular(int);
};

static_assert( HasMoveSentinel<int>);
static_assert( HasMoveSentinel<int*>);
static_assert( HasMoveSentinel<Semiregular>);
static_assert(!HasMoveSentinel<NotSemiregular>);

int main(int, char**) {
return 0;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
//===----------------------------------------------------------------------===//
//
// 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

// <cuda/std/iterator>

// move_sentinel

// template<class S2>
// requires convertible_to<const S2&, S>
// constexpr move_sentinel(const move_sentinel<S2>& s);

#include <cuda/std/iterator>
#include <cuda/std/cassert>
#include <cuda/std/concepts>

struct NonConvertible {
__host__ __device__ explicit NonConvertible();
__host__ __device__ NonConvertible(int i);
__host__ __device__ explicit NonConvertible(long i) = delete;
};
static_assert(cuda::std::semiregular<NonConvertible>);
static_assert(cuda::std::is_convertible_v<long, NonConvertible>);
static_assert(!cuda::std::convertible_to<long, NonConvertible>);

__host__ __device__ constexpr bool test()
{
// Constructing from an lvalue.
{
cuda::std::move_sentinel<int> m(42);
cuda::std::move_sentinel<long> m2 = m;
assert(m2.base() == 42L);
}

// Constructing from an rvalue.
{
cuda::std::move_sentinel<long> m2 = cuda::std::move_sentinel<int>(43);
assert(m2.base() == 43L);
}

// SFINAE checks.
{
static_assert( cuda::std::is_convertible_v<cuda::std::move_sentinel<int>, cuda::std::move_sentinel<long>>);
static_assert( cuda::std::is_convertible_v<cuda::std::move_sentinel<int*>, cuda::std::move_sentinel<const int*>>);
static_assert(!cuda::std::is_convertible_v<cuda::std::move_sentinel<const int*>, cuda::std::move_sentinel<int*>>);
static_assert( cuda::std::is_convertible_v<cuda::std::move_sentinel<int>, cuda::std::move_sentinel<NonConvertible>>);
static_assert(!cuda::std::is_convertible_v<cuda::std::move_sentinel<long>, cuda::std::move_sentinel<NonConvertible>>);
}
return true;
}

int main(int, char**)
{
test();
static_assert(test());

return 0;
}
Loading

0 comments on commit 8deec58

Please sign in to comment.