package carpet.script.value; import carpet.script.exception.InternalExpressionException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Locale; import net.minecraft.nbt.StringTag; import net.minecraft.nbt.Tag; public abstract class LazyListValue extends AbstractListValue implements Iterator { public static LazyListValue rangeDouble(final double from, final double to, final double step) { return new LazyListValue() { { if (step == 0) { throw new InternalExpressionException("Range will never end with a zero step"); } this.start = from; this.current = this.start; this.limit = to; this.stepp = step; } private final double start; private double current; private final double limit; private final double stepp; @Override public Value next() { final Value val = new NumericValue(current); current += stepp; return val; } @Override public void reset() { current = start; } @Override public boolean hasNext() { return stepp > 0 ? (current < limit) : (current > limit); } @Override public String getString() { return String.format(Locale.ROOT, "[%s, %s, ..., %s)", NumericValue.of(start).getString(), NumericValue.of(start + stepp).getString(), NumericValue.of(limit).getString()); } }; } public static LazyListValue rangeLong(final long from, final long to, final long step) { return new LazyListValue() { { if (step == 0) { throw new InternalExpressionException("Range will never end with a zero step"); } this.start = from; this.current = this.start; this.limit = to; this.stepp = step; } private final long start; private long current; private final long limit; private final long stepp; @Override public Value next() { final Value val = new NumericValue(current); current += stepp; return val; } @Override public void reset() { current = start; } @Override public boolean hasNext() { return stepp > 0 ? (current < limit) : (current > limit); } @Override public String getString() { return String.format(Locale.ROOT, "[%s, %s, ..., %s)", NumericValue.of(start).getString(), NumericValue.of(start + stepp).getString(), NumericValue.of(limit).getString()); } }; } @Override public String getString() { return "[...]"; } @Override public boolean getBoolean() { return hasNext(); } @Override public void fatality() { reset(); } public abstract void reset(); @Override public Iterator iterator() { return this; } public List unroll() { final List result = new ArrayList<>(); this.forEachRemaining(result::add); fatality(); return result; } @Override public Value slice(long from, Long to) { if (to == null || to < 0) { to = (long) Integer.MAX_VALUE; } if (from < 0) { from = 0; } if (from > to) { return ListValue.of(); } final List result = new ArrayList<>(); int i; for (i = 0; i < from; i++) { if (hasNext()) { next(); } else { fatality(); return ListValue.wrap(result); } } for (i = (int) from; i < to; i++) { if (hasNext()) { result.add(next()); } else { fatality(); return ListValue.wrap(result); } } return ListValue.wrap(result); } @Override public Value add(final Value other) { throw new InternalExpressionException("Cannot add to iterators"); } @Override public boolean equals(final Object o) { return false; } @Override public String getTypeString() { return "iterator"; } @Override public Object clone() { final Object copy; try { copy = super.clone(); } catch (final CloneNotSupportedException e) { throw new InternalExpressionException("Cannot copy iterators"); } ((LazyListValue) copy).reset(); return copy; } @Override public Value fromConstant() { return (Value) clone(); } @Override public int hashCode() { return ("i" + getString()).hashCode(); } @Override public Tag toTag(final boolean force) { if (!force) { throw new NBTSerializableValue.IncompatibleTypeException(this); } return StringTag.valueOf(getString()); } }