SpECTRE Documentation Coverage Report
Current view: top level - Utilities - RuntimeCache.hpp Hit Total Coverage
Commit: c3e43f8d41800b0ecefb9d1393f1de1d5a280c8f Lines: 2 10 20.0 %
Date: 2026-07-24 22:09:25
Legend: Lines: hit not hit

          Line data    Source code
       1           0 : // Distributed under the MIT License.
       2             : // See LICENSE.txt for details.
       3             : 
       4             : #pragma once
       5             : 
       6             : #include <array>
       7             : #include <cstddef>
       8             : #include <mutex>
       9             : #include <optional>
      10             : #include <type_traits>
      11             : #include <utility>
      12             : 
      13             : #include "Utilities/ErrorHandling/Error.hpp"
      14             : #include "Utilities/Gsl.hpp"
      15             : #include "Utilities/StaticCache.hpp"
      16             : #include "Utilities/TypeTraits/IsInteger.hpp"
      17             : 
      18             : /// \ingroup UtilitiesGroup
      19             : /// A cache that selects and lazily initializes entries at runtime.
      20             : ///
      21             : /// Unlike `StaticCache`, this class does not instantiate the generator once for
      22             : /// every combination of indices. This reduces compile time for large caches at
      23             : /// the cost of runtime index calculation and synchronization.
      24             : ///
      25             : /// \note `RuntimeCache` is tested in `Test_StaticCache.cpp`.
      26             : template <typename Generator, typename T, typename... Ranges>
      27           1 : class RuntimeCache {
      28             :  public:
      29           0 :   explicit RuntimeCache(Generator generator)
      30             :       : generator_{std::move(generator)} {}
      31             : 
      32             :   template <typename... Args>
      33           0 :   const T& operator()(const Args... parameters) const {
      34             :     static_assert(sizeof...(parameters) == sizeof...(Ranges),
      35             :                   "Number of arguments must match number of ranges.");
      36             :     size_t array_location = 0;
      37             :     ((array_location = array_location * static_cast<size_t>(Ranges::size) +
      38             :                        index<Ranges>(parameters)),
      39             :      ...);
      40             :     std::call_once(gsl::at(initialized_, array_location), [this, array_location,
      41             :                                                            &parameters...]() {
      42             :       gsl::at(cached_objects_, array_location)
      43             :           .emplace(generator_(
      44             :               static_cast<typename Ranges::value_type>(parameters)...));
      45             :     });
      46             :     return gsl::at(cached_objects_, array_location).value();
      47             :   }
      48             : 
      49             :  private:
      50             :   template <typename Range, typename U>
      51           0 :   static size_t index(const U parameter) {
      52             :     if constexpr (std::is_enum_v<U>) {
      53             :       static_assert(
      54             :           std::is_same_v<typename Range::value_type, std::remove_cv_t<U>>,
      55             :           "Mismatched enum parameter type and cached type.");
      56             :       for (size_t i = 0; i < Range::size; ++i) {
      57             :         if (parameter == gsl::at(Range::values, i)) {
      58             :           return i;
      59             :         }
      60             :       }
      61             :       ERROR("Uncached enumeration value: " << parameter);
      62             :     } else {
      63             :       static_assert(
      64             :           tt::is_integer_v<std::remove_cv_t<U>>,
      65             :           "The parameter passed for a CacheRange must be an integer type.");
      66             :       if (UNLIKELY(
      67             :               Range::start > static_cast<decltype(Range::start)>(parameter) or
      68             :               static_cast<decltype(Range::start)>(parameter) >= Range::end)) {
      69             :         ERROR("Index out of range: " << Range::start << " <= " << parameter
      70             :                                      << " < " << Range::end);
      71             :       }
      72             :       return static_cast<size_t>(
      73             :           static_cast<typename Range::value_type>(parameter) - Range::start);
      74             :     }
      75             :   }
      76             : 
      77           0 :   static constexpr size_t number_of_entries =
      78             :       (size_t{1} * ... * static_cast<size_t>(Ranges::size));
      79           0 :   Generator generator_;
      80             :   // NOLINTNEXTLINE(spectre-mutable)
      81           0 :   mutable std::array<std::once_flag, number_of_entries> initialized_{};
      82             :   // NOLINTNEXTLINE(spectre-mutable)
      83           0 :   mutable std::array<std::optional<T>, number_of_entries> cached_objects_{};
      84             : };
      85             : 
      86             : /// \ingroup UtilitiesGroup
      87             : /// Create a RuntimeCache, inferring the cached type from the generator.
      88             : template <typename... Ranges, typename Generator>
      89           1 : auto make_runtime_cache(Generator&& generator) {
      90             :   using CachedType = std::remove_cvref_t<decltype(generator(
      91             :       std::declval<typename Ranges::value_type>()...))>;
      92             :   return RuntimeCache<std::remove_cvref_t<Generator>, CachedType, Ranges...>(
      93             :       std::forward<Generator>(generator));
      94             : }

Generated by: LCOV version 1.14