PageRenderTime 48ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/Microsoft.Scripting/Runtime/CustomSymbolDictionary.cs

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