/*
* Quasar: lightweight threads and actors for the JVM.
* Copyright (c) 2013-2014, Parallel Universe Software Co. All rights reserved.
*
* This program and the accompanying materials are dual-licensed under
* either the terms of the Eclipse Public License v1.0 as published by
* the Eclipse Foundation
*
* or (per the licensee's choosing)
*
* under the terms of the GNU Lesser General Public License version 3.0
* as published by the Free Software Foundation.
*/
package co.paralleluniverse.concurrent.util;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
/**
*
* @author pron
*/
public abstract class DelayedValue implements Delayed {
public static DelayedValue instance(boolean sequenced, int value, long millis) {
return sequenced ? new DelayedValue1(value, millis) : new DelayedValue2(value, millis);
}
final long time;
private final int value;
DelayedValue(int value, long millis) {
this.time = System.nanoTime() + TimeUnit.MILLISECONDS.toNanos(millis);
this.value = value;
}
public int getValue() {
return value;
}
@Override
public long getDelay(TimeUnit unit) {
return unit.convert(time - System.nanoTime(), TimeUnit.NANOSECONDS);
}
@Override
public int hashCode() {
int hash = 7;
hash = 13 * hash + (int) (this.time ^ (this.time >>> 32));
hash = 13 * hash + this.value;
return hash;
}
@Override
public boolean equals(Object obj) {
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
final DelayedValue other = (DelayedValue) obj;
if (this.time != other.time)
return false;
if (this.value != other.value)
return false;
return true;
}
@Override
public String toString() {
return "DelayedValue{" + "time=" + time + ", value=" + value + '}';
}
static class DelayedValue1 extends DelayedValue {
/**
* Sequence number to break scheduling ties, and in turn to
* guarantee FIFO order among tied entries.
*/
private static final AtomicLong sequencer = new AtomicLong();
private final long sequenceNumber;
DelayedValue1(int value, long millis) {
super(value, millis);
this.sequenceNumber = sequencer.getAndIncrement();
}
@Override
public int compareTo(Delayed other) {
if (other == this) // compare zero if same object
return 0;
if (other instanceof DelayedValue1) {
DelayedValue1 x = (DelayedValue1) other;
long diff = time - x.time;
if (diff < 0)
return -1;
else if (diff > 0)
return 1;
else if (sequenceNumber < x.sequenceNumber)
return -1;
else
return 1;
}
long diff = getDelay(TimeUnit.NANOSECONDS) - other.getDelay(TimeUnit.NANOSECONDS);
return (diff < 0) ? -1 : (diff > 0) ? 1 : 0;
}
}
static class DelayedValue2 extends DelayedValue {
public DelayedValue2(int value, long millis) {
super(value, millis);
}
@Override
public int compareTo(Delayed other) {
if (other == this) // compare zero if same object
return 0;
if (other instanceof DelayedValue2) {
DelayedValue2 x = (DelayedValue2) other;
long diff = time - x.time;
return (int) diff; // (diff < 0) ? -1 : (diff > 0) ? 1 : 0;
}
long diff = getDelay(TimeUnit.NANOSECONDS) - other.getDelay(TimeUnit.NANOSECONDS);
return (int) diff;
}
}
}