7#include <userver/concurrent/impl/intrusive_hooks.hpp> 
    8#include <userver/concurrent/impl/tagged_ptr.hpp> 
    9#include <userver/utils/assert.hpp> 
   11USERVER_NAMESPACE_BEGIN
 
   27template <
typename T, 
typename HookExtractor>
 
   28class IntrusiveStack final {
 
   29  static_assert(std::is_empty_v<HookExtractor>);
 
   32  constexpr IntrusiveStack() = 
default;
 
   34  IntrusiveStack(IntrusiveStack&&) = 
delete;
 
   35  IntrusiveStack& operator=(IntrusiveStack&&) = 
delete;
 
   37  void Push(T& node) 
noexcept {
 
   38    UASSERT_MSG(GetNext(node).load(std::memory_order_relaxed) == 
nullptr,
 
   39                "This node is already contained in an IntrusiveStack");
 
   41    NodeTaggedPtr expected = stack_head_.load();
 
   43      GetNext(node).store(expected.GetDataPtr());
 
   44      const NodeTaggedPtr desired(&node, expected.GetTag());
 
   45      if (stack_head_.compare_exchange_weak(expected, desired)) {
 
   51  T* TryPop() 
noexcept {
 
   52    NodeTaggedPtr expected = stack_head_.load();
 
   54      T* 
const expected_ptr = expected.GetDataPtr();
 
   55      if (!expected_ptr) 
return nullptr;
 
   56      const NodeTaggedPtr desired(GetNext(*expected_ptr).load(),
 
   57                                  expected.GetNextTag());
 
   58      if (stack_head_.compare_exchange_weak(expected, desired)) {
 
   60        GetNext(*expected_ptr).store(
nullptr, std::memory_order_relaxed);
 
   66  template <
typename Func>
 
   67  void WalkUnsafe(
const Func& func) {
 
   71  template <
typename Func>
 
   72  void WalkUnsafe(
const Func& func) 
const {
 
   73    DoWalk<
const T&>(func);
 
   76  template <
typename DisposerFunc>
 
   77  void DisposeUnsafe(
const DisposerFunc& disposer) 
noexcept {
 
   78    T* iter = stack_head_.load().GetDataPtr();
 
   79    stack_head_.store(
nullptr);
 
   81      T* 
const old_iter = iter;
 
   82      iter = GetNext(*iter).load();
 
   87  std::size_t GetSizeUnsafe() 
const noexcept {
 
   89    WalkUnsafe([&](
auto& ) { ++size; });
 
   94  using NodeTaggedPtr = TaggedPtr<T>;
 
   96  static_assert(std::atomic<NodeTaggedPtr>::is_always_lock_free);
 
   97  static_assert(std::has_unique_object_representations_v<NodeTaggedPtr>);
 
   99  static std::atomic<T*>& GetNext(T& node) 
noexcept {
 
  100    SinglyLinkedHook<T>& hook = HookExtractor{}(node);
 
  104  template <
typename U, 
typename Func>
 
  105  void DoWalk(
const Func& func) 
const {
 
  106    for (
auto* iter = stack_head_.load().GetDataPtr(); iter;
 
  107         iter = GetNext(*iter).load()) {
 
  108      func(
static_cast<U>(*iter));
 
  112  std::atomic<NodeTaggedPtr> stack_head_{
nullptr};