11#include <userver/engine/sleep.hpp>
12#include <userver/utils/assert.hpp>
13#include <userver/utils/shared_readable_ptr.hpp>
15USERVER_NAMESPACE_BEGIN
28class LazySharedPtr final {
31 LazySharedPtr()
noexcept : value_(
nullptr), shared_filled_(
true), get_data_() {}
35 : value_(ptr.Get()), shared_filled_(
true), shared_(std::move(ptr)) {}
38 LazySharedPtr(std::function<utils::SharedReadablePtr<T>()> function)
noexcept : get_data_(std::move(function)) {}
45 : get_data_(other.get_data_)
47 if (other.shared_filled_.load()) {
48 value_.store(other.shared_.Get());
49 shared_ = other.shared_;
50 shared_filled_.store(
true);
56 : value_(other.value_.load()),
57 shared_filled_(other.shared_filled_.load()),
58 shared_(std::move(other.shared_)),
59 get_data_(std::move(other.get_data_)) {}
64 LazySharedPtr&
operator=(
const LazySharedPtr& other) {
65 *
this = LazySharedPtr(other);
70 LazySharedPtr&
operator=(LazySharedPtr&& other)
noexcept {
71 value_.store(other.value_.load(), std::memory_order_relaxed);
72 shared_filled_.store(other.shared_filled_.load(), std::memory_order_relaxed);
73 shared_ = std::move(other.shared_);
74 get_data_ = std::move(other.get_data_);
79 const T*
Get()
const& {
80 if (
const auto* current_value = value_.load(); current_value != kUnfilled) {
83 auto readable = get_data_();
84 if (
const auto* expected = kUnfilled; value_.compare_exchange_strong(expected, readable.Get())) {
85 shared_ = std::move(readable);
86 shared_filled_.store(
true);
93 const utils::SharedReadablePtr<T>&
GetShared()
const& {
94 if (value_ == kUnfilled) {
95 auto readable = get_data_();
96 if (
const auto* expected = kUnfilled; value_.compare_exchange_strong(expected, readable.Get())) {
97 shared_ = std::move(readable);
98 shared_filled_.store(
true);
101 while (!shared_filled_.load()) {
113 const auto* res =
Get();
132 static inline const auto kUnfilled =
reinterpret_cast<
const T*>(std::uintptr_t{1});
134 mutable std::atomic<
const T*> value_{kUnfilled};
135 mutable std::atomic<
bool> shared_filled_{
false};
136 mutable utils::SharedReadablePtr<T> shared_{
nullptr};
137 std::function<utils::SharedReadablePtr<T>()> get_data_{};
147template <
typename Cache>
149 return utils::LazySharedPtr<
typename Cache::DataType>([&cache] {
return cache.Get(); });