package com.github.kratorius.jefs;

import sun.misc.Unsafe;

import java.util.NoSuchElementException;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * Represents a last-in-first-out (LIFO) unbounded stack of objects.
 * The usual {@code push} and {@code pop} operations are provided, as well as
 * a {@code peek} method to peek at the top of the stack.
 *
 * @param <E> the type of elements held in this collection
 */
public class LFStack<E> extends NotSafe {
  private static final Unsafe unsafe = getUnsafe();
  private volatile Node<E> head = null;
  private long headOffset;
  private AtomicInteger itemCount = new AtomicInteger();

  static class Node<E> {
    final E val;
    Node<E> next;

    public Node(E val) {
      this.val = val;
    }
  }

  /**
   * Creates an empty stack.
   */
  public LFStack() {
    try {
      headOffset = unsafe.objectFieldOffset(this.getClass().getDeclaredField("head"));
    } catch (NoSuchFieldException e) {
      throw new RuntimeException();
    }
  }

  /**
   * Tests if the stack is empty.
   * @return {@code true} if and only if this stack contains no items;
   *         {@code false} otherwise
   */
  public boolean empty() {
    /* '==' is atomic for reference variables as per documentation:
     * "Reads and writes are atomic for reference variables and for most
     * primitive variables (all types except long and double).
     * (http://docs.oracle.com/javase/tutorial/essential/concurrency/atomic.html)
     */
    return head == null;
  }

  /**
   * Looks at the object at the top of the stack without removing it.
   * @return the object at the top of this stack
   * @throws java.util.NoSuchElementException if the stack is empty
   */
  public E peek() throws NoSuchElementException {
    Node<E> pop;

    for (;;) {
      pop = head;
      if (unsafe.compareAndSwapObject(this, headOffset, pop, pop)) {
        if (pop == null) {
          throw new NoSuchElementException();
        }
        return pop.val;
      }
    }
  }

  /**
   * Removes the object at the top of the stack and returns that object as the
   * value of this function.
   * @return the object at the top of the stack
   * @throws NoSuchElementException if the stack is empty
   */
  public E pop() throws NoSuchElementException {
    Node<E> pop, newHead;

    for (;;) {
      if ((pop = head) == null) {
        throw new NoSuchElementException();
      }
      newHead = head.next;
      if (unsafe.compareAndSwapObject(this, headOffset, pop, newHead)) {
        itemCount.decrementAndGet();
        return pop.val;
      }
    }
  }

  /**
   * Pushes an item onto the top of the stack.
   * @param item the item to be pushed onto this stack.
   */
  public void push(E item) {
    Node<E> node = new Node<>(item);

    for (;;) {
      node.next = head;
      if (unsafe.compareAndSwapObject(this, headOffset, node.next, node)) {
        itemCount.incrementAndGet();
        break;
      }
    }
  }

  /**
   * Counts the number of elements currently in the stack.
   * @return the number of elements in the stack.
   */
  public int size() {
    return itemCount.get();
  }
}

@@ -1776,32 +1776,26 @@
 %3E pop;%0A%0A    
-for (;;)
+do
  %7B%0A      pop
@@ -1799,38 +1799,42 @@
 pop = head;%0A    
-  if
+%7D while
  (
+!
 unsafe.compareAn
@@ -1873,23 +1873,19 @@
 p, pop))
- %7B%0A    
+;%0A%0A
     if (
@@ -1895,28 +1895,24 @@
  == null) %7B%0A
-    
       throw 
@@ -1945,26 +1945,18 @@
 ();%0A    
- 
-   %7D%0A    
+%7D%0A
     retu
@@ -1963,38 +1963,24 @@
 rn pop.val;%0A
-      %7D%0A    %7D%0A
   %7D%0A%0A  /**%0A 
@@ -2274,32 +2274,26 @@
 wHead;%0A%0A    
-for (;;)
+do
  %7B%0A      if 
@@ -2396,30 +2396,34 @@
 d.next;%0A    
-  if
+%7D while
  (
+!
 unsafe.compa
@@ -2470,23 +2470,19 @@
 ewHead))
- %7B%0A    
+;%0A%0A
     item
@@ -2510,20 +2510,16 @@
 ();%0A    
- 
-   
 return p
@@ -2526,30 +2526,16 @@
 op.val;%0A
-      %7D%0A    %7D%0A
   %7D%0A%0A  /
@@ -2721,16 +2721,10 @@
     
-for (;;)
+do
  %7B%0A 
@@ -2750,22 +2750,26 @@
 ad;%0A    
-  if
+%7D while
  (
+!
 unsafe.c
@@ -2823,23 +2823,19 @@
 , node))
- %7B%0A    
+;%0A%0A
     item
@@ -2863,37 +2863,8 @@
 ();%0A
-        break;%0A      %7D%0A    %7D%0A
   %7D%0A

Use do...while in place of for(;;) for handling CAS in LFStack