class Hamster::LazyList

@private
construct infinite ‘List`s.
By returning a `Cons` that in turn has a {LazyList} as its tail, one can
only called) when one of these operations is performed.
to `#head`, `#tail` and `#empty?`. The list is only realized (i.e. the block is
A `LazyList` takes a block that returns a `List`, i.e. an object that responds

def cached_size?

def cached_size?
  @size != nil
end

def empty?

def empty?
  realize if @atomic.get != 2
  @size == 0
end

def head

def head
  realize if @atomic.get != 2
  @head
end

def initialize(&block)

def initialize(&block)
  @head   = block # doubles as storage for block while yet unrealized
  @tail   = nil
  @atomic = Concurrent::AtomicReference.new(0) # haven't yet run block
  @size   = nil
end

def realize

def realize
  while true
    # try to "claim" the right to run the block which realizes target
    if @atomic.compare_and_swap(0,1) # full memory barrier here
      begin
        list = @head.call
        if list.empty?
          @head, @tail, @size = nil, self, 0
        else
          @head, @tail = list.head, list.tail
        end
      rescue
        @atomic.set(0)
        MUTEX.synchronize { QUEUE.broadcast }
        raise
      end
      @atomic.set(2)
      MUTEX.synchronize { QUEUE.broadcast }
      return
    end
    # we failed to "claim" it, another thread must be running it
    if @atomic.get == 1 # another thread is running the block
      MUTEX.synchronize do
        # check value of @atomic again, in case another thread already changed it
        #   *and* went past the call to QUEUE.broadcast before we got here
        QUEUE.wait(MUTEX) if @atomic.get == 1
      end
    elsif @atomic.get == 2 # another thread finished the block
      return
    end
  end
end

def size

def size
  @size ||= super
end

def tail

def tail
  realize if @atomic.get != 2
  @tail
end