OLD | NEW |
1 // Protocol Buffers - Google's data interchange format | 1 // Protocol Buffers - Google's data interchange format |
2 // Copyright 2008 Google Inc. All rights reserved. | 2 // Copyright 2008 Google Inc. All rights reserved. |
3 // https://developers.google.com/protocol-buffers/ | 3 // https://developers.google.com/protocol-buffers/ |
4 // | 4 // |
5 // Redistribution and use in source and binary forms, with or without | 5 // Redistribution and use in source and binary forms, with or without |
6 // modification, are permitted provided that the following conditions are | 6 // modification, are permitted provided that the following conditions are |
7 // met: | 7 // met: |
8 // | 8 // |
9 // * Redistributions of source code must retain the above copyright | 9 // * Redistributions of source code must retain the above copyright |
10 // notice, this list of conditions and the following disclaimer. | 10 // notice, this list of conditions and the following disclaimer. |
(...skipping 13 matching lines...) Expand all Loading... |
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
30 | 30 |
31 package com.google.protobuf; | 31 package com.google.protobuf; |
32 | 32 |
33 import java.io.IOException; | 33 import java.io.IOException; |
| 34 import java.util.AbstractMap; |
| 35 import java.util.Map; |
34 | 36 |
35 /** | 37 /** |
36 * Implements the lite version of map entry messages. | 38 * Implements the lite version of map entry messages. |
37 * | 39 * |
38 * This class serves as an utility class to help do serialization/parsing of | 40 * This class serves as an utility class to help do serialization/parsing of |
39 * map entries. It's used in generated code and also in the full version | 41 * map entries. It's used in generated code and also in the full version |
40 * MapEntry message. | 42 * MapEntry message. |
41 * | 43 * |
42 * Protobuf internal. Users shouldn't use. | 44 * Protobuf internal. Users shouldn't use. |
43 */ | 45 */ |
44 public class MapEntryLite<K, V> | 46 public class MapEntryLite<K, V> { |
45 extends AbstractMessageLite<MapEntryLite<K, V>, MapEntryLite.Builder<K, V>>
{ | 47 |
46 private static class Metadata<K, V> { | 48 static class Metadata<K, V> { |
47 public final MapEntryLite<K, V> defaultInstance; | |
48 public final WireFormat.FieldType keyType; | 49 public final WireFormat.FieldType keyType; |
| 50 public final K defaultKey; |
49 public final WireFormat.FieldType valueType; | 51 public final WireFormat.FieldType valueType; |
50 public final Parser<MapEntryLite<K, V>> parser; | 52 public final V defaultValue; |
| 53 |
51 public Metadata( | 54 public Metadata( |
52 MapEntryLite<K, V> defaultInstance, | 55 WireFormat.FieldType keyType, K defaultKey, |
53 WireFormat.FieldType keyType, | 56 WireFormat.FieldType valueType, V defaultValue) { |
54 WireFormat.FieldType valueType) { | |
55 this.defaultInstance = defaultInstance; | |
56 this.keyType = keyType; | 57 this.keyType = keyType; |
| 58 this.defaultKey = defaultKey; |
57 this.valueType = valueType; | 59 this.valueType = valueType; |
58 final Metadata<K, V> finalThis = this; | 60 this.defaultValue = defaultValue; |
59 this.parser = new AbstractParser<MapEntryLite<K, V>>() { | |
60 @Override | |
61 public MapEntryLite<K, V> parsePartialFrom( | |
62 CodedInputStream input, ExtensionRegistryLite extensionRegistry) | |
63 throws InvalidProtocolBufferException { | |
64 return new MapEntryLite<K, V>(finalThis, input, extensionRegistry); | |
65 } | |
66 }; | |
67 } | 61 } |
68 } | 62 } |
69 | 63 |
70 private static final int KEY_FIELD_NUMBER = 1; | 64 private static final int KEY_FIELD_NUMBER = 1; |
71 private static final int VALUE_FIELD_NUMBER = 2; | 65 private static final int VALUE_FIELD_NUMBER = 2; |
72 | 66 |
73 private final Metadata<K, V> metadata; | 67 private final Metadata<K, V> metadata; |
74 private final K key; | 68 private final K key; |
75 private final V value; | 69 private final V value; |
76 | 70 |
77 /** Creates a default MapEntryLite message instance. */ | 71 /** Creates a default MapEntryLite message instance. */ |
78 private MapEntryLite( | 72 private MapEntryLite( |
79 WireFormat.FieldType keyType, K defaultKey, | 73 WireFormat.FieldType keyType, K defaultKey, |
80 WireFormat.FieldType valueType, V defaultValue) { | 74 WireFormat.FieldType valueType, V defaultValue) { |
81 this.metadata = new Metadata<K, V>(this, keyType, valueType); | 75 this.metadata = new Metadata<K, V>(keyType, defaultKey, valueType, defaultVa
lue); |
82 this.key = defaultKey; | 76 this.key = defaultKey; |
83 this.value = defaultValue; | 77 this.value = defaultValue; |
84 } | 78 } |
85 | 79 |
86 /** Creates a new MapEntryLite message. */ | 80 /** Creates a new MapEntryLite message. */ |
87 private MapEntryLite(Metadata<K, V> metadata, K key, V value) { | 81 private MapEntryLite(Metadata<K, V> metadata, K key, V value) { |
88 this.metadata = metadata; | 82 this.metadata = metadata; |
89 this.key = key; | 83 this.key = key; |
90 this.value = value; | 84 this.value = value; |
91 } | 85 } |
92 | 86 |
93 public K getKey() { | 87 public K getKey() { |
94 return key; | 88 return key; |
95 } | 89 } |
96 | 90 |
97 public V getValue() { | 91 public V getValue() { |
98 return value; | 92 return value; |
99 } | 93 } |
100 | 94 |
101 /** | 95 /** |
102 * Creates a default MapEntryLite message instance. | 96 * Creates a default MapEntryLite message instance. |
103 * | 97 * |
104 * This method is used by generated code to create the default instance for | 98 * This method is used by generated code to create the default instance for |
105 * a map entry message. The created default instance should be used to create | 99 * a map entry message. The created default instance should be used to create |
106 * new map entry messages of the same type. For each map entry message, only | 100 * new map entry messages of the same type. For each map entry message, only |
107 * one default instance should be created. | 101 * one default instance should be created. |
108 */ | 102 */ |
109 public static <K, V> MapEntryLite<K, V> newDefaultInstance( | 103 public static <K, V> MapEntryLite<K, V> newDefaultInstance( |
110 WireFormat.FieldType keyType, K defaultKey, | 104 WireFormat.FieldType keyType, K defaultKey, |
111 WireFormat.FieldType valueType, V defaultValue) { | 105 WireFormat.FieldType valueType, V defaultValue) { |
112 return new MapEntryLite<K, V>( | 106 return new MapEntryLite<K, V>( |
113 keyType, defaultKey, valueType, defaultValue); | 107 keyType, defaultKey, valueType, defaultValue); |
114 } | 108 } |
115 | 109 |
116 @Override | 110 static <K, V> void writeTo(CodedOutputStream output, Metadata<K, V> metadata,
K key, V value) |
117 public void writeTo(CodedOutputStream output) throws IOException { | 111 throws IOException { |
118 writeField(KEY_FIELD_NUMBER, metadata.keyType, key, output); | 112 FieldSet.writeElement(output, metadata.keyType, KEY_FIELD_NUMBER, key); |
119 writeField(VALUE_FIELD_NUMBER, metadata.valueType, value, output); | 113 FieldSet.writeElement(output, metadata.valueType, VALUE_FIELD_NUMBER, value)
; |
120 } | 114 } |
121 | 115 |
122 private void writeField( | 116 static <K, V> int computeSerializedSize(Metadata<K, V> metadata, K key, V valu
e) { |
123 int number, WireFormat.FieldType type, Object value, | 117 return FieldSet.computeElementSize(metadata.keyType, KEY_FIELD_NUMBER, key) |
124 CodedOutputStream output) throws IOException { | 118 + FieldSet.computeElementSize(metadata.valueType, VALUE_FIELD_NUMBER, va
lue); |
125 output.writeTag(number, type.getWireType()); | |
126 FieldSet.writeElementNoTag(output, type, value); | |
127 } | 119 } |
128 | 120 |
129 private volatile int cachedSerializedSize = -1; | |
130 @Override | |
131 public int getSerializedSize() { | |
132 if (cachedSerializedSize != -1) { | |
133 return cachedSerializedSize; | |
134 } | |
135 int size = 0; | |
136 size += getFieldSize(KEY_FIELD_NUMBER, metadata.keyType, key); | |
137 size += getFieldSize(VALUE_FIELD_NUMBER, metadata.valueType, value); | |
138 cachedSerializedSize = size; | |
139 return size; | |
140 } | |
141 | |
142 private int getFieldSize( | |
143 int number, WireFormat.FieldType type, Object value) { | |
144 return CodedOutputStream.computeTagSize(number) | |
145 + FieldSet.computeElementSizeNoTag(type, value); | |
146 } | |
147 | |
148 /** Parsing constructor. */ | |
149 private MapEntryLite( | |
150 Metadata<K, V> metadata, | |
151 CodedInputStream input, | |
152 ExtensionRegistryLite extensionRegistry) | |
153 throws InvalidProtocolBufferException { | |
154 try { | |
155 K key = metadata.defaultInstance.key; | |
156 V value = metadata.defaultInstance.value; | |
157 while (true) { | |
158 int tag = input.readTag(); | |
159 if (tag == 0) { | |
160 break; | |
161 } | |
162 if (tag == WireFormat.makeTag( | |
163 KEY_FIELD_NUMBER, metadata.keyType.getWireType())) { | |
164 key = mergeField( | |
165 input, extensionRegistry, metadata.keyType, key); | |
166 } else if (tag == WireFormat.makeTag( | |
167 VALUE_FIELD_NUMBER, metadata.valueType.getWireType())) { | |
168 value = mergeField( | |
169 input, extensionRegistry, metadata.valueType, value); | |
170 } else { | |
171 if (!input.skipField(tag)) { | |
172 break; | |
173 } | |
174 } | |
175 } | |
176 this.metadata = metadata; | |
177 this.key = key; | |
178 this.value = value; | |
179 } catch (InvalidProtocolBufferException e) { | |
180 throw e.setUnfinishedMessage(this); | |
181 } catch (IOException e) { | |
182 throw new InvalidProtocolBufferException(e.getMessage()) | |
183 .setUnfinishedMessage(this); | |
184 } | |
185 } | |
186 | |
187 @SuppressWarnings("unchecked") | 121 @SuppressWarnings("unchecked") |
188 private <T> T mergeField( | 122 static <T> T parseField( |
189 CodedInputStream input, ExtensionRegistryLite extensionRegistry, | 123 CodedInputStream input, ExtensionRegistryLite extensionRegistry, |
190 WireFormat.FieldType type, T value) throws IOException { | 124 WireFormat.FieldType type, T value) throws IOException { |
191 switch (type) { | 125 switch (type) { |
192 case MESSAGE: | 126 case MESSAGE: |
193 MessageLite.Builder subBuilder = ((MessageLite) value).toBuilder(); | 127 MessageLite.Builder subBuilder = ((MessageLite) value).toBuilder(); |
194 input.readMessage(subBuilder, extensionRegistry); | 128 input.readMessage(subBuilder, extensionRegistry); |
195 return (T) subBuilder.buildPartial(); | 129 return (T) subBuilder.buildPartial(); |
196 case ENUM: | 130 case ENUM: |
197 return (T) (java.lang.Integer) input.readEnum(); | 131 return (T) (java.lang.Integer) input.readEnum(); |
198 case GROUP: | 132 case GROUP: |
199 throw new RuntimeException("Groups are not allowed in maps."); | 133 throw new RuntimeException("Groups are not allowed in maps."); |
200 default: | 134 default: |
201 return (T) FieldSet.readPrimitiveField(input, type, true); | 135 return (T) FieldSet.readPrimitiveField(input, type, true); |
202 } | 136 } |
203 } | 137 } |
204 | 138 |
205 @Override | 139 /** |
206 public Parser<MapEntryLite<K, V>> getParserForType() { | 140 * Serializes the provided key and value as though they were wrapped by a {@li
nk MapEntryLite} |
207 return metadata.parser; | 141 * to the output stream. This helper method avoids allocation of a {@link MapE
ntryLite} |
208 } | 142 * built with a key and value and is called from generated code directly. |
209 | 143 */ |
210 @Override | 144 public void serializeTo(CodedOutputStream output, int fieldNumber, K key, V va
lue) |
211 public Builder<K, V> newBuilderForType() { | 145 throws IOException { |
212 return new Builder<K, V>(metadata); | 146 output.writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED); |
213 } | 147 output.writeUInt32NoTag(computeSerializedSize(metadata, key, value)); |
214 | 148 writeTo(output, metadata, key, value); |
215 @Override | |
216 public Builder<K, V> toBuilder() { | |
217 return new Builder<K, V>(metadata, key, value); | |
218 } | |
219 | |
220 @Override | |
221 public MapEntryLite<K, V> getDefaultInstanceForType() { | |
222 return metadata.defaultInstance; | |
223 } | |
224 | |
225 @Override | |
226 public boolean isInitialized() { | |
227 if (metadata.valueType.getJavaType() == WireFormat.JavaType.MESSAGE) { | |
228 return ((MessageLite) value).isInitialized(); | |
229 } | |
230 return true; | |
231 } | 149 } |
232 | 150 |
233 /** | 151 /** |
234 * Builder used to create {@link MapEntryLite} messages. | 152 * Computes the message size for the provided key and value as though they wer
e wrapped |
| 153 * by a {@link MapEntryLite}. This helper method avoids allocation of a {@link
MapEntryLite} |
| 154 * built with a key and value and is called from generated code directly. |
235 */ | 155 */ |
236 public static class Builder<K, V> | 156 public int computeMessageSize(int fieldNumber, K key, V value) { |
237 extends AbstractMessageLite.Builder<MapEntryLite<K, V>, Builder<K, V>> { | 157 return CodedOutputStream.computeTagSize(fieldNumber) |
238 private final Metadata<K, V> metadata; | 158 + CodedOutputStream.computeLengthDelimitedFieldSize( |
239 private K key; | 159 computeSerializedSize(metadata, key, value)); |
240 private V value; | 160 } |
241 | 161 |
242 private Builder(Metadata<K, V> metadata) { | 162 /** |
243 this.metadata = metadata; | 163 * Parses an entry off of the input as a {@link Map.Entry}. This helper requir
es an allocation |
244 this.key = metadata.defaultInstance.key; | 164 * so using {@link #parseInto} is preferred if possible. |
245 this.value = metadata.defaultInstance.value; | 165 */ |
| 166 public Map.Entry<K, V> parseEntry(ByteString bytes, ExtensionRegistryLite exte
nsionRegistry) |
| 167 throws IOException { |
| 168 return parseEntry(bytes.newCodedInput(), metadata, extensionRegistry); |
| 169 } |
| 170 |
| 171 static <K, V> Map.Entry<K, V> parseEntry( |
| 172 CodedInputStream input, Metadata<K, V> metadata, ExtensionRegistryLite ext
ensionRegistry) |
| 173 throws IOException{ |
| 174 K key = metadata.defaultKey; |
| 175 V value = metadata.defaultValue; |
| 176 while (true) { |
| 177 int tag = input.readTag(); |
| 178 if (tag == 0) { |
| 179 break; |
| 180 } |
| 181 if (tag == WireFormat.makeTag(KEY_FIELD_NUMBER, metadata.keyType.getWireTy
pe())) { |
| 182 key = parseField(input, extensionRegistry, metadata.keyType, key); |
| 183 } else if (tag == WireFormat.makeTag(VALUE_FIELD_NUMBER, metadata.valueTyp
e.getWireType())) { |
| 184 value = parseField(input, extensionRegistry, metadata.valueType, value); |
| 185 } else { |
| 186 if (!input.skipField(tag)) { |
| 187 break; |
| 188 } |
| 189 } |
246 } | 190 } |
247 | 191 return new AbstractMap.SimpleImmutableEntry<K, V>(key, value); |
248 public K getKey() { | 192 } |
249 return key; | 193 |
250 } | 194 /** |
251 | 195 * Parses an entry off of the input into the map. This helper avoids allocaton
of a |
252 public V getValue() { | 196 * {@link MapEntryLite} by parsing directly into the provided {@link MapFieldL
ite}. |
253 return value; | 197 */ |
254 } | 198 public void parseInto( |
255 | 199 MapFieldLite<K, V> map, CodedInputStream input, ExtensionRegistryLite exte
nsionRegistry) |
256 public Builder<K, V> setKey(K key) { | 200 throws IOException { |
257 this.key = key; | 201 int length = input.readRawVarint32(); |
258 return this; | 202 final int oldLimit = input.pushLimit(length); |
259 } | 203 K key = metadata.defaultKey; |
260 | 204 V value = metadata.defaultValue; |
261 public Builder<K, V> setValue(V value) { | 205 |
262 this.value = value; | 206 while (true) { |
263 return this; | 207 int tag = input.readTag(); |
264 } | 208 if (tag == 0) { |
265 | 209 break; |
266 public Builder<K, V> clearKey() { | 210 } |
267 this.key = metadata.defaultInstance.key; | 211 if (tag == WireFormat.makeTag(KEY_FIELD_NUMBER, metadata.keyType.getWireTy
pe())) { |
268 return this; | 212 key = parseField(input, extensionRegistry, metadata.keyType, key); |
269 } | 213 } else if (tag == WireFormat.makeTag(VALUE_FIELD_NUMBER, metadata.valueTyp
e.getWireType())) { |
270 | 214 value = parseField(input, extensionRegistry, metadata.valueType, value); |
271 public Builder<K, V> clearValue() { | 215 } else { |
272 this.value = metadata.defaultInstance.value; | 216 if (!input.skipField(tag)) { |
273 return this; | 217 break; |
| 218 } |
| 219 } |
274 } | 220 } |
275 | 221 |
276 @Override | 222 input.checkLastTagWas(0); |
277 public Builder<K, V> clear() { | 223 input.popLimit(oldLimit); |
278 this.key = metadata.defaultInstance.key; | 224 map.put(key, value); |
279 this.value = metadata.defaultInstance.value; | |
280 return this; | |
281 } | |
282 | |
283 @Override | |
284 public MapEntryLite<K, V> build() { | |
285 MapEntryLite<K, V> result = buildPartial(); | |
286 if (!result.isInitialized()) { | |
287 throw newUninitializedMessageException(result); | |
288 } | |
289 return result; | |
290 } | |
291 | |
292 @Override | |
293 public MapEntryLite<K, V> buildPartial() { | |
294 return new MapEntryLite<K, V>(metadata, key, value); | |
295 } | |
296 | |
297 @Override | |
298 public MessageLite getDefaultInstanceForType() { | |
299 return metadata.defaultInstance; | |
300 } | |
301 | |
302 @Override | |
303 public boolean isInitialized() { | |
304 if (metadata.valueType.getJavaType() == WireFormat.JavaType.MESSAGE) { | |
305 return ((MessageLite) value).isInitialized(); | |
306 } | |
307 return true; | |
308 } | |
309 | |
310 private Builder(Metadata<K, V> metadata, K key, V value) { | |
311 this.metadata = metadata; | |
312 this.key = key; | |
313 this.value = value; | |
314 } | |
315 | |
316 @Override | |
317 public Builder<K, V> clone() { | |
318 return new Builder<K, V>(metadata, key, value); | |
319 } | |
320 | |
321 @Override | |
322 public Builder<K, V> mergeFrom( | |
323 CodedInputStream input, ExtensionRegistryLite extensionRegistry) | |
324 throws IOException { | |
325 MapEntryLite<K, V> entry = | |
326 new MapEntryLite<K, V>(metadata, input, extensionRegistry); | |
327 this.key = entry.key; | |
328 this.value = entry.value; | |
329 return this; | |
330 } | |
331 | |
332 @Override | |
333 protected Builder<K, V> internalMergeFrom(MapEntryLite<K, V> message) { | |
334 throw new UnsupportedOperationException(); | |
335 } | |
336 } | 225 } |
337 } | 226 } |
OLD | NEW |