|
#pragma once |
|
|
|
#include <atomic> |
|
#include <utility> |
|
|
|
namespace c10 { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template <class T> |
|
class OptimisticLazy { |
|
public: |
|
OptimisticLazy() = default; |
|
OptimisticLazy(const OptimisticLazy& other) { |
|
if (T* value = other.value_.load(std::memory_order_acquire)) { |
|
value_ = new T(*value); |
|
} |
|
} |
|
OptimisticLazy(OptimisticLazy&& other) noexcept |
|
: value_(other.value_.exchange(nullptr, std::memory_order_acq_rel)) {} |
|
~OptimisticLazy() { |
|
reset(); |
|
} |
|
|
|
template <class Factory> |
|
T& ensure(Factory&& factory) { |
|
if (T* value = value_.load(std::memory_order_acquire)) { |
|
return *value; |
|
} |
|
T* value = new T(factory()); |
|
T* old = nullptr; |
|
if (!value_.compare_exchange_strong( |
|
old, value, std::memory_order_release, std::memory_order_acquire)) { |
|
delete value; |
|
value = old; |
|
} |
|
return *value; |
|
} |
|
|
|
|
|
|
|
|
|
OptimisticLazy& operator=(const OptimisticLazy& other) { |
|
*this = OptimisticLazy{other}; |
|
return *this; |
|
} |
|
|
|
OptimisticLazy& operator=(OptimisticLazy&& other) noexcept { |
|
if (this != &other) { |
|
reset(); |
|
value_.store( |
|
other.value_.exchange(nullptr, std::memory_order_acquire), |
|
std::memory_order_release); |
|
} |
|
return *this; |
|
} |
|
|
|
void reset() { |
|
if (T* old = value_.load(std::memory_order_relaxed)) { |
|
value_.store(nullptr, std::memory_order_relaxed); |
|
delete old; |
|
} |
|
} |
|
|
|
private: |
|
std::atomic<T*> value_{nullptr}; |
|
}; |
|
|
|
|
|
|
|
|
|
template <class T> |
|
class LazyValue { |
|
public: |
|
virtual ~LazyValue() = default; |
|
|
|
virtual const T& get() const = 0; |
|
}; |
|
|
|
|
|
|
|
|
|
|
|
template <class T> |
|
class OptimisticLazyValue : public LazyValue<T> { |
|
public: |
|
const T& get() const override { |
|
return value_.ensure([this] { return compute(); }); |
|
} |
|
|
|
private: |
|
virtual T compute() const = 0; |
|
|
|
mutable OptimisticLazy<T> value_; |
|
}; |
|
|
|
|
|
|
|
|
|
|
|
template <class T> |
|
class PrecomputedLazyValue : public LazyValue<T> { |
|
public: |
|
PrecomputedLazyValue(T value) : value_(std::move(value)) {} |
|
|
|
const T& get() const override { |
|
return value_; |
|
} |
|
|
|
private: |
|
T value_; |
|
}; |
|
|
|
} |
|
|