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