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

Commit

Permalink
Implement cuda::resource and cuda::resource_with concepts
Browse files Browse the repository at this point in the history
This also adds the necessary framework for concept emulation
  • Loading branch information
miscco committed Aug 30, 2022
1 parent aff156a commit d31c96f
Show file tree
Hide file tree
Showing 4 changed files with 531 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//

// UNSUPPORTED: c++03, c++11

// cuda::resource, cuda::resource_with
#include <cuda/memory_resource>

#include <cuda/std/cstdint>

struct invalid_argument {};

namespace test_resource {
struct valid_resource {
void* allocate(std::size_t, std::size_t) { return nullptr; }
void deallocate(void*, std::size_t, std::size_t) {}
bool operator==(const valid_resource&) { return true; }
};
static_assert(cuda::resource<valid_resource>, "");

struct invalid_allocate_argument {
void* allocate(invalid_argument, std::size_t) { return nullptr; }
void deallocate(void*, std::size_t, std::size_t) {}
bool operator==(const valid_resource&) { return true; }
};
static_assert(!cuda::resource<invalid_allocate_argument>, "");

struct invalid_allocate_return {
int allocate(std::size_t, std::size_t) { return 42; }
void deallocate(void*, std::size_t, std::size_t) {}
bool operator==(const valid_resource&) { return true; }
};
static_assert(!cuda::resource<invalid_allocate_return>, "");

struct invalid_deallocate_argument {
void* allocate(std::size_t, std::size_t) { return nullptr; }
void deallocate(void*, invalid_argument, std::size_t) {}
bool operator==(const valid_resource&) { return true; }
};
static_assert(!cuda::resource<invalid_deallocate_argument>, "");

struct non_comparable {
void* allocate(std::size_t, std::size_t) { return nullptr; }
void deallocate(void*, std::size_t, std::size_t) {}
};
// TODO: Implement equality_comparable
static_assert(cuda::resource<non_comparable>, "");
} // namespace test_resource

namespace test_has_property {
struct prop_with_value {
using value_type = int;
};
struct prop {};

struct valid_property {
friend void get_property(const valid_property&, prop) {}
};
static_assert(!cuda::has_property<valid_property, prop_with_value>, "");
static_assert(cuda::has_property<valid_property, prop>, "");
static_assert(!cuda::has_property_with<valid_property, prop, int>, "");

struct valid_property_with_value {
friend int get_property(const valid_property_with_value&, prop_with_value) {
return 42;
}
};
static_assert(cuda::has_property<valid_property_with_value, prop_with_value>,
"");
static_assert(!cuda::has_property<valid_property_with_value, prop>, "");
static_assert(
cuda::has_property_with<valid_property_with_value, prop_with_value, int>,
"");
static_assert(!cuda::has_property_with<valid_property_with_value,
prop_with_value, double>,
"");

struct derived_from_property : public valid_property {
friend int get_property(const derived_from_property&, prop_with_value) {
return 42;
}
};
static_assert(cuda::has_property<derived_from_property, prop_with_value>, "");
static_assert(cuda::has_property<derived_from_property, prop>, "");
static_assert(
cuda::has_property_with<derived_from_property, prop_with_value, int>, "");
static_assert(
!cuda::has_property_with<derived_from_property, prop_with_value, double>,
"");
} // namespace test_has_property

namespace test_resource_with {
struct prop_with_value {};
struct prop {};

struct valid_resource_with_property {
void* allocate(std::size_t, std::size_t) { return nullptr; }
void deallocate(void*, std::size_t, std::size_t) {}
bool operator==(const valid_resource_with_property&) { return true; }
friend void get_property(const valid_resource_with_property&,
prop_with_value) {}
};
static_assert(
cuda::resource_with<valid_resource_with_property, prop_with_value>, "");

struct valid_resource_without_property {
void* allocate(std::size_t, std::size_t) { return nullptr; }
void deallocate(void*, std::size_t, std::size_t) {}
bool operator==(const valid_resource_without_property&) { return true; }
};
static_assert(
!cuda::resource_with<valid_resource_without_property, prop_with_value>, "");

struct invalid_resource_with_property {
friend void get_property(const invalid_resource_with_property&,
prop_with_value) {}
};
static_assert(
!cuda::resource_with<invalid_resource_with_property, prop_with_value>, "");

struct resource_with_many_properties {
void* allocate(std::size_t, std::size_t) { return nullptr; }
void deallocate(void*, std::size_t, std::size_t) {}
bool operator==(const resource_with_many_properties&) { return true; }
friend void get_property(const resource_with_many_properties&,
prop_with_value) {}
friend void get_property(const resource_with_many_properties&, prop) {}
};
static_assert(
cuda::resource_with<resource_with_many_properties, prop_with_value, prop>,
"");
static_assert(!cuda::resource_with<resource_with_many_properties,
prop_with_value, int, prop>,
"");

struct derived_with_property : public valid_resource_without_property {
friend void get_property(const derived_with_property&, prop_with_value) {}
};
static_assert(cuda::resource_with<derived_with_property, prop_with_value>, "");
} // namespace test_resource_with

int main(int, char**) { return 0; }
98 changes: 98 additions & 0 deletions include/cuda/memory_resource
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
//===----------------------------------------------------------------------===//
//
// Part of the CUDA Toolkit, 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 _CUDA_MEMORY_RESOURCE
#define _CUDA_MEMORY_RESOURCE

#include <cuda/std/type_traits>

#include <cuda/std/detail/__concepts>
#include <cuda/std/detail/__config>

#include <cuda/std/detail/__pragma_push>

#if _LIBCUDACXX_STD_VER > 11
_LIBCUDACXX_BEGIN_NAMESPACE_CUDA

///////////////////////////////////////////////////////////////////////////////
// memory_resource
_LIBCUDACXX_TEMPLATE(class _Ret, class _Ptr)
(requires _CUDA_VSTD::is_same_v<_Ptr, _Ret>)void _Returns_matching(_Ptr) {}

/// \concept _Has_member_allocate
/// \brief The \c _Has_member_allocate concept
template <class _Resource>
_LIBCUDACXX_CONCEPT_FRAGMENT(
_Has_member_allocate_,
requires(_Resource &__res, size_t __bytes, size_t __alignment) //
(_Returns_matching<void *>(__res.allocate(__bytes, __alignment))));
template <class _Resource>
_LIBCUDACXX_CONCEPT _Has_member_allocate =
_LIBCUDACXX_FRAGMENT(_Has_member_allocate_, _Resource);

/// \concept _Has_member_deallocate
/// \brief The \c _Has_member_deallocate concept
template <class _Resource>
_LIBCUDACXX_CONCEPT_FRAGMENT(_Has_member_deallocate_,
requires(_Resource &__res, void *__ptr,
size_t __bytes,
size_t __alignment) //
(__res.deallocate(__ptr, __bytes, __alignment)));
template <class _Resource>
_LIBCUDACXX_CONCEPT _Has_member_deallocate =
_LIBCUDACXX_FRAGMENT(_Has_member_deallocate_, _Resource);

/// \concept resource
/// \brief The \c resource concept
template <class _Resource>
_LIBCUDACXX_CONCEPT resource =
_Has_member_allocate<_Resource> &&_Has_member_deallocate<_Resource>
/* && _CUDA_VSTD::equality_comparable<_Resource> */;

/// \concept has_property
/// \brief The \c has_property concept
template <class _Resource, class _Property>
_LIBCUDACXX_CONCEPT_FRAGMENT(_Has_property_,
requires(const _Resource &__res) //
(get_property(__res, _Property{})));
template <class _Resource, class _Property>
_LIBCUDACXX_CONCEPT has_property = _LIBCUDACXX_FRAGMENT(_Has_property_,
_Resource, _Property);

/// \concept has_property_with
/// \brief The \c has_property_with concept
template <class _Resource, class _Property, class _Return>
_LIBCUDACXX_CONCEPT_FRAGMENT(
_Has_property_with_,
requires(const _Resource &__res) //
(_Returns_matching<_Return>(get_property(__res, _Property{})),
_Returns_matching<_Return>(
_CUDA_VSTD::declval<typename _Property::value_type>())));
template <class _Resource, class _Property, class _Return>
_LIBCUDACXX_CONCEPT has_property_with =
_LIBCUDACXX_FRAGMENT(_Has_property_with_, _Resource, _Property, _Return);

/// \concept resource
/// \brief The \c resource concept
template <class _Resource, class... _Properties>
#if _LIBCUDACXX_STD_VER < 17
_LIBCUDACXX_CONCEPT resource_with =
resource<_Resource> &&_CUDA_VSTD::conjunction<_CUDA_VSTD::bool_constant<
has_property<_Resource, _Properties>>...>::value;
#else
_LIBCUDACXX_CONCEPT resource_with = resource<_Resource> //
&& (has_property<_Resource, _Properties> &&
...);
#endif

_LIBCUDACXX_END_NAMESPACE_CUDA
#endif // _LIBCUDACXX_STD_VER > 11

#include <cuda/std/detail/__pragma_pop>

#endif //_LIBCUDACXX_BEGIN_NAMESPACE_CUDA
Loading

0 comments on commit d31c96f

Please sign in to comment.