File indexing completed on 2026-10-03 09:29:16
0001
0002
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
0028 VECCORE_ATT_HOST_DEVICE
0029 static T *Allocate(size_t nElems) { return new T[nElems]; }
0030
0031
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
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
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 }
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
0125
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
0151 VECGEOM_ASSERT((!is_preallocated() || fMemorySize >= other.fSize) &&
0152 "Trying to allocate larger vector into a preallocated one");
0153 if (fMemorySize < other.fSize) {
0154
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
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
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
0258 for (size_t i = newsize; i < fSize; ++i) {
0259 Internal::AllocTrait<Type>::Reset(fData[i]);
0260 }
0261 fSize = newsize;
0262 } else {
0263
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
0279 Type *newdata = Internal::AllocTrait<Type>::Allocate(newsize);
0280
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
0316
0317
0318
0319
0320
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 }
0339 }
0340
0341 #endif