From 8f721f5dc76dd96fb8a3db38bf0be759cb4743c1 Mon Sep 17 00:00:00 2001 From: Jon Skeet Date: Thu, 14 Aug 2008 20:38:09 +0100 Subject: Experimental (and currently unused) behaviour to determine whether or not a message has any required fields. --- .../ProtocolBuffers/Descriptors/FileDescriptor.cs | 4 ++ .../Descriptors/MessageDescriptor.cs | 51 ++++++++++++++++++++++ csharp/ProtocolBuffers/GeneratedMessage.cs | 3 ++ 3 files changed, 58 insertions(+) (limited to 'csharp') diff --git a/csharp/ProtocolBuffers/Descriptors/FileDescriptor.cs b/csharp/ProtocolBuffers/Descriptors/FileDescriptor.cs index b3beea0b..429282b7 100644 --- a/csharp/ProtocolBuffers/Descriptors/FileDescriptor.cs +++ b/csharp/ProtocolBuffers/Descriptors/FileDescriptor.cs @@ -221,6 +221,10 @@ namespace Google.ProtocolBuffers.Descriptors { foreach (FieldDescriptor extension in extensions) { extension.CrossLink(); } + + foreach (MessageDescriptor message in messageTypes) { + message.CheckRequiredFields(); + } } /// diff --git a/csharp/ProtocolBuffers/Descriptors/MessageDescriptor.cs b/csharp/ProtocolBuffers/Descriptors/MessageDescriptor.cs index e3df02fe..f387a325 100644 --- a/csharp/ProtocolBuffers/Descriptors/MessageDescriptor.cs +++ b/csharp/ProtocolBuffers/Descriptors/MessageDescriptor.cs @@ -28,6 +28,7 @@ namespace Google.ProtocolBuffers.Descriptors { private readonly IList enumTypes; private readonly IList fields; private readonly IList extensions; + private bool hasRequiredFields; internal MessageDescriptor(DescriptorProto proto, FileDescriptor file, MessageDescriptor parent, int typeIndex) : base(proto, file, ComputeFullName(file, parent, proto.Name), typeIndex) { @@ -83,6 +84,16 @@ namespace Google.ProtocolBuffers.Descriptors { get { return enumTypes; } } + /// + /// Returns a pre-computed result as to whether this message + /// has required fields. This includes optional fields which are + /// message types which in turn have required fields, and any + /// extension fields. + /// + internal bool HasRequiredFields { + get { return hasRequiredFields; } + } + /// /// Determines if the given field number is an extension. /// @@ -131,5 +142,45 @@ namespace Google.ProtocolBuffers.Descriptors { extension.CrossLink(); } } + + internal void CheckRequiredFields() { + IDictionary alreadySeen = new Dictionary(); + hasRequiredFields = CheckRequiredFields(alreadySeen); + } + + private bool CheckRequiredFields(IDictionary alreadySeen) { + + if (alreadySeen.ContainsKey(this)) { + // The type is already in the cache. This means that either: + // a. The type has no required fields. + // b. We are in the midst of checking if the type has required fields, + // somewhere up the stack. In this case, we know that if the type + // has any required fields, they'll be found when we return to it, + // and the whole call to HasRequiredFields() will return true. + // Therefore, we don't have to check if this type has required fields + // here. + return false; + } + alreadySeen[this] = 0; // Value is irrelevant; we want set semantics + + // If the type allows extensions, an extension with message type could contain + // required fields, so we have to be conservative and assume such an + // extension exists. + if (Proto.ExtensionRangeCount != 0) { + return true; + } + + foreach (FieldDescriptor field in Fields) { + if (field.IsRequired) { + return true; + } + if (field.MappedType == MappedType.Message) { + if (field.MessageType.CheckRequiredFields(alreadySeen)) { + return true; + } + } + } + return false; + } } } diff --git a/csharp/ProtocolBuffers/GeneratedMessage.cs b/csharp/ProtocolBuffers/GeneratedMessage.cs index 6198afbf..47722d0b 100644 --- a/csharp/ProtocolBuffers/GeneratedMessage.cs +++ b/csharp/ProtocolBuffers/GeneratedMessage.cs @@ -68,6 +68,9 @@ namespace Google.ProtocolBuffers { public override bool IsInitialized { get { + /* if (!DescriptorForType.HasRequiredFields) { + return true; + }*/ // Check that all required fields are present. foreach (FieldDescriptor field in DescriptorForType.Fields) { if (field.IsRequired && !HasField(field)) { -- cgit v1.2.3