org.stringtemplate.v4.misc.TypeRegistry Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of cassandra-unit-shaded Show documentation
Show all versions of cassandra-unit-shaded Show documentation
Shaded version of cassandra-unit
/*
* [The "BSD license"]
* Copyright (c) 2012 Terence Parr
* Copyright (c) 2012 Sam Harwell
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.stringtemplate.v4.misc;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
*
* @author Sam Harwell
*/
public class TypeRegistry implements Map, V> {
private final Map, V> backingStore = new HashMap, V>();
private final Map, Class> cache = new HashMap, Class>();
public int size() {
return backingStore.size();
}
public boolean isEmpty() {
return backingStore.isEmpty();
}
public boolean containsKey(Object key) {
if (cache.containsKey(key)) {
return true;
}
if (!(key instanceof Class)) {
return false;
}
return get((Class)key) != null;
}
@SuppressWarnings("unchecked")
public boolean containsValue(Object value) {
return values().contains((V)value);
}
/**
* {@inheritDoc}
*
* @throws AmbiguousMatchException if the registry contains more than value
* mapped to a maximally-specific type from which {@code key} is derived.
*/
public V get(Object key) {
V value = backingStore.get(key);
if (value != null) {
return value;
}
Class redirect = cache.get(key);
if (redirect != null) {
if (redirect == Void.TYPE) {
return null;
}
else {
return backingStore.get(redirect);
}
}
if (!(key instanceof Class)) {
return null;
}
Class keyClass = (Class)key;
List> candidates = new ArrayList>();
for (Class clazz : backingStore.keySet()) {
if (clazz.isAssignableFrom(keyClass)) {
candidates.add(clazz);
}
}
if (candidates.isEmpty()) {
cache.put(keyClass, Void.TYPE);
return null;
}
else if (candidates.size() == 1) {
cache.put(keyClass, candidates.get(0));
return backingStore.get(candidates.get(0));
}
else {
for (int i = 0; i < candidates.size() - 1; i++) {
if (candidates.get(i) == null) {
continue;
}
for (int j = i + 1; j < candidates.size(); j++) {
if (candidates.get(i).isAssignableFrom(candidates.get(j))) {
candidates.set(i, null);
break;
}
else if (candidates.get(j).isAssignableFrom(candidates.get(i))) {
candidates.set(j, null);
}
}
}
int j = 0;
for (int i = 0; i < candidates.size(); i++) {
Class current = candidates.get(i);
if (current == null) {
continue;
}
if (i != j) {
candidates.set(j, current);
}
j++;
}
assert j > 0;
if (j != 1) {
StringBuilder builder = new StringBuilder();
builder.append(String.format("The class '%s' does not match a single item in the registry. The %d ambiguous matches are:", keyClass.getName(), j));
for (int i = 0; i < j; i++) {
builder.append(String.format("%n %s", candidates.get(j).getName()));
}
throw new AmbiguousMatchException(builder.toString());
}
cache.put(keyClass, candidates.get(0));
return backingStore.get(candidates.get(0));
}
}
public V put(Class key, V value) {
V result = get(key);
backingStore.put(key, value);
handleAlteration(key);
return result;
}
public V remove(Object key) {
if (!(key instanceof Class)) {
return null;
}
Class clazz = (Class)key;
V previous = get(clazz);
if (backingStore.remove(clazz) != null) {
handleAlteration(clazz);
}
return previous;
}
public void putAll(Map, ? extends V> m) {
for (Map.Entry, ? extends V> entry : m.entrySet()) {
put(entry.getKey(), entry.getValue());
}
}
public void clear() {
backingStore.clear();
cache.clear();
}
public Set> keySet() {
return Collections.unmodifiableSet(backingStore.keySet());
}
public Collection values() {
return Collections.unmodifiableCollection(backingStore.values());
}
public Set, V>> entrySet() {
return Collections.unmodifiableSet(backingStore.entrySet());
}
protected void handleAlteration(Class clazz) {
for (Map.Entry, ?> entry : cache.entrySet()) {
if (clazz.isAssignableFrom(entry.getKey())) {
entry.setValue(null);
}
}
}
}