// -*- C++ -*- //===----------------------------------------------------------------------===// // // 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 // //===----------------------------------------------------------------------===// #ifndef _LIBCUDACXX___MEMORY_CONSTRUCT_AT_H #define _LIBCUDACXX___MEMORY_CONSTRUCT_AT_H #include #if defined(_CCCL_IMPLICIT_SYSTEM_HEADER_GCC) # pragma GCC system_header #elif defined(_CCCL_IMPLICIT_SYSTEM_HEADER_CLANG) # pragma clang system_header #elif defined(_CCCL_IMPLICIT_SYSTEM_HEADER_MSVC) # pragma system_header #endif // no system header #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef _CCCL_CUDA_COMPILER_CLANG # include #endif // _CCCL_CUDA_COMPILER_CLANG #if _CCCL_STD_VER >= 2020 // need to backfill ::std::construct_at # ifndef _CCCL_COMPILER_NVRTC # include # endif // _CCCL_COMPILER_NVRTC # ifndef __cpp_lib_constexpr_dynamic_alloc namespace std { template ()) _Tp(_CUDA_VSTD::declval<_Args>()...))> _LIBCUDACXX_INLINE_VISIBILITY constexpr _Tp* construct_at(_Tp* __location, _Args&&... __args) { # if defined(_LIBCUDACXX_ADDRESSOF) return ::new (_CUDA_VSTD::__voidify(*__location)) _Tp(_CUDA_VSTD::forward<_Args>(__args)...); # else return ::new (const_cast(static_cast(__location))) _Tp(_CUDA_VSTD::forward<_Args>(__args)...); # endif } } // namespace std # endif // __cpp_lib_constexpr_dynamic_alloc #endif // _CCCL_STD_VER >= 2020 _LIBCUDACXX_BEGIN_NAMESPACE_STD // There is a performance issue with placement new, where EDG based compiler insert a nullptr check that is superfluous // Because this is a noticable performance regression, we specialize it for certain types // This is possible because we are calling ::new ignoring any user defined overloads of operator placement new namespace __detail { // We cannot allow narrowing conversions between arithmetic types as the assignment will give errors template struct __is_narrowing_impl : false_type {}; template struct __is_narrowing_impl<_To, _From> : true_type {}; // This is a bit hacky, but we rely on the fact that arithmetic types cannot have more than one argument to their // constructor template struct __is_narrowing_impl<_To, _From, __void_t()})>> : false_type {}; template using __is_narrowing = _If<_CCCL_TRAIT(is_arithmetic, _Tp), __is_narrowing_impl<_Tp, _Args...>, false_type>; // The destination type must be trivially constructible from the arguments and also trivially assignable, because we // technically move assign in the optimization template struct __can_optimize_construct_at : integral_constant::value> {}; } // namespace __detail // construct_at #if _CCCL_STD_VER >= 2020 _CCCL_EXEC_CHECK_DISABLE template ()) _Tp(_CUDA_VSTD::declval<_Args>()...))> _LIBCUDACXX_INLINE_VISIBILITY _CCCL_CONSTEXPR_CXX20 __enable_if_t::value, _Tp*> construct_at(_Tp* __location, _Args&&... __args) { _LIBCUDACXX_ASSERT(__location != nullptr, "null pointer given to construct_at"); // Need to go through `std::construct_at` as that is the explicitly blessed function if (__libcpp_is_constant_evaluated()) { return ::std::construct_at(__location, _CUDA_VSTD::forward<_Args>(__args)...); } return ::new (_CUDA_VSTD::__voidify(*__location)) _Tp(_CUDA_VSTD::forward<_Args>(__args)...); } _CCCL_EXEC_CHECK_DISABLE template ()) _Tp(_CUDA_VSTD::declval<_Args>()...))> _LIBCUDACXX_INLINE_VISIBILITY _CCCL_CONSTEXPR_CXX20 __enable_if_t<__detail::__can_optimize_construct_at<_Tp, _Args...>::value, _Tp*> construct_at(_Tp* __location, _Args&&... __args) { _LIBCUDACXX_ASSERT(__location != nullptr, "null pointer given to construct_at"); // Need to go through `std::construct_at` as that is the explicitly blessed function if (__libcpp_is_constant_evaluated()) { return ::std::construct_at(__location, _CUDA_VSTD::forward<_Args>(__args)...); } *__location = _Tp{_CUDA_VSTD::forward<_Args>(__args)...}; return __location; } #endif // _CCCL_STD_VER >= 2020 _CCCL_EXEC_CHECK_DISABLE template _LIBCUDACXX_INLINE_VISIBILITY _CCCL_CONSTEXPR_CXX20 __enable_if_t::value, _Tp*> __construct_at(_Tp* __location, _Args&&... __args) { _LIBCUDACXX_ASSERT(__location != nullptr, "null pointer given to construct_at"); #if _CCCL_STD_VER >= 2020 // Need to go through `std::construct_at` as that is the explicitly blessed function if (__libcpp_is_constant_evaluated()) { return ::std::construct_at(__location, _CUDA_VSTD::forward<_Args>(__args)...); } #endif // _CCCL_STD_VER >= 2020 return ::new (_CUDA_VSTD::__voidify(*__location)) _Tp(_CUDA_VSTD::forward<_Args>(__args)...); } _CCCL_EXEC_CHECK_DISABLE template _LIBCUDACXX_INLINE_VISIBILITY _CCCL_CONSTEXPR_CXX20 __enable_if_t<__detail::__can_optimize_construct_at<_Tp, _Args...>::value, _Tp*> __construct_at(_Tp* __location, _Args&&... __args) { _LIBCUDACXX_ASSERT(__location != nullptr, "null pointer given to construct_at"); #if _CCCL_STD_VER >= 2020 // Need to go through `std::construct_at` as that is the explicitly blessed function if (__libcpp_is_constant_evaluated()) { return ::std::construct_at(__location, _CUDA_VSTD::forward<_Args>(__args)...); } #endif // _CCCL_STD_VER >= 2020 *__location = _Tp{_CUDA_VSTD::forward<_Args>(__args)...}; return __location; } // destroy_at // The internal functions are available regardless of the language version (with the exception of the `__destroy_at` // taking an array). template _LIBCUDACXX_INLINE_VISIBILITY _CCCL_CONSTEXPR_CXX20 _ForwardIterator __destroy(_ForwardIterator, _ForwardIterator); template ::value, int> = 0> _LIBCUDACXX_INLINE_VISIBILITY _CCCL_CONSTEXPR_CXX20 void __destroy_at(_Tp* __loc) { _LIBCUDACXX_ASSERT(__loc != nullptr, "null pointer given to destroy_at"); __loc->~_Tp(); } #if _CCCL_STD_VER >= 2020 template ::value, int> = 0> _LIBCUDACXX_INLINE_VISIBILITY _CCCL_CONSTEXPR_CXX20 void __destroy_at(_Tp* __loc) { _LIBCUDACXX_ASSERT(__loc != nullptr, "null pointer given to destroy_at"); _CUDA_VSTD::__destroy(_CUDA_VSTD::begin(*__loc), _CUDA_VSTD::end(*__loc)); } #endif template _LIBCUDACXX_INLINE_VISIBILITY _CCCL_CONSTEXPR_CXX20 _ForwardIterator __destroy(_ForwardIterator __first, _ForwardIterator __last) { for (; __first != __last; ++__first) { _CUDA_VSTD::__destroy_at(_CUDA_VSTD::addressof(*__first)); } return __first; } template _LIBCUDACXX_INLINE_VISIBILITY _CCCL_CONSTEXPR_CXX20 _BidirectionalIterator __reverse_destroy(_BidirectionalIterator __first, _BidirectionalIterator __last) { while (__last != __first) { --__last; _CUDA_VSTD::__destroy_at(_CUDA_VSTD::addressof(*__last)); } return __last; } #if _CCCL_STD_VER > 2014 template , int> = 0> _LIBCUDACXX_INLINE_VISIBILITY _CCCL_CONSTEXPR_CXX20 void destroy_at(_Tp* __loc) { _LIBCUDACXX_ASSERT(__loc != nullptr, "null pointer given to destroy_at"); __loc->~_Tp(); } # if _CCCL_STD_VER >= 2020 template , int> = 0> _LIBCUDACXX_INLINE_VISIBILITY _CCCL_CONSTEXPR_CXX20 void destroy_at(_Tp* __loc) { _CUDA_VSTD::__destroy_at(__loc); } # endif // _CCCL_STD_VER >= 2020 template _LIBCUDACXX_INLINE_VISIBILITY _CCCL_CONSTEXPR_CXX20 void destroy(_ForwardIterator __first, _ForwardIterator __last) { (void) _CUDA_VSTD::__destroy(_CUDA_VSTD::move(__first), _CUDA_VSTD::move(__last)); } template _LIBCUDACXX_INLINE_VISIBILITY _CCCL_CONSTEXPR_CXX20 _ForwardIterator destroy_n(_ForwardIterator __first, _Size __n) { for (; __n > 0; (void) ++__first, --__n) { _CUDA_VSTD::__destroy_at(_CUDA_VSTD::addressof(*__first)); } return __first; } #endif // _CCCL_STD_VER > 2014 _LIBCUDACXX_END_NAMESPACE_STD #endif // _LIBCUDACXX___MEMORY_CONSTRUCT_AT_H