// Protocol Buffers - Google's data interchange format // Copyright 2008 Google Inc. All rights reserved. // https://developers.google.com/protocol-buffers/ // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // Author: kenton@google.com (Kenton Varda) // Based on original Protocol Buffers design by // Sanjay Ghemawat, Jeff Dean, and others. #include #include // We're only using this as a standard way for getting the thread id. // We're not using any thread functionality. #include // NOLINT #include #include #include #include #include #include #include #include #include #include #include #include namespace google { namespace protobuf { namespace internal { double Infinity() { return std::numeric_limits::infinity(); } double NaN() { return std::numeric_limits::quiet_NaN(); } ExplicitlyConstructed<::std::string> fixed_address_empty_string; GOOGLE_PROTOBUF_DECLARE_ONCE(empty_string_once_init_); void DeleteEmptyString() { fixed_address_empty_string.Destruct(); } void InitEmptyString() { fixed_address_empty_string.DefaultConstruct(); OnShutdown(&DeleteEmptyString); } size_t StringSpaceUsedExcludingSelfLong(const string& str) { const void* start = &str; const void* end = &str + 1; if (start <= str.data() && str.data() < end) { // The string's data is stored inside the string object itself. return 0; } else { return str.capacity(); } } void InitProtobufDefaults() { GetEmptyString(); } template const T& Get(const void* ptr) { return *static_cast(ptr); } // PrimitiveTypeHelper is a wrapper around the interface of WireFormatLite. // WireFormatLite has a very inconvenient interface with respect to template // meta-programming. This class wraps the different named functions into // a single Serialize / SerializeToArray interface. template struct PrimitiveTypeHelper; template <> struct PrimitiveTypeHelper { typedef bool Type; static void Serialize(const void* ptr, ::google::protobuf::io::CodedOutputStream* output) { WireFormatLite::WriteBoolNoTag(Get(ptr), output); } static uint8* SerializeToArray(const void* ptr, uint8* buffer) { return WireFormatLite::WriteBoolNoTagToArray(Get(ptr), buffer); } }; template <> struct PrimitiveTypeHelper { typedef int32 Type; static void Serialize(const void* ptr, ::google::protobuf::io::CodedOutputStream* output) { WireFormatLite::WriteInt32NoTag(Get(ptr), output); } static uint8* SerializeToArray(const void* ptr, uint8* buffer) { return WireFormatLite::WriteInt32NoTagToArray(Get(ptr), buffer); } }; template <> struct PrimitiveTypeHelper { typedef int32 Type; static void Serialize(const void* ptr, ::google::protobuf::io::CodedOutputStream* output) { WireFormatLite::WriteSInt32NoTag(Get(ptr), output); } static uint8* SerializeToArray(const void* ptr, uint8* buffer) { return WireFormatLite::WriteSInt32NoTagToArray(Get(ptr), buffer); } }; template <> struct PrimitiveTypeHelper { typedef uint32 Type; static void Serialize(const void* ptr, ::google::protobuf::io::CodedOutputStream* output) { WireFormatLite::WriteUInt32NoTag(Get(ptr), output); } static uint8* SerializeToArray(const void* ptr, uint8* buffer) { return WireFormatLite::WriteUInt32NoTagToArray(Get(ptr), buffer); } }; template <> struct PrimitiveTypeHelper { typedef int64 Type; static void Serialize(const void* ptr, ::google::protobuf::io::CodedOutputStream* output) { WireFormatLite::WriteInt64NoTag(Get(ptr), output); } static uint8* SerializeToArray(const void* ptr, uint8* buffer) { return WireFormatLite::WriteInt64NoTagToArray(Get(ptr), buffer); } }; template <> struct PrimitiveTypeHelper { typedef int64 Type; static void Serialize(const void* ptr, ::google::protobuf::io::CodedOutputStream* output) { WireFormatLite::WriteSInt64NoTag(Get(ptr), output); } static uint8* SerializeToArray(const void* ptr, uint8* buffer) { return WireFormatLite::WriteSInt64NoTagToArray(Get(ptr), buffer); } }; template <> struct PrimitiveTypeHelper { typedef uint64 Type; static void Serialize(const void* ptr, ::google::protobuf::io::CodedOutputStream* output) { WireFormatLite::WriteUInt64NoTag(Get(ptr), output); } static uint8* SerializeToArray(const void* ptr, uint8* buffer) { return WireFormatLite::WriteUInt64NoTagToArray(Get(ptr), buffer); } }; template <> struct PrimitiveTypeHelper { typedef uint32 Type; static void Serialize(const void* ptr, ::google::protobuf::io::CodedOutputStream* output) { WireFormatLite::WriteFixed32NoTag(Get(ptr), output); } static uint8* SerializeToArray(const void* ptr, uint8* buffer) { return WireFormatLite::WriteFixed32NoTagToArray(Get(ptr), buffer); } }; template <> struct PrimitiveTypeHelper { typedef uint64 Type; static void Serialize(const void* ptr, ::google::protobuf::io::CodedOutputStream* output) { WireFormatLite::WriteFixed64NoTag(Get(ptr), output); } static uint8* SerializeToArray(const void* ptr, uint8* buffer) { return WireFormatLite::WriteFixed64NoTagToArray(Get(ptr), buffer); } }; template <> struct PrimitiveTypeHelper : PrimitiveTypeHelper {}; template <> struct PrimitiveTypeHelper : PrimitiveTypeHelper { typedef int32 Type; }; template <> struct PrimitiveTypeHelper : PrimitiveTypeHelper { typedef int64 Type; }; template <> struct PrimitiveTypeHelper : PrimitiveTypeHelper { typedef float Type; }; template <> struct PrimitiveTypeHelper : PrimitiveTypeHelper { typedef double Type; }; template <> struct PrimitiveTypeHelper { typedef string Type; static void Serialize(const void* ptr, ::google::protobuf::io::CodedOutputStream* output) { const Type& value = *static_cast(ptr); output->WriteVarint32(value.size()); output->WriteRawMaybeAliased(value.data(), value.size()); } static uint8* SerializeToArray(const void* ptr, uint8* buffer) { const Type& value = *static_cast(ptr); return io::CodedOutputStream::WriteStringWithSizeToArray(value, buffer); } }; template <> struct PrimitiveTypeHelper : PrimitiveTypeHelper {}; template <> struct PrimitiveTypeHelper : PrimitiveTypeHelper {}; // We want to serialize to both CodedOutputStream and directly into byte arrays // without duplicating the code. In fact we might want extra output channels in // the future. template struct OutputHelper; template void SerializeTo(const void* ptr, O* output) { OutputHelper::Serialize(ptr, output); } template void WriteTagTo(uint32 tag, O* output) { SerializeTo(&tag, output); } template void WriteLengthTo(uint32 length, O* output) { SerializeTo(&length, output); } // Specialization for coded output stream template struct OutputHelper<::google::protobuf::io::CodedOutputStream, type> { static void Serialize(const void* ptr, ::google::protobuf::io::CodedOutputStream* output) { PrimitiveTypeHelper::Serialize(ptr, output); } }; // Specialization for writing into a plain array struct ArrayOutput { uint8* ptr; bool is_deterministic; }; template struct OutputHelper { static void Serialize(const void* ptr, ArrayOutput* output) { output->ptr = PrimitiveTypeHelper::SerializeToArray(ptr, output->ptr); } }; void SerializeMessageNoTable(const MessageLite* msg, ::google::protobuf::io::CodedOutputStream* output) { msg->SerializeWithCachedSizes(output); } void SerializeMessageNoTable(const MessageLite* msg, ArrayOutput* output) { output->ptr = msg->InternalSerializeWithCachedSizesToArray( output->is_deterministic, output->ptr); } // Helper to branch to fast path if possible void SerializeMessageDispatch(const ::google::protobuf::MessageLite& msg, const FieldMetadata* field_table, int num_fields, int32 cached_size, ::google::protobuf::io::CodedOutputStream* output) { const uint8* base = reinterpret_cast(&msg); // Try the fast path uint8* ptr = output->GetDirectBufferForNBytesAndAdvance(cached_size); if (ptr) { // We use virtual dispatch to enable dedicated generated code for the // fast path. msg.InternalSerializeWithCachedSizesToArray( output->IsSerializationDeterministic(), ptr); return; } SerializeInternal(base, field_table, num_fields, output); } // Helper to branch to fast path if possible void SerializeMessageDispatch(const ::google::protobuf::MessageLite& msg, const FieldMetadata* field_table, int num_fields, int32 cached_size, ArrayOutput* output) { const uint8* base = reinterpret_cast(&msg); output->ptr = SerializeInternalToArray(base, field_table, num_fields, output->is_deterministic, output->ptr); } // Serializing messages is special as it's not a primitive type and needs an // explicit overload for each output type. template void SerializeMessageTo(const MessageLite* msg, const void* table_ptr, O* output) { const SerializationTable* table = static_cast(table_ptr); if (!table) { // Proto1 WriteLengthTo(msg->GetCachedSize(), output); SerializeMessageNoTable(msg, output); return; } const FieldMetadata* field_table = table->field_table; const uint8* base = reinterpret_cast(msg); int cached_size = *reinterpret_cast(base + field_table->offset); WriteLengthTo(cached_size, output); int num_fields = table->num_fields - 1; SerializeMessageDispatch(*msg, field_table + 1, num_fields, cached_size, output); } // Almost the same as above only it doesn't output the length field. template void SerializeGroupTo(const MessageLite* msg, const void* table_ptr, O* output) { const SerializationTable* table = static_cast(table_ptr); if (!table) { // Proto1 SerializeMessageNoTable(msg, output); return; } const FieldMetadata* field_table = table->field_table; const uint8* base = reinterpret_cast(msg); int cached_size = *reinterpret_cast(base + field_table->offset); int num_fields = table->num_fields - 1; SerializeMessageDispatch(*msg, field_table + 1, num_fields, cached_size, output); } template struct SingularFieldHelper { template static void Serialize(const void* field, const FieldMetadata& md, O* output) { WriteTagTo(md.tag, output); SerializeTo(field, output); } }; template <> struct SingularFieldHelper { template static void Serialize(const void* field, const FieldMetadata& md, O* output) { WriteTagTo(md.tag, output); SerializeTo(&Get(field).Get(), output); } }; template <> struct SingularFieldHelper : SingularFieldHelper {}; template <> struct SingularFieldHelper { template static void Serialize(const void* field, const FieldMetadata& md, O* output) { WriteTagTo(md.tag, output); SerializeGroupTo(Get(field), static_cast(md.ptr), output); WriteTagTo(md.tag + 1, output); } }; template <> struct SingularFieldHelper { template static void Serialize(const void* field, const FieldMetadata& md, O* output) { WriteTagTo(md.tag, output); SerializeMessageTo(Get(field), static_cast(md.ptr), output); } }; template <> struct SingularFieldHelper { template static void Serialize(const void* field, const FieldMetadata& md, O* output) { WriteTagTo(md.tag, output); SerializeTo(&Get<::std::string>(field), output); } }; template struct RepeatedFieldHelper { template static void Serialize(const void* field, const FieldMetadata& md, O* output) { typedef typename PrimitiveTypeHelper::Type T; const RepeatedField& array = Get >(field); for (int i = 0; i < array.size(); i++) { WriteTagTo(md.tag, output); SerializeTo(&array[i], output); } } }; // We need to use a helper class to get access to the private members class AccessorHelper { public: static int Size(const RepeatedPtrFieldBase& x) { return x.size(); } static void const* Get(const RepeatedPtrFieldBase& x, int idx) { return x.raw_data()[idx]; } }; template <> struct RepeatedFieldHelper { template static void Serialize(const void* field, const FieldMetadata& md, O* output) { const internal::RepeatedPtrFieldBase& array = Get(field); for (int i = 0; i < AccessorHelper::Size(array); i++) { WriteTagTo(md.tag, output); SerializeTo(AccessorHelper::Get(array, i), output); } } }; template <> struct RepeatedFieldHelper : RepeatedFieldHelper {}; template <> struct RepeatedFieldHelper { template static void Serialize(const void* field, const FieldMetadata& md, O* output) { const internal::RepeatedPtrFieldBase& array = Get(field); for (int i = 0; i < AccessorHelper::Size(array); i++) { WriteTagTo(md.tag, output); SerializeGroupTo( static_cast(AccessorHelper::Get(array, i)), static_cast(md.ptr), output); WriteTagTo(md.tag + 1, output); } } }; template <> struct RepeatedFieldHelper { template static void Serialize(const void* field, const FieldMetadata& md, O* output) { const internal::RepeatedPtrFieldBase& array = Get(field); for (int i = 0; i < AccessorHelper::Size(array); i++) { WriteTagTo(md.tag, output); SerializeMessageTo( static_cast(AccessorHelper::Get(array, i)), md.ptr, output); } } }; template <> struct RepeatedFieldHelper : RepeatedFieldHelper {}; template struct PackedFieldHelper { template static void Serialize(const void* field, const FieldMetadata& md, O* output) { typedef typename PrimitiveTypeHelper::Type T; const RepeatedField& array = Get >(field); if (array.empty()) return; WriteTagTo(md.tag, output); int cached_size = Get(static_cast(field) + sizeof(RepeatedField)); WriteLengthTo(cached_size, output); for (int i = 0; i < array.size(); i++) { SerializeTo(&array[i], output); } } }; template <> struct PackedFieldHelper { template static void Serialize(const void* field, const FieldMetadata& md, O* output) { GOOGLE_LOG(FATAL) << "Not implemented field number " << md.tag << " with type " << md.type; } }; template <> struct PackedFieldHelper : PackedFieldHelper {}; template <> struct PackedFieldHelper : PackedFieldHelper {}; template <> struct PackedFieldHelper : PackedFieldHelper {}; template <> struct PackedFieldHelper : PackedFieldHelper {}; template struct OneOfFieldHelper { template static void Serialize(const void* field, const FieldMetadata& md, O* output) { SingularFieldHelper::Serialize(field, md, output); } }; template <> struct OneOfFieldHelper { template static void Serialize(const void* field, const FieldMetadata& md, O* output) { SingularFieldHelper::Serialize( Get(field), md, output); } }; void SerializeNotImplemented(int field) { GOOGLE_LOG(FATAL) << "Not implemented field number " << field; } // When switching to c++11 we should make these constexpr functions #define SERIALIZE_TABLE_OP(type, type_class) \ ((type - 1) + static_cast(type_class) * FieldMetadata::kNumTypes) int FieldMetadata::CalculateType(int type, FieldMetadata::FieldTypeClass type_class) { return SERIALIZE_TABLE_OP(type, type_class); } template bool IsNull(const void* ptr) { return *static_cast::Type*>(ptr) == 0; } template <> bool IsNull(const void* ptr) { return static_cast(ptr)->Get().size() == 0; } template <> bool IsNull(const void* ptr) { return static_cast(ptr)->Get().size() == 0; } template <> bool IsNull(const void* ptr) { return Get(ptr) == NULL; } template <> bool IsNull(const void* ptr) { return Get(ptr) == NULL; } template <> bool IsNull(const void* ptr) { return static_cast(ptr)->empty(); } #define SERIALIZERS_FOR_TYPE(type) \ case SERIALIZE_TABLE_OP(type, FieldMetadata::kPresence): \ if (!IsPresent(base, field_metadata.has_offset)) continue; \ SingularFieldHelper::Serialize(ptr, field_metadata, output); \ break; \ case SERIALIZE_TABLE_OP(type, FieldMetadata::kNoPresence): \ if (IsNull(ptr)) continue; \ SingularFieldHelper::Serialize(ptr, field_metadata, output); \ break; \ case SERIALIZE_TABLE_OP(type, FieldMetadata::kRepeated): \ RepeatedFieldHelper::Serialize(ptr, field_metadata, output); \ break; \ case SERIALIZE_TABLE_OP(type, FieldMetadata::kPacked): \ PackedFieldHelper::Serialize(ptr, field_metadata, output); \ break; \ case SERIALIZE_TABLE_OP(type, FieldMetadata::kOneOf): \ if (!IsOneofPresent(base, field_metadata.has_offset, field_metadata.tag)) \ continue; \ OneOfFieldHelper::Serialize(ptr, field_metadata, output); \ break void SerializeInternal(const uint8* base, const FieldMetadata* field_metadata_table, int32 num_fields, ::google::protobuf::io::CodedOutputStream* output) { for (int i = 0; i < num_fields; i++) { const FieldMetadata& field_metadata = field_metadata_table[i]; const uint8* ptr = base + field_metadata.offset; switch (field_metadata.type) { SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_DOUBLE); SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_FLOAT); SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_INT64); SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_UINT64); SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_INT32); SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_FIXED64); SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_FIXED32); SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_BOOL); SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_STRING); SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_GROUP); SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_MESSAGE); SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_BYTES); SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_UINT32); SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_ENUM); SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_SFIXED32); SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_SFIXED64); SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_SINT32); SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_SINT64); SERIALIZERS_FOR_TYPE(FieldMetadata::kInlinedType); // Special cases case FieldMetadata::kSpecial: reinterpret_cast( const_cast(field_metadata.ptr))( base, field_metadata.offset, field_metadata.tag, field_metadata.has_offset, output); break; default: // __builtin_unreachable() SerializeNotImplemented(field_metadata.type); } } } uint8* SerializeInternalToArray(const uint8* base, const FieldMetadata* field_metadata_table, int32 num_fields, bool is_deterministic, uint8* buffer) { ArrayOutput array_output = {buffer, is_deterministic}; ArrayOutput* output = &array_output; for (int i = 0; i < num_fields; i++) { const FieldMetadata& field_metadata = field_metadata_table[i]; const uint8* ptr = base + field_metadata.offset; switch (field_metadata.type) { SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_DOUBLE); SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_FLOAT); SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_INT64); SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_UINT64); SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_INT32); SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_FIXED64); SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_FIXED32); SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_BOOL); SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_STRING); SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_GROUP); SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_MESSAGE); SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_BYTES); SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_UINT32); SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_ENUM); SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_SFIXED32); SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_SFIXED64); SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_SINT32); SERIALIZERS_FOR_TYPE(WireFormatLite::TYPE_SINT64); SERIALIZERS_FOR_TYPE(FieldMetadata::kInlinedType); // Special cases case FieldMetadata::kSpecial: { io::ArrayOutputStream array_stream(array_output.ptr, INT_MAX); io::CodedOutputStream output(&array_stream); output.SetSerializationDeterministic(is_deterministic); reinterpret_cast( const_cast(field_metadata.ptr))( base, field_metadata.offset, field_metadata.tag, field_metadata.has_offset, &output); array_output.ptr += output.ByteCount(); } break; default: // __builtin_unreachable() SerializeNotImplemented(field_metadata.type); } } return array_output.ptr; } #undef SERIALIZERS_FOR_TYPE void ExtensionSerializer(const uint8* ptr, uint32 offset, uint32 tag, uint32 has_offset, ::google::protobuf::io::CodedOutputStream* output) { reinterpret_cast(ptr + offset) ->SerializeWithCachedSizes(tag, has_offset, output); } void UnknownFieldSerializerLite(const uint8* ptr, uint32 offset, uint32 tag, uint32 has_offset, ::google::protobuf::io::CodedOutputStream* output) { output->WriteString( reinterpret_cast(ptr + offset) ->unknown_fields()); } MessageLite* DuplicateIfNonNullInternal(MessageLite* message) { if (message) { MessageLite* ret = message->New(); ret->CheckTypeAndMergeFrom(*message); return ret; } else { return NULL; } } // Returns a message owned by this Arena. This may require Own()ing or // duplicating the message. MessageLite* GetOwnedMessageInternal(Arena* message_arena, MessageLite* submessage, Arena* submessage_arena) { GOOGLE_DCHECK(submessage->GetArena() == submessage_arena); GOOGLE_DCHECK(message_arena != submessage_arena); if (message_arena != NULL && submessage_arena == NULL) { message_arena->Own(submessage); return submessage; } else { MessageLite* ret = submessage->New(message_arena); ret->CheckTypeAndMergeFrom(*submessage); return ret; } } namespace { void InitSCC_DFS(SCCInfoBase* scc) { if (scc->visit_status.load(std::memory_order_relaxed) != SCCInfoBase::kUninitialized) return; scc->visit_status.store(SCCInfoBase::kRunning, std::memory_order_relaxed); // Each base is followed by an array of pointers to deps auto deps = reinterpret_cast(scc + 1); for (int i = 0; i < scc->num_deps; i++) { if (deps[i]) InitSCC_DFS(deps[i]); } scc->init_func(); // Mark done (note we use memory order release here), other threads could // now see this as initialized and thus the initialization must have happened // before. scc->visit_status.store(SCCInfoBase::kInitialized, std::memory_order_release); } } // namespace void InitSCCImpl(SCCInfoBase* scc) { static WrappedMutex mu{GOOGLE_PROTOBUF_LINKER_INITIALIZED}; // Either the default in case no initialization is running or the id of the // thread that is currently initializing. static std::atomic runner; auto me = std::this_thread::get_id(); // This will only happen because the constructor will call InitSCC while // constructing the default instance. if (runner.load(std::memory_order_relaxed) == me) { // Because we're in the process of constructing the default instance. // We can be assured that we're already exploring this SCC. GOOGLE_CHECK_EQ(scc->visit_status.load(std::memory_order_relaxed), SCCInfoBase::kRunning); return; } InitProtobufDefaults(); mu.Lock(); runner.store(me, std::memory_order_relaxed); InitSCC_DFS(scc); runner.store(std::thread::id{}, std::memory_order_relaxed); mu.Unlock(); } } // namespace internal } // namespace protobuf } // namespace google