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(); });