@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); }