org.reactfx.util.ListHelper Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of richtextfx Show documentation
Show all versions of richtextfx Show documentation
FX-Text-Area for formatted text and other special effects.
package org.reactfx.util;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Optional;
import java.util.function.BiFunction;
import java.util.function.BinaryOperator;
import java.util.function.Consumer;
import java.util.function.IntFunction;
public abstract class ListHelper {
public static T get(ListHelper listHelper, int index) {
Lists.checkIndex(index, size(listHelper)); // always throws for listHelper == null
return listHelper.get(index);
}
public static ListHelper add(ListHelper listHelper, T elem) {
if(listHelper == null) {
return new SingleElemHelper<>(elem);
} else {
return listHelper.add(elem);
}
}
public static ListHelper remove(ListHelper listHelper, T elem) {
if(listHelper == null) {
return listHelper;
} else {
return listHelper.remove(elem);
}
}
public static void forEach(ListHelper listHelper, Consumer super T> f) {
if(listHelper != null) {
listHelper.forEach(f);
}
}
public static void forEachBetween(
ListHelper listHelper, int from, int to, Consumer super T> f) {
Lists.checkRange(from, to, size(listHelper));
if(from < to) {
listHelper.forEachBetween(from, to, f);
}
}
public static Iterator iterator(ListHelper listHelper) {
if(listHelper != null) {
return listHelper.iterator();
} else {
return Collections.emptyIterator();
}
}
public static Iterator iterator(ListHelper listHelper, int from, int to) {
Lists.checkRange(from, to, size(listHelper));
if(from < to) {
return listHelper.iterator(from, to);
} else {
return Collections.emptyIterator();
}
}
public static Optional reduce(ListHelper listHelper, BinaryOperator f) {
if(listHelper == null) {
return Optional.empty();
} else {
return listHelper.reduce(f);
}
}
public static U reduce(ListHelper listHelper, U unit, BiFunction f) {
if(listHelper == null) {
return unit;
} else {
return listHelper.reduce(unit, f);
}
}
public static T[] toArray(ListHelper listHelper, IntFunction allocator) {
if(listHelper == null) {
return allocator.apply(0);
} else {
return listHelper.toArray(allocator);
}
}
public static boolean isEmpty(ListHelper listHelper) {
return listHelper == null;
}
public static int size(ListHelper listHelper) {
if(listHelper == null) {
return 0;
} else {
return listHelper.size();
}
}
private ListHelper() {
// private constructor to prevent subclassing
};
abstract T get(int index);
abstract ListHelper add(T elem);
abstract ListHelper remove(T elem);
abstract void forEach(Consumer super T> f);
abstract void forEachBetween(int from, int to, Consumer super T> f);
abstract Iterator iterator();
abstract Iterator iterator(int from, int to);
abstract Optional reduce(BinaryOperator f);
abstract U reduce(U unit, BiFunction f);
abstract T[] toArray(IntFunction allocator);
abstract int size();
private static class SingleElemHelper extends ListHelper {
private final T elem;
SingleElemHelper(T elem) {
this.elem = elem;
}
@Override
T get(int index) {
assert index == 0;
return elem;
}
@Override
ListHelper add(T elem) {
return new MultiElemHelper<>(this.elem, elem);
}
@Override
ListHelper remove(T elem) {
if(Objects.equals(this.elem, elem)) {
return null;
} else {
return this;
}
}
@Override
void forEach(Consumer super T> f) {
f.accept(elem);
}
@Override
void forEachBetween(int from, int to, Consumer super T> f) {
assert from == 0 && to == 1;
f.accept(elem);
}
@Override
Iterator iterator() {
return new Iterator() {
boolean hasNext = true;
@Override
public boolean hasNext() {
return hasNext;
}
@Override
public T next() {
if(hasNext) {
hasNext = false;
return elem;
} else {
throw new NoSuchElementException();
}
}
};
}
@Override
Iterator iterator(int from, int to) {
assert from == 0 && to == 1;
return iterator();
}
@Override
Optional reduce(BinaryOperator f) {
return Optional.of(elem);
}
@Override
U reduce(U unit, BiFunction f) {
return f.apply(unit, elem);
}
@Override
T[] toArray(IntFunction allocator) {
T[] res = allocator.apply(1);
res[0] = elem;
return res;
}
@Override
int size() {
return 1;
}
}
private static class MultiElemHelper extends ListHelper {
private final List elems;
// when > 0, this ListHelper must be immutable,
// i.e. use copy-on-write for mutating operations
private int iterating = 0;
@SafeVarargs
MultiElemHelper(T... elems) {
this(Arrays.asList(elems));
}
private MultiElemHelper(List elems) {
this.elems = new ArrayList<>(elems);
}
private MultiElemHelper copy() {
return new MultiElemHelper<>(elems);
}
@Override
T get(int index) {
return elems.get(index);
}
@Override
ListHelper add(T elem) {
if(iterating > 0) {
return copy().add(elem);
} else {
elems.add(elem);
return this;
}
}
@Override
ListHelper remove(T elem) {
int idx = elems.indexOf(elem);
if(idx == -1) {
return this;
} else {
switch(elems.size()) {
case 0: // fall through
case 1: throw new AssertionError();
case 2: return new SingleElemHelper<>(elems.get(1-idx));
default:
if(iterating > 0) {
return copy().remove(elem);
} else {
elems.remove(elem);
return this;
}
}
}
}
@Override
void forEach(Consumer super T> f) {
++iterating;
try {
elems.forEach(f);
} finally {
--iterating;
}
}
@Override
void forEachBetween(int from, int to, Consumer super T> f) {
++iterating;
try {
elems.subList(from, to).forEach(f);
} finally {
--iterating;
}
}
@Override
Iterator iterator() {
return iterator(0, elems.size());
}
@Override
Iterator iterator(int from, int to) {
assert from < to;
++iterating;
return new Iterator() {
int next = from;
@Override
public boolean hasNext() {
return next < to;
}
@Override
public T next() {
if(next < to) {
T res = elems.get(next);
++next;
if(next == to) {
--iterating;
}
return res;
} else {
throw new NoSuchElementException();
}
}
};
}
@Override
Optional reduce(BinaryOperator f) {
return elems.stream().reduce(f);
}
@Override
U reduce(U unit, BiFunction f) {
U u = unit;
for(T elem: elems) {
u = f.apply(u, elem);
}
return u;
}
@Override
T[] toArray(IntFunction allocator) {
return elems.toArray(allocator.apply(size()));
}
@Override
int size() {
return elems.size();
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy