Skip to content
This repository has been archived by the owner on Mar 21, 2024. It is now read-only.

Commit

Permalink
Add range constructors for static span and add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
miscco committed Oct 25, 2022
1 parent f3f03cf commit 4b08898
Show file tree
Hide file tree
Showing 5 changed files with 272 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
// SPDX-FileCopyrightText: Copyright (c) 2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
//
//===---------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17
// UNSUPPORTED: c++03, c++11

// <span>
// <cuda/std/span>

// template <class It, class End>
// constexpr explicit(Extent != dynamic_extent) span(It first, End last);
Expand All @@ -26,7 +26,7 @@
using cuda::std::span;

template <class T, class Sentinel>
constexpr bool test_ctor() {
__host__ __device__ constexpr bool test_ctor() {
T val[2] = {};
auto s1 = span<T>(cuda::std::begin(val), Sentinel(cuda::std::end(val)));
auto s2 = span<T, 2>(cuda::std::begin(val), Sentinel(cuda::std::end(val)));
Expand All @@ -36,7 +36,7 @@ constexpr bool test_ctor() {
}

template <size_t Extent>
constexpr void test_constructibility() {
__host__ __device__ constexpr void test_constructibility() {
static_assert(cuda::std::is_constructible_v<span<int, Extent>, int*, int*>);
static_assert(!cuda::std::is_constructible_v<span<int, Extent>, const int*, const int*>);
static_assert(!cuda::std::is_constructible_v<span<int, Extent>, volatile int*, volatile int*>);
Expand All @@ -49,14 +49,14 @@ constexpr void test_constructibility() {
static_assert(!cuda::std::is_constructible_v<span<int, Extent>, int*, float*>); // types wrong
}

constexpr bool test() {
__host__ __device__ constexpr bool test() {
test_constructibility<cuda::std::dynamic_extent>();
test_constructibility<3>();
struct A {};
assert((test_ctor<int, int*>()));
assert((test_ctor<int, sized_sentinel<int*>>()));
//assert((test_ctor<int, sized_sentinel<int*>>()));
assert((test_ctor<A, A*>()));
assert((test_ctor<A, sized_sentinel<A*>>()));
//assert((test_ctor<A, sized_sentinel<A*>>()));
return true;
}

Expand Down
144 changes: 144 additions & 0 deletions .upstream-tests/test/std/views/views.span/span.cons/range.pass.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
//===---------------------------------------------------------------------===//
//
// 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) 2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
//
//===---------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11

// <cuda/std/span>

// template<class Container>
// constexpr explicit(Extent != dynamic_extent) span(Container&);
// template<class Container>
// constexpr explicit(Extent != dynamic_extent) span(Container const&);

// This test checks for libc++'s non-conforming temporary extension to cuda::std::span
// to support construction from containers that look like contiguous ranges.
//
// This extension is only supported when we don't ship <ranges>, and we can
// remove it once we get rid of _LIBCUDACXX_HAS_NO_INCOMPLETE_RANGES.

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

#include "test_macros.h"

// Look ma - I'm a container!
template <typename T>
struct IsAContainer {
__host__ __device__ constexpr IsAContainer() : v_{} {}
__host__ __device__ constexpr size_t size() const {return 1;}
__host__ __device__ constexpr T *data() {return &v_;}
__host__ __device__ constexpr const T *data() const {return &v_;}
__host__ __device__ constexpr T *begin() {return &v_;}
__host__ __device__ constexpr const T *begin() const {return &v_;}
__host__ __device__ constexpr T *end() {return &v_ + 1;}
__host__ __device__ constexpr const T *end() const {return &v_ + 1;}

__host__ __device__ constexpr T const *getV() const {return &v_;} // for checking
T v_;
};

template <typename T>
__host__ __device__
constexpr bool unused(T &&) {return true;}

__host__ __device__ void checkCV()
{
IsAContainer<int> v{};

// Types the same
{
cuda::std::span< int> s1{v}; // a span< int> pointing at int.
unused(s1);
}

// types different
{
cuda::std::span<const int> s1{v}; // a span<const int> pointing at int.
cuda::std::span< volatile int> s2{v}; // a span< volatile int> pointing at int.
cuda::std::span< volatile int> s3{v}; // a span< volatile int> pointing at const int.
cuda::std::span<const volatile int> s4{v}; // a span<const volatile int> pointing at int.
unused(s1);
unused(s2);
unused(s3);
unused(s4);
}

// Constructing a const view from a temporary
{
cuda::std::span<const int> s1{IsAContainer<int>()};
unused(s1);
}
}


template <typename T>
__host__ __device__ constexpr bool testConstexprSpan()
{
constexpr IsAContainer<const T> val{};
cuda::std::span<const T> s1{val};
return s1.data() == val.getV() && s1.size() == 1;
}

template <typename T>
__host__ __device__ constexpr bool testConstexprSpanStatic()
{
constexpr IsAContainer<const T> val{};
cuda::std::span<const T, 1> s1{val};
return s1.data() == val.getV() && s1.size() == 1;
}

template <typename T>
__host__ __device__ void testRuntimeSpan()
{
IsAContainer<T> val{};
const IsAContainer<T> cVal;
cuda::std::span<T> s1{val};
cuda::std::span<const T> s2{cVal};
assert(s1.data() == val.getV() && s1.size() == 1);
assert(s2.data() == cVal.getV() && s2.size() == 1);
}

template <typename T>
__host__ __device__ void testRuntimeSpanStatic()
{
IsAContainer<T> val{};
const IsAContainer<T> cVal;
cuda::std::span<T, 1> s1{val};
cuda::std::span<const T, 1> s2{cVal};
assert(s1.data() == val.getV() && s1.size() == 1);
assert(s2.data() == cVal.getV() && s2.size() == 1);
}

struct A{};

int main(int, char**)
{
static_assert(testConstexprSpan<int>(), "");
static_assert(testConstexprSpan<long>(), "");
static_assert(testConstexprSpan<double>(), "");
static_assert(testConstexprSpan<A>(), "");

static_assert(testConstexprSpanStatic<int>(), "");
static_assert(testConstexprSpanStatic<long>(), "");
static_assert(testConstexprSpanStatic<double>(), "");
static_assert(testConstexprSpanStatic<A>(), "");

testRuntimeSpan<int>();
testRuntimeSpan<long>();
testRuntimeSpan<double>();
testRuntimeSpan<A>();

testRuntimeSpanStatic<int>();
testRuntimeSpanStatic<long>();
testRuntimeSpanStatic<double>();
testRuntimeSpanStatic<A>();

checkCV();

return 0;
}
109 changes: 109 additions & 0 deletions .upstream-tests/test/std/views/views.span/span.cons/range.verify.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
//===---------------------------------------------------------------------===//
//
// 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) 2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
//
//===---------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11

// <cuda/std/span>

// template<class Container>
// constexpr explicit(Extent != dynamic_extent) span(Container&);
// template<class Container>
// constexpr explicit(Extent != dynamic_extent) span(Container const&);

// This test checks for libc++'s non-conforming temporary extension to cuda::std::span
// to support construction from containers that look like contiguous ranges.
//
// This extension is only supported when we don't ship <ranges>, and we can
// remove it once we get rid of _LIBCUDACXX_HAS_NO_INCOMPLETE_RANGES.

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

#include "test_macros.h"

// Look ma - I'm a container!
template <typename T>
struct IsAContainer {
__host__ __device__ constexpr IsAContainer() : v_{} {}
__host__ __device__ constexpr size_t size() const {return 1;}
__host__ __device__ constexpr T *data() {return &v_;}
__host__ __device__ constexpr const T *data() const {return &v_;}

__host__ __device__ constexpr const T *getV() const {return &v_;} // for checking
T v_;
};

template <typename T>
struct NotAContainerNoData {
__host__ __device__ size_t size() const {return 0;}
};

template <typename T>
struct NotAContainerNoSize {
__host__ __device__ const T *data() const {return nullptr;}
};

template <typename T>
struct NotAContainerPrivate {
private:
__host__ __device__ size_t size() const {return 0;}
__host__ __device__ const T *data() const {return nullptr;}
};

template<class T, size_t extent, class container>
__host__ __device__ cuda::std::span<T, extent> createImplicitSpan(container c) {
return {c}; // expected-error-re {{no matching constructor for initialization of 'cuda::std::span<{{.+}}>'}}
}

int main(int, char**)
{

// Making non-const spans from const sources (a temporary binds to `const &`)
{
cuda::std::span<int> s1{IsAContainer<int>()}; // expected-error {{no matching constructor for initialization of 'cuda::std::span<int>'}}
}

// Missing size and/or data
{
cuda::std::span<const int> s1{NotAContainerNoData<int>()}; // expected-error {{no matching constructor for initialization of 'cuda::std::span<const int>'}}
cuda::std::span<const int> s3{NotAContainerNoSize<int>()}; // expected-error {{no matching constructor for initialization of 'cuda::std::span<const int>'}}
cuda::std::span<const int> s5{NotAContainerPrivate<int>()}; // expected-error {{no matching constructor for initialization of 'cuda::std::span<const int>'}}
}

// Not the same type
{
IsAContainer<int> c;
cuda::std::span<float> s1{c}; // expected-error {{no matching constructor for initialization of 'cuda::std::span<float>'}}
}

// CV wrong
{
IsAContainer<const int> c;
IsAContainer<const volatile int> cv;
IsAContainer< volatile int> v;

cuda::std::span< int> s1{c}; // expected-error {{no matching constructor for initialization of 'cuda::std::span<int>'}}
cuda::std::span< int> s2{v}; // expected-error {{no matching constructor for initialization of 'cuda::std::span<int>'}}
cuda::std::span< int> s3{cv}; // expected-error {{no matching constructor for initialization of 'cuda::std::span<int>'}}
cuda::std::span<const int> s4{v}; // expected-error {{no matching constructor for initialization of 'cuda::std::span<const int>'}}
cuda::std::span<const int> s5{cv}; // expected-error {{no matching constructor for initialization of 'cuda::std::span<const int>'}}
cuda::std::span< volatile int> s6{c}; // expected-error {{no matching constructor for initialization of 'cuda::std::span<volatile int>'}}
cuda::std::span< volatile int> s7{cv}; // expected-error {{no matching constructor for initialization of 'cuda::std::span<volatile int>'}}
}

// explicit constructor necessary
{
IsAContainer<int> c;
const IsAContainer<int> cc;

createImplicitSpan<int, 1>(c);
createImplicitSpan<int, 1>(cc);
}

return 0;
}
11 changes: 11 additions & 0 deletions include/cuda/std/detail/libcxx/include/span
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,17 @@ public:
_LIBCUDACXX_CONSTEXPR_AFTER_CXX11 span(const span<_OtherElementType, dynamic_extent>& __other) noexcept
: __data{__other.data()} { _LIBCUDACXX_ASSERT(_Extent == __other.size(), "size mismatch in span's constructor (other span)"); }

template <class _Container, enable_if_t<
__is_span_compatible_container<_Container, _Tp>::value, nullptr_t> = nullptr>
_LIBCUDACXX_INLINE_VISIBILITY
constexpr span( _Container& __c) noexcept(noexcept(_CUDA_VSTD::data(__c)))
: __data{_CUDA_VSTD::data(__c)} { _LIBCUDACXX_ASSERT(_Extent == _CUDA::VSTD::size(__c), "size mismatch in span's constructor (other span)"); }

template <class _Container, enable_if_t<
__is_span_compatible_container<_Container, _Tp>::value, nullptr_t> = nullptr>
_LIBCUDACXX_INLINE_VISIBILITY
constexpr span(const _Container& __c) noexcept(noexcept(_CUDA_VSTD::data(__c)))
: __data{_CUDA_VSTD::data(__c)} { _LIBCUDACXX_ASSERT(_Extent == _CUDA::VSTD::size(__c), "size mismatch in span's constructor (other span)"); }

// ~span() noexcept = default;

Expand Down
1 change: 1 addition & 0 deletions llvm-project
Submodule llvm-project added at 377a95

0 comments on commit 4b08898

Please sign in to comment.