Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-09-10 09:29:04

0001 /// \file scalar/Backend.h
0002 /// \author Johannes de Fine Licht (johannes.definelicht@cern.ch)
0003 
0004 #ifndef VECGEOM_BACKEND_SCALARBACKEND_H_
0005 #define VECGEOM_BACKEND_SCALARBACKEND_H_
0006 
0007 #include "VecGeom/base/Global.h"
0008 #include "VecGeom/base/Assert.h"
0009 
0010 #include <algorithm>
0011 #include <cstring>
0012 #include <memory>
0013 #include <type_traits>
0014 #include <utility>
0015 
0016 namespace vecgeom {
0017 inline namespace VECGEOM_IMPL_NAMESPACE {
0018 
0019 struct kScalar {
0020   typedef int int_v;
0021   typedef Precision precision_v;
0022   typedef bool bool_v;
0023   typedef Inside_t inside_v;
0024   // alternative typedefs ( might supercede above typedefs )
0025   typedef int Int_t;
0026   typedef Precision Double_t;
0027   typedef bool Bool_t;
0028   typedef int Index_t; // the type of indices
0029 
0030   constexpr static precision_v kOne  = 1.0;
0031   constexpr static precision_v kZero = 0.0;
0032   const static bool_v kTrue          = true;
0033   const static bool_v kFalse         = false;
0034 
0035   template <class Backend>
0036   VECCORE_ATT_HOST_DEVICE static VECGEOM_CONSTEXPR_RETURN bool IsEqual()
0037   {
0038     return false;
0039   }
0040 
0041   VECCORE_ATT_HOST_DEVICE
0042   VECGEOM_FORCE_INLINE
0043   static Precision Convert(Precision const &input) { return input; }
0044 };
0045 
0046 template <>
0047 VECCORE_ATT_HOST_DEVICE inline VECGEOM_CONSTEXPR_RETURN bool kScalar::IsEqual<kScalar>()
0048 {
0049   return true;
0050 }
0051 
0052 typedef kScalar::int_v ScalarInt;
0053 typedef kScalar::precision_v ScalarDouble;
0054 typedef kScalar::bool_v ScalarBool;
0055 
0056 #ifdef VECGEOM_SCALAR
0057 constexpr size_t kVectorSize = 1;
0058 #define VECGEOM_BACKEND_TYPE vecgeom::kScalar
0059 #define VECGEOM_BACKEND_PRECISION_FROM_PTR(P) (*(P))
0060 #define VECGEOM_BACKEND_PRECISION_TYPE vecgeom::Precision
0061 #define VECGEOM_BACKEND_PRECISION_TYPE_SIZE 1
0062 // #define VECGEOM_BACKEND_PRECISION_NOT_SCALAR
0063 #define VECGEOM_BACKEND_BOOL vecgeom::ScalarBool
0064 #define VECGEOM_BACKEND_INSIDE vecgeom::kScalar::inside_v
0065 #endif
0066 
0067 // template <typename Type>
0068 // VECGEOM_FORCE_INLINE
0069 // VECCORE_ATT_HOST_DEVICE
0070 // void swap(Type &a, Type &b)
0071 //{
0072 //  std::swap(a, b);
0073 //}
0074 
0075 template <typename Type>
0076 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE void copy(Type const *begin, Type const *const end, Type *const target)
0077 {
0078 #ifndef VECCORE_CUDA_DEVICE_COMPILATION
0079   std::copy(begin, end, target);
0080 #else
0081   std::memcpy(target, begin, sizeof(Type) * (end - begin));
0082 #endif
0083 }
0084 
0085 namespace sfinae_impl {
0086 
0087 // SFINAE method to call the static method aligned_sizeof_data(args...) on a type if it provides it.
0088 // Primary template: Assumes the static function does not exist
0089 template <typename, typename, typename = void>
0090 struct has_aligned_sizeof_data : std::false_type {};
0091 
0092 // Specialization: Detects if the static function exists and returns a value
0093 template <typename T, typename Ret, typename... Args>
0094 struct has_aligned_sizeof_data<T, Ret(Args...), std::void_t<decltype(T::aligned_sizeof_data(std::declval<Args>()...))>>
0095     : std::is_same<decltype(T::aligned_sizeof_data(std::declval<Args>()...)), Ret> {};
0096 
0097 // Utility variable template
0098 template <typename T, typename Signature>
0099 constexpr bool has_aligned_sizeof_data_v = has_aligned_sizeof_data<T, Signature>::value;
0100 
0101 // Function template to call the static function if it exists and return its result
0102 template <typename T, typename Ret, typename... Args>
0103 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE std::enable_if_t<has_aligned_sizeof_data_v<T, Ret(Args...)>, Ret>
0104 call_aligned_sizeof_data_if_exists(Args &&...args)
0105 {
0106   return T::aligned_sizeof_data(std::forward<Args>(args)...);
0107 }
0108 
0109 // Overload for when the function does not exist (fallback return value)
0110 template <typename T, typename Ret, typename... Args>
0111 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE std::enable_if_t<!has_aligned_sizeof_data_v<T, Ret(Args...)>, Ret>
0112 call_aligned_sizeof_data_if_exists(Args &&...)
0113 {
0114   return Ret{}; // Returns default-constructed value of Ret (0 for int, "" for string, etc.)
0115 }
0116 } // namespace sfinae_impl
0117 
0118 ///< @brief Helper for managing aligned data in a buffer
0119 ///< @details Usage: Create a memory buffer with the size equal to sizeof(T) + kAlignmentBoundary
0120 ///<   AlignedAllocator a(buffer, buffer_size);
0121 ///<   T* aligned_data = a.aligned_alloc<T>(kAlignmentBoundary, constructor_args...);
0122 ///< Multiple aligned data can be allocated in the same buffer, given that the allocated buffer size fits them
0123 ///<   U* next_aligned_data = a.aligned_alloc<T>(kAlignmentBoundary, constructor_args...);
0124 ///< The aligned_aloc function returns nullptr if the type cannot be fitted aligned in the prealocated buffer
0125 struct AlignedAllocator {
0126   using size_t = std::size_t;
0127   void *address;
0128   size_t sz;
0129 
0130   AlignedAllocator()                         = delete;
0131   AlignedAllocator(const AlignedAllocator &) = delete;
0132 
0133   VECCORE_ATT_HOST_DEVICE
0134   AlignedAllocator(void *buffer, size_t size) : address{buffer}, sz{size} {}
0135 
0136   /**
0137    *  @brief Fit aligned storage in buffer. Copied from bits/aligned.h
0138    *
0139    *  This function tries to fit @a size bytes of storage with alignment
0140    *  @a align into the buffer @a ptr of size @a space bytes.  If such
0141    *  a buffer fits then @a ptr is changed to point to the first byte of the
0142    *  aligned storage and @a space is reduced by the bytes used for alignment.
0143    *
0144    *  C++11 20.6.5 [ptr.align]
0145    *
0146    *  @param align   A fundamental or extended alignment value.
0147    *  @param size    Size of the aligned storage required.
0148    *  @param ptr     Pointer to a buffer of @a space bytes.
0149    *  @param space   Size of the buffer pointed to by @a ptr.
0150    *  @return the updated pointer if the aligned storage fits, otherwise nullptr.
0151    *
0152    */
0153   VECGEOM_FORCE_INLINE
0154   VECCORE_ATT_HOST_DEVICE
0155   void *align(size_t align, size_t size, void *&ptr, size_t &space) noexcept
0156   {
0157     if (space < size) return nullptr;
0158     const auto intptr  = reinterpret_cast<uintptr_t>(ptr);
0159     const auto aligned = (intptr - 1u + align) & -align;
0160     const auto diff    = aligned - intptr;
0161     if (diff > (space - size))
0162       return nullptr;
0163     else {
0164       space -= diff;
0165       return ptr = reinterpret_cast<void *>(aligned);
0166     }
0167   }
0168 
0169   /// @brief Compute buffer size needed to align an array of elements of type T, based on constructor arguments
0170   /// @tparam T Type for which to count the aligned size
0171   /// @tparam ...Args Optional arguments pack, assuming T provides a function having the signature
0172   /// `T::aligned_sizeof_data(args...)` which calculates the size of its aligned data excluding self
0173   /// @param num_elements Number of elements in the array
0174   /// @param alignment Requested alignment of the data
0175   /// @param ...args Concrete arguments passed by value to `T::aligned_sizeof_data`
0176   /// @return Size to be allocated in bytes
0177   template <typename T, typename... Args>
0178   VECCORE_ATT_HOST_DEVICE static size_t aligned_sizeof(size_t num_elements, size_t alignment, const Args... args)
0179   {
0180     size_t aligned_size = num_elements * sizeof(T) + vecCore::math::Max(alignment, alignof(T));
0181     aligned_size += num_elements * sfinae_impl::call_aligned_sizeof_data_if_exists<T, size_t>(args...);
0182     return aligned_size;
0183   }
0184 
0185   /// @brief Allocate and construct an object at the next free aligned address in the buffer.
0186   /// @details The function returns nullptr in case there is not enough aligned space free.
0187   /// @tparam T Type to be allocated
0188   /// @tparam ...Args Argument pack matching a valid constructor
0189   /// @param num_elements Number of elements to be allocated
0190   /// @param alignment Requested alignment, minimum alignof(T), multiple of alignof(T)
0191   /// @param ...args Arguments passed by reference to the constructor
0192   /// @return Pointer to allocated object in the buffer
0193   template <typename T, typename... Args>
0194   VECCORE_ATT_HOST_DEVICE T *aligned_alloc(size_t num_elements, size_t alignment, Args &&...args)
0195   {
0196     if (alignment < alignof(T)) alignment = alignof(T);
0197     if (alignment % alignof(T) == 0 && align(alignment, num_elements * sizeof(T), address, sz)) {
0198       T *result        = nullptr;
0199       auto address_old = reinterpret_cast<T *>(address);
0200       // make room in the buffer for the base object class num_elements times
0201       address = (char *)address + num_elements * sizeof(T);
0202       if (sz < num_elements * sizeof(T)) return nullptr;
0203       sz -= num_elements * sizeof(T);
0204       for (size_t i = 0; i < num_elements; ++i) {
0205         // Call constructor for each element in the right place in the buffer
0206         T *new_obj = new (address_old + i) T(std::forward<Args>(args)...);
0207         if (i == 0) result = new_obj;
0208       }
0209       VECGEOM_ASSERT(((unsigned long)result % alignment == 0));
0210       return result;
0211     }
0212     VECGEOM_VALIDATE(0, << "No space left to allocate in buffer");
0213     return nullptr;
0214   }
0215 };
0216 
0217 template <typename Type>
0218 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE Type *AlignedAllocate(size_t size)
0219 {
0220 #ifndef VECCORE_CUDA
0221   return static_cast<Type *>(vecCore::AlignedAlloc(kAlignmentBoundary, sizeof(Type) * size));
0222 #else
0223   Type *ptr = new Type[size];
0224   VECGEOM_VALIDATE(
0225       ptr != nullptr, << "Error: Memory allocation failed! If on GPU, consider increasing the heap size on GPU with "
0226                          "CudaDeviceSetHeapLimit(new_size)");
0227   return ptr;
0228 #endif
0229 }
0230 
0231 template <typename Type>
0232 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE void AlignedFree(Type *allocated)
0233 {
0234 #ifndef VECCORE_CUDA
0235   vecCore::AlignedFree(allocated);
0236 #else
0237   delete[] allocated;
0238 #endif
0239 }
0240 
0241 template <typename InputIterator1, typename InputIterator2>
0242 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE bool equal(InputIterator1 first, InputIterator1 last,
0243                                                         InputIterator2 target)
0244 {
0245 #ifndef VECCORE_CUDA_DEVICE_COMPILATION
0246   return std::equal(first, last, target);
0247 #else
0248   while (first != last) {
0249     if (*first++ != *target++) return false;
0250   }
0251   return true;
0252 #endif
0253 }
0254 } // namespace VECGEOM_IMPL_NAMESPACE
0255 } // namespace vecgeom
0256 
0257 #endif // VECGEOM_BACKEND_SCALARBACKEND_H_