Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:54:47

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