PageRenderTime 46ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/libs/Microsoft.Scripting/Runtime/SymbolDictionary.cs

http://ironlua.googlecode.com/
C# | 487 lines | 371 code | 79 blank | 37 comment | 79 complexity | 29df676b3cb75872c995770070c3cb3c 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;
  16. using System.Collections;
  17. using System.Collections.Generic;
  18. using System.Text;
  19. using System.Diagnostics;
  20. using Microsoft.Scripting.Utils;
  21. using Microsoft.Contracts;
  22. namespace Microsoft.Scripting.Runtime {
  23. /// <summary>
  24. /// Simple thread-safe SymbolDictionary used for storing collections of members.
  25. ///
  26. /// Like all SymbolDictionaries this supports both indexing using SymbolId's (IAttributesCollection)
  27. /// and via object keys (IDictionary&lt;object, object&gt;).
  28. /// </summary>
  29. public sealed class SymbolDictionary : BaseSymbolDictionary, IDictionary, IDictionary<object, object>, IAttributesCollection {
  30. private Dictionary<SymbolId, object> _data = new Dictionary<SymbolId, object>();
  31. public SymbolDictionary() {
  32. }
  33. public SymbolDictionary(IAttributesCollection from) {
  34. // enumeration of a dictionary requires locking
  35. // the target dictionary.
  36. lock (from) {
  37. foreach (KeyValuePair<object, object> kvp in from) {
  38. AsObjectKeyedDictionary().Add(kvp.Key, kvp.Value);
  39. }
  40. }
  41. }
  42. /// <summary>
  43. /// Symbol dictionaries are usually indexed using literal strings, which is handled using the Symbols.
  44. /// However, some languages allow non-string keys too. We handle this case by lazily creating an object-keyed dictionary,
  45. /// and keeping it in the symbol-indexed dictionary. Such access is slower, which is acceptable.
  46. /// </summary>
  47. private Dictionary<object, object> GetObjectKeysDictionary() {
  48. Dictionary<object, object> objData = GetObjectKeysDictionaryIfExists();
  49. if (objData == null) {
  50. objData = new Dictionary<object, object>();
  51. _data.Add(BaseSymbolDictionary.ObjectKeys, objData);
  52. }
  53. return objData;
  54. }
  55. private Dictionary<object, object> GetObjectKeysDictionaryIfExists() {
  56. object objData;
  57. if (_data.TryGetValue(BaseSymbolDictionary.ObjectKeys, out objData))
  58. return (Dictionary<object, object>)objData;
  59. return null;
  60. }
  61. #region IDictionary<object, object> Members
  62. void IDictionary<object, object>.Add(object key, object value) {
  63. Debug.Assert(!(key is SymbolId));
  64. string strKey = key as string;
  65. lock (this) {
  66. if (strKey != null) {
  67. _data.Add(SymbolTable.StringToId(strKey), value);
  68. } else {
  69. Dictionary<object, object> objData = GetObjectKeysDictionary();
  70. objData[key] = value;
  71. }
  72. }
  73. }
  74. [Confined]
  75. bool IDictionary<object, object>.ContainsKey(object key) {
  76. Debug.Assert(!(key is SymbolId));
  77. string strKey = key as string;
  78. lock (this) {
  79. if (strKey != null) {
  80. if (!SymbolTable.StringHasId(strKey)) {
  81. // Avoid creating a SymbolID if this string does not already have one
  82. return false;
  83. }
  84. return _data.ContainsKey(SymbolTable.StringToId(strKey));
  85. } else {
  86. Dictionary<object, object> objData = GetObjectKeysDictionaryIfExists();
  87. if (objData == null) return false;
  88. return objData.ContainsKey(key);
  89. }
  90. }
  91. }
  92. ICollection<object>/*!*/ IDictionary<object, object>.Keys {
  93. get {
  94. // data.Keys is typed as ICollection<SymbolId>. Hence, we cannot return as a ICollection<object>.
  95. // Instead, we need to copy the data to a List<object>
  96. List<object> res = new List<object>();
  97. lock (this) {
  98. foreach (SymbolId x in _data.Keys) {
  99. if (x == BaseSymbolDictionary.ObjectKeys) continue;
  100. res.Add(SymbolTable.IdToString(x));
  101. }
  102. Dictionary<object, object> objData = GetObjectKeysDictionaryIfExists();
  103. if (objData != null) res.AddRange(objData.Keys);
  104. }
  105. return res;
  106. }
  107. }
  108. bool IDictionary<object, object>.Remove(object key) {
  109. Debug.Assert(!(key is SymbolId));
  110. string strKey = key as string;
  111. lock (this) {
  112. if (strKey != null) {
  113. return _data.Remove(SymbolTable.StringToId(strKey));
  114. } else {
  115. Dictionary<object, object> objData = GetObjectKeysDictionaryIfExists();
  116. if (objData == null) return false;
  117. return objData.Remove(key);
  118. }
  119. }
  120. }
  121. bool IDictionary<object, object>.TryGetValue(object key, out object value) {
  122. Debug.Assert(!(key is SymbolId));
  123. string strKey = key as string;
  124. lock (this) {
  125. if (strKey != null) {
  126. return _data.TryGetValue(SymbolTable.StringToId(strKey), out value);
  127. } else {
  128. value = null;
  129. Dictionary<object, object> objData = GetObjectKeysDictionaryIfExists();
  130. if (objData == null) return false;
  131. return objData.TryGetValue(key, out value);
  132. }
  133. }
  134. }
  135. ICollection<object>/*!*/ IDictionary<object, object>.Values {
  136. get {
  137. // Are there any object-keys? If not we can use a fast-path
  138. lock (this) {
  139. Dictionary<object, object> objData = GetObjectKeysDictionaryIfExists();
  140. if (objData == null)
  141. return _data.Values;
  142. // There any object-keys. We need to flatten out all the values
  143. List<object> res = new List<object>();
  144. foreach (KeyValuePair<SymbolId, object> x in _data) {
  145. if (x.Key == BaseSymbolDictionary.ObjectKeys) continue;
  146. res.Add(x.Value);
  147. }
  148. foreach (object o in objData.Values) {
  149. res.Add(o);
  150. }
  151. return res;
  152. }
  153. }
  154. }
  155. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1065:DoNotRaiseExceptionsInUnexpectedLocations")]
  156. public object this[object key] {
  157. get {
  158. Debug.Assert(!(key is SymbolId));
  159. string strKey = key as string;
  160. lock (this) {
  161. if (strKey != null) {
  162. object value;
  163. if (_data.TryGetValue(SymbolTable.StringToId(strKey), out value))
  164. return value;
  165. } else {
  166. Dictionary<object, object> objData = GetObjectKeysDictionaryIfExists();
  167. if (objData != null)
  168. return objData[key];
  169. }
  170. }
  171. throw new KeyNotFoundException(String.Format("'{0}'", key));
  172. }
  173. set {
  174. Debug.Assert(!(key is SymbolId));
  175. string strKey = key as string;
  176. lock (this) {
  177. if (strKey != null) {
  178. _data[SymbolTable.StringToId(strKey)] = value;
  179. } else {
  180. Dictionary<object, object> objData = GetObjectKeysDictionary();
  181. objData[key] = value;
  182. }
  183. }
  184. }
  185. }
  186. #endregion
  187. #region ICollection<KeyValuePair<object, object>> Members
  188. public void Add(KeyValuePair<object, object> item) {
  189. string strKey = item.Key as string;
  190. lock (this) {
  191. if (strKey != null) {
  192. _data.Add(SymbolTable.StringToId(strKey), item.Value);
  193. } else {
  194. Dictionary<object, object> objData = GetObjectKeysDictionary();
  195. objData[item.Key] = item.Value;
  196. }
  197. }
  198. }
  199. public void Clear() {
  200. lock (this) _data.Clear();
  201. }
  202. [Confined]
  203. public bool Contains(KeyValuePair<object, object> item) {
  204. object value;
  205. if (AsObjectKeyedDictionary().TryGetValue(item.Key, out value) && value == item.Value) return true;
  206. return false;
  207. }
  208. public void CopyTo(KeyValuePair<object, object>[]/*!*/ array, int arrayIndex) {
  209. // TODO:
  210. throw new NotImplementedException();
  211. }
  212. public int Count {
  213. get {
  214. lock (this) {
  215. int count = _data.Count;
  216. Dictionary<object, object> objData = GetObjectKeysDictionaryIfExists();
  217. if (objData != null) {
  218. // -1 is because data contains objData
  219. count += objData.Count - 1;
  220. }
  221. return count;
  222. }
  223. }
  224. }
  225. public bool IsReadOnly {
  226. get { return false; }
  227. }
  228. public bool Remove(KeyValuePair<object, object> item) {
  229. lock (this) {
  230. string strKey = item.Key as string;
  231. if (strKey != null) {
  232. object value;
  233. if (AsObjectKeyedDictionary().TryGetValue(strKey, out value) && value == item.Value) {
  234. _data.Remove(SymbolTable.StringToId(strKey));
  235. return true;
  236. }
  237. }
  238. }
  239. return false;
  240. }
  241. #endregion
  242. #region IEnumerable<KeyValuePair<object,object>> Members
  243. [Pure]
  244. IEnumerator<KeyValuePair<object, object>>/*!*/ IEnumerable<KeyValuePair<object, object>>.GetEnumerator() {
  245. lock (this) {
  246. foreach (KeyValuePair<SymbolId, object> o in _data) {
  247. if (o.Key == BaseSymbolDictionary.ObjectKeys) continue;
  248. yield return new KeyValuePair<object, object>(SymbolTable.IdToString(o.Key), o.Value);
  249. }
  250. Dictionary<object, object> objData = GetObjectKeysDictionaryIfExists();
  251. if (objData != null) {
  252. foreach (KeyValuePair<object, object> o in objData) {
  253. yield return o;
  254. }
  255. }
  256. }
  257. }
  258. #endregion
  259. #region IEnumerable Members
  260. [Pure]
  261. public System.Collections.IEnumerator/*!*/ GetEnumerator() {
  262. foreach (KeyValuePair<SymbolId, object> o in _data) {
  263. if (o.Key == BaseSymbolDictionary.ObjectKeys) continue;
  264. yield return SymbolTable.IdToString(o.Key);
  265. }
  266. IDictionary<object, object> objData = GetObjectKeysDictionaryIfExists();
  267. if (objData != null) {
  268. foreach (object o in objData.Keys)
  269. yield return o;
  270. }
  271. }
  272. #endregion
  273. #region IAttributesDictionary Members
  274. public void Add(SymbolId key, object value) {
  275. lock (this) _data.Add(key, value);
  276. }
  277. public bool ContainsKey(SymbolId key) {
  278. lock (this) return _data.ContainsKey(key);
  279. }
  280. public bool Remove(SymbolId key) {
  281. lock (this) return _data.Remove(key);
  282. }
  283. public bool TryGetValue(SymbolId key, out object value) {
  284. lock (this) return _data.TryGetValue(key, out value);
  285. }
  286. object IAttributesCollection.this[SymbolId key] {
  287. get {
  288. lock (this) return _data[key];
  289. }
  290. set {
  291. lock (this) _data[key] = value;
  292. }
  293. }
  294. public IDictionary<SymbolId, object> SymbolAttributes {
  295. get {
  296. lock (this) {
  297. if (GetObjectKeysDictionaryIfExists() == null) return _data;
  298. Dictionary<SymbolId, object> d = new Dictionary<SymbolId, object>();
  299. foreach (KeyValuePair<SymbolId, object> name in _data) {
  300. if (name.Key == BaseSymbolDictionary.ObjectKeys) continue;
  301. d.Add(name.Key, name.Value);
  302. }
  303. return d;
  304. }
  305. }
  306. }
  307. public void AddObjectKey(object key, object value) {
  308. AsObjectKeyedDictionary().Add(key, value);
  309. }
  310. public bool ContainsObjectKey(object key) {
  311. return AsObjectKeyedDictionary().ContainsKey(key);
  312. }
  313. public bool RemoveObjectKey(object key) {
  314. return AsObjectKeyedDictionary().Remove(key);
  315. }
  316. public bool TryGetObjectValue(object key, out object value) {
  317. return AsObjectKeyedDictionary().TryGetValue(key, out value);
  318. }
  319. public ICollection<object> Keys { get { return AsObjectKeyedDictionary().Keys; } }
  320. public override IDictionary<object, object> AsObjectKeyedDictionary() {
  321. return this;
  322. }
  323. #endregion
  324. #region IDictionary Members
  325. void IDictionary.Add(object/*!*/ key, object value) {
  326. AsObjectKeyedDictionary().Add(key, value);
  327. }
  328. [Pure]
  329. public bool Contains(object/*!*/ key) {
  330. lock (this) return AsObjectKeyedDictionary().ContainsKey(key);
  331. }
  332. [Pure]
  333. IDictionaryEnumerator/*!*/ IDictionary.GetEnumerator() {
  334. Dictionary<object, object> objData = GetObjectKeysDictionaryIfExists();
  335. if (objData == null) return new TransformDictionaryEnumerator(_data);
  336. List<IDictionaryEnumerator> enums = new List<IDictionaryEnumerator>();
  337. enums.Add(new TransformDictionaryEnumerator(_data));
  338. Dictionary<object, object>.Enumerator objDataEnumerator = objData.GetEnumerator();
  339. enums.Add(objDataEnumerator);
  340. return new DictionaryUnionEnumerator(enums);
  341. }
  342. public bool IsFixedSize {
  343. get { return false; }
  344. }
  345. ICollection/*!*/ IDictionary.Keys {
  346. get {
  347. // data.Keys is typed as ICollection<SymbolId>. Hence, we cannot return as a ICollection.
  348. // Instead, we need to copy the data to a List.
  349. List<object> res = new List<object>();
  350. lock (this) {
  351. foreach (SymbolId x in _data.Keys) {
  352. if (x == BaseSymbolDictionary.ObjectKeys) continue;
  353. res.Add(SymbolTable.IdToString(x));
  354. }
  355. Dictionary<object, object> objData = GetObjectKeysDictionaryIfExists();
  356. if (objData != null) res.AddRange(objData.Keys);
  357. }
  358. return res;
  359. }
  360. }
  361. void IDictionary.Remove(object/*!*/ key) {
  362. Debug.Assert(!(key is SymbolId));
  363. string strKey = key as string;
  364. lock (this) {
  365. if (strKey != null) {
  366. _data.Remove(SymbolTable.StringToId(strKey));
  367. } else {
  368. Dictionary<object, object> objData = GetObjectKeysDictionaryIfExists();
  369. if (objData != null)
  370. objData.Remove(key);
  371. }
  372. }
  373. }
  374. ICollection/*!*/ IDictionary.Values {
  375. get {
  376. List<object> res = new List<object>();
  377. lock (this) {
  378. foreach (KeyValuePair<SymbolId, object> x in _data) {
  379. if (x.Key == BaseSymbolDictionary.ObjectKeys) continue;
  380. res.Add(x.Value);
  381. }
  382. Dictionary<object, object> objData = GetObjectKeysDictionaryIfExists();
  383. if (objData != null) res.AddRange(objData.Values);
  384. }
  385. return res;
  386. }
  387. }
  388. object IDictionary.this[object/*!*/ key] {
  389. get { return AsObjectKeyedDictionary()[key]; }
  390. set { AsObjectKeyedDictionary()[key] = value; }
  391. }
  392. #endregion
  393. public void CopyTo(Array/*!*/ array, int index) {
  394. throw new NotImplementedException("The method or operation is not implemented.");
  395. }
  396. public bool IsSynchronized {
  397. get {
  398. return true;
  399. }
  400. }
  401. public object/*!*/ SyncRoot {
  402. get {
  403. // TODO: We should really lock on something else...
  404. return this;
  405. }
  406. }
  407. }
  408. }