ReadOnlyClassToSerializerMap.java
package tools.jackson.databind.ser.impl;
import tools.jackson.databind.JavaType;
import tools.jackson.databind.ValueSerializer;
import tools.jackson.databind.ser.SerializerCache;
import tools.jackson.databind.util.LookupCache;
import tools.jackson.databind.util.TypeKey;
/**
* Optimized lookup table for accessing two types of serializers; typed
* and non-typed. Only accessed from a single thread, so no synchronization
* needed for accessors.
*/
public final class ReadOnlyClassToSerializerMap
{
/**
* Shared cache used for call-throughs in cases where we do not have local matches.
*
* @since 3.0
*/
private final SerializerCache _sharedCache;
private final Bucket[] _buckets;
private final int _size;
private final int _mask;
protected ReadOnlyClassToSerializerMap(SerializerCache shared,
LookupCache<TypeKey, ValueSerializer<Object>> src)
{
_sharedCache = shared;
_size = findSize(src.size());
_mask = (_size-1);
Bucket[] buckets = new Bucket[_size];
src.contents((key, value) -> {
int index = key.hashCode() & _mask;
buckets[index] = new Bucket(buckets[index], key, value);
});
_buckets = buckets;
}
private final static int findSize(int size)
{
// For small enough results (64 or less), we'll require <= 50% fill rate; otherwise 80%
int needed = (size <= 64) ? (size + size) : (size + (size >> 2));
int result = 8;
while (result < needed) {
result += result;
}
return result;
}
/**
* Factory method for constructing an instance.
*/
public static ReadOnlyClassToSerializerMap from(SerializerCache shared,
LookupCache<TypeKey, ValueSerializer<Object>> src) {
return new ReadOnlyClassToSerializerMap(shared, src);
}
/*
/**********************************************************************
/* Public API
/**********************************************************************
*/
public int size() { return _size; }
public ValueSerializer<Object> typedValueSerializer(JavaType type)
{
Bucket bucket = _buckets[TypeKey.typedHash(type) & _mask];
if (bucket != null) {
if (bucket.matchesTyped(type)) {
return bucket.value;
}
while ((bucket = bucket.next) != null) {
if (bucket.matchesTyped(type)) {
return bucket.value;
}
}
}
return _sharedCache.typedValueSerializer(type);
}
public ValueSerializer<Object> typedValueSerializer(Class<?> rawType)
{
Bucket bucket = _buckets[TypeKey.typedHash(rawType) & _mask];
if (bucket != null) {
if (bucket.matchesTyped(rawType)) {
return bucket.value;
}
while ((bucket = bucket.next) != null) {
if (bucket.matchesTyped(rawType)) {
return bucket.value;
}
}
}
return _sharedCache.typedValueSerializer(rawType);
}
public ValueSerializer<Object> untypedValueSerializer(JavaType type)
{
Bucket bucket = _buckets[TypeKey.untypedHash(type) & _mask];
if (bucket != null) {
if (bucket.matchesUntyped(type)) {
return bucket.value;
}
while ((bucket = bucket.next) != null) {
if (bucket.matchesUntyped(type)) {
return bucket.value;
}
}
}
return _sharedCache.untypedValueSerializer(type);
}
public ValueSerializer<Object> untypedValueSerializer(Class<?> rawType)
{
Bucket bucket = _buckets[TypeKey.untypedHash(rawType) & _mask];
if (bucket != null) {
if (bucket.matchesUntyped(rawType)) {
return bucket.value;
}
while ((bucket = bucket.next) != null) {
if (bucket.matchesUntyped(rawType)) {
return bucket.value;
}
}
}
return _sharedCache.untypedValueSerializer(rawType);
}
/*
/**********************************************************************
/* Helper classes
/**********************************************************************
*/
private final static class Bucket
{
public final ValueSerializer<Object> value;
public final Bucket next;
protected final Class<?> _class;
protected final JavaType _type;
protected final boolean _isTyped;
public Bucket(Bucket next, TypeKey key, ValueSerializer<Object> value)
{
this.next = next;
this.value = value;
_isTyped = key.isTyped();
_class = key.getRawType();
_type = key.getType();
}
public boolean matchesTyped(Class<?> key) {
return (_class == key) && _isTyped;
}
public boolean matchesUntyped(Class<?> key) {
return (_class == key) && !_isTyped;
}
public boolean matchesTyped(JavaType key) {
return _isTyped && key.equals(_type);
}
public boolean matchesUntyped(JavaType key) {
return !_isTyped && key.equals(_type);
}
}
}