Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-16 08:52:41

0001 //------------------------------- -*- C++ -*- -------------------------------//
0002 // Copyright Celeritas contributors: see top-level COPYRIGHT file for details
0003 // SPDX-License-Identifier: (Apache-2.0 OR MIT)
0004 //---------------------------------------------------------------------------//
0005 //! \file corecel/data/ObserverPtr.hh
0006 //---------------------------------------------------------------------------//
0007 #pragma once
0008 
0009 #include <type_traits>
0010 
0011 #include "corecel/Types.hh"
0012 #include "corecel/math/Algorithms.hh"
0013 
0014 namespace celeritas
0015 {
0016 //---------------------------------------------------------------------------//
0017 /*!
0018  * Type-safe non-owning pointer.
0019  *
0020  * This class is based on WG21 N4282, "A Proposal for the World’s Dumbest Smart
0021  * Pointer, v4". It adds memspace safety similar to Thrust's host/device_ptr.
0022  *
0023  * The dereferencing operators can *only* be used from the "native" memspace:
0024  * i.e., host data can be accessed from a .cc file, and device data from a .cu
0025  * file.
0026  *
0027  * A manual pointer cast function can be used to access the pointer with no
0028  * memspace checking.
0029  */
0030 template<class T, MemSpace M = MemSpace::native>
0031 class ObserverPtr
0032 {
0033   public:
0034     //!@{
0035     //! \name Type aliases
0036     using element_type = T;
0037     using pointer = std::add_pointer_t<T>;
0038     using reference = std::add_lvalue_reference_t<T>;
0039     //!@}
0040 
0041   public:
0042     //!@{
0043     //! Construct a pointer
0044     constexpr ObserverPtr() noexcept = default;
0045     CELER_CONSTEXPR_FUNCTION ObserverPtr(std::nullptr_t) noexcept {}
0046     CELER_CONSTEXPR_FUNCTION explicit ObserverPtr(pointer ptr) noexcept
0047         : ptr_{ptr}
0048     {
0049     }
0050 
0051     template<class T2>
0052     CELER_CONSTEXPR_FUNCTION ObserverPtr(ObserverPtr<T2, M> other) noexcept
0053         : ptr_{other.ptr_}
0054     {
0055     }
0056     //!@}
0057 
0058     //!@{
0059     //! Access the pointer
0060     CELER_CONSTEXPR_FUNCTION pointer get() const noexcept
0061     {
0062         static_assert(M == MemSpace::native, "accessing from invalid memspace");
0063         return ptr_;
0064     }
0065     CELER_CONSTEXPR_FUNCTION reference operator*() const noexcept
0066     {
0067         return *this->get();
0068     }
0069     CELER_CONSTEXPR_FUNCTION pointer operator->() const noexcept
0070     {
0071         return this->get();
0072     }
0073     CELER_CONSTEXPR_FUNCTION explicit operator pointer() const noexcept
0074     {
0075         return ptr_;
0076     }
0077     CELER_CONSTEXPR_FUNCTION explicit operator bool() const noexcept
0078     {
0079         return ptr_ != nullptr;
0080     }
0081     //!@}
0082 
0083     //!@{
0084     //! Modify the pointer
0085     CELER_CONSTEXPR_FUNCTION pointer release() noexcept
0086     {
0087         return ::celeritas::exchange(ptr_, nullptr);
0088     }
0089     CELER_CONSTEXPR_FUNCTION void reset(pointer ptr = nullptr) noexcept
0090     {
0091         ptr_ = ptr;
0092     }
0093     CELER_CONSTEXPR_FUNCTION void swap(ObserverPtr& other) noexcept
0094     {
0095         ::celeritas::trivial_swap(ptr_, other.ptr_);
0096     }
0097     //!@}
0098 
0099   private:
0100     pointer ptr_{nullptr};
0101 
0102     CELER_CONSTEXPR_FUNCTION pointer checked_get() const noexcept
0103     {
0104         static_assert(M == MemSpace::native, "accessing from invalid memspace");
0105         return ptr_;
0106     }
0107 
0108     template<class, MemSpace>
0109     friend class ObserverPtr;
0110 };
0111 
0112 //---------------------------------------------------------------------------//
0113 // DEDUCTION GUIDES
0114 //---------------------------------------------------------------------------//
0115 template<class T>
0116 CELER_FUNCTION ObserverPtr(T*) -> ObserverPtr<T>;
0117 
0118 //---------------------------------------------------------------------------//
0119 // FREE FUNCTIONS
0120 //---------------------------------------------------------------------------//
0121 //! Swap two pointers
0122 template<class T, MemSpace M>
0123 CELER_CONSTEXPR_FUNCTION void
0124 swap(ObserverPtr<T, M>& lhs, ObserverPtr<T, M>& rhs) noexcept
0125 {
0126     return lhs.swap(rhs);
0127 }
0128 
0129 //---------------------------------------------------------------------------//
0130 //!@{
0131 //! Comparators
0132 #define CELER_DEFINE_OBSPTR_CMP(TOKEN)                                         \
0133     template<class T1, class T2, MemSpace M>                                   \
0134     CELER_CONSTEXPR_FUNCTION bool operator TOKEN(                              \
0135         ObserverPtr<T1, M> const& lhs, ObserverPtr<T2, M> const& rhs) noexcept \
0136     {                                                                          \
0137         return lhs.get() TOKEN rhs.get();                                      \
0138     }
0139 CELER_DEFINE_OBSPTR_CMP(==)
0140 CELER_DEFINE_OBSPTR_CMP(!=)
0141 CELER_DEFINE_OBSPTR_CMP(<)
0142 CELER_DEFINE_OBSPTR_CMP(>)
0143 CELER_DEFINE_OBSPTR_CMP(<=)
0144 CELER_DEFINE_OBSPTR_CMP(>=)
0145 #undef CELER_DEFINE_OBSPTR_CMP
0146 
0147 template<class T, MemSpace M>
0148 CELER_CONSTEXPR_FUNCTION bool
0149 operator==(ObserverPtr<T, M> const& lhs, std::nullptr_t) noexcept
0150 {
0151     return !static_cast<bool>(lhs);
0152 }
0153 template<class T, MemSpace M>
0154 CELER_CONSTEXPR_FUNCTION bool
0155 operator!=(ObserverPtr<T, M> const& lhs, std::nullptr_t) noexcept
0156 {
0157     return static_cast<bool>(lhs);
0158 }
0159 template<class T, MemSpace M>
0160 CELER_CONSTEXPR_FUNCTION bool
0161 operator==(std::nullptr_t, ObserverPtr<T, M> const& rhs) noexcept
0162 {
0163     return !static_cast<bool>(rhs);
0164 }
0165 template<class T, MemSpace M>
0166 CELER_CONSTEXPR_FUNCTION bool
0167 operator!=(std::nullptr_t, ObserverPtr<T, M> const& rhs) noexcept
0168 {
0169     return static_cast<bool>(rhs);
0170 }
0171 //!@}
0172 
0173 //---------------------------------------------------------------------------//
0174 //! Create an observer pointer from a pointer in the native memspace.
0175 template<class T>
0176 inline ObserverPtr<T> make_observer(T* ptr) noexcept
0177 {
0178     return ObserverPtr<T>{ptr};
0179 }
0180 
0181 //---------------------------------------------------------------------------//
0182 }  // namespace celeritas