package xapi.time.impl;
import static xapi.time.X_Time.threadStart;
import xapi.time.api.Moment;
import xapi.util.api.ReceivesValue;
public class RunOnce {
private static final Runnable NO_OP = new Runnable() {
@Override
public void run() {}
};
@SuppressWarnings("rawtypes")
private static final ReceivesValue NO_OP_RECEIVER = new ReceivesValue.NoOp();
public static Runnable runOnce(final Runnable job) {
return runOnce(job, false);
}
public static Runnable runOnce(final Runnable job, final boolean oncePerMoment) {
if (oncePerMoment) {
return new Runnable() {
RunOnce lock = new RunOnce();
@Override
public void run() {
if (lock.shouldRun(oncePerMoment)) {
job.run();
}
}
};
} else {
return new Runnable() {
Runnable once = job;
@Override
public void run() {
once.run();
once = NO_OP;
}
};
}
}
public static <X> ReceivesValue<X> setOnce(final ReceivesValue<X> job) {
return setOnce(job, false);
}
public static <X> ReceivesValue<X> setOnce(final ReceivesValue<X> job, final boolean oncePerMoment) {
if (oncePerMoment) {
return new ReceivesValue<X>() {
RunOnce lock = new RunOnce();
@Override
public void set(X from) {
if (lock.shouldRun(oncePerMoment)) {
job.set(from);
}
}
};
} else {
return new ReceivesValue<X>() {
ReceivesValue<X> once = job;
@Override
@SuppressWarnings("unchecked")
public void set(X from) {
once.set(from);
once = NO_OP_RECEIVER;
}
};
}
}
private Moment once;
public boolean shouldRun(boolean oncePerMoment) {
if (once == null) {
synchronized (this) {
if (once != null) {
return false;
}
once = threadStart();
return true;
}
} else {
if (oncePerMoment) {
//do not run more than once per tick of X_Time.
//this allows you to call this method as many times as you want,
//but only perform the heavyweight operation of synchronization once.
Moment now = threadStart();
synchronized (this) {
if (once.equals(now)){
return false;
}
once = now;
}
return true;
} else {
return false;
}
}
}
}