blob: 7cdf1b9379d1bcbdd034efbfe6d3a6b6681a5a65 [file] [log] [blame]
Brian Silverman9c614bc2016-02-15 20:20:02 -05001// Protocol Buffers - Google's data interchange format
2// Copyright 2008 Google Inc. All rights reserved.
3// https://developers.google.com/protocol-buffers/
4//
5// Redistribution and use in source and binary forms, with or without
6// modification, are permitted provided that the following conditions are
7// met:
8//
9// * Redistributions of source code must retain the above copyright
10// notice, this list of conditions and the following disclaimer.
11// * Redistributions in binary form must reproduce the above
12// copyright notice, this list of conditions and the following disclaimer
13// in the documentation and/or other materials provided with the
14// distribution.
15// * Neither the name of Google Inc. nor the names of its
16// contributors may be used to endorse or promote products derived from
17// this software without specific prior written permission.
18//
19// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
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.
30
31#ifndef GOOGLE_PROTOBUF_MAP_ENTRY_LITE_H__
32#define GOOGLE_PROTOBUF_MAP_ENTRY_LITE_H__
33
34#include <google/protobuf/map_type_handler.h>
35#include <google/protobuf/wire_format_lite_inl.h>
36
37namespace google {
38namespace protobuf {
39class Arena;
40namespace internal {
41template <typename Key, typename Value,
42 WireFormatLite::FieldType kKeyFieldType,
43 WireFormatLite::FieldType kValueFieldType,
44 int default_enum_value>
45class MapEntry;
46template <typename Key, typename Value,
47 WireFormatLite::FieldType kKeyFieldType,
48 WireFormatLite::FieldType kValueFieldType,
49 int default_enum_value>
50class MapFieldLite;
51} // namespace internal
52} // namespace protobuf
53
54namespace protobuf {
55namespace internal {
56
57// MapEntryLite is used to implement parsing and serialization of map for lite
58// runtime.
59template <typename Key, typename Value,
60 WireFormatLite::FieldType kKeyFieldType,
61 WireFormatLite::FieldType kValueFieldType,
62 int default_enum_value>
63class MapEntryLite : public MessageLite {
64 // Provide utilities to parse/serialize key/value. Provide utilities to
65 // manipulate internal stored type.
66 typedef MapTypeHandler<kKeyFieldType, Key> KeyTypeHandler;
67 typedef MapTypeHandler<kValueFieldType, Value> ValueTypeHandler;
68
69 // Define internal memory layout. Strings and messages are stored as
70 // pointers, while other types are stored as values.
71 typedef typename KeyTypeHandler::TypeOnMemory KeyOnMemory;
72 typedef typename ValueTypeHandler::TypeOnMemory ValueOnMemory;
73
74 // Enum type cannot be used for MapTypeHandler::Read. Define a type
75 // which will replace Enum with int.
76 typedef typename KeyTypeHandler::MapEntryAccessorType KeyMapEntryAccessorType;
77 typedef typename ValueTypeHandler::MapEntryAccessorType
78 ValueMapEntryAccessorType;
79
80 // Constants for field number.
81 static const int kKeyFieldNumber = 1;
82 static const int kValueFieldNumber = 2;
83
84 // Constants for field tag.
85 static const uint8 kKeyTag = GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(
86 kKeyFieldNumber, KeyTypeHandler::kWireType);
87 static const uint8 kValueTag = GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(
88 kValueFieldNumber, ValueTypeHandler::kWireType);
89 static const int kTagSize = 1;
90
91 public:
92 ~MapEntryLite() {
93 if (this != default_instance_) {
94 if (GetArenaNoVirtual() != NULL) return;
95 KeyTypeHandler::DeleteNoArena(key_);
96 ValueTypeHandler::DeleteNoArena(value_);
97 }
98 }
99
100 // accessors ======================================================
101
102 virtual inline const KeyMapEntryAccessorType& key() const {
103 return KeyTypeHandler::GetExternalReference(key_);
104 }
105 virtual inline const ValueMapEntryAccessorType& value() const {
106 GOOGLE_CHECK(default_instance_ != NULL);
107 return ValueTypeHandler::DefaultIfNotInitialized(value_,
108 default_instance_->value_);
109 }
110 inline KeyMapEntryAccessorType* mutable_key() {
111 set_has_key();
112 return KeyTypeHandler::EnsureMutable(&key_, GetArenaNoVirtual());
113 }
114 inline ValueMapEntryAccessorType* mutable_value() {
115 set_has_value();
116 return ValueTypeHandler::EnsureMutable(&value_, GetArenaNoVirtual());
117 }
118
119 // implements MessageLite =========================================
120
121 // MapEntryLite is for implementation only and this function isn't called
122 // anywhere. Just provide a fake implementation here for MessageLite.
123 string GetTypeName() const { return ""; }
124
125 void CheckTypeAndMergeFrom(const MessageLite& other) {
126 MergeFrom(*::google::protobuf::down_cast<const MapEntryLite*>(&other));
127 }
128
129 bool MergePartialFromCodedStream(::google::protobuf::io::CodedInputStream* input) {
130 uint32 tag;
131
132 for (;;) {
133 // 1) corrupted data: return false;
134 // 2) unknown field: skip without putting into unknown field set;
135 // 3) unknown enum value: keep it in parsing. In proto2, caller should
136 // check the value and put this entry into containing message's unknown
137 // field set if the value is an unknown enum. In proto3, caller doesn't
138 // need to care whether the value is unknown enum;
139 // 4) missing key/value: missed key/value will have default value. caller
140 // should take this entry as if key/value is set to default value.
141 tag = input->ReadTag();
142 switch (tag) {
143 case kKeyTag:
144 if (!KeyTypeHandler::Read(input, mutable_key())) {
145 return false;
146 }
147 set_has_key();
148 if (!input->ExpectTag(kValueTag)) break;
149 GOOGLE_FALLTHROUGH_INTENDED;
150
151 case kValueTag:
152 if (!ValueTypeHandler::Read(input, mutable_value())) {
153 return false;
154 }
155 set_has_value();
156 if (input->ExpectAtEnd()) return true;
157 break;
158
159 default:
160 if (tag == 0 ||
161 WireFormatLite::GetTagWireType(tag) ==
162 WireFormatLite::WIRETYPE_END_GROUP) {
163 return true;
164 }
165 if (!WireFormatLite::SkipField(input, tag)) return false;
166 break;
167 }
168 }
169 }
170
171 int ByteSize() const {
172 int size = 0;
173 size += has_key() ? kTagSize + KeyTypeHandler::ByteSize(key()) : 0;
174 size += has_value() ? kTagSize + ValueTypeHandler::ByteSize(value()) : 0;
175 return size;
176 }
177
178 void SerializeWithCachedSizes(::google::protobuf::io::CodedOutputStream* output) const {
179 KeyTypeHandler::Write(kKeyFieldNumber, key(), output);
180 ValueTypeHandler::Write(kValueFieldNumber, value(), output);
181 }
182
183 ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
184 output = KeyTypeHandler::WriteToArray(kKeyFieldNumber, key(), output);
185 output = ValueTypeHandler::WriteToArray(kValueFieldNumber, value(), output);
186 return output;
187 }
188
189 int GetCachedSize() const {
190 int size = 0;
191 size += has_key()
192 ? kTagSize + KeyTypeHandler::GetCachedSize(key())
193 : 0;
194 size += has_value()
195 ? kTagSize + ValueTypeHandler::GetCachedSize(
196 value())
197 : 0;
198 return size;
199 }
200
201 bool IsInitialized() const { return ValueTypeHandler::IsInitialized(value_); }
202
203 MessageLite* New() const {
204 MapEntryLite* entry = new MapEntryLite;
205 entry->default_instance_ = default_instance_;
206 return entry;
207 }
208
209 MessageLite* New(Arena* arena) const {
210 MapEntryLite* entry = Arena::CreateMessage<MapEntryLite>(arena);
211 entry->default_instance_ = default_instance_;
212 return entry;
213 }
214
215 int SpaceUsed() const {
216 int size = sizeof(MapEntryLite);
217 size += KeyTypeHandler::SpaceUsedInMapEntry(key_);
218 size += ValueTypeHandler::SpaceUsedInMapEntry(value_);
219 return size;
220 }
221
222 void MergeFrom(const MapEntryLite& from) {
223 if (from._has_bits_[0]) {
224 if (from.has_key()) {
225 KeyTypeHandler::EnsureMutable(&key_, GetArenaNoVirtual());
226 KeyTypeHandler::Merge(from.key(), &key_, GetArenaNoVirtual());
227 set_has_key();
228 }
229 if (from.has_value()) {
230 ValueTypeHandler::EnsureMutable(&value_, GetArenaNoVirtual());
231 ValueTypeHandler::Merge(from.value(), &value_, GetArenaNoVirtual());
232 set_has_value();
233 }
234 }
235 }
236
237 void Clear() {
238 KeyTypeHandler::Clear(&key_, GetArenaNoVirtual());
239 ValueTypeHandler::ClearMaybeByDefaultEnum(
240 &value_, GetArenaNoVirtual(), default_enum_value);
241 clear_has_key();
242 clear_has_value();
243 }
244
245 void InitAsDefaultInstance() {
246 KeyTypeHandler::AssignDefaultValue(&key_);
247 ValueTypeHandler::AssignDefaultValue(&value_);
248 }
249
250 Arena* GetArena() const {
251 return GetArenaNoVirtual();
252 }
253
254 // Create a MapEntryLite for given key and value from google::protobuf::Map in
255 // serialization. This function is only called when value is enum. Enum is
256 // treated differently because its type in MapEntry is int and its type in
257 // google::protobuf::Map is enum. We cannot create a reference to int from an enum.
258 static MapEntryLite* EnumWrap(const Key& key, const Value value,
259 Arena* arena) {
260 return Arena::CreateMessage<MapEnumEntryWrapper<
261 Key, Value, kKeyFieldType, kValueFieldType, default_enum_value> >(
262 arena, key, value);
263 }
264
265 // Like above, but for all the other types. This avoids value copy to create
266 // MapEntryLite from google::protobuf::Map in serialization.
267 static MapEntryLite* Wrap(const Key& key, const Value& value, Arena* arena) {
268 return Arena::CreateMessage<MapEntryWrapper<Key, Value, kKeyFieldType,
269 kValueFieldType,
270 default_enum_value> >(
271 arena, key, value);
272 }
273
274 protected:
275 void set_has_key() { _has_bits_[0] |= 0x00000001u; }
276 bool has_key() const { return (_has_bits_[0] & 0x00000001u) != 0; }
277 void clear_has_key() { _has_bits_[0] &= ~0x00000001u; }
278 void set_has_value() { _has_bits_[0] |= 0x00000002u; }
279 bool has_value() const { return (_has_bits_[0] & 0x00000002u) != 0; }
280 void clear_has_value() { _has_bits_[0] &= ~0x00000002u; }
281
282 private:
283 // Serializing a generated message containing map field involves serializing
284 // key-value pairs from google::protobuf::Map. The wire format of each key-value pair
285 // after serialization should be the same as that of a MapEntry message
286 // containing the same key and value inside it. However, google::protobuf::Map doesn't
287 // store key and value as MapEntry message, which disables us to use existing
288 // code to serialize message. In order to use existing code to serialize
289 // message, we need to construct a MapEntry from key-value pair. But it
290 // involves copy of key and value to construct a MapEntry. In order to avoid
291 // this copy in constructing a MapEntry, we need the following class which
292 // only takes references of given key and value.
293 template <typename K, typename V, WireFormatLite::FieldType k_wire_type,
294 WireFormatLite::FieldType v_wire_type, int default_enum>
295 class MapEntryWrapper
296 : public MapEntryLite<K, V, k_wire_type, v_wire_type, default_enum> {
297 typedef MapEntryLite<K, V, k_wire_type, v_wire_type, default_enum> Base;
298 typedef typename Base::KeyMapEntryAccessorType KeyMapEntryAccessorType;
299 typedef typename Base::ValueMapEntryAccessorType ValueMapEntryAccessorType;
300
301 public:
302 MapEntryWrapper(Arena* arena, const K& key, const V& value)
303 : MapEntryLite<K, V, k_wire_type, v_wire_type, default_enum>(arena),
304 key_(key),
305 value_(value) {
306 Base::set_has_key();
307 Base::set_has_value();
308 }
309 inline const KeyMapEntryAccessorType& key() const { return key_; }
310 inline const ValueMapEntryAccessorType& value() const { return value_; }
311
312 private:
313 const Key& key_;
314 const Value& value_;
315
316 friend class ::google::protobuf::Arena;
317 typedef void InternalArenaConstructable_;
318 typedef void DestructorSkippable_;
319 };
320
321 // Like above, but for enum value only, which stores value instead of
322 // reference of value field inside. This is needed because the type of value
323 // field in constructor is an enum, while we need to store it as an int. If we
324 // initialize a reference to int with a reference to enum, compiler will
325 // generate a temporary int from enum and initialize the reference to int with
326 // the temporary.
327 template <typename K, typename V, WireFormatLite::FieldType k_wire_type,
328 WireFormatLite::FieldType v_wire_type, int default_enum>
329 class MapEnumEntryWrapper
330 : public MapEntryLite<K, V, k_wire_type, v_wire_type, default_enum> {
331 typedef MapEntryLite<K, V, k_wire_type, v_wire_type, default_enum> Base;
332 typedef typename Base::KeyMapEntryAccessorType KeyMapEntryAccessorType;
333 typedef typename Base::ValueMapEntryAccessorType ValueMapEntryAccessorType;
334
335 public:
336 MapEnumEntryWrapper(Arena* arena, const K& key, const V& value)
337 : MapEntryLite<K, V, k_wire_type, v_wire_type, default_enum>(arena),
338 key_(key),
339 value_(value) {
340 Base::set_has_key();
341 Base::set_has_value();
342 }
343 inline const KeyMapEntryAccessorType& key() const { return key_; }
344 inline const ValueMapEntryAccessorType& value() const { return value_; }
345
346 private:
347 const KeyMapEntryAccessorType& key_;
348 const ValueMapEntryAccessorType value_;
349
350 friend class google::protobuf::Arena;
351 typedef void DestructorSkippable_;
352 };
353
354 MapEntryLite() : default_instance_(NULL), arena_(NULL) {
355 KeyTypeHandler::Initialize(&key_, NULL);
356 ValueTypeHandler::InitializeMaybeByDefaultEnum(
357 &value_, default_enum_value, NULL);
358 _has_bits_[0] = 0;
359 }
360
361 explicit MapEntryLite(Arena* arena)
362 : default_instance_(NULL), arena_(arena) {
363 KeyTypeHandler::Initialize(&key_, arena);
364 ValueTypeHandler::InitializeMaybeByDefaultEnum(
365 &value_, default_enum_value, arena);
366 _has_bits_[0] = 0;
367 }
368
369 inline Arena* GetArenaNoVirtual() const {
370 return arena_;
371 }
372
373 void set_default_instance(MapEntryLite* default_instance) {
374 default_instance_ = default_instance;
375 }
376
377 MapEntryLite* default_instance_;
378
379 KeyOnMemory key_;
380 ValueOnMemory value_;
381 Arena* arena_;
382 uint32 _has_bits_[1];
383
384 friend class ::google::protobuf::Arena;
385 typedef void InternalArenaConstructable_;
386 typedef void DestructorSkippable_;
387 template <typename K, typename V, WireFormatLite::FieldType,
388 WireFormatLite::FieldType, int>
389 friend class internal::MapEntry;
390 template <typename K, typename V, WireFormatLite::FieldType,
391 WireFormatLite::FieldType, int>
392 friend class internal::MapFieldLite;
393
394 GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MapEntryLite);
395};
396
397} // namespace internal
398} // namespace protobuf
399
400} // namespace google
401#endif // GOOGLE_PROTOBUF_MAP_ENTRY_LITE_H__