Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-10-03 09:29:16

0001 /// \file Vector.h
0002 /// \author Johannes de Fine Licht (johannes.definelicht@cern.ch)
0003 
0004 #ifndef VECGEOM_BASE_VECTOR_H_
0005 #define VECGEOM_BASE_VECTOR_H_
0006 
0007 #include "VecGeom/base/Config.h"
0008 #include "VecGeom/base/Cuda.h"
0009 #include "VecGeom/base/Global.h"
0010 #include "VecGeom/backend/scalar/Backend.h"
0011 #include <initializer_list>
0012 #ifdef VECGEOM_ENABLE_CUDA
0013 #include "VecGeom/backend/cuda/Interface.h"
0014 #endif
0015 
0016 namespace vecgeom {
0017 
0018 VECGEOM_DEVICE_FORWARD_DECLARE(template <typename Type> class Vector;);
0019 VECGEOM_DEVICE_DECLARE_CONV_TEMPLATE(class, Vector, typename);
0020 
0021 inline namespace VECGEOM_IMPL_NAMESPACE {
0022 
0023 namespace Internal {
0024 template <typename T>
0025 struct AllocTrait {
0026 
0027   // Allocate raw buffer to hold the element.
0028   VECCORE_ATT_HOST_DEVICE
0029   static T *Allocate(size_t nElems) { return new T[nElems]; }
0030 
0031   // Release raw buffer to hold the element.
0032   VECCORE_ATT_HOST_DEVICE
0033   static void Deallocate(T *startBuffer) { delete[] startBuffer; }
0034 
0035   VECCORE_ATT_HOST_DEVICE
0036   static void Destroy(T &obj) { obj.~T(); };
0037 
0038   VECCORE_ATT_HOST_DEVICE
0039   static void Destroy(T *arr, size_t nElem)
0040   {
0041     for (size_t i = 0; i < nElem; ++i)
0042       Destroy(arr[i]);
0043   }
0044 
0045   VECCORE_ATT_HOST_DEVICE
0046   static void Reset(T &obj)
0047   {
0048     obj.~T();
0049     new (&obj) T();
0050   }
0051 
0052   VECCORE_ATT_HOST_DEVICE
0053   static void Reset(T *arr, size_t nElem)
0054   {
0055     for (size_t i = 0; i < nElem; ++i)
0056       Reset(arr[i]);
0057   }
0058 };
0059 
0060 template <typename T>
0061 struct AllocTrait<T *> {
0062 
0063   // Allocate raw buffer to hold the element.
0064   VECCORE_ATT_HOST_DEVICE
0065   static T **Allocate(size_t nElems)
0066   {
0067     T **ptr = new T *[nElems];
0068     VECGEOM_VALIDATE(
0069         ptr != nullptr, << "Error: Memory allocation failed! If on GPU, consider increasing the heap size on GPU "
0070                            "with CudaDeviceSetHeapLimit(new_size)");
0071     return ptr;
0072   }
0073 
0074   // Release raw buffer to hold the element.
0075   VECCORE_ATT_HOST_DEVICE
0076   static void Deallocate(T **startBuffer) { delete[] startBuffer; }
0077 
0078   VECCORE_ATT_HOST_DEVICE
0079   static void Destroy(T *&) {}
0080 
0081   VECCORE_ATT_HOST_DEVICE
0082   static void Destroy(T **, size_t) {}
0083 
0084   VECCORE_ATT_HOST_DEVICE
0085   static void Reset(T *&ptr) { ptr = nullptr; }
0086 
0087   VECCORE_ATT_HOST_DEVICE
0088   static void Reset(T **arr, size_t nElem)
0089   {
0090     if (arr == nullptr) return;
0091     for (size_t i = 0; i < nElem; ++i)
0092       Reset(arr[i]);
0093   }
0094 };
0095 } // namespace Internal
0096 
0097 template <typename Type>
0098 class VectorBase {
0099 
0100 private:
0101   Type *fData{nullptr};
0102   size_t fSize{0};
0103   size_t fMemorySize{0};
0104   bool fAllocated{false};
0105 
0106 public:
0107   using value_type = Type;
0108 
0109   VectorBase() = default;
0110 
0111   VECCORE_ATT_HOST_DEVICE
0112   VectorBase(size_t maxsize) { reserve(maxsize); }
0113 
0114   VECCORE_ATT_HOST_DEVICE
0115   VectorBase(size_t maxsize, AlignedAllocator &a) : fSize(maxsize), fMemorySize(maxsize)
0116   {
0117     fData = a.aligned_alloc<Type>(maxsize, alignof(Type));
0118     VECGEOM_VALIDATE(fData != nullptr, << "insufficient space in buffer");
0119   }
0120 
0121   VECCORE_ATT_HOST_DEVICE
0122   VectorBase(Type *const vec, const int sz) : fData(vec), fSize(sz), fMemorySize(sz)
0123   {
0124     // May be called by ConstructOnGpu with an empty list
0125     // VECGEOM_ASSERT(sz > 0 && "Trying to initialize from a zero-size array");
0126   }
0127 
0128   VECCORE_ATT_HOST_DEVICE
0129   VectorBase(Type *const vec, const int sz, const int maxsize) : fData(vec), fSize(sz), fMemorySize(maxsize)
0130   {
0131     VECGEOM_ASSERT(sz > 0 && "Trying to initialize from a zero-size array");
0132     VECGEOM_ASSERT(fMemorySize >= fSize && "Maximum size cannot be smaller than actual size");
0133   }
0134 
0135   VECCORE_ATT_HOST_DEVICE
0136   VectorBase(VectorBase const &other) : fSize(other.fSize), fMemorySize(other.fMemorySize)
0137   {
0138     if (other.fMemorySize > 0) {
0139       fAllocated = true;
0140       fData      = Internal::AllocTrait<Type>::Allocate(fMemorySize);
0141       for (size_t i = 0; i < fSize; ++i)
0142         fData[i] = other.fData[i];
0143     }
0144   }
0145 
0146   VECCORE_ATT_HOST_DEVICE
0147   VectorBase &operator=(VectorBase const &other)
0148   {
0149     if (&other != this) {
0150       // The array must be either already allocated or buffered with a larger size to fit the elements
0151       VECGEOM_ASSERT((!is_preallocated() || fMemorySize >= other.fSize) &&
0152                      "Trying to allocate larger vector into a preallocated one");
0153       if (fMemorySize < other.fSize) {
0154         // Need to re-allocate the array with the right size
0155         if (fAllocated) Internal::AllocTrait<Type>::Deallocate(fData);
0156         fData       = Internal::AllocTrait<Type>::Allocate(other.fSize);
0157         fAllocated  = true;
0158         fMemorySize = other.fSize;
0159       } else {
0160         // Reset all elements
0161         Internal::AllocTrait<Type>::Reset(fData, fSize);
0162       }
0163       for (size_t i = 0; i < other.fSize; ++i)
0164         fData[i] = other.fData[i];
0165       fSize = other.fSize;
0166     }
0167     return *this;
0168   }
0169 
0170   VECCORE_ATT_HOST_DEVICE
0171   VectorBase(std::initializer_list<Type> entries)
0172   {
0173     fData      = Internal::AllocTrait<Type>::Allocate(entries.size());
0174     fAllocated = true;
0175     for (auto const &itm : entries)
0176       new (&fData[fSize++]) Type(itm);
0177     fMemorySize = fSize;
0178   }
0179 
0180   VECCORE_ATT_HOST_DEVICE
0181   ~VectorBase()
0182   {
0183     if (fAllocated) {
0184       Internal::AllocTrait<Type>::Deallocate(fData);
0185       fData       = nullptr;
0186       fAllocated  = false;
0187       fMemorySize = fSize = 0;
0188     }
0189   }
0190 
0191   VECCORE_ATT_HOST_DEVICE
0192   void clear()
0193   {
0194     Internal::AllocTrait<Type>::Reset(fData, fSize);
0195     fSize = 0;
0196   }
0197 
0198   VECCORE_ATT_HOST_DEVICE
0199   VECGEOM_FORCE_INLINE
0200   Type &operator[](const int index) { return fData[index]; }
0201 
0202   VECCORE_ATT_HOST_DEVICE
0203   VECGEOM_FORCE_INLINE
0204   Type const &operator[](const int index) const { return fData[index]; }
0205 
0206   VECCORE_ATT_HOST_DEVICE
0207   void push_back(const Type &item)
0208   {
0209     if (fSize == fMemorySize) {
0210       size_t newsize = (fSize == 0) ? 4 : 2 * fMemorySize;
0211       reserve(newsize);
0212     }
0213     // Copy-construct in place
0214     new (&fData[fSize++]) Type(item);
0215   }
0216 
0217   typedef Type *iterator;
0218   typedef Type const *const_iterator;
0219 
0220   VECCORE_ATT_HOST_DEVICE
0221   VECGEOM_FORCE_INLINE
0222   bool is_allocated() const { return fAllocated; }
0223 
0224   VECCORE_ATT_HOST_DEVICE
0225   VECGEOM_FORCE_INLINE
0226   bool is_preallocated() const { return (!fAllocated && fData); }
0227 
0228   VECCORE_ATT_HOST_DEVICE
0229   VECGEOM_FORCE_INLINE
0230   iterator begin() const { return &fData[0]; }
0231 
0232   VECCORE_ATT_HOST_DEVICE
0233   VECGEOM_FORCE_INLINE
0234   iterator end() const { return &fData[fSize]; }
0235 
0236   VECCORE_ATT_HOST_DEVICE
0237   VECGEOM_FORCE_INLINE
0238   const_iterator cbegin() const { return &fData[0]; }
0239 
0240   VECCORE_ATT_HOST_DEVICE
0241   VECGEOM_FORCE_INLINE
0242   const_iterator cend() const { return &fData[fSize]; }
0243 
0244   VECCORE_ATT_HOST_DEVICE
0245   VECGEOM_FORCE_INLINE
0246   size_t size() const { return fSize; }
0247 
0248   VECCORE_ATT_HOST_DEVICE
0249   VECGEOM_FORCE_INLINE
0250   size_t capacity() const { return fMemorySize; }
0251 
0252   VECCORE_ATT_HOST_DEVICE
0253   VECGEOM_FORCE_INLINE
0254   void resize(size_t newsize, const Type &value)
0255   {
0256     if (newsize <= fSize) {
0257       // shrinking: reset exceeding elements
0258       for (size_t i = newsize; i < fSize; ++i) {
0259         Internal::AllocTrait<Type>::Reset(fData[i]);
0260       }
0261       fSize = newsize;
0262     } else {
0263       // expanding
0264       if (newsize > fMemorySize) {
0265         reserve(newsize);
0266       }
0267       for (size_t i = fSize; i < newsize; ++i)
0268         push_back(value);
0269     }
0270   }
0271 
0272   VECCORE_ATT_HOST_DEVICE
0273   VECGEOM_FORCE_INLINE
0274   void reserve(size_t newsize)
0275   {
0276     if (newsize > fMemorySize) {
0277       VECGEOM_VALIDATE(!is_preallocated(), << "Trying to increase a pre-allocated vector");
0278       // Allocate an array of elements of size newsize, constructed in place
0279       Type *newdata = Internal::AllocTrait<Type>::Allocate(newsize);
0280       // Copy existing elements into the new array
0281       for (size_t i = 0; i < fSize; ++i)
0282         new (&newdata[i]) Type(fData[i]);
0283       if (fAllocated) {
0284         Internal::AllocTrait<Type>::Deallocate(fData);
0285       }
0286       fData       = newdata;
0287       fMemorySize = newsize;
0288       fAllocated  = true;
0289     }
0290   }
0291 
0292   VECCORE_ATT_HOST_DEVICE
0293   VECGEOM_FORCE_INLINE
0294   iterator erase(const_iterator position)
0295   {
0296     iterator where = (begin() + (position - cbegin()));
0297     if (where + 1 != end()) {
0298       auto last = cend();
0299       for (auto c = where; (c + 1) != last; ++c)
0300         *c = *(c + 1);
0301     }
0302     --fSize;
0303     if (fSize) Internal::AllocTrait<Type>::Reset(fData[fSize]);
0304     return where;
0305   }
0306 };
0307 
0308 template <typename Type>
0309 class Vector : public VectorBase<Type> {
0310 public:
0311   using VectorBase<Type>::VectorBase;
0312   using typename VectorBase<Type>::iterator;
0313   using typename VectorBase<Type>::const_iterator;
0314 
0315   /// @brief Get size of the data held by initSize elements, with specified alignment
0316   /// @tparam ...Args Argument pack to pass to Type::aligned_sizeof_data in case Type is non-arithmetic
0317   /// @param initSize Number of elements held ny the vector
0318   /// @param alignment Alignment requirement for the data pack held by the vector. If zero, alignof(Type) is used
0319   /// @param ...args Arguments to pass to Type::aligned_sizeof_data for non-arithmetic types
0320   /// @return Size needed in bytes
0321   template <typename... Args>
0322   VECCORE_ATT_HOST_DEVICE VECGEOM_FORCE_INLINE static size_t aligned_sizeof_data(const size_t numElements,
0323                                                                                  const size_t alignment,
0324                                                                                  const Args... args)
0325   {
0326     return (AlignedAllocator::aligned_sizeof<Type>(numElements, alignment, args...));
0327   }
0328 
0329 #ifdef VECGEOM_CUDA_INTERFACE
0330   DevicePtr<cuda::Vector<CudaType_t<Type>>> CopyToGpu(DevicePtr<CudaType_t<Type>> const gpu_ptr_arr,
0331                                                       DevicePtr<cuda::Vector<CudaType_t<Type>>> const gpu_ptr) const
0332   {
0333     gpu_ptr.Construct(gpu_ptr_arr, VectorBase<Type>::size());
0334     return gpu_ptr;
0335   }
0336 #endif
0337 };
0338 } // namespace VECGEOM_IMPL_NAMESPACE
0339 } // namespace vecgeom
0340 
0341 #endif // VECGEOM_BASE_CONTAINER_H_