lib/concurrent/collection/lock_free_stack.rb in concurrent-ruby-1.1.0.pre1 vs lib/concurrent/collection/lock_free_stack.rb in concurrent-ruby-1.1.0.pre2

- old
+ new

@@ -1,16 +1,22 @@ module Concurrent - # @!visibility private + # @!macro warn.edge class LockFreeStack < Synchronization::Object safe_initialization! class Node # TODO (pitr-ch 20-Dec-2016): Could be unified with Stack class? - attr_reader :value, :next_node + # @return [Node] + attr_reader :next_node + + # @return [Object] + attr_reader :value + + # @!visibility private # allow to nil-ify to free GC when the entry is no longer relevant, not synchronised attr_writer :value def initialize(value, next_node) @value = value @@ -18,95 +24,120 @@ end singleton_class.send :alias_method, :[], :new end - class Empty < Node - def next_node - self - end + # The singleton for empty node + EMPTY = Node[nil, nil] + def EMPTY.next_node + self end - EMPTY = Empty[nil, nil] - attr_atomic(:head) private :head, :head=, :swap_head, :compare_and_set_head, :update_head + # @!visibility private def self.of1(value) new Node[value, EMPTY] end + # @!visibility private def self.of2(value1, value2) new Node[value1, Node[value2, EMPTY]] end + # @param [Node] head def initialize(head = EMPTY) super() self.head = head end + # @param [Node] head + # @return [true, false] def empty?(head = self.head) head.equal? EMPTY end + # @param [Node] head + # @param [Object] value + # @return [true, false] def compare_and_push(head, value) compare_and_set_head head, Node[value, head] end + # @param [Object] value + # @return [self] def push(value) while true current_head = head return self if compare_and_set_head current_head, Node[value, current_head] end end + # @return [Node] def peek head end + # @param [Node] head + # @return [true, false] def compare_and_pop(head) compare_and_set_head head, head.next_node end + # @return [Object] def pop while true current_head = head return current_head.value if compare_and_set_head current_head, current_head.next_node end end + # @param [Node] head + # @return [true, false] def compare_and_clear(head) compare_and_set_head head, EMPTY end include Enumerable + # @param [Node] head + # @return [self] def each(head = nil) return to_enum(:each, head) unless block_given? it = head || peek until it.equal?(EMPTY) yield it.value it = it.next_node end self end + # @return [true, false] def clear while true current_head = head return false if current_head == EMPTY return true if compare_and_set_head current_head, EMPTY end end + # @param [Node] head + # @return [true, false] def clear_if(head) compare_and_set_head head, EMPTY end + # @param [Node] head + # @param [Node] new_head + # @return [true, false] def replace_if(head, new_head) compare_and_set_head head, new_head end + # @return [self] + # @yield over the cleared stack + # @yieldparam [Object] value def clear_each(&block) while true current_head = head return self if current_head == EMPTY if compare_and_set_head current_head, EMPTY