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 {
32 : value_(
nullptr), shared_filled_(
true), get_data_() {}
36 : value_(ptr.Get()), shared_filled_(
true), shared_(std::move(ptr)) {}
39 LazySharedPtr(std::function<utils::SharedReadablePtr<T>()> function)
noexcept
40 : get_data_(std::move(function)) {}
46 LazySharedPtr(
const LazySharedPtr& other) : 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(),
73 std::memory_order_relaxed);
74 shared_ = std::move(other.shared_);
75 get_data_ = std::move(other.get_data_);
80 const T*
Get()
const& {
81 if (
const auto* current_value = value_.load(); current_value != kUnfilled) {
84 auto readable = get_data_();
85 if (
const auto* expected = kUnfilled;
86 value_.compare_exchange_strong(expected, readable.Get())) {
87 shared_ = std::move(readable);
88 shared_filled_.store(
true);
95 const utils::SharedReadablePtr<T>&
GetShared()
const& {
96 if (value_ == kUnfilled) {
97 auto readable = get_data_();
98 if (
const auto* expected = kUnfilled;
99 value_.compare_exchange_strong(expected, readable.Get())) {
100 shared_ = std::move(readable);
101 shared_filled_.store(
true);
104 while (!shared_filled_.load()) {
116 const auto* res =
Get();
135 static inline const auto kUnfilled =
136 reinterpret_cast<
const T*>(std::uintptr_t{1});
138 mutable std::atomic<
const T*> value_{kUnfilled};
139 mutable std::atomic<
bool> shared_filled_{
false};
140 mutable utils::SharedReadablePtr<T> shared_{
nullptr};
141 std::function<utils::SharedReadablePtr<T>()> get_data_{};
151template <
typename Cache>
153 return utils::LazySharedPtr<
typename Cache::DataType>(
154 [&cache] {
return cache.Get(); });