PageRenderTime 49ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/Runtime/Microsoft.Dynamic/Runtime/CustomStringDictionary.cs

http://github.com/IronLanguages/main
C# | 456 lines | 332 code | 84 blank | 40 comment | 93 complexity | 0ceb67f50aaeb225ce1e70baab186719 MD5 | raw file
Possible License(s): CPL-1.0, BSD-3-Clause, ISC, GPL-2.0, MPL-2.0-no-copyleft-exception
  1. /* ****************************************************************************
  2. *
  3. * Copyright (c) Microsoft Corporation.
  4. *
  5. * This source code is subject to terms and conditions of the Apache License, Version 2.0. 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 Apache License, Version 2.0, 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 Apache License, Version 2.0.
  10. *
  11. * You must not remove this notice, or any other, from this software.
  12. *
  13. *
  14. * ***************************************************************************/
  15. #if FEATURE_CORE_DLR
  16. using System.Linq.Expressions;
  17. #else
  18. using Microsoft.Scripting.Ast;
  19. #endif
  20. using System;
  21. using System.Collections;
  22. using System.Collections.Generic;
  23. using System.Diagnostics;
  24. using Microsoft.Scripting.Utils;
  25. namespace Microsoft.Scripting.Runtime {
  26. /// <summary>
  27. /// Abstract base class used for optimized thread-safe dictionaries which have a set
  28. /// of pre-defined string keys.
  29. ///
  30. /// Implementers derive from this class and override the GetExtraKeys, TrySetExtraValue,
  31. /// and TryGetExtraValue methods. When looking up a value first the extra keys will be
  32. /// searched using the optimized Try*ExtraValue functions. If the value isn't found there
  33. /// then the value is stored in the underlying .NET dictionary.
  34. ///
  35. /// This dictionary can store object values in addition to string values. It also supports
  36. /// null keys.
  37. /// </summary>
  38. [DebuggerDisplay("Count = {Count}")]
  39. public abstract class CustomStringDictionary :
  40. #if CLR2
  41. IValueEquality,
  42. #endif
  43. IDictionary, IDictionary<object, object> {
  44. private Dictionary<object, object> _data;
  45. private static readonly object _nullObject = new object();
  46. protected CustomStringDictionary() {
  47. }
  48. /// <summary>
  49. /// Gets a list of the extra keys that are cached by the the optimized implementation
  50. /// of the module.
  51. /// </summary>
  52. public abstract string[] GetExtraKeys();
  53. /// <summary>
  54. /// Try to set the extra value and return true if the specified key was found in the
  55. /// list of extra values.
  56. /// </summary>
  57. protected internal abstract bool TrySetExtraValue(string key, object value);
  58. /// <summary>
  59. /// Try to get the extra value and returns true if the specified key was found in the
  60. /// list of extra values. Returns true even if the value is Uninitialized.
  61. /// </summary>
  62. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1007:UseGenericsWhereAppropriate")]
  63. protected internal abstract bool TryGetExtraValue(string key, out object value);
  64. private void InitializeData() {
  65. Debug.Assert(_data == null);
  66. _data = new Dictionary<object, object>();
  67. }
  68. #region IDictionary<object, object> Members
  69. void IDictionary<object, object>.Add(object key, object value) {
  70. string strKey = key as string;
  71. if (strKey != null) {
  72. lock (this) {
  73. if (_data == null) InitializeData();
  74. if (TrySetExtraValue(strKey, value))
  75. return;
  76. _data.Add(strKey, value);
  77. }
  78. } else {
  79. AddObjectKey(key, value);
  80. }
  81. }
  82. private void AddObjectKey(object key, object value) {
  83. if (_data == null) {
  84. InitializeData();
  85. }
  86. _data[key] = value;
  87. }
  88. bool IDictionary<object, object>.ContainsKey(object key) {
  89. lock (this) {
  90. if (_data == null) {
  91. return false;
  92. }
  93. object dummy;
  94. return _data.TryGetValue(key, out dummy);
  95. }
  96. }
  97. public ICollection<object> Keys {
  98. get {
  99. List<object> res = new List<object>();
  100. lock (this) {
  101. if (_data != null) {
  102. res.AddRange(_data.Keys);
  103. }
  104. }
  105. foreach (var key in GetExtraKeys()) {
  106. object dummy;
  107. if (TryGetExtraValue(key, out dummy) && dummy != Uninitialized.Instance) {
  108. res.Add(key);
  109. }
  110. }
  111. return res;
  112. }
  113. }
  114. bool IDictionary<object, object>.Remove(object key) {
  115. string strKey = key as string;
  116. if (strKey != null) {
  117. lock (this) {
  118. if (TrySetExtraValue(strKey, Uninitialized.Instance)) return true;
  119. if (_data == null) return false;
  120. return _data.Remove(strKey);
  121. }
  122. }
  123. return RemoveObjectKey(key);
  124. }
  125. private bool RemoveObjectKey(object key) {
  126. return _data.Remove(key);
  127. }
  128. public bool TryGetValue(object key, out object value) {
  129. string strKey = key as string;
  130. if (strKey != null) {
  131. lock (this) {
  132. if (TryGetExtraValue(strKey, out value) && value != Uninitialized.Instance) return true;
  133. if (_data == null) return false;
  134. return _data.TryGetValue(strKey, out value);
  135. }
  136. }
  137. return TryGetObjectValue(key, out value);
  138. }
  139. private bool TryGetObjectValue(object key, out object value) {
  140. if (_data == null) {
  141. value = null;
  142. return false;
  143. }
  144. return _data.TryGetValue(key, out value);
  145. }
  146. ICollection<object> IDictionary<object, object>.Values {
  147. get {
  148. List<object> res = new List<object>();
  149. lock (this) {
  150. if (_data != null) {
  151. res.AddRange(_data.Values);
  152. }
  153. }
  154. foreach (var key in GetExtraKeys()) {
  155. object value;
  156. if (TryGetExtraValue(key, out value) && value != Uninitialized.Instance) {
  157. res.Add(value);
  158. }
  159. }
  160. return res;
  161. }
  162. }
  163. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1065:DoNotRaiseExceptionsInUnexpectedLocations")]
  164. public object this[object key] {
  165. get {
  166. string strKey = key as string;
  167. object res;
  168. if (strKey != null) {
  169. lock (this) {
  170. if (TryGetExtraValue(strKey, out res) && !(res is Uninitialized)) return res;
  171. if (_data == null) {
  172. throw new KeyNotFoundException(strKey);
  173. }
  174. return _data[strKey];
  175. }
  176. }
  177. if (TryGetObjectValue(key, out res))
  178. return res;
  179. throw new KeyNotFoundException(key.ToString());
  180. }
  181. set {
  182. string strKey = key as string;
  183. if (strKey != null) {
  184. lock (this) {
  185. if (TrySetExtraValue(strKey, value)) return;
  186. if (_data == null) InitializeData();
  187. _data[strKey] = value;
  188. }
  189. } else {
  190. AddObjectKey(key, value);
  191. }
  192. }
  193. }
  194. #endregion
  195. #region ICollection<KeyValuePair<string,object>> Members
  196. public void Add(KeyValuePair<object, object> item) {
  197. throw new NotImplementedException();
  198. }
  199. public void Clear() {
  200. lock (this) {
  201. foreach (var key in GetExtraKeys()) {
  202. TrySetExtraValue(key, Uninitialized.Instance);
  203. }
  204. _data = null;
  205. }
  206. }
  207. public bool Contains(KeyValuePair<object, object> item) {
  208. throw new NotImplementedException();
  209. }
  210. public void CopyTo(KeyValuePair<object, object>[] array, int arrayIndex) {
  211. ContractUtils.RequiresNotNull(array, "array");
  212. ContractUtils.RequiresArrayRange(array, arrayIndex, Count, "araryIndex", "Count");
  213. foreach (KeyValuePair<object, object> kvp in ((IEnumerable<KeyValuePair<object, object>>)this)) {
  214. array[arrayIndex++] = kvp;
  215. }
  216. }
  217. public int Count {
  218. get {
  219. int count = _data != null ? _data.Count : 0;
  220. lock (this) {
  221. foreach (var key in GetExtraKeys()) {
  222. object dummy;
  223. if (TryGetExtraValue(key, out dummy) && dummy != Uninitialized.Instance) count++;
  224. }
  225. }
  226. return count;
  227. }
  228. }
  229. public bool IsReadOnly {
  230. get { return false; }
  231. }
  232. public bool Remove(KeyValuePair<object, object> item) {
  233. throw new NotImplementedException();
  234. }
  235. public bool Remove(object key) {
  236. string strKey = key as string;
  237. if (strKey != null) {
  238. if (TrySetExtraValue(strKey, Uninitialized.Instance)) {
  239. return true;
  240. }
  241. lock (this) {
  242. if (_data != null) {
  243. return _data.Remove(strKey);
  244. }
  245. return false;
  246. }
  247. } else {
  248. return RemoveObjectKey(key);
  249. }
  250. }
  251. #endregion
  252. #region IEnumerable<KeyValuePair<object,object>> Members
  253. IEnumerator<KeyValuePair<object, object>> IEnumerable<KeyValuePair<object, object>>.GetEnumerator() {
  254. if (_data != null) {
  255. foreach (KeyValuePair<object, object> o in _data) {
  256. yield return o;
  257. }
  258. }
  259. foreach (var o in GetExtraKeys()) {
  260. object val;
  261. if (TryGetExtraValue(o, out val) && val != Uninitialized.Instance) {
  262. yield return new KeyValuePair<object, object>(o, val);
  263. }
  264. }
  265. }
  266. #endregion
  267. #region IEnumerable Members
  268. public System.Collections.IEnumerator GetEnumerator() {
  269. List<object> l = new List<object>(this.Keys);
  270. for (int i = 0; i < l.Count; i++) {
  271. object baseVal = l[i];
  272. object nullVal = l[i] = CustomStringDictionary.ObjToNull(l[i]);
  273. if (baseVal != nullVal) {
  274. // we've transformed null, stop looking
  275. break;
  276. }
  277. }
  278. return l.GetEnumerator();
  279. }
  280. #endregion
  281. #region IDictionary Members
  282. void IDictionary.Add(object key, object value) {
  283. ((IDictionary<object, object>)this).Add(key, value);
  284. }
  285. public bool Contains(object key) {
  286. object dummy;
  287. return ((IDictionary<object, object>)this).TryGetValue(key, out dummy);
  288. }
  289. IDictionaryEnumerator IDictionary.GetEnumerator() {
  290. List<IDictionaryEnumerator> enums = new List<IDictionaryEnumerator>();
  291. enums.Add(new ExtraKeyEnumerator(this));
  292. if (_data != null) enums.Add(((IDictionary)_data).GetEnumerator());
  293. return new DictionaryUnionEnumerator(enums);
  294. }
  295. public bool IsFixedSize {
  296. get { return false; }
  297. }
  298. ICollection IDictionary.Keys {
  299. get {
  300. return new List<object>(((IDictionary<object, object>)this).Keys);
  301. }
  302. }
  303. void IDictionary.Remove(object key) {
  304. Remove(key);
  305. }
  306. ICollection IDictionary.Values {
  307. get {
  308. return new List<object>(((IDictionary<object, object>)this).Values);
  309. }
  310. }
  311. #endregion
  312. #region IValueEquality Members
  313. public int GetValueHashCode() {
  314. throw Error.DictionaryNotHashable();
  315. }
  316. public virtual bool ValueEquals(object other) {
  317. if (Object.ReferenceEquals(this, other)) return true;
  318. IDictionary<object, object> oth = other as IDictionary<object, object>;
  319. IDictionary<object, object> ths = this as IDictionary<object, object>;
  320. if (oth == null) return false;
  321. if (oth.Count != ths.Count) return false;
  322. foreach (KeyValuePair<object, object> o in ths) {
  323. object res;
  324. if (!oth.TryGetValue(o.Key, out res))
  325. return false;
  326. #if CLR2
  327. IValueEquality ve = res as IValueEquality;
  328. if (ve != null) {
  329. if (!ve.ValueEquals(o.Value)) return false;
  330. } else if ((ve = (o.Value as IValueEquality)) != null) {
  331. if (!ve.Equals(res)) return false;
  332. } else
  333. #endif
  334. if (res != null) {
  335. if (!res.Equals(o.Value)) return false;
  336. } else if (o.Value != null) {
  337. if (!o.Value.Equals(res)) return false;
  338. } // else both null and are equal
  339. }
  340. return true;
  341. }
  342. #endregion
  343. public void CopyTo(Array array, int index) {
  344. throw Error.MethodOrOperatorNotImplemented();
  345. }
  346. public bool IsSynchronized {
  347. get {
  348. return true;
  349. }
  350. }
  351. public object SyncRoot {
  352. get {
  353. // TODO: Sync root shouldn't be this, it should be data.
  354. return this;
  355. }
  356. }
  357. public static object NullToObj(object o) {
  358. if (o == null) return _nullObject;
  359. return o;
  360. }
  361. public static object ObjToNull(object o) {
  362. if (o == _nullObject) return null;
  363. return o;
  364. }
  365. public static bool IsNullObject(object o) {
  366. return o == _nullObject;
  367. }
  368. }
  369. [Obsolete("Derive directly from CustomStringDictionary instead")]
  370. public abstract class CustomSymbolDictionary : CustomStringDictionary {
  371. }
  372. }