2#ifndef __ASE_ATOMICS_HH__ 
    3#define __ASE_ATOMICS_HH__ 
    7#include <boost/atomic/atomic.hpp>       
   14template<
class T> 
using Atomic = boost::atomic<T>;
 
   28                   "Required: std::atomic<T*>& atomic_next_ptrref (T&)");
 
   34    return head_.
load() == 
nullptr;
 
 
   40    AtomicTPtr &last_nextptr = atomic_next_ptrref (last);
 
   42    T *exchange = head_.
load();
 
   44      last_nextptr = exchange;
 
   46    const bool was_empty = exchange == 
nullptr;
 
 
   60    T *exchange = head_.
load();
 
 
   71    T *current = 
pop_all(), *prev = 
nullptr;;
 
   74        AtomicTPtr &el_nextptr = atomic_next_ptrref (current);
 
 
 
   95template<
typename Node> 
 
  101    thead.next = (Node*) TAIL_;         
 
  109    Head nhead, ohead = head_.load();
 
  112        nhead.aba_counter = ohead.aba_counter;
 
  113        nhead.next = 
nullptr;
 
  115    while (!head_.compare_exchange_weak (ohead, nhead));
 
  116    ohead = head_.load();
 
  117    assert (ohead.next == 
nullptr);     
 
  122    const Head ohead = head_.load();
 
  123    return ohead.next == (Node*) TAIL_;
 
  128    assert (node && !node->intr_ptr_);  
 
  129    Head nhead, ohead = head_.load();
 
  133        node->intr_ptr_ = ohead.next;   
 
  134        nhead.aba_counter = ohead.aba_counter;  
 
  137    while (!head_.compare_exchange_weak (ohead, nhead));
 
  138    const bool was_empty = ohead.next == (Node*) TAIL_;
 
  145    Head nhead, ohead = head_.load();
 
  150        if (node == (Node*) TAIL_)
 
  152        nhead.next = node->intr_ptr_;   
 
  153        nhead.aba_counter = ohead.aba_counter + 1;  
 
  155    while (!head_.compare_exchange_weak (ohead, nhead));
 
  156    node->intr_ptr_ = 
nullptr;          
 
  163    const Head ohead = head_.load();
 
  168    Node     *next = 
nullptr;
 
  172  static constexpr uintptr_t TAIL_ = ~uintptr_t (0);
 
 
  178template<
typename Value, 
template<
class> 
class GrowOnlyAllocator = 
Loft::Allocator>
 
  181  bool  empty()
 const   { 
return stack_.empty(); }
 
  186    Node *node = node_realloc (
nullptr);
 
  188    return stack_.push (node);
 
 
  200    Node *node = stack_.pop();
 
  203    value = std::move (node->value);
 
 
  211    Atomic<Node*> intr_ptr_ = 
nullptr; 
 
  213  MpmcStack<Node> stack_;
 
  215  node_realloc (Node *node)
 
  217    static constexpr GrowOnlyAllocator<Node> grow_only_alloc;
 
  218    static_assert (GrowOnlyAllocator<Node>::allows_read_after_free == 
true);
 
  220      grow_only_alloc.deallocate (node, 1);
 
  223      node = grow_only_alloc.allocate (1);
 
 
  239    size_t u_ = ~size_t (0), s_ = 0;
 
  240    AtomicU64& ubits()
 const { 
return const_cast<Iter*
> (
this)->atomics_->u64 (u_); }
 
  241    size_t     usize()
 const { 
return atomics_ ? atomics_->usize() : 0; }
 
  243    explicit Iter     (
AtomicBits *a, 
size_t p) : atomics_ (a), u_ (p >> 6), s_ (p & 63) {}
 
  246    Iter&    operator= (
const Iter&) = 
default;
 
  247    size_t   position ()
 const { 
return u_ + s_; }
 
  248    bool     is_set   ()
 const { 
return valid() && ubits().
load() & (
uint64 (1) << s_); }
 
  249    bool     done     ()
 const { 
return !valid(); }
 
  250    bool     valid    ()
 const { 
return atomics_ && u_ < usize(); }
 
  252    bool     set      (
bool toggle);
 
  253    bool     xor_     (
bool toggle);
 
  255    Iter&    operator=  (
bool toggle) { set (toggle); 
return *
this; }
 
  256    Iter&    operator^= (
bool toggle) { xor_ (toggle); 
return *
this; }
 
  257    Iter&    operator|= (
bool toggle) { 
if (toggle) set (1); 
return *
this; }
 
  258    Iter&    operator&= (
bool toggle) { 
if (!toggle) set (0); 
return *
this; }
 
  259    Iter&    operator++ () { 
if (!done()) { s_ = (s_ + 1) & 63; u_ += s_ == 0; } 
return *
this;}
 
  260    Iter&    operator++ (
int) { 
return this->operator++(); }
 
  261    bool     operator== (
const Iter &o)
 const { 
return (done() && o.done()) || position() == o.position(); }
 
  262    bool     operator!= (
const Iter &o)
 const { 
return !operator== (o); }
 
  263    bool     operator== (
bool b)
 const { 
return b == is_set(); }
 
  264    bool     operator!= (
bool b)
 const { 
return b != is_set(); }
 
  265    explicit operator bool ()
 const { 
return is_set(); }
 
 
  269  explicit    AtomicBits (
const AtomicBits&) = 
delete;
 
  270  size_t      usize      ()
 const { 
return base().
size(); }
 
  271  size_t      size       ()
 const { 
return 64 * usize(); }
 
  272  uint64      u64        (
size_t upos)
 const { 
return base()[upos]; }
 
  273  AtomicU64&  u64        (
size_t upos) { 
return base()[upos]; }
 
  274  AtomicBits& operator=  (
const AtomicBits&) = 
delete;
 
  275  Iter        iter       (
size_t pos) { 
return Iter (
this, pos); }
 
  276  Iter        begin      () { 
return iter (0); }
 
  277  Iter        end        ()
 const { 
return {}; }
 
  278  bool        all        (
bool toggle) 
const;
 
  279  bool        any        (
bool toggle) 
const;
 
  280  bool        set        (
size_t pos, 
bool toggle) { 
return iter (pos).set (toggle); }
 
  281  bool        operator[] (
size_t pos)
 const { 
return const_cast<AtomicBits*
> (
this)->iter (pos).is_set(); }
 
  282  Iter        operator[] (
size_t pos) { 
return iter (pos); }
 
 
  286AtomicBits::all (
bool toggle)
 const 
  288  const uint64 match = toggle * ~uint64 (0);
 
  289  for (
size_t u = 0; u < usize(); u++)
 
  290    if (u64 (u) != match)
 
  296AtomicBits::any (
bool toggle)
 const 
  299    for (
size_t u = 0; u < usize(); u++)
 
  303    for (
size_t u = 0; u < usize(); u++)
 
  304      if (u64 (u) != ~uint64 (0))
 
  311AtomicBits::Iter::set (
bool toggle)
 
  323AtomicBits::Iter::clear()
 
  332AtomicBits::Iter::xor_ (
bool toggle)
 
  336  last = ubits().fetch_xor (toggle ? 
uint64 (1) << s_ : 0);
 
  341inline AtomicBits::Iter&
 
  352  while (!ubits().load() && u_ < usize());
 
 
Iter & big_inc1()
Increment iterator by 1, allow big increments skipping zero bits.
 
Vector of atomic bits, operates in blocks of 64 bits.
 
bool push_chain(T *first, T *last)
Atomically push linked nodes first->…->last onto the stack, returns was_empty.
 
bool push(T *el)
Atomically push el onto the stack, returns was_empty.
 
bool empty() const
Check if poppingreturns null.
 
Allocator for STL containers.
 
T compare_exchange_strong(T... args)
 
T construct_at(T... args)
 
#define ASE_ASSERT_RETURN(expr,...)
Return from the current function if expr evaluates to false and issue an assertion warning.
 
#define ASE_RETURN_UNLESS(cond,...)
Return silently if cond does not evaluate to true, with return value ...
 
#define ASE_ISLIKELY(expr)
Compiler hint to optimize for expr evaluating to true.
 
The Anklang C++ API namespace.
 
boost::atomic< T > Atomic
Substitute for std::atomic<> with fixes for GCC.
 
uint64_t uint64
A 64-bit unsigned integer, use PRI*64 in format strings.
 
bool push(const Value &value)
Add a copy of value to top of the stack, returns if the stack was empty (true).
 
bool empty() const
Return true if the stack holds no items.
 
bool pop(Value &value)
Pop value from top of the stack, returns if value was reassigned (true), otherwise the stack was empt...
 
bool push(Value &&value)
Add value to top of the stack, returns if the stack was empty (true).
 
Value type used to interface with various property types.