/IronPython_2_0/Src/Microsoft.Scripting/SymbolTable.cs

# · C# · 154 lines · 98 code · 29 blank · 27 comment · 22 complexity · 9990a97fa466e63fc26ae91279145efc MD5 · raw file

  1. /* ****************************************************************************
  2. *
  3. * Copyright (c) Microsoft Corporation.
  4. *
  5. * This source code is subject to terms and conditions of the Microsoft Public License. A
  6. * copy of the license can be found in the License.html file at the root of this distribution. If
  7. * you cannot locate the Microsoft Public License, please send an email to
  8. * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
  9. * by the terms of the Microsoft Public License.
  10. *
  11. * You must not remove this notice, or any other, from this software.
  12. *
  13. *
  14. * ***************************************************************************/
  15. using System; using Microsoft;
  16. using System.Collections.Generic;
  17. using System.Diagnostics;
  18. using Microsoft.Scripting.Utils;
  19. namespace Microsoft.Scripting {
  20. public static class SymbolTable {
  21. private static readonly object _lockObj = new object();
  22. private static readonly Dictionary<string, int> _idDict = new Dictionary<string, int>(InitialTableSize);
  23. private const int InitialTableSize = 256;
  24. private static readonly Dictionary<int, string> _fieldDict = CreateFieldDictionary();
  25. [MultiRuntimeAware]
  26. private static int _nextCaseInsensitiveId = 1;
  27. private static Dictionary<int, string> CreateFieldDictionary() {
  28. Dictionary<int, string> result = new Dictionary<int, string>(InitialTableSize);
  29. result[0] = null; // initialize the null string
  30. return result;
  31. }
  32. public static SymbolId StringToId(string field) {
  33. ContractUtils.RequiresNotNull(field, "field");
  34. int res;
  35. lock (_lockObj) {
  36. // First, look up the identifier case-sensitively.
  37. if (!_idDict.TryGetValue(field, out res)) {
  38. string invariantField = field.ToUpper(System.Globalization.CultureInfo.InvariantCulture);
  39. // OK, didn't find it, so let's look up the case-insensitive
  40. // identifier.
  41. if (_idDict.TryGetValue(invariantField, out res)) {
  42. // OK, this is a new casing of an existing identifier.
  43. Debug.Assert(res < 0, "Must have invariant bit set!");
  44. // Throw if we've exhausted the number of casings.
  45. if (unchecked(((uint)res & 0x00FFFFFF) == 0x00FFFFFF)) {
  46. throw Error.CantAddCasing(field);
  47. }
  48. int invariantRes = res + 0x01000000;
  49. // Mask off the high bit.
  50. res = unchecked((int)((uint)res & 0x7FFFFFFF));
  51. _idDict[field] = res;
  52. _idDict[invariantField] = invariantRes;
  53. _fieldDict[res] = field;
  54. } else {
  55. // This is a whole new identifier.
  56. if (_nextCaseInsensitiveId == int.MaxValue) {
  57. throw Error.CantAddIdentifier(field);
  58. }
  59. // register new id...
  60. res = _nextCaseInsensitiveId++;
  61. // Console.WriteLine("Registering {0} as {1}", field, res);
  62. _fieldDict[res] = invariantField;
  63. if (field != invariantField) {
  64. res |= 0x01000000;
  65. _idDict[field] = res;
  66. _fieldDict[res] = field;
  67. }
  68. _idDict[invariantField] = unchecked((int)(((uint)res | 0x80000000) + 0x01000000));
  69. }
  70. } else {
  71. // If this happens to be the invariant field, then we need to
  72. // mask off the top byte, since that's just used to pick the next
  73. // id for this identifier.
  74. if (res < 0) {
  75. res &= 0x00FFFFFF;
  76. }
  77. }
  78. }
  79. return new SymbolId(res);
  80. }
  81. public static SymbolId StringToCaseInsensitiveId(string field) {
  82. return StringToId(field.ToUpper(System.Globalization.CultureInfo.InvariantCulture));
  83. }
  84. public static SymbolId[] QualifiedStringToIds(string fields) {
  85. if (fields != null) {
  86. string[] strings = fields.Split('.');
  87. SymbolId[] identifiers = new SymbolId[strings.Length];
  88. for (int i = 0; i < strings.Length; i++) {
  89. identifiers[i] = StringToId(strings[i]);
  90. }
  91. return identifiers;
  92. }
  93. return null;
  94. }
  95. public static string IdToString(SymbolId id) {
  96. return _fieldDict[id.Id];
  97. }
  98. // Tries to lookup the SymbolId to see if it is valid
  99. public static bool ContainsId(SymbolId id) {
  100. return _fieldDict.ContainsKey(id.Id);
  101. }
  102. public static string[] IdsToStrings(IList<SymbolId> ids) {
  103. string[] ret = new string[ids.Count];
  104. for (int i = 0; i < ids.Count; i++) {
  105. if (ids[i] == SymbolId.Empty) ret[i] = null;
  106. else ret[i] = IdToString(ids[i]);
  107. }
  108. return ret;
  109. }
  110. public static SymbolId[] StringsToIds(IList<string> strings) {
  111. SymbolId[] ret = new SymbolId[strings.Count];
  112. for (int i = 0; i < strings.Count; i++) {
  113. if (strings[i] == null) ret[i] = SymbolId.Empty;
  114. else ret[i] = StringToId(strings[i]);
  115. }
  116. return ret;
  117. }
  118. public static bool StringHasId(string symbol) {
  119. ContractUtils.RequiresNotNull(symbol, "symbol");
  120. lock (_lockObj) {
  121. return _idDict.ContainsKey(symbol);
  122. }
  123. }
  124. }
  125. }