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; | |
36 | 34 |
37 /** | 35 /** |
38 * Implements the lite version of map entry messages. | 36 * Implements the lite version of map entry messages. |
39 * | 37 * |
40 * This class serves as an utility class to help do serialization/parsing of | 38 * This class serves as an utility class to help do serialization/parsing of |
41 * map entries. It's used in generated code and also in the full version | 39 * map entries. It's used in generated code and also in the full version |
42 * MapEntry message. | 40 * MapEntry message. |
43 * | 41 * |
44 * Protobuf internal. Users shouldn't use. | 42 * Protobuf internal. Users shouldn't use. |
45 */ | 43 */ |
46 public class MapEntryLite<K, V> { | 44 public class MapEntryLite<K, V> |
47 | 45 extends AbstractMessageLite<MapEntryLite<K, V>, MapEntryLite.Builder<K, V>>
{ |
48 static class Metadata<K, V> { | 46 private static class Metadata<K, V> { |
| 47 public final MapEntryLite<K, V> defaultInstance; |
49 public final WireFormat.FieldType keyType; | 48 public final WireFormat.FieldType keyType; |
50 public final K defaultKey; | |
51 public final WireFormat.FieldType valueType; | 49 public final WireFormat.FieldType valueType; |
52 public final V defaultValue; | 50 public final Parser<MapEntryLite<K, V>> parser; |
53 | |
54 public Metadata( | 51 public Metadata( |
55 WireFormat.FieldType keyType, K defaultKey, | 52 MapEntryLite<K, V> defaultInstance, |
56 WireFormat.FieldType valueType, V defaultValue) { | 53 WireFormat.FieldType keyType, |
| 54 WireFormat.FieldType valueType) { |
| 55 this.defaultInstance = defaultInstance; |
57 this.keyType = keyType; | 56 this.keyType = keyType; |
58 this.defaultKey = defaultKey; | |
59 this.valueType = valueType; | 57 this.valueType = valueType; |
60 this.defaultValue = defaultValue; | 58 final Metadata<K, V> finalThis = this; |
| 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 }; |
61 } | 67 } |
62 } | 68 } |
63 | 69 |
64 private static final int KEY_FIELD_NUMBER = 1; | 70 private static final int KEY_FIELD_NUMBER = 1; |
65 private static final int VALUE_FIELD_NUMBER = 2; | 71 private static final int VALUE_FIELD_NUMBER = 2; |
66 | 72 |
67 private final Metadata<K, V> metadata; | 73 private final Metadata<K, V> metadata; |
68 private final K key; | 74 private final K key; |
69 private final V value; | 75 private final V value; |
70 | 76 |
71 /** Creates a default MapEntryLite message instance. */ | 77 /** Creates a default MapEntryLite message instance. */ |
72 private MapEntryLite( | 78 private MapEntryLite( |
73 WireFormat.FieldType keyType, K defaultKey, | 79 WireFormat.FieldType keyType, K defaultKey, |
74 WireFormat.FieldType valueType, V defaultValue) { | 80 WireFormat.FieldType valueType, V defaultValue) { |
75 this.metadata = new Metadata<K, V>(keyType, defaultKey, valueType, defaultVa
lue); | 81 this.metadata = new Metadata<K, V>(this, keyType, valueType); |
76 this.key = defaultKey; | 82 this.key = defaultKey; |
77 this.value = defaultValue; | 83 this.value = defaultValue; |
78 } | 84 } |
79 | 85 |
80 /** Creates a new MapEntryLite message. */ | 86 /** Creates a new MapEntryLite message. */ |
81 private MapEntryLite(Metadata<K, V> metadata, K key, V value) { | 87 private MapEntryLite(Metadata<K, V> metadata, K key, V value) { |
82 this.metadata = metadata; | 88 this.metadata = metadata; |
83 this.key = key; | 89 this.key = key; |
84 this.value = value; | 90 this.value = value; |
85 } | 91 } |
86 | 92 |
87 public K getKey() { | 93 public K getKey() { |
88 return key; | 94 return key; |
89 } | 95 } |
90 | 96 |
91 public V getValue() { | 97 public V getValue() { |
92 return value; | 98 return value; |
93 } | 99 } |
94 | 100 |
95 /** | 101 /** |
96 * Creates a default MapEntryLite message instance. | 102 * Creates a default MapEntryLite message instance. |
97 * | 103 * |
98 * This method is used by generated code to create the default instance for | 104 * This method is used by generated code to create the default instance for |
99 * a map entry message. The created default instance should be used to create | 105 * a map entry message. The created default instance should be used to create |
100 * new map entry messages of the same type. For each map entry message, only | 106 * new map entry messages of the same type. For each map entry message, only |
101 * one default instance should be created. | 107 * one default instance should be created. |
102 */ | 108 */ |
103 public static <K, V> MapEntryLite<K, V> newDefaultInstance( | 109 public static <K, V> MapEntryLite<K, V> newDefaultInstance( |
104 WireFormat.FieldType keyType, K defaultKey, | 110 WireFormat.FieldType keyType, K defaultKey, |
105 WireFormat.FieldType valueType, V defaultValue) { | 111 WireFormat.FieldType valueType, V defaultValue) { |
106 return new MapEntryLite<K, V>( | 112 return new MapEntryLite<K, V>( |
107 keyType, defaultKey, valueType, defaultValue); | 113 keyType, defaultKey, valueType, defaultValue); |
108 } | 114 } |
109 | 115 |
110 static <K, V> void writeTo(CodedOutputStream output, Metadata<K, V> metadata,
K key, V value) | 116 @Override |
111 throws IOException { | 117 public void writeTo(CodedOutputStream output) throws IOException { |
112 FieldSet.writeElement(output, metadata.keyType, KEY_FIELD_NUMBER, key); | 118 writeField(KEY_FIELD_NUMBER, metadata.keyType, key, output); |
113 FieldSet.writeElement(output, metadata.valueType, VALUE_FIELD_NUMBER, value)
; | 119 writeField(VALUE_FIELD_NUMBER, metadata.valueType, value, output); |
114 } | 120 } |
115 | 121 |
116 static <K, V> int computeSerializedSize(Metadata<K, V> metadata, K key, V valu
e) { | 122 private void writeField( |
117 return FieldSet.computeElementSize(metadata.keyType, KEY_FIELD_NUMBER, key) | 123 int number, WireFormat.FieldType type, Object value, |
118 + FieldSet.computeElementSize(metadata.valueType, VALUE_FIELD_NUMBER, va
lue); | 124 CodedOutputStream output) throws IOException { |
| 125 output.writeTag(number, type.getWireType()); |
| 126 FieldSet.writeElementNoTag(output, type, value); |
119 } | 127 } |
120 | 128 |
| 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 |
121 @SuppressWarnings("unchecked") | 187 @SuppressWarnings("unchecked") |
122 static <T> T parseField( | 188 private <T> T mergeField( |
123 CodedInputStream input, ExtensionRegistryLite extensionRegistry, | 189 CodedInputStream input, ExtensionRegistryLite extensionRegistry, |
124 WireFormat.FieldType type, T value) throws IOException { | 190 WireFormat.FieldType type, T value) throws IOException { |
125 switch (type) { | 191 switch (type) { |
126 case MESSAGE: | 192 case MESSAGE: |
127 MessageLite.Builder subBuilder = ((MessageLite) value).toBuilder(); | 193 MessageLite.Builder subBuilder = ((MessageLite) value).toBuilder(); |
128 input.readMessage(subBuilder, extensionRegistry); | 194 input.readMessage(subBuilder, extensionRegistry); |
129 return (T) subBuilder.buildPartial(); | 195 return (T) subBuilder.buildPartial(); |
130 case ENUM: | 196 case ENUM: |
131 return (T) (java.lang.Integer) input.readEnum(); | 197 return (T) (java.lang.Integer) input.readEnum(); |
132 case GROUP: | 198 case GROUP: |
133 throw new RuntimeException("Groups are not allowed in maps."); | 199 throw new RuntimeException("Groups are not allowed in maps."); |
134 default: | 200 default: |
135 return (T) FieldSet.readPrimitiveField(input, type, true); | 201 return (T) FieldSet.readPrimitiveField(input, type, true); |
136 } | 202 } |
137 } | 203 } |
138 | 204 |
139 /** | 205 @Override |
140 * Serializes the provided key and value as though they were wrapped by a {@li
nk MapEntryLite} | 206 public Parser<MapEntryLite<K, V>> getParserForType() { |
141 * to the output stream. This helper method avoids allocation of a {@link MapE
ntryLite} | 207 return metadata.parser; |
142 * built with a key and value and is called from generated code directly. | 208 } |
143 */ | 209 |
144 public void serializeTo(CodedOutputStream output, int fieldNumber, K key, V va
lue) | 210 @Override |
145 throws IOException { | 211 public Builder<K, V> newBuilderForType() { |
146 output.writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED); | 212 return new Builder<K, V>(metadata); |
147 output.writeUInt32NoTag(computeSerializedSize(metadata, key, value)); | 213 } |
148 writeTo(output, metadata, key, value); | 214 |
| 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; |
149 } | 231 } |
150 | 232 |
151 /** | 233 /** |
152 * Computes the message size for the provided key and value as though they wer
e wrapped | 234 * Builder used to create {@link MapEntryLite} messages. |
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. | |
155 */ | 235 */ |
156 public int computeMessageSize(int fieldNumber, K key, V value) { | 236 public static class Builder<K, V> |
157 return CodedOutputStream.computeTagSize(fieldNumber) | 237 extends AbstractMessageLite.Builder<MapEntryLite<K, V>, Builder<K, V>> { |
158 + CodedOutputStream.computeLengthDelimitedFieldSize( | 238 private final Metadata<K, V> metadata; |
159 computeSerializedSize(metadata, key, value)); | 239 private K key; |
160 } | 240 private V value; |
161 | 241 |
162 /** | 242 private Builder(Metadata<K, V> metadata) { |
163 * Parses an entry off of the input as a {@link Map.Entry}. This helper requir
es an allocation | 243 this.metadata = metadata; |
164 * so using {@link #parseInto} is preferred if possible. | 244 this.key = metadata.defaultInstance.key; |
165 */ | 245 this.value = metadata.defaultInstance.value; |
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 } | |
190 } | 246 } |
191 return new AbstractMap.SimpleImmutableEntry<K, V>(key, value); | 247 |
192 } | 248 public K getKey() { |
193 | 249 return key; |
194 /** | 250 } |
195 * Parses an entry off of the input into the map. This helper avoids allocaton
of a | 251 |
196 * {@link MapEntryLite} by parsing directly into the provided {@link MapFieldL
ite}. | 252 public V getValue() { |
197 */ | 253 return value; |
198 public void parseInto( | 254 } |
199 MapFieldLite<K, V> map, CodedInputStream input, ExtensionRegistryLite exte
nsionRegistry) | 255 |
200 throws IOException { | 256 public Builder<K, V> setKey(K key) { |
201 int length = input.readRawVarint32(); | 257 this.key = key; |
202 final int oldLimit = input.pushLimit(length); | 258 return this; |
203 K key = metadata.defaultKey; | 259 } |
204 V value = metadata.defaultValue; | 260 |
205 | 261 public Builder<K, V> setValue(V value) { |
206 while (true) { | 262 this.value = value; |
207 int tag = input.readTag(); | 263 return this; |
208 if (tag == 0) { | 264 } |
209 break; | 265 |
210 } | 266 public Builder<K, V> clearKey() { |
211 if (tag == WireFormat.makeTag(KEY_FIELD_NUMBER, metadata.keyType.getWireTy
pe())) { | 267 this.key = metadata.defaultInstance.key; |
212 key = parseField(input, extensionRegistry, metadata.keyType, key); | 268 return this; |
213 } else if (tag == WireFormat.makeTag(VALUE_FIELD_NUMBER, metadata.valueTyp
e.getWireType())) { | 269 } |
214 value = parseField(input, extensionRegistry, metadata.valueType, value); | 270 |
215 } else { | 271 public Builder<K, V> clearValue() { |
216 if (!input.skipField(tag)) { | 272 this.value = metadata.defaultInstance.value; |
217 break; | 273 return this; |
218 } | |
219 } | |
220 } | 274 } |
221 | 275 |
222 input.checkLastTagWas(0); | 276 @Override |
223 input.popLimit(oldLimit); | 277 public Builder<K, V> clear() { |
224 map.put(key, value); | 278 this.key = metadata.defaultInstance.key; |
| 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 } |
225 } | 336 } |
226 } | 337 } |
OLD | NEW |