blob: e02413611dc49c502f558455d5ac3c8e82f2d4a5 [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// 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>
Austin Schuh40c16522018-10-28 20:27:54 -070038// We're only using this as a standard way for getting the thread id.
39// We're not using any thread functionality.
40#include <thread> // NOLINT
41#include <vector>
Brian Silverman9c614bc2016-02-15 20:20:02 -050042
Austin Schuh40c16522018-10-28 20:27:54 -070043#include <google/protobuf/io/coded_stream_inl.h>
44#include <google/protobuf/io/coded_stream.h>
45#include <google/protobuf/arenastring.h>
46#include <google/protobuf/extension_set.h>
47#include <google/protobuf/message_lite.h>
48#include <google/protobuf/metadata_lite.h>
49#include <google/protobuf/stubs/mutex.h>
50#include <google/protobuf/stubs/port.h>
51#include <google/protobuf/repeated_field.h>
52#include <google/protobuf/wire_format_lite.h>
53#include <google/protobuf/wire_format_lite_inl.h>
Brian Silverman9c614bc2016-02-15 20:20:02 -050054
55namespace google {
Austin Schuh40c16522018-10-28 20:27:54 -070056
Brian Silverman9c614bc2016-02-15 20:20:02 -050057namespace protobuf {
58namespace internal {
59
Austin Schuh40c16522018-10-28 20:27:54 -070060void DestroyMessage(const void* message) {
61 static_cast<const MessageLite*>(message)->~MessageLite();
62}
63void DestroyString(const void* s) { static_cast<const string*>(s)->~string(); }
64
65ExplicitlyConstructed<std::string> fixed_address_empty_string;
66
Brian Silverman9c614bc2016-02-15 20:20:02 -050067double Infinity() {
68 return std::numeric_limits<double>::infinity();
69}
70double NaN() {
71 return std::numeric_limits<double>::quiet_NaN();
72}
73
Austin Schuh40c16522018-10-28 20:27:54 -070074static bool InitProtobufDefaultsImpl() {
75 fixed_address_empty_string.DefaultConstruct();
76 OnShutdownDestroyString(fixed_address_empty_string.get_mutable());
77 return true;
Brian Silverman9c614bc2016-02-15 20:20:02 -050078}
79
Austin Schuh40c16522018-10-28 20:27:54 -070080void InitProtobufDefaults() {
81 static bool is_inited = InitProtobufDefaultsImpl();
82 (void)is_inited;
Brian Silverman9c614bc2016-02-15 20:20:02 -050083}
84
Austin Schuh40c16522018-10-28 20:27:54 -070085size_t StringSpaceUsedExcludingSelfLong(const string& str) {
Brian Silverman9c614bc2016-02-15 20:20:02 -050086 const void* start = &str;
87 const void* end = &str + 1;
88 if (start <= str.data() && str.data() < end) {
89 // The string's data is stored inside the string object itself.
90 return 0;
91 } else {
92 return str.capacity();
93 }
94}
95
Austin Schuh40c16522018-10-28 20:27:54 -070096template <typename T>
97const T& Get(const void* ptr) {
98 return *static_cast<const T*>(ptr);
99}
Brian Silverman9c614bc2016-02-15 20:20:02 -0500100
Austin Schuh40c16522018-10-28 20:27:54 -0700101// PrimitiveTypeHelper is a wrapper around the interface of WireFormatLite.
102// WireFormatLite has a very inconvenient interface with respect to template
103// meta-programming. This class wraps the different named functions into
104// a single Serialize / SerializeToArray interface.
105template <int type>
106struct PrimitiveTypeHelper;
107
108template <>
109struct PrimitiveTypeHelper<WireFormatLite::TYPE_BOOL> {
110 typedef bool Type;
111 static void Serialize(const void* ptr,
112 ::google::protobuf::io::CodedOutputStream* output) {
113 WireFormatLite::WriteBoolNoTag(Get<bool>(ptr), output);
114 }
115 static uint8* SerializeToArray(const void* ptr, uint8* buffer) {
116 return WireFormatLite::WriteBoolNoTagToArray(Get<Type>(ptr), buffer);
117 }
118};
119
120template <>
121struct PrimitiveTypeHelper<WireFormatLite::TYPE_INT32> {
122 typedef int32 Type;
123 static void Serialize(const void* ptr,
124 ::google::protobuf::io::CodedOutputStream* output) {
125 WireFormatLite::WriteInt32NoTag(Get<int32>(ptr), output);
126 }
127 static uint8* SerializeToArray(const void* ptr, uint8* buffer) {
128 return WireFormatLite::WriteInt32NoTagToArray(Get<Type>(ptr), buffer);
129 }
130};
131
132template <>
133struct PrimitiveTypeHelper<WireFormatLite::TYPE_SINT32> {
134 typedef int32 Type;
135 static void Serialize(const void* ptr,
136 ::google::protobuf::io::CodedOutputStream* output) {
137 WireFormatLite::WriteSInt32NoTag(Get<int32>(ptr), output);
138 }
139 static uint8* SerializeToArray(const void* ptr, uint8* buffer) {
140 return WireFormatLite::WriteSInt32NoTagToArray(Get<Type>(ptr), buffer);
141 }
142};
143
144template <>
145struct PrimitiveTypeHelper<WireFormatLite::TYPE_UINT32> {
146 typedef uint32 Type;
147 static void Serialize(const void* ptr,
148 ::google::protobuf::io::CodedOutputStream* output) {
149 WireFormatLite::WriteUInt32NoTag(Get<uint32>(ptr), output);
150 }
151 static uint8* SerializeToArray(const void* ptr, uint8* buffer) {
152 return WireFormatLite::WriteUInt32NoTagToArray(Get<Type>(ptr), buffer);
153 }
154};
155template <>
156struct PrimitiveTypeHelper<WireFormatLite::TYPE_INT64> {
157 typedef int64 Type;
158 static void Serialize(const void* ptr,
159 ::google::protobuf::io::CodedOutputStream* output) {
160 WireFormatLite::WriteInt64NoTag(Get<int64>(ptr), output);
161 }
162 static uint8* SerializeToArray(const void* ptr, uint8* buffer) {
163 return WireFormatLite::WriteInt64NoTagToArray(Get<Type>(ptr), buffer);
164 }
165};
166
167template <>
168struct PrimitiveTypeHelper<WireFormatLite::TYPE_SINT64> {
169 typedef int64 Type;
170 static void Serialize(const void* ptr,
171 ::google::protobuf::io::CodedOutputStream* output) {
172 WireFormatLite::WriteSInt64NoTag(Get<int64>(ptr), output);
173 }
174 static uint8* SerializeToArray(const void* ptr, uint8* buffer) {
175 return WireFormatLite::WriteSInt64NoTagToArray(Get<Type>(ptr), buffer);
176 }
177};
178template <>
179struct PrimitiveTypeHelper<WireFormatLite::TYPE_UINT64> {
180 typedef uint64 Type;
181 static void Serialize(const void* ptr,
182 ::google::protobuf::io::CodedOutputStream* output) {
183 WireFormatLite::WriteUInt64NoTag(Get<uint64>(ptr), output);
184 }
185 static uint8* SerializeToArray(const void* ptr, uint8* buffer) {
186 return WireFormatLite::WriteUInt64NoTagToArray(Get<Type>(ptr), buffer);
187 }
188};
189
190template <>
191struct PrimitiveTypeHelper<WireFormatLite::TYPE_FIXED32> {
192 typedef uint32 Type;
193 static void Serialize(const void* ptr,
194 ::google::protobuf::io::CodedOutputStream* output) {
195 WireFormatLite::WriteFixed32NoTag(Get<uint32>(ptr), output);
196 }
197 static uint8* SerializeToArray(const void* ptr, uint8* buffer) {
198 return WireFormatLite::WriteFixed32NoTagToArray(Get<Type>(ptr), buffer);
199 }
200};
201
202template <>
203struct PrimitiveTypeHelper<WireFormatLite::TYPE_FIXED64> {
204 typedef uint64 Type;
205 static void Serialize(const void* ptr,
206 ::google::protobuf::io::CodedOutputStream* output) {
207 WireFormatLite::WriteFixed64NoTag(Get<uint64>(ptr), output);
208 }
209 static uint8* SerializeToArray(const void* ptr, uint8* buffer) {
210 return WireFormatLite::WriteFixed64NoTagToArray(Get<Type>(ptr), buffer);
211 }
212};
213
214template <>
215struct PrimitiveTypeHelper<WireFormatLite::TYPE_ENUM>
216 : PrimitiveTypeHelper<WireFormatLite::TYPE_INT32> {};
217
218template <>
219struct PrimitiveTypeHelper<WireFormatLite::TYPE_SFIXED32>
220 : PrimitiveTypeHelper<WireFormatLite::TYPE_FIXED32> {
221 typedef int32 Type;
222};
223template <>
224struct PrimitiveTypeHelper<WireFormatLite::TYPE_SFIXED64>
225 : PrimitiveTypeHelper<WireFormatLite::TYPE_FIXED64> {
226 typedef int64 Type;
227};
228template <>
229struct PrimitiveTypeHelper<WireFormatLite::TYPE_FLOAT>
230 : PrimitiveTypeHelper<WireFormatLite::TYPE_FIXED32> {
231 typedef float Type;
232};
233template <>
234struct PrimitiveTypeHelper<WireFormatLite::TYPE_DOUBLE>
235 : PrimitiveTypeHelper<WireFormatLite::TYPE_FIXED64> {
236 typedef double Type;
237};
238
239template <>
240struct PrimitiveTypeHelper<WireFormatLite::TYPE_STRING> {
241 typedef string Type;
242 static void Serialize(const void* ptr,
243 ::google::protobuf::io::CodedOutputStream* output) {
244 const Type& value = *static_cast<const Type*>(ptr);
245 output->WriteVarint32(value.size());
246 output->WriteRawMaybeAliased(value.data(), value.size());
247 }
248 static uint8* SerializeToArray(const void* ptr, uint8* buffer) {
249 const Type& value = *static_cast<const Type*>(ptr);
250 return io::CodedOutputStream::WriteStringWithSizeToArray(value, buffer);
251 }
252};
253
254template <>
255struct PrimitiveTypeHelper<WireFormatLite::TYPE_BYTES>
256 : PrimitiveTypeHelper<WireFormatLite::TYPE_STRING> {};
257
258
259template <>
260struct PrimitiveTypeHelper<FieldMetadata::kInlinedType>
261 : PrimitiveTypeHelper<WireFormatLite::TYPE_STRING> {};
262
263// We want to serialize to both CodedOutputStream and directly into byte arrays
264// without duplicating the code. In fact we might want extra output channels in
265// the future.
266template <typename O, int type>
267struct OutputHelper;
268
269template <int type, typename O>
270void SerializeTo(const void* ptr, O* output) {
271 OutputHelper<O, type>::Serialize(ptr, output);
272}
273
274template <typename O>
275void WriteTagTo(uint32 tag, O* output) {
276 SerializeTo<WireFormatLite::TYPE_UINT32>(&tag, output);
277}
278
279template <typename O>
280void WriteLengthTo(uint32 length, O* output) {
281 SerializeTo<WireFormatLite::TYPE_UINT32>(&length, output);
282}
283
284// Specialization for coded output stream
285template <int type>
286struct OutputHelper<::google::protobuf::io::CodedOutputStream, type> {
287 static void Serialize(const void* ptr,
288 ::google::protobuf::io::CodedOutputStream* output) {
289 PrimitiveTypeHelper<type>::Serialize(ptr, output);
290 }
291};
292
293// Specialization for writing into a plain array
294struct ArrayOutput {
295 uint8* ptr;
296 bool is_deterministic;
297};
298
299template <int type>
300struct OutputHelper<ArrayOutput, type> {
301 static void Serialize(const void* ptr, ArrayOutput* output) {
302 output->ptr = PrimitiveTypeHelper<type>::SerializeToArray(ptr, output->ptr);
303 }
304};
305
306void SerializeMessageNoTable(const MessageLite* msg,
307 ::google::protobuf::io::CodedOutputStream* output) {
308 msg->SerializeWithCachedSizes(output);
309}
310
311void SerializeMessageNoTable(const MessageLite* msg, ArrayOutput* output) {
312 output->ptr = msg->InternalSerializeWithCachedSizesToArray(
313 output->is_deterministic, output->ptr);
314}
315
316// Helper to branch to fast path if possible
317void SerializeMessageDispatch(const ::google::protobuf::MessageLite& msg,
318 const FieldMetadata* field_table, int num_fields,
319 int32 cached_size,
320 ::google::protobuf::io::CodedOutputStream* output) {
321 const uint8* base = reinterpret_cast<const uint8*>(&msg);
322 // Try the fast path
323 uint8* ptr = output->GetDirectBufferForNBytesAndAdvance(cached_size);
324 if (ptr) {
325 // We use virtual dispatch to enable dedicated generated code for the
326 // fast path.
327 msg.InternalSerializeWithCachedSizesToArray(
328 output->IsSerializationDeterministic(), ptr);
329 return;
330 }
331 SerializeInternal(base, field_table, num_fields, output);
332}
333
334// Helper to branch to fast path if possible
335void SerializeMessageDispatch(const ::google::protobuf::MessageLite& msg,
336 const FieldMetadata* field_table, int num_fields,
337 int32 cached_size, ArrayOutput* output) {
338 const uint8* base = reinterpret_cast<const uint8*>(&msg);
339 output->ptr = SerializeInternalToArray(base, field_table, num_fields,
340 output->is_deterministic, output->ptr);
341}
342
343// Serializing messages is special as it's not a primitive type and needs an
344// explicit overload for each output type.
345template <typename O>
346void SerializeMessageTo(const MessageLite* msg, const void* table_ptr,
347 O* output) {
348 const SerializationTable* table =
349 static_cast<const SerializationTable*>(table_ptr);
350 if (!table) {
351 // Proto1
352 WriteLengthTo(msg->GetCachedSize(), output);
353 SerializeMessageNoTable(msg, output);
354 return;
355 }
356 const FieldMetadata* field_table = table->field_table;
357 const uint8* base = reinterpret_cast<const uint8*>(msg);
358 int cached_size = *reinterpret_cast<const int32*>(base + field_table->offset);
359 WriteLengthTo(cached_size, output);
360 int num_fields = table->num_fields - 1;
361 SerializeMessageDispatch(*msg, field_table + 1, num_fields, cached_size,
362 output);
363}
364
365// Almost the same as above only it doesn't output the length field.
366template <typename O>
367void SerializeGroupTo(const MessageLite* msg, const void* table_ptr,
368 O* output) {
369 const SerializationTable* table =
370 static_cast<const SerializationTable*>(table_ptr);
371 if (!table) {
372 // Proto1
373 SerializeMessageNoTable(msg, output);
374 return;
375 }
376 const FieldMetadata* field_table = table->field_table;
377 const uint8* base = reinterpret_cast<const uint8*>(msg);
378 int cached_size = *reinterpret_cast<const int32*>(base + field_table->offset);
379 int num_fields = table->num_fields - 1;
380 SerializeMessageDispatch(*msg, field_table + 1, num_fields, cached_size,
381 output);
382}
383
384template <int type>
385struct SingularFieldHelper {
386 template <typename O>
387 static void Serialize(const void* field, const FieldMetadata& md, O* output) {
388 WriteTagTo(md.tag, output);
389 SerializeTo<type>(field, output);
390 }
391};
392
393template <>
394struct SingularFieldHelper<WireFormatLite::TYPE_STRING> {
395 template <typename O>
396 static void Serialize(const void* field, const FieldMetadata& md, O* output) {
397 WriteTagTo(md.tag, output);
398 SerializeTo<WireFormatLite::TYPE_STRING>(&Get<ArenaStringPtr>(field).Get(),
399 output);
400 }
401};
402
403template <>
404struct SingularFieldHelper<WireFormatLite::TYPE_BYTES>
405 : SingularFieldHelper<WireFormatLite::TYPE_STRING> {};
406
407template <>
408struct SingularFieldHelper<WireFormatLite::TYPE_GROUP> {
409 template <typename O>
410 static void Serialize(const void* field, const FieldMetadata& md, O* output) {
411 WriteTagTo(md.tag, output);
412 SerializeGroupTo(Get<const MessageLite*>(field),
413 static_cast<const SerializationTable*>(md.ptr), output);
414 WriteTagTo(md.tag + 1, output);
415 }
416};
417
418template <>
419struct SingularFieldHelper<WireFormatLite::TYPE_MESSAGE> {
420 template <typename O>
421 static void Serialize(const void* field, const FieldMetadata& md, O* output) {
422 WriteTagTo(md.tag, output);
423 SerializeMessageTo(Get<const MessageLite*>(field),
424 static_cast<const SerializationTable*>(md.ptr), output);
425 }
426};
427
428template <>
429struct SingularFieldHelper<FieldMetadata::kInlinedType> {
430 template <typename O>
431 static void Serialize(const void* field, const FieldMetadata& md, O* output) {
432 WriteTagTo(md.tag, output);
433 SerializeTo<FieldMetadata::kInlinedType>(&Get<::std::string>(field), output);
434 }
435};
436
437template <int type>
438struct RepeatedFieldHelper {
439 template <typename O>
440 static void Serialize(const void* field, const FieldMetadata& md, O* output) {
441 typedef typename PrimitiveTypeHelper<type>::Type T;
442 const RepeatedField<T>& array = Get<RepeatedField<T> >(field);
443 for (int i = 0; i < array.size(); i++) {
444 WriteTagTo(md.tag, output);
445 SerializeTo<type>(&array[i], output);
446 }
447 }
448};
449
450// We need to use a helper class to get access to the private members
451class AccessorHelper {
452 public:
453 static int Size(const RepeatedPtrFieldBase& x) { return x.size(); }
454 static void const* Get(const RepeatedPtrFieldBase& x, int idx) {
455 return x.raw_data()[idx];
456 }
457};
458
459template <>
460struct RepeatedFieldHelper<WireFormatLite::TYPE_STRING> {
461 template <typename O>
462 static void Serialize(const void* field, const FieldMetadata& md, O* output) {
463 const internal::RepeatedPtrFieldBase& array =
464 Get<internal::RepeatedPtrFieldBase>(field);
465 for (int i = 0; i < AccessorHelper::Size(array); i++) {
466 WriteTagTo(md.tag, output);
467 SerializeTo<WireFormatLite::TYPE_STRING>(AccessorHelper::Get(array, i),
468 output);
469 }
470 }
471};
472
473template <>
474struct RepeatedFieldHelper<WireFormatLite::TYPE_BYTES>
475 : RepeatedFieldHelper<WireFormatLite::TYPE_STRING> {};
476
477template <>
478struct RepeatedFieldHelper<WireFormatLite::TYPE_GROUP> {
479 template <typename O>
480 static void Serialize(const void* field, const FieldMetadata& md, O* output) {
481 const internal::RepeatedPtrFieldBase& array =
482 Get<internal::RepeatedPtrFieldBase>(field);
483 for (int i = 0; i < AccessorHelper::Size(array); i++) {
484 WriteTagTo(md.tag, output);
485 SerializeGroupTo(
486 static_cast<const MessageLite*>(AccessorHelper::Get(array, i)),
487 static_cast<const SerializationTable*>(md.ptr), output);
488 WriteTagTo(md.tag + 1, output);
489 }
490 }
491};
492
493template <>
494struct RepeatedFieldHelper<WireFormatLite::TYPE_MESSAGE> {
495 template <typename O>
496 static void Serialize(const void* field, const FieldMetadata& md, O* output) {
497 const internal::RepeatedPtrFieldBase& array =
498 Get<internal::RepeatedPtrFieldBase>(field);
499 for (int i = 0; i < AccessorHelper::Size(array); i++) {
500 WriteTagTo(md.tag, output);
501 SerializeMessageTo(
502 static_cast<const MessageLite*>(AccessorHelper::Get(array, i)), md.ptr,
503 output);
504 }
505 }
506};
507
508
509template <>
510struct RepeatedFieldHelper<FieldMetadata::kInlinedType>
511 : RepeatedFieldHelper<WireFormatLite::TYPE_STRING> {};
512
513template <int type>
514struct PackedFieldHelper {
515 template <typename O>
516 static void Serialize(const void* field, const FieldMetadata& md, O* output) {
517 typedef typename PrimitiveTypeHelper<type>::Type T;
518 const RepeatedField<T>& array = Get<RepeatedField<T> >(field);
519 if (array.empty()) return;
520 WriteTagTo(md.tag, output);
521 int cached_size =
522 Get<int>(static_cast<const uint8*>(field) + sizeof(RepeatedField<T>));
523 WriteLengthTo(cached_size, output);
524 for (int i = 0; i < array.size(); i++) {
525 SerializeTo<type>(&array[i], output);
526 }
527 }
528};
529
530template <>
531struct PackedFieldHelper<WireFormatLite::TYPE_STRING> {
532 template <typename O>
533 static void Serialize(const void* field, const FieldMetadata& md, O* output) {
534 GOOGLE_LOG(FATAL) << "Not implemented field number " << md.tag << " with type "
535 << md.type;
536 }
537};
538
539template <>
540struct PackedFieldHelper<WireFormatLite::TYPE_BYTES>
541 : PackedFieldHelper<WireFormatLite::TYPE_STRING> {};
542template <>
543struct PackedFieldHelper<WireFormatLite::TYPE_GROUP>
544 : PackedFieldHelper<WireFormatLite::TYPE_STRING> {};
545template <>
546struct PackedFieldHelper<WireFormatLite::TYPE_MESSAGE>
547 : PackedFieldHelper<WireFormatLite::TYPE_STRING> {};
548template <>
549struct PackedFieldHelper<FieldMetadata::kInlinedType>
550 : PackedFieldHelper<WireFormatLite::TYPE_STRING> {};
551
552template <int type>
553struct OneOfFieldHelper {
554 template <typename O>
555 static void Serialize(const void* field, const FieldMetadata& md, O* output) {
556 SingularFieldHelper<type>::Serialize(field, md, output);
557 }
558};
559
560
561template <>
562struct OneOfFieldHelper<FieldMetadata::kInlinedType> {
563 template <typename O>
564 static void Serialize(const void* field, const FieldMetadata& md, O* output) {
565 SingularFieldHelper<FieldMetadata::kInlinedType>::Serialize(
566 Get<const ::std::string*>(field), md, output);
567 }
568};
569
570void SerializeNotImplemented(int field) {
571 GOOGLE_LOG(FATAL) << "Not implemented field number " << field;
572}
573
574// When switching to c++11 we should make these constexpr functions
575#define SERIALIZE_TABLE_OP(type, type_class) \
576 ((type - 1) + static_cast<int>(type_class) * FieldMetadata::kNumTypes)
577
578int FieldMetadata::CalculateType(int type,
579 FieldMetadata::FieldTypeClass type_class) {
580 return SERIALIZE_TABLE_OP(type, type_class);
581}
582
583template <int type>
584bool IsNull(const void* ptr) {
585 return *static_cast<const typename PrimitiveTypeHelper<type>::Type*>(ptr) ==
586 0;
587}
588
589template <>
590bool IsNull<WireFormatLite::TYPE_STRING>(const void* ptr) {
591 return static_cast<const ArenaStringPtr*>(ptr)->Get().size() == 0;
592}
593
594template <>
595bool IsNull<WireFormatLite::TYPE_BYTES>(const void* ptr) {
596 return static_cast<const ArenaStringPtr*>(ptr)->Get().size() == 0;
597}
598
599template <>
600bool IsNull<WireFormatLite::TYPE_GROUP>(const void* ptr) {
601 return Get<const MessageLite*>(ptr) == NULL;
602}
603
604template <>
605bool IsNull<WireFormatLite::TYPE_MESSAGE>(const void* ptr) {
606 return Get<const MessageLite*>(ptr) == NULL;
607}
608
609
610template <>
611bool IsNull<FieldMetadata::kInlinedType>(const void* ptr) {
612 return static_cast<const ::std::string*>(ptr)->empty();
613}
614
615#define SERIALIZERS_FOR_TYPE(type) \
616 case SERIALIZE_TABLE_OP(type, FieldMetadata::kPresence): \
617 if (!IsPresent(base, field_metadata.has_offset)) continue; \
618 SingularFieldHelper<type>::Serialize(ptr, field_metadata, output); \
619 break; \
620 case SERIALIZE_TABLE_OP(type, FieldMetadata::kNoPresence): \
621 if (IsNull<type>(ptr)) continue; \
622 SingularFieldHelper<type>::Serialize(ptr, field_metadata, output); \
623 break; \
624 case SERIALIZE_TABLE_OP(type, FieldMetadata::kRepeated): \
625 RepeatedFieldHelper<type>::Serialize(ptr, field_metadata, output); \
626 break; \
627 case SERIALIZE_TABLE_OP(type, FieldMetadata::kPacked): \
628 PackedFieldHelper<type>::Serialize(ptr, field_metadata, output); \
629 break; \
630 case SERIALIZE_TABLE_OP(type, FieldMetadata::kOneOf): \
631 if (!IsOneofPresent(base, field_metadata.has_offset, field_metadata.tag)) \
632 continue; \
633 OneOfFieldHelper<type>::Serialize(ptr, field_metadata, output); \
634 break
635
636void SerializeInternal(const uint8* base,
637 const FieldMetadata* field_metadata_table,
638 int32 num_fields,
639 ::google::protobuf::io::CodedOutputStream* output) {
640 for (int i = 0; i < num_fields; i++) {
641 const FieldMetadata& field_metadata = field_metadata_table[i];
642 const uint8* ptr = base + field_metadata.offset;
643 switch (field_metadata.type) {
644 SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_DOUBLE);
645 SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_FLOAT);
646 SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_INT64);
647 SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_UINT64);
648 SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_INT32);
649 SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_FIXED64);
650 SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_FIXED32);
651 SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_BOOL);
652 SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_STRING);
653 SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_GROUP);
654 SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_MESSAGE);
655 SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_BYTES);
656 SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_UINT32);
657 SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_ENUM);
658 SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_SFIXED32);
659 SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_SFIXED64);
660 SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_SINT32);
661 SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_SINT64);
662 SERIALIZERS_FOR_TYPE(FieldMetadata::kInlinedType);
663
664 // Special cases
665 case FieldMetadata::kSpecial:
666 reinterpret_cast<SpecialSerializer>(
667 const_cast<void*>(field_metadata.ptr))(
668 base, field_metadata.offset, field_metadata.tag,
669 field_metadata.has_offset, output);
670 break;
671 default:
672 // __builtin_unreachable()
673 SerializeNotImplemented(field_metadata.type);
674 }
675 }
676}
677
678uint8* SerializeInternalToArray(const uint8* base,
679 const FieldMetadata* field_metadata_table,
680 int32 num_fields, bool is_deterministic,
681 uint8* buffer) {
682 ArrayOutput array_output = {buffer, is_deterministic};
683 ArrayOutput* output = &array_output;
684 for (int i = 0; i < num_fields; i++) {
685 const FieldMetadata& field_metadata = field_metadata_table[i];
686 const uint8* ptr = base + field_metadata.offset;
687 switch (field_metadata.type) {
688 SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_DOUBLE);
689 SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_FLOAT);
690 SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_INT64);
691 SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_UINT64);
692 SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_INT32);
693 SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_FIXED64);
694 SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_FIXED32);
695 SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_BOOL);
696 SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_STRING);
697 SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_GROUP);
698 SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_MESSAGE);
699 SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_BYTES);
700 SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_UINT32);
701 SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_ENUM);
702 SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_SFIXED32);
703 SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_SFIXED64);
704 SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_SINT32);
705 SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_SINT64);
706 SERIALIZERS_FOR_TYPE(FieldMetadata::kInlinedType);
707 // Special cases
708 case FieldMetadata::kSpecial: {
709 io::ArrayOutputStream array_stream(array_output.ptr, INT_MAX);
710 io::CodedOutputStream output(&array_stream);
711 output.SetSerializationDeterministic(is_deterministic);
712 reinterpret_cast<SpecialSerializer>(
713 const_cast<void*>(field_metadata.ptr))(
714 base, field_metadata.offset, field_metadata.tag,
715 field_metadata.has_offset, &output);
716 array_output.ptr += output.ByteCount();
717 } break;
718 default:
719 // __builtin_unreachable()
720 SerializeNotImplemented(field_metadata.type);
721 }
722 }
723 return array_output.ptr;
724}
725#undef SERIALIZERS_FOR_TYPE
726
727void ExtensionSerializer(const uint8* ptr, uint32 offset, uint32 tag,
728 uint32 has_offset,
729 ::google::protobuf::io::CodedOutputStream* output) {
730 reinterpret_cast<const ExtensionSet*>(ptr + offset)
731 ->SerializeWithCachedSizes(tag, has_offset, output);
732}
733
734void UnknownFieldSerializerLite(const uint8* ptr, uint32 offset, uint32 tag,
735 uint32 has_offset,
736 ::google::protobuf::io::CodedOutputStream* output) {
737 output->WriteString(
738 reinterpret_cast<const InternalMetadataWithArenaLite*>(ptr + offset)
739 ->unknown_fields());
740}
741
742MessageLite* DuplicateIfNonNullInternal(MessageLite* message) {
743 if (message) {
744 MessageLite* ret = message->New();
745 ret->CheckTypeAndMergeFrom(*message);
746 return ret;
747 } else {
748 return NULL;
749 }
750}
751
752// Returns a message owned by this Arena. This may require Own()ing or
753// duplicating the message.
754MessageLite* GetOwnedMessageInternal(Arena* message_arena,
755 MessageLite* submessage,
756 Arena* submessage_arena) {
757 GOOGLE_DCHECK(submessage->GetArena() == submessage_arena);
758 GOOGLE_DCHECK(message_arena != submessage_arena);
759 if (message_arena != NULL && submessage_arena == NULL) {
760 message_arena->Own(submessage);
761 return submessage;
762 } else {
763 MessageLite* ret = submessage->New(message_arena);
764 ret->CheckTypeAndMergeFrom(*submessage);
765 return ret;
766 }
767}
768
769namespace {
770
771void InitSCC_DFS(SCCInfoBase* scc) {
772 if (scc->visit_status.load(std::memory_order_relaxed) !=
773 SCCInfoBase::kUninitialized) return;
774 scc->visit_status.store(SCCInfoBase::kRunning, std::memory_order_relaxed);
775 // Each base is followed by an array of pointers to deps
776 auto deps = reinterpret_cast<SCCInfoBase* const*>(scc + 1);
777 for (int i = 0; i < scc->num_deps; i++) {
778 if (deps[i]) InitSCC_DFS(deps[i]);
779 }
780 scc->init_func();
781 // Mark done (note we use memory order release here), other threads could
782 // now see this as initialized and thus the initialization must have happened
783 // before.
784 scc->visit_status.store(SCCInfoBase::kInitialized, std::memory_order_release);
785}
786
787} // namespace
788
789void InitSCCImpl(SCCInfoBase* scc) {
790 static WrappedMutex mu{GOOGLE_PROTOBUF_LINKER_INITIALIZED};
791 // Either the default in case no initialization is running or the id of the
792 // thread that is currently initializing.
793 static std::atomic<std::thread::id> runner;
794 auto me = std::this_thread::get_id();
795 // This will only happen because the constructor will call InitSCC while
796 // constructing the default instance.
797 if (runner.load(std::memory_order_relaxed) == me) {
798 // Because we're in the process of constructing the default instance.
799 // We can be assured that we're already exploring this SCC.
800 GOOGLE_CHECK_EQ(scc->visit_status.load(std::memory_order_relaxed),
801 SCCInfoBase::kRunning);
802 return;
803 }
804 InitProtobufDefaults();
805 mu.Lock();
806 runner.store(me, std::memory_order_relaxed);
807 InitSCC_DFS(scc);
808 runner.store(std::thread::id{}, std::memory_order_relaxed);
809 mu.Unlock();
810}
Brian Silverman9c614bc2016-02-15 20:20:02 -0500811
812} // namespace internal
813} // namespace protobuf
814} // namespace google