JBIterable<E> () { // iterate through the previous result fully before proceeding while (it != null && it.advance()) /* no-op */ ; it = null; // empty case: check hasNext() only if nothing is stored to be compatible with JBIterator#cursor() if (stored == null && !orig.hasNext()) { if (st < 0 && mode != Split.BEFORE && mode != Split.GROUP) { st = 1; return empty(); } return stop(); } // general case: add empty between 2 separators in KEEP mode; otherwise go with some state logic if (st == -2 && mode == Split.AROUND) { st = -1; return empty(); } E tmp = stored; stored = null; return of(tmp).append(once((it = JBIterator.wrap(orig)).takeWhile(e -> { boolean sep = condition.value(e); int st0 = st; st = st0 < 0 && sep ? -2 : st0 > 0 && !sep ? 2 : sep ? -1 : 1; boolean result; switch (mode) { case AFTER: result = st != -2 && (st != 1 || st0 == 0); break; case BEFORE: result = st != -2 && st != -1; break; case AROUND: result = st0 >= 0 && st > 0; break; case GROUP: result = st0 >= 0 && st > 0 || st0 <= 0 && st < 0; break; case OFF: result = st > 0; break; default: throw new AssertionError(st); } stored = !result && mode != Split.OFF ? e : null; return result; }))); }