//===----------------------------------------------------------------------===// // // Part of the libcu++ 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) 2025 NVIDIA CORPORATION & AFFILIATES. // //===----------------------------------------------------------------------===// #ifndef _CUDA___NUMERIC_NARROW_H #define _CUDA___NUMERIC_NARROW_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 _CCCL_BEGIN_NAMESPACE_CUDA //! Uses static_cast to cast a value \p __from to type \p _To. \p _To needs to be constructible from \p _From, and \p //! implement operator!=. This function is intended to show that narrowing and a potential change of the value is //! intended. Modelled after `gsl::narrow_cast`. See also the C++ Core Guidelines ES.46 and ES.49. template [[nodiscard]] _CCCL_API constexpr _To narrow_cast(_From&& __from) noexcept(noexcept(static_cast<_To>(::cuda::std::forward<_From>(__from)))) { return static_cast<_To>(::cuda::std::forward<_From>(__from)); } #if _CCCL_HAS_EXCEPTIONS() struct narrowing_error : ::std::runtime_error { _CCCL_HOST_API narrowing_error() : ::std::runtime_error("Narrowing error") {} }; #endif // _CCCL_HAS_EXCEPTIONS() //! Uses static_cast to cast a value \p __from to type \p _To and checks whether the value has changed. \p _To needs //! to be constructible from \p _From and vice versa, and \p implement operator!=. Throws \ref narrowing_error in host //! code and traps in device code if the value has changed. Modelled after `gsl::narrow`. See also the C++ Core //! Guidelines ES.46 and ES.49. template [[nodiscard]] _CCCL_API constexpr _To narrow(_From __from) { static_assert(::cuda::std::is_constructible_v<_From, _To>); static_assert(::cuda::std::is_constructible_v<_To, _From>); const auto __converted = static_cast<_To>(__from); if (static_cast<_From>(__converted) != __from) { _CCCL_THROW(::cuda::narrowing_error); } if constexpr (::cuda::std::is_arithmetic_v<_From>) { if constexpr (::cuda::std::is_signed_v<_From> && !::cuda::std::is_signed_v<_To>) { if (__from < _From{}) { _CCCL_THROW(::cuda::narrowing_error); } } if constexpr (!::cuda::std::is_signed_v<_From> && ::cuda::std::is_signed_v<_To>) { if (__converted < _To{}) { _CCCL_THROW(::cuda::narrowing_error); } } } return __converted; } _CCCL_END_NAMESPACE_CUDA #include #endif // _CUDA___NUMERIC_NARROW_H