Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-18 09:09:37

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/detail/CollectionImpl.hh
0006 //---------------------------------------------------------------------------//
0007 #pragma once
0008 
0009 #include <type_traits>
0010 
0011 #ifndef CELER_DEVICE_COMPILE
0012 #    include <vector>
0013 
0014 #    include "../DeviceVector.hh"
0015 #endif
0016 
0017 #include "corecel/Assert.hh"
0018 #include "corecel/OpaqueId.hh"
0019 #include "corecel/Types.hh"
0020 #include "corecel/cont/Span.hh"
0021 #include "corecel/sys/Device.hh"
0022 
0023 #include "DisabledStorage.hh"
0024 #include "TypeTraits.hh"
0025 #include "../Copier.hh"
0026 #include "../LdgIterator.hh"
0027 #include "../PinnedAllocator.hh"
0028 
0029 namespace celeritas
0030 {
0031 namespace detail
0032 {
0033 //---------------------------------------------------------------------------//
0034 template<class T, Ownership W, MemSpace M, typename = void>
0035 struct CollectionTraits
0036 {
0037     using type = T;
0038     using const_type = T const;
0039     using reference_type = type&;
0040     using const_reference_type = const_type&;
0041     using SpanT = Span<type>;
0042     using SpanConstT = Span<const_type>;
0043 };
0044 
0045 //---------------------------------------------------------------------------//
0046 template<class T, MemSpace M>
0047 struct CollectionTraits<T, Ownership::reference, M, void>
0048 {
0049     using type = T;
0050     using const_type = T;
0051     using reference_type = type&;
0052     using const_reference_type = const_type&;
0053     using SpanT = Span<type>;
0054     using SpanConstT = Span<const_type>;
0055 };
0056 
0057 //---------------------------------------------------------------------------//
0058 template<class T, MemSpace M>
0059 struct CollectionTraits<T,
0060                         Ownership::const_reference,
0061                         M,
0062                         std::enable_if_t<!is_ldg_supported_v<std::add_const_t<T>>>>
0063 {
0064     using type = T const;
0065     using const_type = T const;
0066     using reference_type = type&;
0067     using const_reference_type = const_type&;
0068     using SpanT = Span<type>;
0069     using SpanConstT = Span<const_type>;
0070 };
0071 
0072 //---------------------------------------------------------------------------//
0073 template<class T, MemSpace M>
0074 struct CollectionTraits<T,
0075                         Ownership::const_reference,
0076                         M,
0077                         std::enable_if_t<is_ldg_supported_v<std::add_const_t<T>>>>
0078 {
0079     using type = T const;
0080     using const_type = T const;
0081     using reference_type = type&;
0082     using const_reference_type = const_type&;
0083     using SpanT = Span<type>;
0084     using SpanConstT = Span<const_type>;
0085 };
0086 
0087 //---------------------------------------------------------------------------//
0088 template<class T>
0089 struct CollectionTraits<T,
0090                         Ownership::const_reference,
0091                         MemSpace::device,
0092                         std::enable_if_t<is_ldg_supported_v<std::add_const_t<T>>>>
0093 {
0094     using type = T const;
0095     using const_type = T const;
0096     using reference_type = type;
0097     using const_reference_type = const_type;
0098     using SpanT = LdgSpan<const_type>;
0099     using SpanConstT = LdgSpan<const_type>;
0100 };
0101 
0102 //---------------------------------------------------------------------------//
0103 //! Memspace-dependent storage for a collection
0104 template<class T, Ownership W, MemSpace M>
0105 struct CollectionStorage
0106 {
0107     using type = typename CollectionTraits<T, W, M>::SpanT;
0108     type data;
0109 
0110     inline static constexpr Ownership ownership = W;
0111     inline static constexpr MemSpace memspace = M;
0112 };
0113 
0114 //---------------------------------------------------------------------------//
0115 //! Storage implementation for managed host data
0116 template<class T>
0117 struct CollectionStorage<T, Ownership::value, MemSpace::host>
0118 {
0119     static_assert(!std::is_same<T, bool>::value,
0120                   "bool is not compatible between vector and anything else");
0121 #ifdef CELER_DEVICE_COMPILE
0122     // Use "not implemented" but __host__ __device__ decorated functions when
0123     // compiling in CUDA
0124     using type = DisabledStorage<T>;
0125 #else
0126     using type = std::vector<T>;
0127 #endif
0128     type data;
0129 
0130     inline static constexpr Ownership ownership = Ownership::value;
0131     inline static constexpr MemSpace memspace = MemSpace::host;
0132 };
0133 
0134 //! Storage implementation for managed device data
0135 template<class T>
0136 struct CollectionStorage<T, Ownership::value, MemSpace::device>
0137 {
0138 #ifdef CELER_DEVICE_COMPILE
0139     // Use "not implemented" but __host__ __device__ decorated functions when
0140     // compiling in CUDA
0141     using type = DisabledStorage<T>;
0142 #else
0143     using type = DeviceVector<T>;
0144 #endif
0145     type data;
0146 
0147     inline static constexpr Ownership ownership = Ownership::value;
0148     inline static constexpr MemSpace memspace = MemSpace::device;
0149 };
0150 
0151 //! Storage implementation for mapped host/device data
0152 template<class T>
0153 struct CollectionStorage<T, Ownership::value, MemSpace::mapped>
0154 {
0155     static_assert(!std::is_same<T, bool>::value,
0156                   "bool is not compatible between vector and anything else");
0157 #ifdef CELER_DEVICE_COMPILE
0158     // Use "not implemented" but __host__ __device__ decorated functions when
0159     // compiling in CUDA
0160     using type = DisabledStorage<T>;
0161 #else
0162     using type = std::vector<T, PinnedAllocator<T>>;
0163 #endif
0164     type data;
0165 
0166     inline static constexpr Ownership ownership = Ownership::value;
0167     inline static constexpr MemSpace memspace = MemSpace::mapped;
0168 };
0169 
0170 //---------------------------------------------------------------------------//
0171 //! Check that sizes are acceptable when creating references from values
0172 template<Ownership W>
0173 struct CollectionStorageValidator
0174 {
0175     template<class Size, class OtherSize>
0176     void operator()(Size, OtherSize)
0177     {
0178         /* No validation needed */
0179     }
0180 };
0181 
0182 template<>
0183 struct CollectionStorageValidator<Ownership::value>
0184 {
0185     template<class Size, class OtherSize>
0186     void operator()(Size dst, OtherSize src)
0187     {
0188         CELER_VALIDATE(dst == src,
0189                        << "collection is too large (" << sizeof(Size)
0190                        << "-byte int cannot hold " << src << " elements)");
0191     }
0192 };
0193 
0194 //---------------------------------------------------------------------------//
0195 /*!
0196  * Copy assign a collection via its storage.
0197  */
0198 template<class S, class T, Ownership DW, MemSpace DM>
0199 void copy_collection(S& src, CollectionStorage<T, DW, DM>* dst)
0200 {
0201     constexpr MemSpace SM = std::remove_const_t<S>::memspace;
0202     using DstStorageT = typename CollectionStorage<T, DW, DM>::type;
0203 
0204     auto* data = src.data.data();
0205     size_type size = src.data.size();
0206 
0207     if constexpr (DW == Ownership::value && DM == MemSpace::mapped)
0208     {
0209         CELER_VALIDATE(celeritas::device().can_map_host_memory(),
0210                        << "device " << celeritas::device().device_id()
0211                        << " doesn't support unified addressing");
0212     }
0213 
0214     if constexpr (DW == Ownership::value && DM == SM)
0215     {
0216         // Allocate and copy at the same time: destination "owns" the memory
0217         dst->data.assign(data, data + size);
0218     }
0219     else if constexpr (DM == SM)
0220     {
0221         // Copy pointers in same memspace, prohibiting const violation
0222         constexpr Ownership SW = std::remove_const_t<S>::ownership;
0223 
0224         static_assert(
0225             !(SW == Ownership::const_reference && DW == Ownership::reference),
0226             "cannot assign from const reference to reference");
0227 
0228         dst->data = DstStorageT{data, size};
0229     }
0230     else
0231     {
0232         if constexpr (DW == Ownership::value)
0233         {
0234             // Allocate destination
0235             dst->data = DstStorageT(size);
0236         }
0237 
0238         CELER_VALIDATE(dst->data.size() == size,
0239                        << "collection assignment from " << to_cstring(SM)
0240                        << " to " << to_cstring(DM)
0241                        << " failed: cannot copy from source size " << size
0242                        << " to destination size " << dst->data.size());
0243 
0244         // Copy across memory boundary
0245         Copier<T, DM> copy_to_dst{{dst->data.data(), dst->data.size()}};
0246         copy_to_dst(SM, {data, size});
0247     }
0248 }
0249 
0250 //---------------------------------------------------------------------------//
0251 }  // namespace detail
0252 }  // namespace celeritas