|
|
|||
File indexing completed on 2025-10-25 07:55:29
0001 // This file is part of the ACTS project. 0002 // 0003 // Copyright (C) 2016 CERN for the benefit of the ACTS project 0004 // 0005 // This Source Code Form is subject to the terms of the Mozilla Public 0006 // License, v. 2.0. If a copy of the MPL was not distributed with this 0007 // file, You can obtain one at https://mozilla.org/MPL/2.0/. 0008 0009 #pragma once 0010 0011 #include "Acts/Definitions/Algebra.hpp" 0012 #include "Acts/Utilities/PointerTraits.hpp" 0013 0014 #include <algorithm> 0015 #include <array> 0016 #include <iostream> 0017 #include <limits> 0018 #include <memory> 0019 #include <type_traits> 0020 #include <vector> 0021 0022 #define ACTS_CHECK_BIT(value, mask) ((value & mask) == mask) 0023 0024 namespace Acts { 0025 0026 /// Helper function to unpack a vector of smart pointers (e.g. @c shared_ptr ) into a vector of raw 0027 /// const pointers 0028 /// @tparam T the stored type 0029 /// @param items The vector of smart pointers 0030 /// @return The unpacked vector 0031 0032 template <SmartPointerConcept T> 0033 std::vector<std::add_pointer_t<std::add_const_t<typename T::element_type>>> 0034 unpackConstSmartPointers(const std::vector<T>& items) { 0035 std::vector<std::add_pointer_t<std::add_const_t<typename T::element_type>>> 0036 rawPtrs{}; 0037 rawPtrs.reserve(items.size()); 0038 for (const auto& ptr : items) { 0039 rawPtrs.push_back(ptr.operator->()); 0040 } 0041 return rawPtrs; 0042 } 0043 0044 /// Helper function to unpack a vector of @c shared_ptr into a vector of raw 0045 /// pointers 0046 /// @tparam T the stored type 0047 /// @param items The vector of @c shared_ptr 0048 /// @return The unpacked vector 0049 template <SmartPointerConcept T> 0050 std::vector<std::add_pointer_t<typename T::element_type>> unpackSmartPointers( 0051 const std::vector<T>& items) { 0052 std::vector<std::add_pointer_t<typename T::element_type>> rawPtrs{}; 0053 rawPtrs.reserve(items.size()); 0054 for (const auto& ptr : items) { 0055 rawPtrs.push_back(&*ptr); 0056 } 0057 return rawPtrs; 0058 } 0059 0060 /// Helper function to unpack a vector of @c shared_ptr into a vector of raw 0061 /// pointers (const version) 0062 /// @tparam T the stored type 0063 /// @param items The vector of @c shared_ptr 0064 /// @return The unpacked vector 0065 template <typename T> 0066 std::vector<const T*> unpackSmartPointers( 0067 const std::vector<std::shared_ptr<const T>>& items) { 0068 std::vector<const T*> rawPtrs; 0069 rawPtrs.reserve(items.size()); 0070 for (const std::shared_ptr<const T>& item : items) { 0071 rawPtrs.push_back(item.get()); 0072 } 0073 return rawPtrs; 0074 } 0075 0076 /// @brief Converts a vector to a fixed-size array with truncating or padding. 0077 /// 0078 /// This function copies elements from the input vector into a fixed-size array. 0079 /// If the vector contains more than `kDIM` elements, the array is truncated to 0080 /// fit. If the vector contains fewer elements than `kDIM`, the remaining array 0081 /// elements are value-initialized (default-initialized, i.e., filled with zero 0082 /// or default values). 0083 /// 0084 /// @tparam kDIM The size of the resulting array. 0085 /// @tparam value_t The type of elements in the vector and the array. 0086 /// @param vecvals The input vector to be converted to an array. 0087 /// 0088 /// @return An array containing the first `kDIM` elements of the vector. 0089 template <std::size_t kDIM, typename value_t> 0090 std::array<value_t, kDIM> toArray(const std::vector<value_t>& vecvals) { 0091 std::array<value_t, kDIM> arr = {}; 0092 std::copy_n(vecvals.begin(), std::min(vecvals.size(), kDIM), arr.begin()); 0093 return arr; 0094 } 0095 0096 /// @brief Dispatch a call based on a runtime value on a function taking the 0097 /// value at compile time. 0098 /// 0099 /// This function allows to write a templated functor, which accepts a @c std::size_t 0100 /// like parameter at compile time. It is then possible to make a call to the 0101 /// corresponding instance of the functor based on a runtime value. To achieve 0102 /// this, the function essentially created a if cascade between @c N and @c 0103 /// NMAX, attempting to find the right instance. Because the cascade is visible 0104 /// to the compiler entirely, it should be able to optimize. 0105 /// 0106 /// @tparam Callable Type which takes a std::size_t as a compile time param 0107 /// @tparam N Value from which to start the dispatch chain, i.e. 0 in most cases 0108 /// @tparam NMAX Maximum value up to which to attempt a dispatch 0109 /// @param v The runtime value to dispatch on 0110 /// @param args Additional arguments passed to @c Callable::invoke(). 0111 /// @return The result of calling the dispatched template instance 0112 /// @note @c Callable is expected to have a static member function @c invoke 0113 /// that is callable with @c Args 0114 template <template <std::size_t> class Callable, std::size_t N, 0115 std::size_t NMAX, typename... Args> 0116 auto template_switch(std::size_t v, Args&&... args) { 0117 if (v == N) { 0118 return Callable<N>::invoke(std::forward<Args>(args)...); 0119 } 0120 if (v == 0) { 0121 std::cerr << "template_switch<Fn, " << N << ", " << NMAX << ">(v=" << v 0122 << ") is not valid (v == 0 and N != 0)" << std::endl; 0123 std::abort(); 0124 } 0125 if constexpr (N < NMAX) { 0126 return template_switch<Callable, N + 1, NMAX>(v, 0127 std::forward<Args>(args)...); 0128 } 0129 std::cerr << "template_switch<Fn, " << N << ", " << NMAX << ">(v=" << v 0130 << ") is not valid (v > NMAX)" << std::endl; 0131 std::abort(); 0132 } 0133 0134 /// Alternative version of @c template_switch which accepts a generic 0135 /// lambda and communicates the dimension via an integral constant type 0136 /// @tparam N Value from which to start the dispatch chain, i.e. 0 in most cases 0137 /// @tparam NMAX Maximum value up to which to attempt a dispatch 0138 /// @param v The runtime value to dispatch on 0139 /// @param func The lambda to invoke 0140 /// @param args Additional arguments passed to @p func 0141 /// @return The result of calling the dispatched lambda function 0142 template <std::size_t N, std::size_t NMAX, typename Lambda, typename... Args> 0143 auto template_switch_lambda(std::size_t v, Lambda&& func, Args&&... args) { 0144 if (v == N) { 0145 return func(std::integral_constant<std::size_t, N>{}, 0146 std::forward<Args>(args)...); 0147 } 0148 if (v == 0) { 0149 std::cerr << "template_switch<Fn, " << N << ", " << NMAX << ">(v=" << v 0150 << ") is not valid (v == 0 and N != 0)" << std::endl; 0151 std::abort(); 0152 } 0153 if constexpr (N < NMAX) { 0154 return template_switch_lambda<N + 1, NMAX>(v, func, 0155 std::forward<Args>(args)...); 0156 } 0157 std::cerr << "template_switch<Fn, " << N << ", " << NMAX << ">(v=" << v 0158 << ") is not valid (v > NMAX)" << std::endl; 0159 std::abort(); 0160 } 0161 0162 /// Clamp a numeric value to another type, respecting range of the target type 0163 /// @tparam T the target type 0164 /// @tparam U the source type 0165 /// @param value the value to clamp 0166 /// @return the clamped value 0167 template <typename T, typename U> 0168 T clampValue(U value) { 0169 return std::clamp(value, static_cast<U>(std::numeric_limits<T>::lowest()), 0170 static_cast<U>(std::numeric_limits<T>::max())); 0171 } 0172 0173 /// Return range and medium of an unsorted numeric series 0174 /// 0175 /// @tparam T a numeric series 0176 /// 0177 /// @param tseries is the number series 0178 /// 0179 /// @return [ range, medium ] in an tuple 0180 template <typename T> 0181 std::tuple<typename T::value_type, double> range_medium(const T& tseries) { 0182 auto [minIt, maxIt] = std::ranges::minmax_element(tseries); 0183 typename T::value_type range = (*maxIt - *minIt); 0184 double medium = static_cast<double>((*maxIt + *minIt) * 0.5); 0185 return {range, medium}; 0186 } 0187 0188 /// Convert enum to its underlying type value 0189 /// @param value Enum value to convert 0190 /// @return Underlying type value 0191 template <typename enum_t> 0192 constexpr std::underlying_type_t<enum_t> toUnderlying(enum_t value) { 0193 return static_cast<std::underlying_type_t<enum_t>>(value); 0194 } 0195 0196 /// This can be replaced with C++23 to use the std::ranges::contains method 0197 /// 0198 /// This function searches through the given range for a specified value 0199 /// and returns `true` if the value is found, or `false` otherwise. 0200 /// 0201 /// @tparam R The type of the range (e.g., vector, list, array). 0202 /// @tparam T The type of the value to search for within the range. 0203 /// 0204 /// @param range The range to search within. This can be any range-compatible container. 0205 /// @param value The value to search for in the range. 0206 /// 0207 /// @return `true` if the value is found within the range, `false` otherwise. 0208 template <typename R, typename T> 0209 bool rangeContainsValue(const R& range, const T& value) { 0210 return std::ranges::find(range, value) != std::ranges::end(range); 0211 } 0212 0213 /// Helper struct that can turn a set of lambdas into a single entity with 0214 /// overloaded call operator. This can be useful for example in a std::visit 0215 /// call. 0216 /// ```cpp 0217 /// std::visit(overloaded{ 0218 /// [](const int& i) { std::cout << "int: " << i << std::endl; }, 0219 /// [](const std::string& s) { std::cout << "string: " << s << std::endl; }, 0220 /// }, variant); 0221 /// ``` 0222 template <class... Ts> 0223 struct overloaded : Ts... { 0224 using Ts::operator()...; 0225 }; 0226 0227 /// Deduction guide for overloaded visitor pattern 0228 template <class... Ts> 0229 overloaded(Ts...) -> overloaded<Ts...>; 0230 0231 namespace detail { 0232 0233 /// Computes the minimum, maximum, and bin count for a given vector of values. 0234 /// 0235 /// This function processes a vector of doubles to compute: 0236 /// - The minimum value (@c xMin) 0237 /// - The maximum value (@c xMax), adjusted to include an additional bin 0238 /// - The bin count (@c xBinCount) based on the number of unique values 0239 /// 0240 /// The computation is performed as follows: 0241 /// 1. Sorts the input vector using @c std::ranges::sort to prepare for uniqueness. 0242 /// 2. Determines the number of unique values using @c std::unique and calculates the bin count. 0243 /// 3. Calculates the minimum and maximum using @c std::ranges::minmax. 0244 /// 4. Adjusts the maximum to include an additional bin by adding the bin step 0245 /// size. 0246 /// 0247 /// @param xPos A reference to a vector of doubles. 0248 /// @return A tuple containing: 0249 /// - The minimum value (double) 0250 /// - The adjusted maximum value (double) 0251 /// - The bin count (std::size_t) 0252 /// 0253 /// @note The vector xPos will be modified during the call. 0254 inline auto getMinMaxAndBinCount(std::vector<double>& xPos) { 0255 // sort the values for unique() 0256 std::ranges::sort(xPos); 0257 0258 // get the number of bins over unique values 0259 auto it = std::unique(xPos.begin(), xPos.end()); 0260 const std::size_t xBinCount = std::distance(xPos.begin(), it); 0261 0262 // get the minimum and maximum 0263 auto [xMin, xMax] = std::ranges::minmax(xPos); 0264 0265 // calculate maxima (add one last bin, because bin value always corresponds to 0266 // left boundary) 0267 const double stepX = (xMax - xMin) / static_cast<double>(xBinCount - 1); 0268 xMax += stepX; 0269 0270 // Return all values as a tuple 0271 return std::make_tuple(xMin, xMax, xBinCount); 0272 } 0273 0274 } // namespace detail 0275 0276 } // namespace Acts
| [ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
|
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |
|