
org.osgl.util.LazyRange Maven / Gradle / Ivy
The newest version!
package org.osgl.util;
/*-
* #%L
* Java Tool
* %%
* Copyright (C) 2014 - 2017 OSGL (Open Source General Library)
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import org.osgl.$;
import org.osgl.exception.InvalidArgException;
import org.osgl.exception.NotAppliedException;
import java.io.IOException;
import java.io.InvalidObjectException;
import java.io.ObjectInputStream;
import java.io.Serializable;
import java.util.Comparator;
import java.util.Iterator;
/**
* Implement {@link C.Range} using {@link LazySeq}.
*/
public class LazyRange extends LazySeq
implements C.Range, Serializable {
private final ELEMENT to;
private final Comparator order;
private final $.Func2 step;
protected final int ordering;
private final int size;
protected final $.F1 next;
protected final $.F1 prev;
public LazyRange(final ELEMENT from, final ELEMENT to, final $.Func2 step) {
this(from, to, $.F.NATURAL_ORDER, step);
}
public LazyRange(final ELEMENT from, final ELEMENT to, final Comparator order,
final $.Func2 step
) {
E.NPE(from, to, order, step);
ordering = N.sign(order.compare(from, to));
boolean eq = $.eq(from, to);
E.invalidArgIf(eq, "[from] shall not be equals to [to]");
// check if step align with order
ELEMENT next = step.apply(from, -ordering);
int ordering2 = order.compare(from, next);
if (N.sign(ordering2) != N.sign(ordering)) {
E.invalidArg("step function doesn't align to the direction between [from] and [to]");
}
// find out the size of the range
if (from instanceof Number) {
int n0 = ((Number)from).intValue();
int n1 = ((Number)to).intValue();
int n2 = ((Number)next).intValue();
int distance = n1 - n0;
int unit = n2 - n0;
int mod = distance%unit;
if (mod > 0) {
size = (distance + mod) / unit - 1;
} else {
size = distance / unit;
}
} else {
size = -1;
}
this.to = to;
this.head = from;
this.order = order;
this.step = step;
$.F2 f2 = $.f2(step());
this.next = f2.curry(-ordering);
this.prev = f2.curry(ordering);
this.tail = new $.F0>() {
@Override
public C.Sequence apply() throws NotAppliedException, $.Break {
if ($.eq(from, to)) {
return Nil.seq();
} else {
return of(LazyRange.this.next.apply(from), to);
}
}
};
this.setFeature(C.Feature.LIMITED);
}
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (obj instanceof C.Range) {
C.Range that = (C.Range) obj;
return $.eq(that.from(), from()) && $.eq(that.to(), to()) && $.eq(that.order(), order()) && $.eq(that.step(), step());
}
return false;
}
@Override
public int hashCode() {
return $.hc(from(), to(), order(), step());
}
@Override
public String toString() {
return new StringBuilder("[").append(from()).append(",").append(to()).append(")").toString();
}
@Override
public int size() throws UnsupportedOperationException {
if (size < 0) {
throw new UnsupportedOperationException();
} else {
return size;
}
}
protected LazyRange of(ELEMENT from, ELEMENT to) {
return new LazyRange(from, to, order, step);
}
public final ELEMENT from() {
return head();
}
@Override
public final ELEMENT to() {
return to;
}
@Override
public Comparator order() {
return order;
}
@Override
public $.Func2 step() {
return step;
}
@Override
public C.Range merge(C.Range r2) throws InvalidArgException {
if ($.ne(step(), r2.step()) || $.ne(order(), r2.order())) {
throw E.invalidArg("r2 and this range does not have the same step or order operator");
}
int ordering2 = N.sign(order.compare(r2.from(), r2.to()));
if (ordering2 != ordering) {
throw E.invalidArg("r2 and this range doesn't have the same ordering direction");
}
ELEMENT from1 = from(), to1 = step().apply(to, -1), from2 = r2.from(), to2 = r2.step().apply(r2.to(), -1);
boolean fromInThis = contains(from2), toInThis = contains(to2);
if (fromInThis && toInThis) {
return this;
}
boolean fromInThat = r2.contains(from1), toInThat = r2.contains(to1);
if (fromInThat && toInThat) {
return r2;
}
if ((fromInThis && toInThat) || ($.eq(to(), from2))) {
return of(from1, r2.to());
}
if ((toInThis && fromInThat) || ($.eq(from1, r2.to()))) {
return of(from2, to);
}
throw E.invalidArg("r2 and this range cannot be merged together");
}
@Override
public ELEMENT last() throws UnsupportedOperationException {
return prev.apply(to);
}
@Override
public C.Range tail() throws UnsupportedOperationException {
ELEMENT from = next.apply(from());
if ($.eq(from, to)) {
return Nil.range();
}
return of(next.apply(from()), to);
}
@Override
public C.Range head(int n) {
return take(n);
}
@Override
public C.Range tail(int n) throws UnsupportedOperationException {
E.illegalArgumentIf(n <= 0, "n must be a positive int");
return of(step().apply(to, -n), to);
}
@Override
public C.Range take(int n) {
E.invalidArgIf(n <= 0, "n must be a positive int");
ELEMENT from = from();
return of(from, step().apply(from, n));
}
@Override
public C.Range drop(int n) {
E.invalidArgIf(n <= 0, "n must be a positive int");
ELEMENT from = from();
return of(step().apply(from, n), to);
}
@Override
public C.Range reverse() throws UnsupportedOperationException {
return of(prev.apply(to), prev.apply(from()));
}
@Override
public Iterator reverseIterator() {
return reverse().iterator();
}
@Override
public R reduceRight(R identity, $.Func2 accumulator) {
return reverse().reduceLeft(identity, accumulator);
}
@Override
public LazyRange accept($.Visitor super ELEMENT> visitor) {
super.accept(visitor);
return this;
}
@Override
public LazyRange forEach($.Visitor super ELEMENT> visitor) {
return accept(visitor);
}
@Override
public LazyRange each($.Visitor super ELEMENT> visitor) {
return accept(visitor);
}
@Override
public LazyRange acceptLeft($.Visitor super ELEMENT> visitor) {
super.acceptLeft(visitor);
return this;
}
@Override
public LazyRange acceptRight($.Visitor super ELEMENT> visitor) {
reverse().acceptLeft(visitor);
return this;
}
@Override
public $.Option reduceRight($.Func2 accumulator) {
return reverse().reduceLeft(accumulator);
}
@Override
public $.Option findLast($.Function super ELEMENT, Boolean> predicate) {
return reverse().findFirst(predicate);
}
@Override
public boolean contains(ELEMENT t) {
E.NPE(t);
if (0 == ordering) {
return $.eq(to, t);
}
ELEMENT from = from();
if ($.eq(from, t)) {
return true;
}
int withFrom = order.compare(t, from);
if (ordering < 0 && withFrom < 0) {
return false;
}
int withTo = order.compare(t, to);
return withFrom * withTo < 0;
}
@Override
public boolean containsAll(C.Range range) {
E.NPE(range);
return contains(range.from()) && contains(prev.apply(range.to()));
}
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
throw new InvalidObjectException("Proxy required");
}
private static class SerializationProxy implements Serializable {
ELEMENT from;
ELEMENT to;
Comparator order;
$.Func2 step;
SerializationProxy(LazyRange r) {
from = r.from();
to = r.to();
order = r.order;
step = r.step;
}
private Object readResolve() {
return new LazyRange(from, to, order, step);
}
private static final long serialVersionUID = 21864874113505L;
}
private Object writeReplace() {
return new SerializationProxy(this);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy