package tc.oc.commons.core.collection; import java.util.HashMap; import java.util.Map; import javax.annotation.Nullable; import com.google.common.collect.ForwardingMap; import java.time.Duration; import java.time.Instant; import tc.oc.time.Clock; import tc.oc.commons.core.util.Comparables; /** * A general purpose map of {@link K} -> {@link Instant} that knows * the current time through a provided {@link Clock}, and provides * some extra time-related methods. */ public class InstantMap<K> extends ForwardingMap<K, Instant> implements MapHelper<K, Instant> { private final @Nullable Clock clock; private final Map<K, Instant> map; public InstantMap(Clock clock, Map<K, Instant> map) { this.clock = clock; this.map = map; } public InstantMap(Clock clock) { this(clock, new HashMap<>()); } @Override protected Map<K, Instant> delegate() { return map; } /** * Set the given key to the current time, and return the previous time, if any. */ public @Nullable Instant put(K key) { return put(key, clock.instant()); } /** * Set key to given time unless current value is after given time * * @return null if key was changed, otherwise current value for key */ public @Nullable Instant putUnlessAfter(K key, Instant time) { final Instant then = get(key); if(then == null || !then.isAfter(time)) { put(key, time); return null; } return then; } /** * Set key to now unless current value is newer than given age * * @return null if key was changed, otherwise current value for key */ public @Nullable Instant putUnlessNewer(K key, Duration age) { final Instant then = get(key), now = clock.instant(); // Don't do arithmetic on age, because it may overflow if(then == null || Comparables.greaterOrEqual(Duration.between(then, now), age)) { put(key, now); return null; } return then; } }