| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266 | 
							- using System.Collections.Generic;
 
- using System;
 
- using System.Text;
 
- using System.Text.RegularExpressions;
 
- namespace Google.ProtocolBuffers.Descriptors {
 
-   /// <summary>
 
-   /// Contains lookup tables containing all the descriptors defined in a particular file.
 
-   /// </summary>
 
-   internal class DescriptorPool {
 
-     private readonly IDictionary<string, IDescriptor> descriptorsByName =
 
-         new Dictionary<string, IDescriptor>();
 
-     private readonly IDictionary<DescriptorIntPair, FieldDescriptor> fieldsByNumber =
 
-         new Dictionary<DescriptorIntPair, FieldDescriptor>();
 
-     private readonly IDictionary<DescriptorIntPair, EnumValueDescriptor> enumValuesByNumber =
 
-         new Dictionary<DescriptorIntPair, EnumValueDescriptor>();
 
-     private readonly DescriptorPool[] dependencies;
 
-     internal DescriptorPool(FileDescriptor[] dependencyFiles) {
 
-       dependencies = new DescriptorPool[dependencyFiles.Length];
 
-       for (int i = 0; i < dependencyFiles.Length; i++) {
 
-         dependencies[i] = dependencyFiles[i].DescriptorPool;
 
-       }
 
-       foreach (FileDescriptor dependency in dependencyFiles) {
 
-         AddPackage(dependency.Package, dependency);
 
-       }
 
-     }
 
-     /// <summary>
 
-     /// Finds a symbol of the given name within the pool.
 
-     /// </summary>
 
-     /// <typeparam name="T">The type of symbol to look for</typeparam>
 
-     /// <param name="fullName">Fully-qualified name to look up</param>
 
-     /// <returns>The symbol with the given name and type,
 
-     /// or null if the symbol doesn't exist or has the wrong type</returns>
 
-     internal T FindSymbol<T>(string fullName) where T : class, IDescriptor {
 
-       IDescriptor result;
 
-       descriptorsByName.TryGetValue(fullName, out result);
 
-       T descriptor = result as T;
 
-       if (descriptor != null) {
 
-         return descriptor;
 
-       }
 
-       foreach (DescriptorPool dependency in dependencies) {
 
-         dependency.descriptorsByName.TryGetValue(fullName, out result);
 
-         descriptor = result as T;
 
-         if (descriptor != null) {
 
-           return descriptor;
 
-         }
 
-       }
 
-       return null;
 
-     }
 
-     /// <summary>
 
-     /// Adds a package to the symbol tables. If a package by the same name
 
-     /// already exists, that is fine, but if some other kind of symbol
 
-     /// exists under the same name, an exception is thrown. If the package
 
-     /// has multiple components, this also adds the parent package(s).
 
-     /// </summary>
 
-     internal void AddPackage(string fullName, FileDescriptor file) {
 
-       int dotpos = fullName.LastIndexOf('.');
 
-       String name;
 
-       if (dotpos != -1) {
 
-         AddPackage(fullName.Substring(0, dotpos), file);
 
-         name = fullName.Substring(dotpos + 1);
 
-       } else {
 
-         name = fullName;
 
-       }
 
-       IDescriptor old;
 
-       if (descriptorsByName.TryGetValue(fullName, out old)) {
 
-         if (!(old is PackageDescriptor)) {
 
-           throw new DescriptorValidationException(file,
 
-            "\"" + name + "\" is already defined (as something other than a " +
 
-             "package) in file \"" + old.File.Name + "\".");
 
-         }
 
-       }
 
-       // TODO(jonskeet): Check issue 25 wrt the ordering of these parameters
 
-       descriptorsByName[fullName] = new PackageDescriptor(fullName, name, file);
 
-     }
 
-     /// <summary>
 
-     /// Adds a symbol to the symbol table.
 
-     /// </summary>
 
-     /// <exception cref="DescriptorValidationException">The symbol already existed
 
-     /// in the symbol table.</exception>
 
-     internal void AddSymbol(IDescriptor descriptor) {
 
-       ValidateSymbolName(descriptor);
 
-       String fullName = descriptor.FullName;
 
-       IDescriptor old;
 
-       if (descriptorsByName.TryGetValue(fullName, out old)) {
 
-         int dotPos = fullName.LastIndexOf('.');
 
-         string message;
 
-         if (descriptor.File == old.File) {
 
-           if (dotPos == -1) {
 
-             message = "\"" + fullName + "\" is already defined.";
 
-           } else {
 
-             message = "\"" + fullName.Substring(dotPos + 1) + "\" is already defined in \"" + fullName.Substring(0, dotPos) + "\".";
 
-           }
 
-         } else {
 
-           message = "\"" + fullName + "\" is already defined in file \"" + old.File.Name + "\".";
 
-         }
 
-         throw new DescriptorValidationException(descriptor, message);
 
-       }
 
-       descriptorsByName[fullName] = descriptor;
 
-     }
 
-     private static readonly Regex ValidationRegex = new Regex("^[_A-Za-z][_A-Za-z0-9]*$", RegexOptions.Compiled);
 
-     /// <summary>
 
-     /// Verifies that the descriptor's name is valid (i.e. it contains
 
-     /// only letters, digits and underscores, and does not start with a digit).
 
-     /// </summary>
 
-     /// <param name="descriptor"></param>
 
-     private static void ValidateSymbolName(IDescriptor descriptor) {
 
-       if (descriptor.Name == "") {
 
-         throw new DescriptorValidationException(descriptor, "Missing name.");
 
-       }
 
-       if (!ValidationRegex.IsMatch(descriptor.Name)) {
 
-         throw new DescriptorValidationException(descriptor,
 
-             "\"" + descriptor.Name + "\" is not a valid identifier.");
 
-       }
 
-     }
 
-     /// <summary>
 
-     /// Returns the field with the given number in the given descriptor,
 
-     /// or null if it can't be found.
 
-     /// </summary>
 
-     internal FieldDescriptor FindFieldByNumber(MessageDescriptor messageDescriptor, int number) {
 
-       FieldDescriptor ret;
 
-       fieldsByNumber.TryGetValue(new DescriptorIntPair(messageDescriptor, number), out ret);
 
-       return ret;
 
-     }
 
-     internal EnumValueDescriptor FindEnumValueByNumber(EnumDescriptor enumDescriptor, int number) {
 
-       EnumValueDescriptor ret;
 
-       enumValuesByNumber.TryGetValue(new DescriptorIntPair(enumDescriptor, number), out ret);
 
-       return ret;
 
-     }
 
-     /// <summary>
 
-     /// Adds a field to the fieldsByNumber table.
 
-     /// </summary>
 
-     /// <exception cref="DescriptorValidationException">A field with the same
 
-     /// containing type and number already exists.</exception>
 
-     internal void AddFieldByNumber(FieldDescriptor field) {
 
-       DescriptorIntPair key = new DescriptorIntPair(field.ContainingType, field.FieldNumber);
 
-       FieldDescriptor old;
 
-       if (fieldsByNumber.TryGetValue(key, out old)) {
 
-         throw new DescriptorValidationException(field, "Field number " + field.FieldNumber +
 
-           "has already been used in \"" + field.ContainingType.FullName +
 
-           "\" by field \"" + old.Name + "\".");
 
-       }
 
-       fieldsByNumber[key] = field;
 
-     }
 
-     /// <summary>
 
-     /// Adds an enum value to the enumValuesByNumber table. If an enum value
 
-     /// with the same type and number already exists, this method does nothing.
 
-     /// (This is allowed; the first value defined with the number takes precedence.)
 
-     /// </summary>
 
-     internal void AddEnumValueByNumber(EnumValueDescriptor enumValue) {
 
-       DescriptorIntPair key = new DescriptorIntPair(enumValue.EnumDescriptor, enumValue.Number);
 
-       if (!enumValuesByNumber.ContainsKey(key)) {
 
-         enumValuesByNumber[key] = enumValue;
 
-       }
 
-     }
 
-     /// <summary>
 
-     /// Looks up a descriptor by name, relative to some other descriptor.
 
-     /// The name may be fully-qualified (with a leading '.'), partially-qualified,
 
-     /// or unqualified. C++-like name lookup semantics are used to search for the
 
-     /// matching descriptor.
 
-     /// </summary>
 
-     public IDescriptor LookupSymbol(string name, IDescriptor relativeTo) {
 
-       // TODO(jonskeet):  This could be optimized in a number of ways.
 
-       IDescriptor result;
 
-       if (name.StartsWith(".")) {
 
-         // Fully-qualified name.
 
-         result = FindSymbol<IDescriptor>(name.Substring(1));
 
-       } else {
 
-         // If "name" is a compound identifier, we want to search for the
 
-         // first component of it, then search within it for the rest.
 
-         int firstPartLength = name.IndexOf('.');
 
-         string firstPart = firstPartLength == -1 ? name : name.Substring(0, firstPartLength);
 
-         // We will search each parent scope of "relativeTo" looking for the
 
-         // symbol.
 
-         StringBuilder scopeToTry = new StringBuilder(relativeTo.FullName);
 
-         while (true) {
 
-           // Chop off the last component of the scope.
 
-           // TODO(jonskeet): Make this more efficient. May not be worth using StringBuilder at all
 
-           int dotpos = scopeToTry.ToString().LastIndexOf(".");
 
-           if (dotpos == -1) {
 
-             result = FindSymbol<IDescriptor>(name);
 
-             break;
 
-           } else {
 
-             scopeToTry.Length = dotpos + 1;
 
-             // Append firstPart and try to find.
 
-             scopeToTry.Append(firstPart);
 
-             result = FindSymbol<IDescriptor>(scopeToTry.ToString());
 
-             if (result != null) {
 
-               if (firstPartLength != -1) {
 
-                 // We only found the first part of the symbol.  Now look for
 
-                 // the whole thing.  If this fails, we *don't* want to keep
 
-                 // searching parent scopes.
 
-                 scopeToTry.Length = dotpos + 1;
 
-                 scopeToTry.Append(name);
 
-                 result = FindSymbol<IDescriptor>(scopeToTry.ToString());
 
-               }
 
-               break;
 
-             }
 
-             // Not found.  Remove the name so we can try again.
 
-             scopeToTry.Length = dotpos;
 
-           }
 
-         }
 
-       }
 
-       if (result == null) {
 
-         throw new DescriptorValidationException(relativeTo, "\"" + name + "\" is not defined.");
 
-       } else {
 
-         return result;
 
-       }
 
-     }
 
-     /// <summary>
 
-     /// Struct used to hold the keys for the fieldByNumber table.
 
-     /// </summary>
 
-     struct DescriptorIntPair : IEquatable<DescriptorIntPair> {
 
-       private readonly int number;
 
-       private readonly IDescriptor descriptor;
 
-       internal DescriptorIntPair(IDescriptor descriptor, int number) {
 
-         this.number = number;
 
-         this.descriptor = descriptor;
 
-       }
 
-       public bool Equals(DescriptorIntPair other) {
 
-         return descriptor == other.descriptor
 
-             && number == other.number;
 
-       }
 
-       public override bool Equals(object obj) {
 
-         if (obj is DescriptorIntPair) {
 
-           return Equals((DescriptorIntPair)obj);
 
-         }
 
-         return false;
 
-       }
 
-       public override int GetHashCode() {
 
-         return descriptor.GetHashCode() * ((1 << 16) - 1) + number;
 
-       }
 
-     }
 
-   }
 
- }
 
 
  |