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)) {}
44 LazySharedPtr(
const LazySharedPtr& other) : get_data_(other.get_data_) {
45 if (other.shared_filled_.load()) {
46 value_.store(other.shared_.Get());
47 shared_ = other.shared_;
48 shared_filled_.store(
true);
54 : value_(other.value_.load()),
55 shared_filled_(other.shared_filled_.load()),
56 shared_(std::move(other.shared_)),
57 get_data_(std::move(other.get_data_)) {}
62 LazySharedPtr&
operator=(
const LazySharedPtr& other) {
63 *
this = LazySharedPtr(other);
68 LazySharedPtr&
operator=(LazySharedPtr&& other)
noexcept {
69 value_.store(other.value_.load(), std::memory_order_relaxed);
70 shared_filled_.store(other.shared_filled_.load(), std::memory_order_relaxed);
71 shared_ = std::move(other.shared_);
72 get_data_ = std::move(other.get_data_);
77 const T*
Get()
const& {
78 if (
const auto* current_value = value_.load(); current_value != kUnfilled) {
81 auto readable = get_data_();
82 if (
const auto* expected = kUnfilled; value_.compare_exchange_strong(expected, readable.Get())) {
83 shared_ = std::move(readable);
84 shared_filled_.store(
true);
92 if (value_ == kUnfilled) {
93 auto readable = get_data_();
94 if (
const auto* expected = kUnfilled; value_.compare_exchange_strong(expected, readable.Get())) {
95 shared_ = std::move(readable);
96 shared_filled_.store(
true);
99 while (!shared_filled_.load()) {
111 const auto* res =
Get();
130 static inline const auto kUnfilled =
reinterpret_cast<
const T*>(std::uintptr_t{1});
132 mutable std::atomic<
const T*> value_{kUnfilled};
133 mutable std::atomic<
bool> shared_filled_{
false};
134 mutable utils::SharedReadablePtr<T> shared_{
nullptr};
135 std::function<
utils::SharedReadablePtr<T>()> get_data_{};
145template <
typename Cache>
147 return utils::LazySharedPtr<
typename Cache::DataType>([&cache] {
return cache.Get(); });