1 // 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 // Author: kenton@google.com (Kenton Varda)
32 // Based on original Protocol Buffers design by
33 // Sanjay Ghemawat, Jeff Dean, and others.
34
35 #include <google/protobuf/generated_message_util.h>
36
37 #include <limits>
38 #include <vector>
39
40 #include <google/protobuf/io/coded_stream_inl.h>
41 #include <google/protobuf/io/coded_stream.h>
42 #include <google/protobuf/arenastring.h>
43 #include <google/protobuf/extension_set.h>
44 #include <google/protobuf/message_lite.h>
45 #include <google/protobuf/metadata_lite.h>
46 #include <google/protobuf/repeated_field.h>
47 #include <google/protobuf/wire_format_lite.h>
48 #include <google/protobuf/wire_format_lite_inl.h>
49
50 namespace google {
51 namespace protobuf {
52 namespace internal {
53
Infinity()54 double Infinity() {
55 return std::numeric_limits<double>::infinity();
56 }
NaN()57 double NaN() {
58 return std::numeric_limits<double>::quiet_NaN();
59 }
60
61 ExplicitlyConstructed< ::std::string> fixed_address_empty_string;
62 GOOGLE_PROTOBUF_DECLARE_ONCE(empty_string_once_init_);
63
DeleteEmptyString()64 void DeleteEmptyString() { fixed_address_empty_string.Destruct(); }
65
InitEmptyString()66 void InitEmptyString() {
67 fixed_address_empty_string.DefaultConstruct();
68 OnShutdown(&DeleteEmptyString);
69 }
70
StringSpaceUsedExcludingSelfLong(const string & str)71 size_t StringSpaceUsedExcludingSelfLong(const string& str) {
72 const void* start = &str;
73 const void* end = &str + 1;
74 if (start <= str.data() && str.data() < end) {
75 // The string's data is stored inside the string object itself.
76 return 0;
77 } else {
78 return str.capacity();
79 }
80 }
81
82
83
InitProtobufDefaults()84 void InitProtobufDefaults() {
85 GetEmptyString();
86 }
87
88 template <typename T>
Get(const void * ptr)89 const T& Get(const void* ptr) {
90 return *static_cast<const T*>(ptr);
91 }
92
93 // PrimitiveTypeHelper is a wrapper around the interface of WireFormatLite.
94 // WireFormatLite has a very inconvenient interface with respect to template
95 // meta-programming. This class wraps the different named functions into
96 // a single Serialize / SerializeToArray interface.
97 template <int type>
98 struct PrimitiveTypeHelper;
99
100 template <>
101 struct PrimitiveTypeHelper<WireFormatLite::TYPE_BOOL> {
102 typedef bool Type;
Serializegoogle::protobuf::internal::PrimitiveTypeHelper103 static void Serialize(const void* ptr,
104 ::google::protobuf::io::CodedOutputStream* output) {
105 WireFormatLite::WriteBoolNoTag(Get<bool>(ptr), output);
106 }
SerializeToArraygoogle::protobuf::internal::PrimitiveTypeHelper107 static uint8* SerializeToArray(const void* ptr, uint8* buffer) {
108 return WireFormatLite::WriteBoolNoTagToArray(Get<Type>(ptr), buffer);
109 }
110 };
111
112 template <>
113 struct PrimitiveTypeHelper<WireFormatLite::TYPE_INT32> {
114 typedef int32 Type;
Serializegoogle::protobuf::internal::PrimitiveTypeHelper115 static void Serialize(const void* ptr,
116 ::google::protobuf::io::CodedOutputStream* output) {
117 WireFormatLite::WriteInt32NoTag(Get<int32>(ptr), output);
118 }
SerializeToArraygoogle::protobuf::internal::PrimitiveTypeHelper119 static uint8* SerializeToArray(const void* ptr, uint8* buffer) {
120 return WireFormatLite::WriteInt32NoTagToArray(Get<Type>(ptr), buffer);
121 }
122 };
123
124 template <>
125 struct PrimitiveTypeHelper<WireFormatLite::TYPE_SINT32> {
126 typedef int32 Type;
Serializegoogle::protobuf::internal::PrimitiveTypeHelper127 static void Serialize(const void* ptr,
128 ::google::protobuf::io::CodedOutputStream* output) {
129 WireFormatLite::WriteSInt32NoTag(Get<int32>(ptr), output);
130 }
SerializeToArraygoogle::protobuf::internal::PrimitiveTypeHelper131 static uint8* SerializeToArray(const void* ptr, uint8* buffer) {
132 return WireFormatLite::WriteSInt32NoTagToArray(Get<Type>(ptr), buffer);
133 }
134 };
135
136 template <>
137 struct PrimitiveTypeHelper<WireFormatLite::TYPE_UINT32> {
138 typedef uint32 Type;
Serializegoogle::protobuf::internal::PrimitiveTypeHelper139 static void Serialize(const void* ptr,
140 ::google::protobuf::io::CodedOutputStream* output) {
141 WireFormatLite::WriteUInt32NoTag(Get<uint32>(ptr), output);
142 }
SerializeToArraygoogle::protobuf::internal::PrimitiveTypeHelper143 static uint8* SerializeToArray(const void* ptr, uint8* buffer) {
144 return WireFormatLite::WriteUInt32NoTagToArray(Get<Type>(ptr), buffer);
145 }
146 };
147 template <>
148 struct PrimitiveTypeHelper<WireFormatLite::TYPE_INT64> {
149 typedef int64 Type;
Serializegoogle::protobuf::internal::PrimitiveTypeHelper150 static void Serialize(const void* ptr,
151 ::google::protobuf::io::CodedOutputStream* output) {
152 WireFormatLite::WriteInt64NoTag(Get<int64>(ptr), output);
153 }
SerializeToArraygoogle::protobuf::internal::PrimitiveTypeHelper154 static uint8* SerializeToArray(const void* ptr, uint8* buffer) {
155 return WireFormatLite::WriteInt64NoTagToArray(Get<Type>(ptr), buffer);
156 }
157 };
158
159 template <>
160 struct PrimitiveTypeHelper<WireFormatLite::TYPE_SINT64> {
161 typedef int64 Type;
Serializegoogle::protobuf::internal::PrimitiveTypeHelper162 static void Serialize(const void* ptr,
163 ::google::protobuf::io::CodedOutputStream* output) {
164 WireFormatLite::WriteSInt64NoTag(Get<int64>(ptr), output);
165 }
SerializeToArraygoogle::protobuf::internal::PrimitiveTypeHelper166 static uint8* SerializeToArray(const void* ptr, uint8* buffer) {
167 return WireFormatLite::WriteSInt64NoTagToArray(Get<Type>(ptr), buffer);
168 }
169 };
170 template <>
171 struct PrimitiveTypeHelper<WireFormatLite::TYPE_UINT64> {
172 typedef uint64 Type;
Serializegoogle::protobuf::internal::PrimitiveTypeHelper173 static void Serialize(const void* ptr,
174 ::google::protobuf::io::CodedOutputStream* output) {
175 WireFormatLite::WriteUInt64NoTag(Get<uint64>(ptr), output);
176 }
SerializeToArraygoogle::protobuf::internal::PrimitiveTypeHelper177 static uint8* SerializeToArray(const void* ptr, uint8* buffer) {
178 return WireFormatLite::WriteUInt64NoTagToArray(Get<Type>(ptr), buffer);
179 }
180 };
181
182 template <>
183 struct PrimitiveTypeHelper<WireFormatLite::TYPE_FIXED32> {
184 typedef uint32 Type;
Serializegoogle::protobuf::internal::PrimitiveTypeHelper185 static void Serialize(const void* ptr,
186 ::google::protobuf::io::CodedOutputStream* output) {
187 WireFormatLite::WriteFixed32NoTag(Get<uint32>(ptr), output);
188 }
SerializeToArraygoogle::protobuf::internal::PrimitiveTypeHelper189 static uint8* SerializeToArray(const void* ptr, uint8* buffer) {
190 return WireFormatLite::WriteFixed32NoTagToArray(Get<Type>(ptr), buffer);
191 }
192 };
193
194 template <>
195 struct PrimitiveTypeHelper<WireFormatLite::TYPE_FIXED64> {
196 typedef uint64 Type;
Serializegoogle::protobuf::internal::PrimitiveTypeHelper197 static void Serialize(const void* ptr,
198 ::google::protobuf::io::CodedOutputStream* output) {
199 WireFormatLite::WriteFixed64NoTag(Get<uint64>(ptr), output);
200 }
SerializeToArraygoogle::protobuf::internal::PrimitiveTypeHelper201 static uint8* SerializeToArray(const void* ptr, uint8* buffer) {
202 return WireFormatLite::WriteFixed64NoTagToArray(Get<Type>(ptr), buffer);
203 }
204 };
205
206 template <>
207 struct PrimitiveTypeHelper<WireFormatLite::TYPE_ENUM>
208 : PrimitiveTypeHelper<WireFormatLite::TYPE_INT32> {};
209
210 template <>
211 struct PrimitiveTypeHelper<WireFormatLite::TYPE_SFIXED32>
212 : PrimitiveTypeHelper<WireFormatLite::TYPE_FIXED32> {
213 typedef int32 Type;
214 };
215 template <>
216 struct PrimitiveTypeHelper<WireFormatLite::TYPE_SFIXED64>
217 : PrimitiveTypeHelper<WireFormatLite::TYPE_FIXED64> {
218 typedef int64 Type;
219 };
220 template <>
221 struct PrimitiveTypeHelper<WireFormatLite::TYPE_FLOAT>
222 : PrimitiveTypeHelper<WireFormatLite::TYPE_FIXED32> {
223 typedef float Type;
224 };
225 template <>
226 struct PrimitiveTypeHelper<WireFormatLite::TYPE_DOUBLE>
227 : PrimitiveTypeHelper<WireFormatLite::TYPE_FIXED64> {
228 typedef double Type;
229 };
230
231 template <>
232 struct PrimitiveTypeHelper<WireFormatLite::TYPE_STRING> {
233 typedef string Type;
Serializegoogle::protobuf::internal::PrimitiveTypeHelper234 static void Serialize(const void* ptr,
235 ::google::protobuf::io::CodedOutputStream* output) {
236 const Type& value = *static_cast<const Type*>(ptr);
237 output->WriteVarint32(value.size());
238 output->WriteRawMaybeAliased(value.data(), value.size());
239 }
SerializeToArraygoogle::protobuf::internal::PrimitiveTypeHelper240 static uint8* SerializeToArray(const void* ptr, uint8* buffer) {
241 const Type& value = *static_cast<const Type*>(ptr);
242 return io::CodedOutputStream::WriteStringWithSizeToArray(value, buffer);
243 }
244 };
245
246 template <>
247 struct PrimitiveTypeHelper<WireFormatLite::TYPE_BYTES>
248 : PrimitiveTypeHelper<WireFormatLite::TYPE_STRING> {};
249
250
251 // We want to serialize to both CodedOutputStream and directly into byte arrays
252 // without duplicating the code. In fact we might want extra output channels in
253 // the future.
254 template <typename O, int type>
255 struct OutputHelper;
256
257 template <int type, typename O>
SerializeTo(const void * ptr,O * output)258 void SerializeTo(const void* ptr, O* output) {
259 OutputHelper<O, type>::Serialize(ptr, output);
260 }
261
262 template <typename O>
WriteTagTo(uint32 tag,O * output)263 void WriteTagTo(uint32 tag, O* output) {
264 SerializeTo<WireFormatLite::TYPE_UINT32>(&tag, output);
265 }
266
267 template <typename O>
WriteLengthTo(uint32 length,O * output)268 void WriteLengthTo(uint32 length, O* output) {
269 SerializeTo<WireFormatLite::TYPE_UINT32>(&length, output);
270 }
271
272 // Specialization for coded output stream
273 template <int type>
274 struct OutputHelper< ::google::protobuf::io::CodedOutputStream, type> {
Serializegoogle::protobuf::internal::OutputHelper275 static void Serialize(const void* ptr,
276 ::google::protobuf::io::CodedOutputStream* output) {
277 PrimitiveTypeHelper<type>::Serialize(ptr, output);
278 }
279 };
280
281 // Specialization for writing into a plain array
282 struct ArrayOutput {
283 uint8* ptr;
284 bool is_deterministic;
285 };
286
287 template <int type>
288 struct OutputHelper<ArrayOutput, type> {
Serializegoogle::protobuf::internal::OutputHelper289 static void Serialize(const void* ptr, ArrayOutput* output) {
290 output->ptr = PrimitiveTypeHelper<type>::SerializeToArray(ptr, output->ptr);
291 }
292 };
293
SerializeMessageNoTable(const MessageLite * msg,::google::protobuf::io::CodedOutputStream * output)294 void SerializeMessageNoTable(const MessageLite* msg,
295 ::google::protobuf::io::CodedOutputStream* output) {
296 msg->SerializeWithCachedSizes(output);
297 }
298
SerializeMessageNoTable(const MessageLite * msg,ArrayOutput * output)299 void SerializeMessageNoTable(const MessageLite* msg, ArrayOutput* output) {
300 output->ptr = msg->InternalSerializeWithCachedSizesToArray(
301 output->is_deterministic, output->ptr);
302 }
303
304 // Helper to branch to fast path if possible
SerializeMessageDispatch(const::google::protobuf::MessageLite & msg,const FieldMetadata * field_table,int num_fields,int32 cached_size,::google::protobuf::io::CodedOutputStream * output)305 void SerializeMessageDispatch(const ::google::protobuf::MessageLite& msg,
306 const FieldMetadata* field_table, int num_fields,
307 int32 cached_size,
308 ::google::protobuf::io::CodedOutputStream* output) {
309 const uint8* base = reinterpret_cast<const uint8*>(&msg);
310 // Try the fast path
311 uint8* ptr = output->GetDirectBufferForNBytesAndAdvance(cached_size);
312 if (ptr) {
313 // We use virtual dispatch to enable dedicated generated code for the
314 // fast path.
315 msg.InternalSerializeWithCachedSizesToArray(
316 output->IsSerializationDeterministic(), ptr);
317 return;
318 }
319 SerializeInternal(base, field_table, num_fields, output);
320 }
321
322 // Helper to branch to fast path if possible
SerializeMessageDispatch(const::google::protobuf::MessageLite & msg,const FieldMetadata * field_table,int num_fields,int32 cached_size,ArrayOutput * output)323 void SerializeMessageDispatch(const ::google::protobuf::MessageLite& msg,
324 const FieldMetadata* field_table, int num_fields,
325 int32 cached_size, ArrayOutput* output) {
326 const uint8* base = reinterpret_cast<const uint8*>(&msg);
327 output->ptr = SerializeInternalToArray(base, field_table, num_fields,
328 output->is_deterministic, output->ptr);
329 }
330
331 // Serializing messages is special as it's not a primitive type and needs an
332 // explicit overload for each output type.
333 template <typename O>
SerializeMessageTo(const MessageLite * msg,const void * table_ptr,O * output)334 void SerializeMessageTo(const MessageLite* msg, const void* table_ptr,
335 O* output) {
336 const SerializationTable* table =
337 static_cast<const SerializationTable*>(table_ptr);
338 if (!table) {
339 // Proto1
340 WriteLengthTo(msg->GetCachedSize(), output);
341 SerializeMessageNoTable(msg, output);
342 return;
343 }
344 const FieldMetadata* field_table = table->field_table;
345 const uint8* base = reinterpret_cast<const uint8*>(msg);
346 int cached_size = *reinterpret_cast<const int32*>(base + field_table->offset);
347 WriteLengthTo(cached_size, output);
348 int num_fields = table->num_fields - 1;
349 SerializeMessageDispatch(*msg, field_table + 1, num_fields, cached_size,
350 output);
351 }
352
353 // Almost the same as above only it doesn't output the length field.
354 template <typename O>
SerializeGroupTo(const MessageLite * msg,const void * table_ptr,O * output)355 void SerializeGroupTo(const MessageLite* msg, const void* table_ptr,
356 O* output) {
357 const SerializationTable* table =
358 static_cast<const SerializationTable*>(table_ptr);
359 if (!table) {
360 // Proto1
361 SerializeMessageNoTable(msg, output);
362 return;
363 }
364 const FieldMetadata* field_table = table->field_table;
365 const uint8* base = reinterpret_cast<const uint8*>(msg);
366 int cached_size = *reinterpret_cast<const int32*>(base + field_table->offset);
367 int num_fields = table->num_fields - 1;
368 SerializeMessageDispatch(*msg, field_table + 1, num_fields, cached_size,
369 output);
370 }
371
372 template <int type>
373 struct SingularFieldHelper {
374 template <typename O>
Serializegoogle::protobuf::internal::SingularFieldHelper375 static void Serialize(const void* field, const FieldMetadata& md, O* output) {
376 WriteTagTo(md.tag, output);
377 SerializeTo<type>(field, output);
378 }
379 };
380
381 template <>
382 struct SingularFieldHelper<WireFormatLite::TYPE_STRING> {
383 template <typename O>
Serializegoogle::protobuf::internal::SingularFieldHelper384 static void Serialize(const void* field, const FieldMetadata& md, O* output) {
385 WriteTagTo(md.tag, output);
386 SerializeTo<WireFormatLite::TYPE_STRING>(&Get<ArenaStringPtr>(field).Get(),
387 output);
388 }
389 };
390
391 template <>
392 struct SingularFieldHelper<WireFormatLite::TYPE_BYTES>
393 : SingularFieldHelper<WireFormatLite::TYPE_STRING> {};
394
395 template <>
396 struct SingularFieldHelper<WireFormatLite::TYPE_GROUP> {
397 template <typename O>
Serializegoogle::protobuf::internal::SingularFieldHelper398 static void Serialize(const void* field, const FieldMetadata& md, O* output) {
399 WriteTagTo(md.tag, output);
400 SerializeGroupTo(Get<const MessageLite*>(field),
401 static_cast<const SerializationTable*>(md.ptr), output);
402 WriteTagTo(md.tag + 1, output);
403 }
404 };
405
406 template <>
407 struct SingularFieldHelper<WireFormatLite::TYPE_MESSAGE> {
408 template <typename O>
Serializegoogle::protobuf::internal::SingularFieldHelper409 static void Serialize(const void* field, const FieldMetadata& md, O* output) {
410 WriteTagTo(md.tag, output);
411 SerializeMessageTo(Get<const MessageLite*>(field),
412 static_cast<const SerializationTable*>(md.ptr), output);
413 }
414 };
415
416 template <int type>
417 struct RepeatedFieldHelper {
418 template <typename O>
Serializegoogle::protobuf::internal::RepeatedFieldHelper419 static void Serialize(const void* field, const FieldMetadata& md, O* output) {
420 typedef typename PrimitiveTypeHelper<type>::Type T;
421 const RepeatedField<T>& array = Get<RepeatedField<T> >(field);
422 for (int i = 0; i < array.size(); i++) {
423 WriteTagTo(md.tag, output);
424 SerializeTo<type>(&array[i], output);
425 }
426 }
427 };
428
429 // We need to use a helper class to get access to the private members
430 class AccessorHelper {
431 public:
Size(const RepeatedPtrFieldBase & x)432 static int Size(const RepeatedPtrFieldBase& x) { return x.size(); }
Get(const RepeatedPtrFieldBase & x,int idx)433 static void const* Get(const RepeatedPtrFieldBase& x, int idx) {
434 return x.raw_data()[idx];
435 }
436 };
437
438 template <>
439 struct RepeatedFieldHelper<WireFormatLite::TYPE_STRING> {
440 template <typename O>
Serializegoogle::protobuf::internal::RepeatedFieldHelper441 static void Serialize(const void* field, const FieldMetadata& md, O* output) {
442 const internal::RepeatedPtrFieldBase& array =
443 Get<internal::RepeatedPtrFieldBase>(field);
444 for (int i = 0; i < AccessorHelper::Size(array); i++) {
445 WriteTagTo(md.tag, output);
446 SerializeTo<WireFormatLite::TYPE_STRING>(AccessorHelper::Get(array, i),
447 output);
448 }
449 }
450 };
451
452 template <>
453 struct RepeatedFieldHelper<WireFormatLite::TYPE_BYTES>
454 : RepeatedFieldHelper<WireFormatLite::TYPE_STRING> {};
455
456 template <>
457 struct RepeatedFieldHelper<WireFormatLite::TYPE_GROUP> {
458 template <typename O>
Serializegoogle::protobuf::internal::RepeatedFieldHelper459 static void Serialize(const void* field, const FieldMetadata& md, O* output) {
460 const internal::RepeatedPtrFieldBase& array =
461 Get<internal::RepeatedPtrFieldBase>(field);
462 for (int i = 0; i < AccessorHelper::Size(array); i++) {
463 WriteTagTo(md.tag, output);
464 SerializeGroupTo(
465 static_cast<const MessageLite*>(AccessorHelper::Get(array, i)),
466 static_cast<const SerializationTable*>(md.ptr), output);
467 WriteTagTo(md.tag + 1, output);
468 }
469 }
470 };
471
472 template <>
473 struct RepeatedFieldHelper<WireFormatLite::TYPE_MESSAGE> {
474 template <typename O>
Serializegoogle::protobuf::internal::RepeatedFieldHelper475 static void Serialize(const void* field, const FieldMetadata& md, O* output) {
476 const internal::RepeatedPtrFieldBase& array =
477 Get<internal::RepeatedPtrFieldBase>(field);
478 for (int i = 0; i < AccessorHelper::Size(array); i++) {
479 WriteTagTo(md.tag, output);
480 SerializeMessageTo(
481 static_cast<const MessageLite*>(AccessorHelper::Get(array, i)), md.ptr,
482 output);
483 }
484 }
485 };
486
487
488 template <int type>
489 struct PackedFieldHelper {
490 template <typename O>
Serializegoogle::protobuf::internal::PackedFieldHelper491 static void Serialize(const void* field, const FieldMetadata& md, O* output) {
492 typedef typename PrimitiveTypeHelper<type>::Type T;
493 const RepeatedField<T>& array = Get<RepeatedField<T> >(field);
494 if (array.empty()) return;
495 WriteTagTo(md.tag, output);
496 int cached_size =
497 Get<int>(static_cast<const uint8*>(field) + sizeof(RepeatedField<T>));
498 WriteLengthTo(cached_size, output);
499 for (int i = 0; i < array.size(); i++) {
500 SerializeTo<type>(&array[i], output);
501 }
502 }
503 };
504
505 template <>
506 struct PackedFieldHelper<WireFormatLite::TYPE_STRING> {
507 template <typename O>
Serializegoogle::protobuf::internal::PackedFieldHelper508 static void Serialize(const void* field, const FieldMetadata& md, O* output) {
509 GOOGLE_LOG(FATAL) << "Not implemented field number " << md.tag << " with type "
510 << md.type;
511 }
512 };
513
514 template <>
515 struct PackedFieldHelper<WireFormatLite::TYPE_BYTES>
516 : PackedFieldHelper<WireFormatLite::TYPE_STRING> {};
517 template <>
518 struct PackedFieldHelper<WireFormatLite::TYPE_GROUP>
519 : PackedFieldHelper<WireFormatLite::TYPE_STRING> {};
520 template <>
521 struct PackedFieldHelper<WireFormatLite::TYPE_MESSAGE>
522 : PackedFieldHelper<WireFormatLite::TYPE_STRING> {};
523
524 template <int type>
525 struct OneOfFieldHelper {
526 template <typename O>
Serializegoogle::protobuf::internal::OneOfFieldHelper527 static void Serialize(const void* field, const FieldMetadata& md, O* output) {
528 SingularFieldHelper<type>::Serialize(field, md, output);
529 }
530 };
531
532
SerializeNotImplemented(int field)533 void SerializeNotImplemented(int field) {
534 GOOGLE_LOG(FATAL) << "Not implemented field number " << field;
535 }
536
537 // When switching to c++11 we should make these constexpr functions
538 #define SERIALIZE_TABLE_OP(type, type_class) \
539 ((type - 1) + static_cast<int>(type_class) * FieldMetadata::kNumTypes)
540
CalculateType(int type,FieldMetadata::FieldTypeClass type_class)541 int FieldMetadata::CalculateType(int type,
542 FieldMetadata::FieldTypeClass type_class) {
543 return SERIALIZE_TABLE_OP(type, type_class);
544 }
545
546 template <int type>
IsNull(const void * ptr)547 bool IsNull(const void* ptr) {
548 return *static_cast<const typename PrimitiveTypeHelper<type>::Type*>(ptr) ==
549 0;
550 }
551
552 template <>
IsNull(const void * ptr)553 bool IsNull<WireFormatLite::TYPE_STRING>(const void* ptr) {
554 return static_cast<const ArenaStringPtr*>(ptr)->Get().size() == 0;
555 }
556
557 template <>
IsNull(const void * ptr)558 bool IsNull<WireFormatLite::TYPE_BYTES>(const void* ptr) {
559 return static_cast<const ArenaStringPtr*>(ptr)->Get().size() == 0;
560 }
561
562 template <>
IsNull(const void * ptr)563 bool IsNull<WireFormatLite::TYPE_GROUP>(const void* ptr) {
564 return Get<const MessageLite*>(ptr) == NULL;
565 }
566
567 template <>
IsNull(const void * ptr)568 bool IsNull<WireFormatLite::TYPE_MESSAGE>(const void* ptr) {
569 return Get<const MessageLite*>(ptr) == NULL;
570 }
571
572
573 #define SERIALIZERS_FOR_TYPE(type) \
574 case SERIALIZE_TABLE_OP(type, FieldMetadata::kPresence): \
575 if (!IsPresent(base, field_metadata.has_offset)) continue; \
576 SingularFieldHelper<type>::Serialize(ptr, field_metadata, output); \
577 break; \
578 case SERIALIZE_TABLE_OP(type, FieldMetadata::kNoPresence): \
579 if (IsNull<type>(ptr)) continue; \
580 SingularFieldHelper<type>::Serialize(ptr, field_metadata, output); \
581 break; \
582 case SERIALIZE_TABLE_OP(type, FieldMetadata::kRepeated): \
583 RepeatedFieldHelper<type>::Serialize(ptr, field_metadata, output); \
584 break; \
585 case SERIALIZE_TABLE_OP(type, FieldMetadata::kPacked): \
586 PackedFieldHelper<type>::Serialize(ptr, field_metadata, output); \
587 break; \
588 case SERIALIZE_TABLE_OP(type, FieldMetadata::kOneOf): \
589 if (!IsOneofPresent(base, field_metadata.has_offset, field_metadata.tag)) \
590 continue; \
591 OneOfFieldHelper<type>::Serialize(ptr, field_metadata, output); \
592 break
593
SerializeInternal(const uint8 * base,const FieldMetadata * field_metadata_table,int32 num_fields,::google::protobuf::io::CodedOutputStream * output)594 void SerializeInternal(const uint8* base,
595 const FieldMetadata* field_metadata_table,
596 int32 num_fields,
597 ::google::protobuf::io::CodedOutputStream* output) {
598 for (int i = 0; i < num_fields; i++) {
599 const FieldMetadata& field_metadata = field_metadata_table[i];
600 const uint8* ptr = base + field_metadata.offset;
601 switch (field_metadata.type) {
602 SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_DOUBLE);
603 SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_FLOAT);
604 SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_INT64);
605 SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_UINT64);
606 SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_INT32);
607 SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_FIXED64);
608 SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_FIXED32);
609 SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_BOOL);
610 SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_STRING);
611 SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_GROUP);
612 SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_MESSAGE);
613 SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_BYTES);
614 SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_UINT32);
615 SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_ENUM);
616 SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_SFIXED32);
617 SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_SFIXED64);
618 SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_SINT32);
619 SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_SINT64);
620
621 // Special cases
622 case FieldMetadata::kSpecial:
623 reinterpret_cast<SpecialSerializer>(
624 const_cast<void*>(field_metadata.ptr))(
625 base, field_metadata.offset, field_metadata.tag,
626 field_metadata.has_offset, output);
627 break;
628 default:
629 // __builtin_unreachable()
630 SerializeNotImplemented(field_metadata.type);
631 }
632 }
633 }
634
SerializeInternalToArray(const uint8 * base,const FieldMetadata * field_metadata_table,int32 num_fields,bool is_deterministic,uint8 * buffer)635 uint8* SerializeInternalToArray(const uint8* base,
636 const FieldMetadata* field_metadata_table,
637 int32 num_fields, bool is_deterministic,
638 uint8* buffer) {
639 ArrayOutput array_output = {buffer, is_deterministic};
640 ArrayOutput* output = &array_output;
641 for (int i = 0; i < num_fields; i++) {
642 const FieldMetadata& field_metadata = field_metadata_table[i];
643 const uint8* ptr = base + field_metadata.offset;
644 switch (field_metadata.type) {
645 SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_DOUBLE);
646 SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_FLOAT);
647 SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_INT64);
648 SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_UINT64);
649 SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_INT32);
650 SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_FIXED64);
651 SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_FIXED32);
652 SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_BOOL);
653 SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_STRING);
654 SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_GROUP);
655 SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_MESSAGE);
656 SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_BYTES);
657 SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_UINT32);
658 SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_ENUM);
659 SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_SFIXED32);
660 SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_SFIXED64);
661 SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_SINT32);
662 SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_SINT64);
663 // Special cases
664 case FieldMetadata::kSpecial: {
665 io::ArrayOutputStream array_stream(array_output.ptr, INT_MAX);
666 io::CodedOutputStream output(&array_stream);
667 output.SetSerializationDeterministic(is_deterministic);
668 reinterpret_cast<SpecialSerializer>(
669 const_cast<void*>(field_metadata.ptr))(
670 base, field_metadata.offset, field_metadata.tag,
671 field_metadata.has_offset, &output);
672 array_output.ptr += output.ByteCount();
673 } break;
674 default:
675 // __builtin_unreachable()
676 SerializeNotImplemented(field_metadata.type);
677 }
678 }
679 return array_output.ptr;
680 }
681 #undef SERIALIZERS_FOR_TYPE
682
ExtensionSerializer(const uint8 * ptr,uint32 offset,uint32 tag,uint32 has_offset,::google::protobuf::io::CodedOutputStream * output)683 void ExtensionSerializer(const uint8* ptr, uint32 offset, uint32 tag,
684 uint32 has_offset,
685 ::google::protobuf::io::CodedOutputStream* output) {
686 reinterpret_cast<const ExtensionSet*>(ptr + offset)
687 ->SerializeWithCachedSizes(tag, has_offset, output);
688 }
689
UnknownFieldSerializerLite(const uint8 * ptr,uint32 offset,uint32 tag,uint32 has_offset,::google::protobuf::io::CodedOutputStream * output)690 void UnknownFieldSerializerLite(const uint8* ptr, uint32 offset, uint32 tag,
691 uint32 has_offset,
692 ::google::protobuf::io::CodedOutputStream* output) {
693 output->WriteString(
694 reinterpret_cast<const InternalMetadataWithArenaLite*>(ptr + offset)
695 ->unknown_fields());
696 }
697
698 } // namespace internal
699 } // namespace protobuf
700 } // namespace google
701