1 package com.fasterxml.jackson.databind.ser.impl;
2
3 import java.util.*;
4
5 import com.fasterxml.jackson.databind.JavaType;
6 import com.fasterxml.jackson.databind.JsonSerializer;
7 import com.fasterxml.jackson.databind.util.TypeKey;
8
9 /**
10  * Optimized lookup table for accessing two types of serializers; typed
11  * and non-typed. Only accessed from a single thread, so no synchronization
12  * needed for accessors.
13  *<p>
14  * Note that before 2.6 this class was much smaller, and referred most
15  * operations to separate <code>JsonSerializerMap</code>, but in 2.6
16  * functions were combined.
17  */

18 public final class ReadOnlyClassToSerializerMap
19 {
20     private final Bucket[] _buckets;
21
22     private final int _size;
23
24     private final int _mask;
25
26     public ReadOnlyClassToSerializerMap(Map<TypeKey,JsonSerializer<Object>> serializers)
27     {
28         int size = findSize(serializers.size());
29         _size = size;
30         _mask = (size-1);
31         Bucket[] buckets = new Bucket[size];
32         for (Map.Entry<TypeKey,JsonSerializer<Object>> entry : serializers.entrySet()) {
33             TypeKey key = entry.getKey();
34             int index = key.hashCode() & _mask;
35             buckets[index] = new Bucket(buckets[index], key, entry.getValue());
36         }
37         _buckets = buckets;
38     }
39     
40     private final static int findSize(int size)
41     {
42         // For small enough results (64 or less), we'll require <= 50% fill rate; otherwise 80%
43         int needed = (size <= 64) ? (size + size) : (size + (size >> 2));
44         int result = 8;
45         while (result < needed) {
46             result += result;
47         }
48         return result;
49     }
50
51     /**
52      * Factory method for constructing an instance.
53      */

54     public static ReadOnlyClassToSerializerMap from(HashMap<TypeKey, JsonSerializer<Object>> src) {
55         return new ReadOnlyClassToSerializerMap(src);
56     }
57
58     /*
59     /**********************************************************
60     /* Public API
61     /**********************************************************
62      */

63
64     public int size() { return _size; }
65     
66     public JsonSerializer<Object> typedValueSerializer(JavaType type)
67     {
68         Bucket bucket = _buckets[TypeKey.typedHash(type) & _mask];
69         if (bucket == null) {
70             return null;
71         }
72         if (bucket.matchesTyped(type)) {
73             return bucket.value;
74         }
75         while ((bucket = bucket.next) != null) {
76             if (bucket.matchesTyped(type)) {
77                 return bucket.value;
78             }
79         }
80         return null;
81     }
82
83     public JsonSerializer<Object> typedValueSerializer(Class<?> type)
84     {
85         Bucket bucket = _buckets[TypeKey.typedHash(type) & _mask];
86         if (bucket == null) {
87             return null;
88         }
89         if (bucket.matchesTyped(type)) {
90             return bucket.value;
91         }
92         while ((bucket = bucket.next) != null) {
93             if (bucket.matchesTyped(type)) {
94                 return bucket.value;
95             }
96         }
97         return null;
98     }
99
100     public JsonSerializer<Object> untypedValueSerializer(JavaType type)
101     {
102         Bucket bucket = _buckets[TypeKey.untypedHash(type) & _mask];
103         if (bucket == null) {
104             return null;
105         }
106         if (bucket.matchesUntyped(type)) {
107             return bucket.value;
108         }
109         while ((bucket = bucket.next) != null) {
110             if (bucket.matchesUntyped(type)) {
111                 return bucket.value;
112             }
113         }
114         return null;
115     }
116
117     public JsonSerializer<Object> untypedValueSerializer(Class<?> type)
118     {
119         Bucket bucket = _buckets[TypeKey.untypedHash(type) & _mask];
120         if (bucket == null) {
121             return null;
122         }
123         if (bucket.matchesUntyped(type)) {
124             return bucket.value;
125         }
126         while ((bucket = bucket.next) != null) {
127             if (bucket.matchesUntyped(type)) {
128                 return bucket.value;
129             }
130         }
131         return null;
132     }    
133
134     /*
135     /**********************************************************
136     /* Helper classes
137     /**********************************************************
138      */

139
140     private final static class Bucket
141     {
142         public final JsonSerializer<Object> value;
143         public final Bucket next;
144
145         protected final Class<?> _class;
146         protected final JavaType _type;
147
148         protected final boolean _isTyped;
149         
150         public Bucket(Bucket next, TypeKey key, JsonSerializer<Object> value)
151         {
152             this.next = next;
153             this.value = value;
154             _isTyped = key.isTyped();
155             _class = key.getRawType();
156             _type = key.getType();
157         }
158
159         public boolean matchesTyped(Class<?> key) {
160             return (_class == key) && _isTyped;
161         }
162
163         public boolean matchesUntyped(Class<?> key) {
164             return (_class == key) && !_isTyped;
165         }
166
167         public boolean matchesTyped(JavaType key) {
168             return _isTyped && key.equals(_type);
169         }
170
171         public boolean matchesUntyped(JavaType key) {
172             return !_isTyped && key.equals(_type);
173         }
174     }
175 }
176