/**
* Copyright (C) 2013 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.engine.depgraph.ambiguity;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import com.google.common.collect.ImmutableSet;
import com.opengamma.engine.value.ValueRequirement;
/**
* Cache of visited requirement, to detect recursion, and of resolved requirements to reduce the workload.
* <p>
* This is only for use by a single thread.
*/
/* package */class CheckingCache {
private static final class VisitedKey {
private final Object _key;
private ValueRequirement _requirement;
public VisitedKey() {
_key = new Object();
}
public VisitedKey(final ValueRequirement requirement) {
_key = new Object();
_requirement = requirement;
}
private VisitedKey(final VisitedKey copyFrom) {
_key = copyFrom._key;
_requirement = copyFrom._requirement;
}
public void setRequirement(final ValueRequirement requirement) {
_requirement = requirement;
}
@Override
public boolean equals(final Object o) {
if (o == this) {
return false;
}
final VisitedKey other = (VisitedKey) o;
if (other._key != _key) {
return false;
}
return _requirement.equals(other._requirement);
}
@Override
public int hashCode() {
return _key.hashCode() ^ _requirement.hashCode();
}
@Override
public VisitedKey clone() {
return new VisitedKey(this);
}
}
private final Set<ValueRequirement> _visited = new HashSet<ValueRequirement>();
private final Map<Set<ValueRequirement>, VisitedKey> _visitedKey;
private final ConcurrentMap<VisitedKey, FullRequirementResolution> _cache;
private final VisitedKey _greedyCacheKey;
@SuppressWarnings("unchecked")
public CheckingCache(final boolean greedyCaching, final ConcurrentMap<?, FullRequirementResolution> cache) {
_visitedKey = greedyCaching ? null : new HashMap<Set<ValueRequirement>, VisitedKey>();
_cache = (cache != null) ? (ConcurrentMap<VisitedKey, FullRequirementResolution>) cache : new ConcurrentHashMap<VisitedKey, FullRequirementResolution>();
_greedyCacheKey = greedyCaching ? new VisitedKey() : null;
}
public boolean begin(final ValueRequirement requirement) {
return _visited.add(requirement);
}
public void end(final ValueRequirement requirement) {
_visited.remove(requirement);
}
private VisitedKey getVisitedKey(final ValueRequirement requirement) {
if (_greedyCacheKey != null) {
_greedyCacheKey.setRequirement(requirement);
return _greedyCacheKey;
}
VisitedKey key = _visitedKey.get(_visited);
if (key != null) {
key.setRequirement(requirement);
} else {
key = new VisitedKey(requirement);
_visitedKey.put(ImmutableSet.copyOf(_visited), key);
}
return key;
}
public FullRequirementResolution get(final ValueRequirement requirement) {
return _cache.get(getVisitedKey(requirement));
}
public FullRequirementResolution put(final FullRequirementResolution resolved) {
final FullRequirementResolution existing = _cache.putIfAbsent(getVisitedKey(resolved.getRequirement()).clone(), resolved);
return (existing != null) ? existing : resolved;
}
}