PageRenderTime 26ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/libs/Microsoft.Scripting/Runtime/CustomSymbolDictionary.cs

http://ironlua.googlecode.com/
C# | 617 lines | 437 code | 111 blank | 69 comment | 135 complexity | 73a9ce1d363bacd9307a626647cdb0b5 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.Diagnostics;
  19. using Microsoft.Scripting.Utils;
  20. using Microsoft.Contracts;
  21. namespace Microsoft.Scripting.Runtime {
  22. /// <summary>
  23. /// Abstract base class used for optimized thread-safe SymbolDictionaries.
  24. ///
  25. /// Implementers derive from this class and override the GetExtraKeys, TrySetExtraValue,
  26. /// and TryGetExtraValue methods. When looking up a value first the extra keys will be
  27. /// searched using the optimized Try*ExtraValue functions. If the value isn't found there
  28. /// then the value is stored in the underlying .NET dictionary.
  29. ///
  30. /// Implementors can optionally override the object key functionality to store object keys
  31. /// using their own mechanism. By default object keys are stored in their own dictionary
  32. /// which is stored in the primary SymbolId dictionary under an invalid symbol id.
  33. /// </summary>
  34. public abstract class CustomSymbolDictionary : BaseSymbolDictionary, IDictionary, IDictionary<object, object>, IAttributesCollection {
  35. private Dictionary<SymbolId, object> _data;
  36. protected CustomSymbolDictionary() {
  37. }
  38. /// <summary>
  39. /// Gets a list of the extra keys that are cached by the the optimized implementation
  40. /// of the module.
  41. /// </summary>
  42. public abstract SymbolId[] GetExtraKeys();
  43. /// <summary>
  44. /// Try to set the extra value and return true if the specified key was found in the
  45. /// list of extra values.
  46. /// </summary>
  47. protected internal abstract bool TrySetExtraValue(SymbolId key, object value);
  48. /// <summary>
  49. /// Try to get the extra value and returns true if the specified key was found in the
  50. /// list of extra values. Returns true even if the value is Uninitialized.
  51. /// </summary>
  52. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1007:UseGenericsWhereAppropriate")]
  53. protected internal abstract bool TryGetExtraValue(SymbolId key, out object value);
  54. private void InitializeData() {
  55. Debug.Assert(_data == null);
  56. _data = new Dictionary<SymbolId, object>();
  57. }
  58. /// <summary>
  59. /// Field dictionaries are usually indexed using literal strings, which is handled using the Symbols.
  60. /// However, Python does allow non-string keys too. We handle this case by lazily creating an object-keyed dictionary,
  61. /// and keeping it in the symbol-indexed dictionary. Such access is slower, which is acceptable.
  62. /// </summary>
  63. private Dictionary<object, object> GetObjectKeysDictionary() {
  64. Dictionary<object, object> objData = GetObjectKeysDictionaryIfExists();
  65. if (objData == null) {
  66. if (_data == null) InitializeData();
  67. objData = new Dictionary<object, object>();
  68. _data.Add(ObjectKeys, objData);
  69. }
  70. return objData;
  71. }
  72. private Dictionary<object, object> GetObjectKeysDictionaryIfExists() {
  73. if (_data == null) return null;
  74. object objData;
  75. if (_data.TryGetValue(ObjectKeys, out objData))
  76. return (Dictionary<object, object>)objData;
  77. return null;
  78. }
  79. #region IDictionary<object, object> Members
  80. void IDictionary<object, object>.Add(object key, object value) {
  81. Debug.Assert(!(key is SymbolId));
  82. string strKey = key as string;
  83. if (strKey != null) {
  84. lock (this) {
  85. if (_data == null) InitializeData();
  86. SymbolId keyId = SymbolTable.StringToId(strKey);
  87. if (TrySetExtraValue(keyId, value))
  88. return;
  89. _data.Add(keyId, value);
  90. }
  91. } else {
  92. AddObjectKey(key, value);
  93. }
  94. }
  95. [Confined]
  96. bool IDictionary<object, object>.ContainsKey(object key) {
  97. Debug.Assert(!(key is SymbolId));
  98. lock (this) {
  99. object dummy;
  100. return AsObjectKeyedDictionary().TryGetValue(key, out dummy);
  101. }
  102. }
  103. ICollection<object>/*!*/ IDictionary<object, object>.Keys {
  104. get {
  105. List<object> res = new List<object>();
  106. lock (this) if (_data != null) {
  107. foreach (SymbolId x in _data.Keys) {
  108. if (x == ObjectKeys) continue;
  109. res.Add(SymbolTable.IdToString(x));
  110. }
  111. }
  112. foreach (SymbolId key in GetExtraKeys()) {
  113. if (key.Id < 0) break;
  114. object dummy;
  115. if (TryGetExtraValue(key, out dummy) && dummy != Uninitialized.Instance) {
  116. res.Add(SymbolTable.IdToString(key));
  117. }
  118. }
  119. GetObjectKeys(res);
  120. return res;
  121. }
  122. }
  123. bool IDictionary<object, object>.Remove(object key) {
  124. Debug.Assert(!(key is SymbolId));
  125. string strKey = key as string;
  126. if (strKey != null) {
  127. lock (this) {
  128. SymbolId fieldId = SymbolTable.StringToId(strKey);
  129. if (TrySetExtraValue(fieldId, Uninitialized.Instance)) return true;
  130. if (_data == null) return false;
  131. return _data.Remove(fieldId);
  132. }
  133. }
  134. return RemoveObjectKey(key);
  135. }
  136. bool IDictionary<object, object>.TryGetValue(object key, out object value) {
  137. Debug.Assert(!(key is SymbolId));
  138. string strKey = key as string;
  139. if (strKey != null) {
  140. lock (this) {
  141. SymbolId fieldId = SymbolTable.StringToId(strKey);
  142. if (TryGetExtraValue(fieldId, out value) && value != Uninitialized.Instance) return true;
  143. if (_data == null) return false;
  144. return _data.TryGetValue(fieldId, out value);
  145. }
  146. }
  147. return TryGetObjectValue(key, out value);
  148. }
  149. ICollection<object>/*!*/ IDictionary<object, object>.Values {
  150. get {
  151. List<object> res = new List<object>();
  152. lock (this) {
  153. if (_data != null) {
  154. foreach (SymbolId x in _data.Keys) {
  155. if (x == ObjectKeys) continue;
  156. res.Add(_data[x]);
  157. }
  158. }
  159. }
  160. foreach (SymbolId key in GetExtraKeys()) {
  161. if (key.Id < 0) break;
  162. object value;
  163. if (TryGetExtraValue(key, out value) && value != Uninitialized.Instance) {
  164. res.Add(value);
  165. }
  166. }
  167. GetObjectValues(res);
  168. return res;
  169. }
  170. }
  171. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1065:DoNotRaiseExceptionsInUnexpectedLocations")]
  172. public object this[object key] {
  173. get {
  174. Debug.Assert(!(key is SymbolId));
  175. string strKey = key as string;
  176. object res;
  177. if (strKey != null) {
  178. lock (this) {
  179. SymbolId id = SymbolTable.StringToId(strKey);
  180. if (TryGetExtraValue(id, out res) && !(res is Uninitialized)) return res;
  181. if (_data == null) {
  182. throw new KeyNotFoundException(key.ToString());
  183. }
  184. return _data[id];
  185. }
  186. }
  187. if (TryGetObjectValue(key, out res))
  188. return res;
  189. throw new KeyNotFoundException(key.ToString());
  190. }
  191. set {
  192. Debug.Assert(!(key is SymbolId));
  193. string strKey = key as string;
  194. if (strKey != null) {
  195. lock (this) {
  196. SymbolId id = SymbolTable.StringToId(strKey);
  197. if (TrySetExtraValue(id, value)) return;
  198. if (_data == null) InitializeData();
  199. _data[id] = value;
  200. }
  201. } else {
  202. AddObjectKey(key, value);
  203. }
  204. }
  205. }
  206. #endregion
  207. #region ICollection<KeyValuePair<string,object>> Members
  208. public void Add(KeyValuePair<object, object> item) {
  209. throw new NotImplementedException();
  210. }
  211. public void Clear() {
  212. lock (this) {
  213. foreach (SymbolId key in GetExtraKeys()) {
  214. if (key.Id < 0) break;
  215. TrySetExtraValue(key, Uninitialized.Instance);
  216. }
  217. _data = null;
  218. }
  219. }
  220. [Confined]
  221. public bool Contains(KeyValuePair<object, object> item) {
  222. throw new NotImplementedException();
  223. }
  224. public void CopyTo(KeyValuePair<object, object>[]/*!*/ array, int arrayIndex) {
  225. throw new NotImplementedException();
  226. }
  227. public int Count {
  228. get {
  229. int count = GetObjectKeyCount();
  230. lock (this) {
  231. if (_data != null) {
  232. count = _data.Count;
  233. }
  234. foreach (SymbolId key in GetExtraKeys()) {
  235. if (key.Id < 0) break;
  236. object dummy;
  237. if (TryGetExtraValue(key, out dummy) && dummy != Uninitialized.Instance) count++;
  238. }
  239. }
  240. return count;
  241. }
  242. }
  243. public bool IsReadOnly {
  244. get { return false; }
  245. }
  246. public bool Remove(KeyValuePair<object, object> item) {
  247. throw new NotImplementedException();
  248. }
  249. #endregion
  250. #region IEnumerable<KeyValuePair<object,object>> Members
  251. [Pure]
  252. IEnumerator<KeyValuePair<object, object>>/*!*/ IEnumerable<KeyValuePair<object, object>>.GetEnumerator() {
  253. if (_data != null) {
  254. foreach (KeyValuePair<SymbolId, object> o in _data) {
  255. if (o.Key == SymbolId.Invalid) break;
  256. if (o.Key == ObjectKeys) continue;
  257. yield return new KeyValuePair<object, object>(SymbolTable.IdToString(o.Key), o.Value);
  258. }
  259. }
  260. foreach (SymbolId o in GetExtraKeys()) {
  261. if (o.Id < 0) break;
  262. object val;
  263. if (TryGetExtraValue(o, out val) && val != Uninitialized.Instance) {
  264. yield return new KeyValuePair<object, object>(SymbolTable.IdToString(o), val);
  265. }
  266. }
  267. IDictionaryEnumerator objItems = GetObjectItems();
  268. if (objItems != null) {
  269. while (objItems.MoveNext()) {
  270. yield return new KeyValuePair<object, object>(objItems.Key, objItems.Value);
  271. }
  272. }
  273. }
  274. #endregion
  275. #region IEnumerable Members
  276. [Pure]
  277. public System.Collections.IEnumerator/*!*/ GetEnumerator() {
  278. List<object> l = new List<object>(this.Keys);
  279. for (int i = 0; i < l.Count; i++) {
  280. object baseVal = l[i];
  281. object nullVal = l[i] = BaseSymbolDictionary.ObjToNull(l[i]);
  282. if (baseVal != nullVal) {
  283. // we've transformed null, stop looking
  284. break;
  285. }
  286. }
  287. return l.GetEnumerator();
  288. }
  289. #endregion
  290. #region IAttributesDictionary Members
  291. public void Add(SymbolId name, object value) {
  292. lock (this) {
  293. if (TrySetExtraValue(name, value)) return;
  294. if (_data == null) InitializeData();
  295. _data.Add(name, value);
  296. }
  297. }
  298. public bool ContainsKey(SymbolId name) {
  299. object value;
  300. if (TryGetExtraValue(name, out value) && value != Uninitialized.Instance) return true;
  301. if (_data == null) return false;
  302. lock (this) return _data.ContainsKey(name);
  303. }
  304. public bool Remove(SymbolId name) {
  305. object value;
  306. if (TryGetExtraValue(name, out value)) {
  307. if (value == Uninitialized.Instance) return false;
  308. if (TrySetExtraValue(name, Uninitialized.Instance)) return true;
  309. }
  310. if (_data == null) return false;
  311. lock (this) return _data.Remove(name);
  312. }
  313. public bool TryGetValue(SymbolId name, out object value) {
  314. if (TryGetExtraValue(name, out value) && value != Uninitialized.Instance) return true;
  315. if (_data == null) return false;
  316. lock (this) return _data.TryGetValue(name, out value);
  317. }
  318. object IAttributesCollection.this[SymbolId name] {
  319. get {
  320. object res;
  321. if (TryGetExtraValue(name, out res) && res != Uninitialized.Instance) return res;
  322. lock (this) {
  323. if (_data == null) throw new KeyNotFoundException(SymbolTable.IdToString(name));
  324. return _data[name];
  325. }
  326. }
  327. set {
  328. if (TrySetExtraValue(name, value)) return;
  329. lock (this) {
  330. if (_data == null) InitializeData();
  331. _data[name] = value;
  332. }
  333. }
  334. }
  335. public IDictionary<SymbolId, object> SymbolAttributes {
  336. get {
  337. Dictionary<SymbolId, object> d = new Dictionary<SymbolId, object>();
  338. lock (this) {
  339. if (_data != null) {
  340. foreach (KeyValuePair<SymbolId, object> name in _data) {
  341. if (name.Key == ObjectKeys) continue;
  342. d.Add(name.Key, name.Value);
  343. }
  344. }
  345. foreach (SymbolId extraKey in GetExtraKeys()) {
  346. object value;
  347. if (TryGetExtraValue(extraKey, out value) && !(value is Uninitialized))
  348. d.Add(extraKey, value);
  349. }
  350. }
  351. return d;
  352. }
  353. }
  354. /// <summary>
  355. /// Appends the object keys to the provided list.
  356. /// </summary>
  357. protected virtual void GetObjectKeys(List<object> res) {
  358. lock (this) {
  359. Dictionary<object, object> objData = GetObjectKeysDictionaryIfExists();
  360. if (objData != null) res.AddRange(objData.Keys);
  361. }
  362. }
  363. /// <summary>
  364. /// Appends the values stored under object keys to the provided list.
  365. /// </summary>
  366. protected virtual void GetObjectValues(List<object> res) {
  367. lock (this) {
  368. Dictionary<object, object> objData = GetObjectKeysDictionaryIfExists();
  369. if (objData != null) res.AddRange(objData.Values);
  370. }
  371. }
  372. /// <summary>
  373. /// Gets the count of object keys.
  374. /// </summary>
  375. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] // TODO: fix
  376. protected virtual int GetObjectKeyCount() {
  377. lock (this) {
  378. Dictionary<object, object> objData = GetObjectKeysDictionaryIfExists();
  379. if (objData != null) {
  380. // -1 is because data contains objData
  381. return objData.Count;
  382. }
  383. }
  384. return 0;
  385. }
  386. /// <summary>
  387. /// Gets an IDictionaryEnumerator for all of the object key/value pairs.
  388. /// </summary>
  389. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] // TODO: fix
  390. public virtual IDictionaryEnumerator GetObjectItems() {
  391. lock (this) {
  392. Dictionary<object, object> objData = GetObjectKeysDictionaryIfExists();
  393. if (objData != null) {
  394. return objData.GetEnumerator();
  395. }
  396. }
  397. return null;
  398. }
  399. /// <summary>
  400. /// Stores the specified value under the specified object key.
  401. /// </summary>
  402. public virtual void AddObjectKey(object name, object value) {
  403. lock (this) {
  404. Dictionary<object, object> objData = GetObjectKeysDictionary();
  405. objData[name] = value;
  406. }
  407. }
  408. public bool ContainsObjectKey(object name) {
  409. return AsObjectKeyedDictionary().ContainsKey(name);
  410. }
  411. /// <summary>
  412. /// Removes the specified object key from the dictionary.
  413. /// </summary>
  414. public virtual bool RemoveObjectKey(object name) {
  415. lock (this) {
  416. Dictionary<object, object> objData = GetObjectKeysDictionaryIfExists();
  417. if (objData == null) return false;
  418. return objData.Remove(name);
  419. }
  420. }
  421. /// <summary>
  422. /// Attemps to get the value stored under the specified object key.
  423. ///
  424. /// Returns true if the key was found, false if not found.
  425. /// </summary>
  426. public virtual bool TryGetObjectValue(object name, out object value) {
  427. string strKey = name as string;
  428. if (strKey != null) {
  429. return ((IAttributesCollection)this).TryGetValue(SymbolTable.StringToId(strKey), out value);
  430. }
  431. lock (this) {
  432. Dictionary<object, object> objData = GetObjectKeysDictionaryIfExists();
  433. if (objData != null)
  434. return objData.TryGetValue(name, out value);
  435. }
  436. value = null;
  437. return false;
  438. }
  439. public ICollection<object> Keys { get { return AsObjectKeyedDictionary().Keys; } }
  440. public override IDictionary<object, object> AsObjectKeyedDictionary() {
  441. return this;
  442. }
  443. #endregion
  444. #region IDictionary Members
  445. [Pure]
  446. void IDictionary.Add(object/*!*/ key, object value) {
  447. AsObjectKeyedDictionary().Add(key, value);
  448. }
  449. [Pure]
  450. public bool Contains(object/*!*/ key) {
  451. return AsObjectKeyedDictionary().ContainsKey(key);
  452. }
  453. [Pure]
  454. IDictionaryEnumerator/*!*/ IDictionary.GetEnumerator() {
  455. List<IDictionaryEnumerator> enums = new List<IDictionaryEnumerator>();
  456. enums.Add(new ExtraKeyEnumerator(this));
  457. if (_data != null) enums.Add(new TransformDictionaryEnumerator(_data));
  458. IDictionaryEnumerator objItems = GetObjectItems();
  459. if (objItems != null) {
  460. enums.Add(objItems);
  461. }
  462. return new DictionaryUnionEnumerator(enums);
  463. }
  464. public bool IsFixedSize {
  465. get { return false; }
  466. }
  467. ICollection/*!*/ IDictionary.Keys {
  468. get { return new List<object>(AsObjectKeyedDictionary().Keys); }
  469. }
  470. void IDictionary.Remove(object/*!*/ key) {
  471. Debug.Assert(!(key is SymbolId));
  472. string strKey = key as string;
  473. if (strKey != null) {
  474. SymbolId id = SymbolTable.StringToId(strKey);
  475. if (TrySetExtraValue(id, Uninitialized.Instance)) return;
  476. lock (this) if (_data != null) _data.Remove(id);
  477. } else {
  478. RemoveObjectKey(key);
  479. }
  480. }
  481. ICollection/*!*/ IDictionary.Values {
  482. get {
  483. return new List<object>(AsObjectKeyedDictionary().Values);
  484. }
  485. }
  486. object IDictionary.this[object/*!*/ key] {
  487. get { return AsObjectKeyedDictionary()[key]; }
  488. set { AsObjectKeyedDictionary()[key] = value; }
  489. }
  490. #endregion
  491. public void CopyTo(Array/*!*/ array, int index) {
  492. throw new NotImplementedException("The method or operation is not implemented.");
  493. }
  494. public bool IsSynchronized {
  495. get {
  496. return true;
  497. }
  498. }
  499. public object/*!*/ SyncRoot {
  500. get {
  501. // TODO: Sync root shouldn't be this, it should be data.
  502. return this;
  503. }
  504. }
  505. }
  506. }