LCOV - code coverage report
Current view: top level - home/runner/.local/lib/python3.9/site-packages/torch/include/c10/util - Lazy.h (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 0 4 0.0 %
Date: 2025-11-25 13:55:50 Functions: 0 1 0.0 %

          Line data    Source code
       1             : #pragma once
       2             : 
       3             : #include <atomic>
       4             : #include <utility>
       5             : 
       6             : namespace c10 {
       7             : 
       8             : /**
       9             :  * Thread-safe lazy value with opportunistic concurrency: on concurrent first
      10             :  * access, the factory may be called by multiple threads, but only one result is
      11             :  * stored and its reference returned to all the callers.
      12             :  *
      13             :  * Value is heap-allocated; this optimizes for the case in which the value is
      14             :  * never actually computed.
      15             :  */
      16             : template <class T>
      17             : class OptimisticLazy {
      18             :  public:
      19             :   OptimisticLazy() = default;
      20             :   OptimisticLazy(const OptimisticLazy& other) {
      21             :     if (T* value = other.value_.load(std::memory_order_acquire)) {
      22             :       value_ = new T(*value);
      23             :     }
      24             :   }
      25             :   OptimisticLazy(OptimisticLazy&& other) noexcept
      26             :       : value_(other.value_.exchange(nullptr, std::memory_order_acq_rel)) {}
      27             :   ~OptimisticLazy() {
      28             :     reset();
      29             :   }
      30             : 
      31             :   template <class Factory>
      32             :   T& ensure(const Factory& factory) {
      33             :     if (T* value = value_.load(std::memory_order_acquire)) {
      34             :       return *value;
      35             :     }
      36             :     T* value = new T(factory());
      37             :     T* old = nullptr;
      38             :     if (!value_.compare_exchange_strong(
      39             :             old, value, std::memory_order_release, std::memory_order_acquire)) {
      40             :       delete value;
      41             :       value = old;
      42             :     }
      43             :     return *value;
      44             :   }
      45             : 
      46             :   // The following methods are not thread-safe: they should not be called
      47             :   // concurrently with any other method.
      48             : 
      49             :   OptimisticLazy& operator=(const OptimisticLazy& other) {
      50             :     *this = OptimisticLazy{other};
      51             :     return *this;
      52             :   }
      53             : 
      54             :   OptimisticLazy& operator=(OptimisticLazy&& other) noexcept {
      55             :     if (this != &other) {
      56             :       reset();
      57             :       value_.store(
      58             :           other.value_.exchange(nullptr, std::memory_order_acquire),
      59             :           std::memory_order_release);
      60             :     }
      61             :     return *this;
      62             :   }
      63             : 
      64           0 :   void reset() {
      65           0 :     if (T* old = value_.load(std::memory_order_relaxed)) {
      66             :       value_.store(nullptr, std::memory_order_relaxed);
      67           0 :       delete old;
      68             :     }
      69           0 :   }
      70             : 
      71             :  private:
      72             :   std::atomic<T*> value_{nullptr};
      73             : };
      74             : 
      75             : /**
      76             :  * Interface for a value that is computed on first access.
      77             :  */
      78             : template <class T>
      79             : class LazyValue {
      80             :  public:
      81             :   virtual ~LazyValue() = default;
      82             : 
      83             :   virtual const T& get() const = 0;
      84             : };
      85             : 
      86             : /**
      87             :  * Convenience thread-safe LazyValue implementation with opportunistic
      88             :  * concurrency.
      89             :  */
      90             : template <class T>
      91             : class OptimisticLazyValue : public LazyValue<T> {
      92             :  public:
      93             :   const T& get() const override {
      94             :     return value_.ensure([this] { return compute(); });
      95             :   }
      96             : 
      97             :  private:
      98             :   virtual T compute() const = 0;
      99             : 
     100             :   mutable OptimisticLazy<T> value_;
     101             : };
     102             : 
     103             : /**
     104             :  * Convenience immutable (thus thread-safe) LazyValue implementation for cases
     105             :  * in which the value is not actually lazy.
     106             :  */
     107             : template <class T>
     108             : class PrecomputedLazyValue : public LazyValue<T> {
     109             :  public:
     110             :   PrecomputedLazyValue(T value) : value_(std::move(value)) {}
     111             : 
     112             :   const T& get() const override {
     113             :     return value_;
     114             :   }
     115             : 
     116             :  private:
     117             :   T value_;
     118             : };
     119             : 
     120             : } // namespace c10

Generated by: LCOV version 1.16