@Override
 public void onError(final Throwable e) {
   // TODO throw if fatal ?;
   FastList list;
   synchronized (this) {
     if (terminated) {
       return;
     }
     if (emitting) {
       if (queue == null) {
         queue = new FastList();
       }
       queue.add(new ErrorSentinel(e));
       return;
     }
     emitting = true;
     list = queue;
     queue = null;
   }
   drainQueue(list);
   delegate.onError(e);
   synchronized (this) {
     emitting = false;
   }
 }
 @Override
 @Test
 public void addAtIndex() {
   MutableList<Integer> integers = this.newWith(1, 2, 3, 5);
   integers.add(3, 4);
   Verify.assertStartsWith(integers, 1, 2, 3, 4, 5);
   integers.add(5, 6);
   Verify.assertStartsWith(integers, 1, 2, 3, 4, 5, 6);
   integers.add(0, 0);
   Verify.assertStartsWith(integers, 0, 1, 2, 3, 4, 5, 6);
   FastList<String> zeroSizedList = FastList.newList(0);
   zeroSizedList.add(0, "1");
   Verify.assertStartsWith(zeroSizedList, "1");
   zeroSizedList.add(1, "3");
   Verify.assertStartsWith(zeroSizedList, "1", "3");
   zeroSizedList.add(1, "2");
   Verify.assertStartsWith(zeroSizedList, "1", "2", "3");
   MutableList<Integer> midList = FastList.<Integer>newList(2).with(1, 3);
   midList.add(1, 2);
   Verify.assertStartsWith(midList, 1, 2, 3);
   Verify.assertThrows(IndexOutOfBoundsException.class, () -> midList.add(-1, -1));
 }
 @Override
 public void onComplete() {
   FastList list;
   synchronized (this) {
     if (terminated) {
       return;
     }
     terminated = true;
     if (emitting) {
       if (queue == null) {
         queue = new FastList();
       }
       queue.add(COMPLETE_SENTINEL);
       return;
     }
     emitting = true;
     list = queue;
     queue = null;
   }
   drainQueue(list);
   delegate.onComplete();
 }
  @Override
  public void onNext(T t) {
    FastList list;

    synchronized (this) {
      if (terminated) {
        return;
      }
      if (emitting) {
        if (queue == null) {
          queue = new FastList();
        }
        queue.add(t != null ? t : NULL_SENTINEL);
        // another thread is emitting so we add to the queue and return
        return;
      }
      // we can emit
      emitting = true;
      // reference to the list to drain before emitting our value
      list = queue;
      queue = null;
    }

    // we only get here if we won the right to emit, otherwise we returned in the if(emitting) block
    // above
    boolean skipFinal = false;
    try {
      int iter = MAX_DRAIN_ITERATION;
      do {
        drainQueue(list);
        if (iter == MAX_DRAIN_ITERATION) {
          // after the first draining we emit our own value
          delegate.onNext(t);
        }
        --iter;
        if (iter > 0) {
          synchronized (this) {
            list = queue;
            queue = null;
            if (list == null) {
              emitting = false;
              skipFinal = true;
              return;
            }
          }
        }
      } while (iter > 0);
    } finally {
      if (!skipFinal) {
        synchronized (this) {
          if (terminated) {
            list = queue;
            queue = null;
          } else {
            emitting = false;
            list = null;
          }
        }
      }
    }

    // this will only drain if terminated (done here outside of synchronized block)
    drainQueue(list);
  }