PageRenderTime 45ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 1ms

/Languages/IronPython/IronPython/Runtime/PythonDictionary.cs

http://github.com/IronLanguages/main
C# | 1857 lines | 1444 code | 350 blank | 63 comment | 186 complexity | 158bfa48f4e98563d6e9d81ed1b37308 MD5 | raw file
Possible License(s): CPL-1.0, BSD-3-Clause, ISC, GPL-2.0, MPL-2.0-no-copyleft-exception

Large files files are truncated, but you can click here to view the full file

  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. using System;
  16. using System.Collections;
  17. using System.Collections.Generic;
  18. using System.Diagnostics;
  19. using System.Security;
  20. using System.Text;
  21. using Microsoft.Scripting;
  22. using Microsoft.Scripting.Runtime;
  23. using IronPython.Runtime.Operations;
  24. using IronPython.Runtime.Types;
  25. namespace IronPython.Runtime {
  26. [PythonType("dict"), Serializable, DebuggerTypeProxy(typeof(PythonDictionary.DebugProxy)), DebuggerDisplay("Count = {Count}")]
  27. public class PythonDictionary : IDictionary<object, object>, IDictionary,
  28. #if CLR2
  29. IValueEquality,
  30. #endif
  31. ICodeFormattable, IStructuralEquatable {
  32. internal DictionaryStorage _storage;
  33. internal static object MakeDict(CodeContext/*!*/ context, PythonType cls) {
  34. if (cls == TypeCache.Dict) {
  35. return new PythonDictionary();
  36. }
  37. return PythonCalls.Call(context, cls);
  38. }
  39. #region Constructors
  40. public PythonDictionary() {
  41. _storage = EmptyDictionaryStorage.Instance;
  42. }
  43. internal PythonDictionary(DictionaryStorage storage) {
  44. _storage = storage;
  45. }
  46. internal PythonDictionary(IDictionary dict) {
  47. var storage = new CommonDictionaryStorage();
  48. foreach (DictionaryEntry de in dict) {
  49. storage.AddNoLock(de.Key, de.Value);
  50. }
  51. _storage = storage;
  52. }
  53. internal PythonDictionary(PythonDictionary dict) {
  54. _storage = dict._storage.Clone();
  55. }
  56. internal PythonDictionary(CodeContext/*!*/ context, object o)
  57. : this() {
  58. update(context, o);
  59. }
  60. internal PythonDictionary(int size) {
  61. _storage = new CommonDictionaryStorage(size);
  62. }
  63. internal static PythonDictionary FromIAC(CodeContext context, PythonDictionary iac) {
  64. return iac.GetType() == typeof(PythonDictionary) ? (PythonDictionary)iac : MakeDictFromIAC(context, iac);
  65. }
  66. private static PythonDictionary MakeDictFromIAC(CodeContext context, PythonDictionary iac) {
  67. return new PythonDictionary(new ObjectAttributesAdapter(context, iac));
  68. }
  69. internal static PythonDictionary MakeSymbolDictionary() {
  70. return new PythonDictionary(new StringDictionaryStorage());
  71. }
  72. internal static PythonDictionary MakeSymbolDictionary(int count) {
  73. return new PythonDictionary(new StringDictionaryStorage(count));
  74. }
  75. public void __init__(CodeContext/*!*/ context, object o\u00F8, [ParamDictionary]IDictionary<object, object> kwArgs) {
  76. update(context, o\u00F8);
  77. update(context, kwArgs);
  78. }
  79. public void __init__(CodeContext/*!*/ context, [ParamDictionary]IDictionary<object, object> kwArgs) {
  80. update(context, kwArgs);
  81. }
  82. public void __init__(CodeContext/*!*/ context, object o\u00F8) {
  83. update(context, o\u00F8);
  84. }
  85. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
  86. public void __init__() {
  87. }
  88. #endregion
  89. #region IDictionary<object,object> Members
  90. [PythonHidden]
  91. public void Add(object key, object value) {
  92. _storage.Add(ref _storage, key, value);
  93. }
  94. [PythonHidden]
  95. public bool ContainsKey(object key) {
  96. return _storage.Contains(key);
  97. }
  98. public ICollection<object> Keys {
  99. [PythonHidden]
  100. get { return keys(); }
  101. }
  102. [PythonHidden]
  103. public bool Remove(object key) {
  104. try {
  105. __delitem__(key);
  106. return true;
  107. } catch (KeyNotFoundException) {
  108. return false;
  109. }
  110. }
  111. [PythonHidden]
  112. public bool RemoveDirect(object key) {
  113. // Directly remove the value, without calling __delitem__
  114. // This is used to implement pop() in a manner consistent with CPython, which does
  115. // not call __delitem__ on pop().
  116. return _storage.Remove(ref _storage, key);
  117. }
  118. [PythonHidden]
  119. public bool TryGetValue(object key, out object value) {
  120. if (_storage.TryGetValue(key, out value)) {
  121. return true;
  122. }
  123. // we need to manually look up a slot to get the correct behavior when
  124. // the __missing__ function is declared on a sub-type which is an old-class
  125. if (GetType() != typeof(PythonDictionary) &&
  126. PythonTypeOps.TryInvokeBinaryOperator(DefaultContext.Default,
  127. this,
  128. key,
  129. "__missing__",
  130. out value)) {
  131. return true;
  132. }
  133. return false;
  134. }
  135. internal bool TryGetValueNoMissing(object key, out object value) {
  136. return _storage.TryGetValue(key, out value);
  137. }
  138. public ICollection<object> Values {
  139. [PythonHidden]
  140. get { return values(); }
  141. }
  142. #endregion
  143. #region ICollection<KeyValuePair<object,object>> Members
  144. [PythonHidden]
  145. public void Add(KeyValuePair<object, object> item) {
  146. _storage.Add(ref _storage, item.Key, item.Value);
  147. }
  148. [PythonHidden]
  149. public void Clear() {
  150. _storage.Clear(ref _storage);
  151. }
  152. [PythonHidden]
  153. public bool Contains(KeyValuePair<object, object> item) {
  154. object result;
  155. return _storage.TryGetValue(item.Key, out result) &&
  156. PythonOps.EqualRetBool(result, item.Value);
  157. }
  158. [PythonHidden]
  159. public void CopyTo(KeyValuePair<object, object>[] array, int arrayIndex) {
  160. _storage.GetItems().CopyTo(array, arrayIndex);
  161. }
  162. public int Count {
  163. [PythonHidden]
  164. get { return _storage.Count; }
  165. }
  166. bool ICollection<KeyValuePair<object, object>>.IsReadOnly {
  167. get { return false; }
  168. }
  169. [PythonHidden]
  170. public bool Remove(KeyValuePair<object, object> item) {
  171. return _storage.Remove(ref _storage, item.Key);
  172. }
  173. #endregion
  174. #region IEnumerable<KeyValuePair<object,object>> Members
  175. [PythonHidden]
  176. public IEnumerator<KeyValuePair<object, object>> GetEnumerator() {
  177. foreach (KeyValuePair<object, object> kvp in _storage.GetItems()) {
  178. yield return kvp;
  179. }
  180. }
  181. #endregion
  182. #region IEnumerable Members
  183. IEnumerator IEnumerable.GetEnumerator() {
  184. return Converter.ConvertToIEnumerator(__iter__());
  185. }
  186. public virtual object __iter__() {
  187. return new DictionaryKeyEnumerator(_storage);
  188. }
  189. #endregion
  190. #region IMapping Members
  191. public object get(object key) {
  192. return DictionaryOps.get(this, key);
  193. }
  194. public object get(object key, object defaultValue) {
  195. return DictionaryOps.get(this, key, defaultValue);
  196. }
  197. public virtual object this[params object[] key] {
  198. get {
  199. if (key == null) {
  200. return GetItem(null);
  201. }
  202. if (key.Length == 0) {
  203. throw PythonOps.TypeError("__getitem__() takes exactly one argument (0 given)");
  204. }
  205. return this[PythonTuple.MakeTuple(key)];
  206. }
  207. set {
  208. if (key == null) {
  209. SetItem(null, value);
  210. return;
  211. }
  212. if (key.Length == 0) {
  213. throw PythonOps.TypeError("__setitem__() takes exactly two argument (1 given)");
  214. }
  215. this[PythonTuple.MakeTuple(key)] = value;
  216. }
  217. }
  218. public virtual object this[object key] {
  219. get {
  220. return GetItem(key);
  221. }
  222. set {
  223. SetItem(key, value);
  224. }
  225. }
  226. internal void SetItem(object key, object value) {
  227. _storage.Add(ref _storage, key, value);
  228. }
  229. private object GetItem(object key) {
  230. object ret;
  231. if (TryGetValue(key, out ret)) {
  232. return ret;
  233. }
  234. throw PythonOps.KeyError(key);
  235. }
  236. public virtual void __delitem__(object key) {
  237. if (!this.RemoveDirect(key)) {
  238. throw PythonOps.KeyError(key);
  239. }
  240. }
  241. public virtual void __delitem__(params object[] key) {
  242. if (key == null) {
  243. __delitem__((object)null);
  244. } else if (key.Length > 0) {
  245. __delitem__(PythonTuple.MakeTuple(key));
  246. } else {
  247. throw PythonOps.TypeError("__delitem__() takes exactly one argument (0 given)");
  248. }
  249. }
  250. #endregion
  251. #region IPythonContainer Members
  252. public virtual int __len__() {
  253. return Count;
  254. }
  255. #endregion
  256. #region Python dict implementation
  257. public void clear() {
  258. _storage.Clear(ref _storage);
  259. }
  260. [Python3Warning("dict.has_key() not supported in 3.x; use the in operator")]
  261. public bool has_key(object key) {
  262. return DictionaryOps.has_key(this, key);
  263. }
  264. public object pop(object key) {
  265. return DictionaryOps.pop(this, key);
  266. }
  267. public object pop(object key, object defaultValue) {
  268. return DictionaryOps.pop(this, key, defaultValue);
  269. }
  270. public PythonTuple popitem() {
  271. return DictionaryOps.popitem(this);
  272. }
  273. public object setdefault(object key) {
  274. return DictionaryOps.setdefault(this, key);
  275. }
  276. public object setdefault(object key, object defaultValue) {
  277. return DictionaryOps.setdefault(this, key, defaultValue);
  278. }
  279. public virtual List keys() {
  280. List res = new List();
  281. foreach (KeyValuePair<object, object> kvp in _storage.GetItems()) {
  282. res.append(kvp.Key);
  283. }
  284. return res;
  285. }
  286. public virtual List values() {
  287. List res = new List();
  288. foreach (KeyValuePair<object, object> kvp in _storage.GetItems()) {
  289. res.append(kvp.Value);
  290. }
  291. return res;
  292. }
  293. public virtual List items() {
  294. List res = new List();
  295. foreach (KeyValuePair<object, object> kvp in _storage.GetItems()) {
  296. res.append(PythonTuple.MakeTuple(kvp.Key, kvp.Value));
  297. }
  298. return res;
  299. }
  300. public IEnumerator iteritems() {
  301. return new DictionaryItemEnumerator(_storage);
  302. }
  303. public IEnumerator iterkeys() {
  304. return new DictionaryKeyEnumerator(_storage);
  305. }
  306. public IEnumerator itervalues() {
  307. return new DictionaryValueEnumerator(_storage);
  308. }
  309. public IEnumerable viewitems() {
  310. return new DictionaryItemView(this);
  311. }
  312. public IEnumerable viewkeys() {
  313. return new DictionaryKeyView(this);
  314. }
  315. public IEnumerable viewvalues() {
  316. return new DictionaryValueView(this);
  317. }
  318. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
  319. public void update() {
  320. }
  321. public void update(CodeContext/*!*/ context, [ParamDictionary]IDictionary<object, object> other\u00F8) {
  322. DictionaryOps.update(context, this, other\u00F8);
  323. }
  324. public void update(CodeContext/*!*/ context, object other\u00F8) {
  325. DictionaryOps.update(context, this, other\u00F8);
  326. }
  327. public void update(CodeContext/*!*/ context, object other\u00F8, [ParamDictionary]IDictionary<object, object> otherArgs\u00F8) {
  328. DictionaryOps.update(context, this, other\u00F8);
  329. DictionaryOps.update(context, this, otherArgs\u00F8);
  330. }
  331. private static object fromkeysAny(CodeContext/*!*/ context, PythonType cls, object o, object value) {
  332. PythonDictionary pyDict;
  333. object dict;
  334. if (cls == TypeCache.Dict) {
  335. string str;
  336. ICollection ic = o as ICollection;
  337. // creating our own dict, try and get the ideal size and add w/o locks
  338. if (ic != null) {
  339. pyDict = new PythonDictionary(new CommonDictionaryStorage(ic.Count));
  340. } else if ((str = o as string) != null) {
  341. pyDict = new PythonDictionary(str.Length);
  342. } else {
  343. pyDict = new PythonDictionary();
  344. }
  345. IEnumerator i = PythonOps.GetEnumerator(o);
  346. while (i.MoveNext()) {
  347. pyDict._storage.AddNoLock(ref pyDict._storage, i.Current, value);
  348. }
  349. return pyDict;
  350. } else {
  351. // call the user type constructor
  352. dict = MakeDict(context, cls);
  353. pyDict = dict as PythonDictionary;
  354. }
  355. if (pyDict != null) {
  356. // then store all the keys with their associated value
  357. IEnumerator i = PythonOps.GetEnumerator(o);
  358. while (i.MoveNext()) {
  359. pyDict[i.Current] = value;
  360. }
  361. } else {
  362. // slow path, cls.__new__ returned a user defined dictionary instead of a PythonDictionary.
  363. PythonContext pc = PythonContext.GetContext(context);
  364. IEnumerator i = PythonOps.GetEnumerator(o);
  365. while (i.MoveNext()) {
  366. pc.SetIndex(dict, i.Current, value);
  367. }
  368. }
  369. return dict;
  370. }
  371. [ClassMethod]
  372. public static object fromkeys(CodeContext context, PythonType cls, object seq) {
  373. return fromkeys(context, cls, seq, null);
  374. }
  375. [ClassMethod]
  376. public static object fromkeys(CodeContext context, PythonType cls, object seq, object value) {
  377. XRange xr = seq as XRange;
  378. if (xr != null) {
  379. int n = xr.__len__();
  380. object ret = PythonContext.GetContext(context).CallSplat(cls);
  381. if (ret.GetType() == typeof(PythonDictionary)) {
  382. PythonDictionary dr = ret as PythonDictionary;
  383. for (int i = 0; i < n; i++) {
  384. dr[xr[i]] = value;
  385. }
  386. } else {
  387. // slow path, user defined dict
  388. PythonContext pc = PythonContext.GetContext(context);
  389. for (int i = 0; i < n; i++) {
  390. pc.SetIndex(ret, xr[i], value);
  391. }
  392. }
  393. return ret;
  394. }
  395. return fromkeysAny(context, cls, seq, value);
  396. }
  397. public virtual PythonDictionary copy(CodeContext/*!*/ context) {
  398. return new PythonDictionary(_storage.Clone());
  399. }
  400. public virtual bool __contains__(object key) {
  401. return _storage.Contains(key);
  402. }
  403. // Dictionary has an odd not-implemented check to support custom dictionaries and therefore
  404. // needs a custom __eq__ / __ne__ implementation.
  405. [return: MaybeNotImplemented]
  406. public object __eq__(CodeContext/*!*/ context, object other) {
  407. if (!(other is PythonDictionary || other is IDictionary<object, object>))
  408. return NotImplementedType.Value;
  409. return ScriptingRuntimeHelpers.BooleanToObject(
  410. ((IStructuralEquatable)this).Equals(other, PythonContext.GetContext(context).EqualityComparerNonGeneric)
  411. );
  412. }
  413. [return: MaybeNotImplemented]
  414. public object __ne__(CodeContext/*!*/ context, object other) {
  415. if (!(other is PythonDictionary || other is IDictionary<object, object>))
  416. return NotImplementedType.Value;
  417. return ScriptingRuntimeHelpers.BooleanToObject(
  418. !((IStructuralEquatable)this).Equals(other, PythonContext.GetContext(context).EqualityComparerNonGeneric)
  419. );
  420. }
  421. [return: MaybeNotImplemented]
  422. public object __cmp__(CodeContext context, object other) {
  423. IDictionary<object, object> oth = other as IDictionary<object, object>;
  424. // CompareTo is allowed to throw (string, int, etc... all do it if they don't get a matching type)
  425. if (oth == null) {
  426. object len, iteritems;
  427. if (!PythonOps.TryGetBoundAttr(context, other, "__len__", out len) ||
  428. !PythonOps.TryGetBoundAttr(context, other, "iteritems", out iteritems)) {
  429. return NotImplementedType.Value;
  430. }
  431. // user-defined dictionary...
  432. int lcnt = Count;
  433. int rcnt = PythonContext.GetContext(context).ConvertToInt32(PythonOps.CallWithContext(context, len));
  434. if (lcnt != rcnt) return lcnt > rcnt ? 1 : -1;
  435. return DictionaryOps.CompareToWorker(context, this, new List(PythonOps.CallWithContext(context, iteritems)));
  436. }
  437. CompareUtil.Push(this, oth);
  438. try {
  439. return DictionaryOps.CompareTo(context, this, oth);
  440. } finally {
  441. CompareUtil.Pop(this, oth);
  442. }
  443. }
  444. public int __cmp__(CodeContext/*!*/ context, [NotNull]PythonDictionary/*!*/ other) {
  445. CompareUtil.Push(this, other);
  446. try {
  447. return DictionaryOps.CompareTo(context, this, other);
  448. } finally {
  449. CompareUtil.Pop(this, other);
  450. }
  451. }
  452. // these are present in CPython but always return NotImplemented.
  453. [return: MaybeNotImplemented]
  454. [Python3Warning("dict inequality comparisons not supported in 3.x")]
  455. public static NotImplementedType operator > (PythonDictionary self, PythonDictionary other) {
  456. return PythonOps.NotImplemented;
  457. }
  458. [return: MaybeNotImplemented]
  459. [Python3Warning("dict inequality comparisons not supported in 3.x")]
  460. public static NotImplementedType operator <(PythonDictionary self, PythonDictionary other) {
  461. return PythonOps.NotImplemented;
  462. }
  463. [return: MaybeNotImplemented]
  464. [Python3Warning("dict inequality comparisons not supported in 3.x")]
  465. public static NotImplementedType operator >=(PythonDictionary self, PythonDictionary other) {
  466. return PythonOps.NotImplemented;
  467. }
  468. [return: MaybeNotImplemented]
  469. [Python3Warning("dict inequality comparisons not supported in 3.x")]
  470. public static NotImplementedType operator <=(PythonDictionary self, PythonDictionary other) {
  471. return PythonOps.NotImplemented;
  472. }
  473. #endregion
  474. #region IValueEquality Members
  475. #if CLR2
  476. int IValueEquality.GetValueHashCode() {
  477. throw PythonOps.TypeErrorForUnhashableType("dict");
  478. }
  479. bool IValueEquality.ValueEquals(object other) {
  480. return EqualsWorker(other, null);
  481. }
  482. #endif
  483. #endregion
  484. #region IStructuralEquatable Members
  485. public const object __hash__ = null;
  486. int IStructuralEquatable.GetHashCode(IEqualityComparer comparer) {
  487. if (CompareUtil.Check(this)) {
  488. return 0;
  489. }
  490. int res;
  491. SetStorage pairs = new SetStorage();
  492. foreach (KeyValuePair<object, object> kvp in _storage.GetItems()) {
  493. pairs.AddNoLock(PythonTuple.MakeTuple(kvp.Key, kvp.Value));
  494. }
  495. CompareUtil.Push(this);
  496. try {
  497. IStructuralEquatable eq = FrozenSetCollection.Make(TypeCache.FrozenSet, pairs);
  498. res = eq.GetHashCode(comparer);
  499. } finally {
  500. CompareUtil.Pop(this);
  501. }
  502. return res;
  503. }
  504. bool IStructuralEquatable.Equals(object other, IEqualityComparer comparer) {
  505. return EqualsWorker(other, comparer);
  506. }
  507. private bool EqualsWorker(object other, IEqualityComparer comparer) {
  508. if (Object.ReferenceEquals(this, other)) return true;
  509. IDictionary<object, object> oth = other as IDictionary<object, object>;
  510. if (oth == null) return false;
  511. if (oth.Count != Count) return false;
  512. PythonDictionary pd = other as PythonDictionary;
  513. if (pd != null) {
  514. return ValueEqualsPythonDict(pd, comparer);
  515. }
  516. // we cannot call Compare here and compare against zero because Python defines
  517. // value equality even if the keys/values are unordered.
  518. List myKeys = keys();
  519. foreach (object o in myKeys) {
  520. object res;
  521. if (!oth.TryGetValue(o, out res)) return false;
  522. CompareUtil.Push(res);
  523. try {
  524. if (comparer == null) {
  525. if (!PythonOps.EqualRetBool(res, this[o])) return false;
  526. } else {
  527. if (!comparer.Equals(res, this[o])) return false;
  528. }
  529. } finally {
  530. CompareUtil.Pop(res);
  531. }
  532. }
  533. return true;
  534. }
  535. private bool ValueEqualsPythonDict(PythonDictionary pd, IEqualityComparer comparer) {
  536. List myKeys = keys();
  537. foreach (object o in myKeys) {
  538. object res;
  539. if (!pd.TryGetValueNoMissing(o, out res)) return false;
  540. CompareUtil.Push(res);
  541. try {
  542. if (comparer == null) {
  543. if (!PythonOps.EqualRetBool(res, this[o])) return false;
  544. } else {
  545. if (!comparer.Equals(res, this[o])) return false;
  546. }
  547. } finally {
  548. CompareUtil.Pop(res);
  549. }
  550. }
  551. return true;
  552. }
  553. #endregion
  554. #region IDictionary Members
  555. [PythonHidden]
  556. public bool Contains(object key) {
  557. return __contains__(key);
  558. }
  559. internal class DictEnumerator : IDictionaryEnumerator {
  560. private IEnumerator<KeyValuePair<object, object>> _enumerator;
  561. private bool _moved;
  562. public DictEnumerator(IEnumerator<KeyValuePair<object, object>> enumerator) {
  563. _enumerator = enumerator;
  564. }
  565. #region IDictionaryEnumerator Members
  566. public DictionaryEntry Entry {
  567. get {
  568. // List<T> enumerator doesn't throw, so we need to.
  569. if (!_moved) throw new InvalidOperationException();
  570. return new DictionaryEntry(_enumerator.Current.Key, _enumerator.Current.Value);
  571. }
  572. }
  573. public object Key {
  574. get { return Entry.Key; }
  575. }
  576. public object Value {
  577. get { return Entry.Value; }
  578. }
  579. #endregion
  580. #region IEnumerator Members
  581. public object Current {
  582. get { return Entry; }
  583. }
  584. public bool MoveNext() {
  585. if (_enumerator.MoveNext()) {
  586. _moved = true;
  587. return true;
  588. }
  589. _moved = false;
  590. return false;
  591. }
  592. public void Reset() {
  593. _enumerator.Reset();
  594. _moved = false;
  595. }
  596. #endregion
  597. }
  598. IDictionaryEnumerator IDictionary.GetEnumerator() {
  599. return new DictEnumerator(_storage.GetItems().GetEnumerator());
  600. }
  601. bool IDictionary.IsFixedSize {
  602. get { return false; }
  603. }
  604. bool IDictionary.IsReadOnly {
  605. get { return false; }
  606. }
  607. ICollection IDictionary.Keys {
  608. get { return this.keys(); }
  609. }
  610. ICollection IDictionary.Values {
  611. get { return values(); }
  612. }
  613. void IDictionary.Remove(object key) {
  614. ((IDictionary<object, object>)this).Remove(key);
  615. }
  616. #endregion
  617. #region ICollection Members
  618. void ICollection.CopyTo(Array array, int index) {
  619. throw new NotImplementedException("The method or operation is not implemented.");
  620. }
  621. bool ICollection.IsSynchronized {
  622. get { return false; }
  623. }
  624. object ICollection.SyncRoot {
  625. get { return null; }
  626. }
  627. #endregion
  628. #region ICodeFormattable Members
  629. public virtual string/*!*/ __repr__(CodeContext/*!*/ context) {
  630. return DictionaryOps.__repr__(context, this);
  631. }
  632. #endregion
  633. internal bool TryRemoveValue(object key, out object value) {
  634. return _storage.TryRemoveValue(ref _storage, key, out value);
  635. }
  636. #region Debugger View
  637. internal class DebugProxy {
  638. private readonly PythonDictionary _dict;
  639. public DebugProxy(PythonDictionary dict) {
  640. _dict = dict;
  641. }
  642. [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
  643. public List<KeyValueDebugView> Members {
  644. get {
  645. var res = new List<KeyValueDebugView>();
  646. foreach (var v in _dict) {
  647. res.Add(new KeyValueDebugView(v.Key, v.Value));
  648. }
  649. return res;
  650. }
  651. }
  652. }
  653. [DebuggerDisplay("{Value}", Name = "{Key,nq}", Type = "{TypeInfo,nq}")]
  654. internal class KeyValueDebugView {
  655. public readonly object Key;
  656. public readonly object Value;
  657. public KeyValueDebugView(object key, object value) {
  658. Key = key;
  659. Value = value;
  660. }
  661. [DebuggerBrowsable(DebuggerBrowsableState.Never)]
  662. public string TypeInfo {
  663. get {
  664. return "Key: " + PythonTypeOps.GetName(Key) + ", " + "Value: " + PythonTypeOps.GetName(Value);
  665. }
  666. }
  667. }
  668. #endregion
  669. }
  670. #if FEATURE_PROCESS
  671. [Serializable]
  672. internal sealed class EnvironmentDictionaryStorage : DictionaryStorage {
  673. private readonly CommonDictionaryStorage/*!*/ _storage = new CommonDictionaryStorage();
  674. public EnvironmentDictionaryStorage() {
  675. AddEnvironmentVars();
  676. }
  677. private void AddEnvironmentVars() {
  678. try {
  679. foreach (DictionaryEntry de in Environment.GetEnvironmentVariables()) {
  680. _storage.Add(de.Key, de.Value);
  681. }
  682. } catch (SecurityException) {
  683. // environment isn't available under partial trust
  684. }
  685. }
  686. public override void Add(ref DictionaryStorage storage, object key, object value) {
  687. _storage.Add(key, value);
  688. string s1 = key as string;
  689. string s2 = value as string;
  690. if (s1 != null && s2 != null) {
  691. Environment.SetEnvironmentVariable(s1, s2);
  692. }
  693. }
  694. public override bool Remove(ref DictionaryStorage storage, object key) {
  695. bool res = _storage.Remove(key);
  696. string s = key as string;
  697. if (s != null) {
  698. Environment.SetEnvironmentVariable(s, string.Empty);
  699. }
  700. return res;
  701. }
  702. public override bool Contains(object key) {
  703. return _storage.Contains(key);
  704. }
  705. public override bool TryGetValue(object key, out object value) {
  706. return _storage.TryGetValue(key, out value);
  707. }
  708. public override int Count {
  709. get { return _storage.Count; }
  710. }
  711. public override void Clear(ref DictionaryStorage storage) {
  712. foreach (var x in GetItems()) {
  713. string key = x.Key as string;
  714. if (key != null) {
  715. Environment.SetEnvironmentVariable(key, string.Empty);
  716. }
  717. }
  718. _storage.Clear(ref storage);
  719. }
  720. public override List<KeyValuePair<object, object>> GetItems() {
  721. return _storage.GetItems();
  722. }
  723. }
  724. #endif
  725. /// <summary>
  726. /// Note:
  727. /// IEnumerator innerEnum = Dictionary&lt;K,V&gt;.KeysCollections.GetEnumerator();
  728. /// innerEnum.MoveNext() will throw InvalidOperation even if the values get changed,
  729. /// which is supported in python
  730. /// </summary>
  731. [PythonType("dictionary-keyiterator")]
  732. public sealed class DictionaryKeyEnumerator : IEnumerator, IEnumerator<object> {
  733. private readonly int _size;
  734. private readonly DictionaryStorage _dict;
  735. private readonly IEnumerator<object> _keys;
  736. private int _pos;
  737. internal DictionaryKeyEnumerator(DictionaryStorage dict) {
  738. _dict = dict;
  739. _size = dict.Count;
  740. _keys = dict.GetKeys().GetEnumerator();
  741. _pos = -1;
  742. }
  743. bool IEnumerator.MoveNext() {
  744. if (_size != _dict.Count) {
  745. _pos = _size - 1; // make the length 0
  746. throw PythonOps.RuntimeError("dictionary changed size during iteration");
  747. }
  748. if (_keys.MoveNext()) {
  749. _pos++;
  750. return true;
  751. } else {
  752. return false;
  753. }
  754. }
  755. void IEnumerator.Reset() {
  756. _keys.Reset();
  757. _pos = -1;
  758. }
  759. object IEnumerator.Current {
  760. get {
  761. return _keys.Current;
  762. }
  763. }
  764. object IEnumerator<object>.Current {
  765. get {
  766. return _keys.Current;
  767. }
  768. }
  769. void IDisposable.Dispose() {
  770. }
  771. public object __iter__() {
  772. return this;
  773. }
  774. public int __length_hint__() {
  775. return _size - _pos - 1;
  776. }
  777. }
  778. /// <summary>
  779. /// Note:
  780. /// IEnumerator innerEnum = Dictionary&lt;K,V&gt;.KeysCollections.GetEnumerator();
  781. /// innerEnum.MoveNext() will throw InvalidOperation even if the values get changed,
  782. /// which is supported in python
  783. /// </summary>
  784. [PythonType("dictionary-valueiterator")]
  785. public sealed class DictionaryValueEnumerator : IEnumerator, IEnumerator<object> {
  786. private readonly int _size;
  787. DictionaryStorage _dict;
  788. private readonly object[] _values;
  789. private int _pos;
  790. internal DictionaryValueEnumerator(DictionaryStorage dict) {
  791. _dict = dict;
  792. _size = dict.Count;
  793. _values = new object[_size];
  794. int i = 0;
  795. foreach (KeyValuePair<object, object> kvp in dict.GetItems()) {
  796. _values[i++] = kvp.Value;
  797. }
  798. _pos = -1;
  799. }
  800. public bool MoveNext() {
  801. if (_size != _dict.Count) {
  802. _pos = _size - 1; // make the length 0
  803. throw PythonOps.RuntimeError("dictionary changed size during iteration");
  804. }
  805. if (_pos + 1 < _size) {
  806. _pos++;
  807. return true;
  808. } else {
  809. return false;
  810. }
  811. }
  812. public void Reset() {
  813. _pos = -1;
  814. }
  815. public object Current {
  816. get {
  817. return _values[_pos];
  818. }
  819. }
  820. public void Dispose() {
  821. }
  822. public object __iter__() {
  823. return this;
  824. }
  825. public int __len__() {
  826. return _size - _pos - 1;
  827. }
  828. }
  829. /// <summary>
  830. /// Note:
  831. /// IEnumerator innerEnum = Dictionary&lt;K,V&gt;.KeysCollections.GetEnumerator();
  832. /// innerEnum.MoveNext() will throw InvalidOperation even if the values get changed,
  833. /// which is supported in python
  834. /// </summary>
  835. [PythonType("dictionary-itemiterator")]
  836. public sealed class DictionaryItemEnumerator : IEnumerator, IEnumerator<object> {
  837. private readonly int _size;
  838. private readonly DictionaryStorage _dict;
  839. private readonly List<object> _keys;
  840. private readonly List<object> _values;
  841. private int _pos;
  842. internal DictionaryItemEnumerator(DictionaryStorage dict) {
  843. _dict = dict;
  844. _keys = new List<object>(dict.Count);
  845. _values = new List<object>(dict.Count);
  846. foreach (KeyValuePair<object, object> kvp in dict.GetItems()) {
  847. _keys.Add(kvp.Key);
  848. _values.Add(kvp.Value);
  849. }
  850. _size = _values.Count;
  851. _pos = -1;
  852. }
  853. public bool MoveNext() {
  854. if (_size != _dict.Count) {
  855. _pos = _size - 1; // make the length 0
  856. throw PythonOps.RuntimeError("dictionary changed size during iteration");
  857. }
  858. if (_pos + 1 < _size) {
  859. _pos++;
  860. return true;
  861. } else {
  862. return false;
  863. }
  864. }
  865. public void Reset() {
  866. _pos = -1;
  867. }
  868. public object Current {
  869. get {
  870. return PythonOps.MakeTuple(_keys[_pos], _values[_pos]);
  871. }
  872. }
  873. public void Dispose() {
  874. }
  875. public object __iter__() {
  876. return this;
  877. }
  878. public int __len__() {
  879. return _size - _pos - 1;
  880. }
  881. }
  882. [PythonType("dict_values")]
  883. public sealed class DictionaryValueView : IEnumerable, IEnumerable<object>, ICodeFormattable {
  884. private readonly PythonDictionary _dict;
  885. internal DictionaryValueView(PythonDictionary/*!*/ dict) {
  886. Debug.Assert(dict != null);
  887. _dict = dict;
  888. }
  889. [PythonHidden]
  890. public IEnumerator GetEnumerator() {
  891. return _dict.itervalues();
  892. }
  893. IEnumerator<object> IEnumerable<object>.GetEnumerator() {
  894. return new DictionaryValueEnumerator(_dict._storage);
  895. }
  896. public int __len__() {
  897. return _dict.Count;
  898. }
  899. #region ICodeFormattable Members
  900. public string __repr__(CodeContext context) {
  901. StringBuilder res = new StringBuilder(20);
  902. res.Append("dict_values([");
  903. string comma = "";
  904. foreach (object value in this) {
  905. res.Append(comma);
  906. comma = ", ";
  907. res.Append(PythonOps.Repr(context, value));
  908. }
  909. res.Append("])");
  910. return res.ToString();
  911. }
  912. #endregion
  913. }
  914. [PythonType("dict_keys")]
  915. public sealed class DictionaryKeyView : ICollection<object>, ICodeFormattable {
  916. internal readonly PythonDictionary _dict;
  917. internal DictionaryKeyView(PythonDictionary/*!*/ dict) {
  918. Debug.Assert(dict != null);
  919. _dict = dict;
  920. }
  921. [PythonHidden]
  922. public IEnumerator GetEnumerator() {
  923. return _dict.iterkeys();
  924. }
  925. IEnumerator<object> IEnumerable<object>.GetEnumerator() {
  926. return new DictionaryKeyEnumerator(_dict._storage);
  927. }
  928. #region ICollection<object> Members
  929. void ICollection<object>.Add(object key) {
  930. throw new NotSupportedException("Collection is read-only");
  931. }
  932. void ICollection<object>.Clear() {
  933. throw new NotSupportedException("Collection is read-only");
  934. }
  935. [PythonHidden]
  936. public bool Contains(object key) {
  937. return _dict.__contains__(key);
  938. }
  939. [PythonHidden]
  940. public void CopyTo(object[] array, int arrayIndex) {
  941. int i = arrayIndex;
  942. foreach (object item in this) {
  943. array[i++] = item;
  944. if (i >= array.Length) {
  945. break;
  946. }
  947. }
  948. }
  949. public int Count {
  950. [PythonHidden]
  951. get { return _dict.Count; }
  952. }
  953. public bool IsReadOnly {
  954. [PythonHidden]
  955. get { return true; }
  956. }
  957. bool ICollection<object>.Remove(object item) {
  958. throw new NotSupportedException("Collection is read-only");
  959. }
  960. #endregion
  961. #region Generated Set Operations (Keys)
  962. // *** BEGIN GENERATED CODE ***
  963. // generated by function: _gen_ops from: generate_dict_views.py
  964. public static SetCollection operator |(DictionaryKeyView x, IEnumerable y) {
  965. return new SetCollection(SetStorage.Union(
  966. SetStorage.GetItemsWorker(x.GetEnumerator()),
  967. SetStorage.GetItems(y)
  968. ));
  969. }
  970. public static SetCollection operator |(IEnumerable y, DictionaryKeyView x) {
  971. return new SetCollection(SetStorage.Union(
  972. SetStorage.GetItemsWorker(x.GetEnumerator()),
  973. SetStorage.GetItems(y)
  974. ));
  975. }
  976. public static SetCollection operator &(DictionaryKeyView x, IEnumerable y) {
  977. return new SetCollection(SetStorage.Intersection(
  978. SetStorage.GetItemsWorker(x.GetEnumerator()),
  979. SetStorage.GetItems(y)
  980. ));
  981. }
  982. public static SetCollection operator &(IEnumerable y, DictionaryKeyView x) {
  983. return new SetCollection(SetStorage.Intersection(
  984. SetStorage.GetItemsWorker(x.GetEnumerator()),
  985. SetStorage.GetItems(y)
  986. ));
  987. }
  988. public static SetCollection operator ^(DictionaryKeyView x, IEnumerable y) {
  989. return new SetCollection(SetStorage.SymmetricDifference(
  990. SetStorage.GetItemsWorker(x.GetEnumerator()),
  991. SetStorage.GetItems(y)
  992. ));
  993. }
  994. public static SetCollection operator ^(IEnumerable y, DictionaryKeyView x) {
  995. return new SetCollection(SetStorage.SymmetricDifference(
  996. SetStorage.GetItemsWorker(x.GetEnumerator()),
  997. SetStorage.GetItems(y)
  998. ));
  999. }
  1000. public static SetCollection operator -(DictionaryKeyView x, IEnumerable y) {
  1001. return new SetCollection(SetStorage.Difference(
  1002. SetStorage.GetItemsWorker(x.GetEnumerator()),
  1003. SetStorage.GetItems(y)
  1004. ));
  1005. }
  1006. public static SetCollection operator -(IEnumerable y, DictionaryKeyView x) {
  1007. return new SetCollection(SetStorage.Difference(
  1008. SetStorage.GetItemsWorker(x.GetEnumerator()),
  1009. SetStorage.GetItems(y)
  1010. ));
  1011. }
  1012. // *** END GENERATED CODE ***
  1013. #endregion
  1014. #region Generated Set Comparison Operations (Keys)
  1015. // *** BEGIN GENERATED CODE ***
  1016. // generated by function: _gen_comps from: generate_dict_views.py
  1017. public override bool Equals(object obj) {
  1018. if (obj == null) {
  1019. return false;
  1020. }
  1021. if (obj is DictionaryKeyView) {
  1022. return this == (DictionaryKeyView)obj;
  1023. } else if (obj is DictionaryItemView) {
  1024. return this == (DictionaryItemView)obj;
  1025. } else if (obj is SetCollection) {
  1026. return this == (SetCollection)obj;
  1027. } else if (obj is FrozenSetCollection) {
  1028. return this == (FrozenSetCollection)obj;
  1029. }
  1030. return false;
  1031. }
  1032. public static bool operator ==(DictionaryKeyView x, DictionaryKeyView y) {
  1033. if (object.ReferenceEquals(x._dict, y._dict)) {
  1034. return true;
  1035. }
  1036. SetStorage xs = SetStorage.GetItemsWorker(x.GetEnumerator());
  1037. SetStorage ys = SetStorage.GetItemsWorker(y.GetEnumerator());
  1038. return xs.Count == ys.Count && xs.IsSubset(ys);
  1039. }
  1040. public static bool operator !=(DictionaryKeyView x, DictionaryKeyView y) {
  1041. if (object.ReferenceEquals(x._dict, y._dict)) {
  1042. return false;
  1043. }
  1044. SetStorage xs = SetStorage.GetItemsWorker(x.GetEnumerator());
  1045. SetStorage ys = SetStorage.GetItemsWorker(y.GetEnumerator());
  1046. return xs.Count != ys.Count || !xs.IsSubset(ys);
  1047. }
  1048. public static bool operator >(DictionaryKeyView x, DictionaryKeyView y) {
  1049. if (object.ReferenceEquals(x._dict, y._dict)) {
  1050. return false;
  1051. }
  1052. SetStorage xs = SetStorage.GetItemsWorker(x.GetEnumerator());
  1053. SetStorage ys = SetStorage.GetItemsWorker(y.GetEnumerator());
  1054. return ys.IsStrictSubset(xs);
  1055. }
  1056. public static bool operator <(DictionaryKeyView x, DictionaryKeyView y) {
  1057. if (object.ReferenceEquals(x._dict, y._dict)) {
  1058. return false;
  1059. }
  1060. SetStorage xs = SetStorage.GetItemsWorker(x.GetEnumerator());
  1061. SetStorage ys = SetStorage.GetItemsWorker(y.GetEnumerator());
  1062. return xs.IsStrictSubset(ys);
  1063. }
  1064. public static bool operator >=(DictionaryKeyView x, DictionaryKeyView y) {
  1065. if (object.ReferenceEquals(x._dict, y._dict)) {
  1066. return true;
  1067. }
  1068. SetStorage xs = SetStorage.GetItemsWorker(x.GetEnumerator());
  1069. SetStorage ys = SetStorage.GetItemsWorker(y.GetEnumerator());
  1070. return ys.IsSubset(xs);
  1071. }
  1072. public static bool operator <=(DictionaryKeyView x, DictionaryKeyView y) {
  1073. if (object.ReferenceEquals(x._dict, y._dict)) {
  1074. return true;
  1075. }
  1076. SetStorage xs = SetStorage.GetItemsWorker(x.GetEnumerator());
  1077. SetStorage ys = SetStorage.GetItemsWorker(y.GetEnumerator());
  1078. return xs.IsSubset(ys);
  1079. }
  1080. public static bool operator ==(DictionaryKeyView x, DictionaryItemView y) {
  1081. if (object.ReferenceEquals(x._dict, y._dict)) {
  1082. return false;
  1083. }
  1084. SetStorage xs = SetStorage.GetItemsWorker(x.GetEnumerator());
  1085. SetStorage ys = SetStorage.GetItemsWorker(y.GetEnumerator());
  1086. return xs.Count == ys.Count && xs.IsSubset(ys);
  1087. }
  1088. public static bool operator !=(DictionaryKeyView x, DictionaryItemView y) {
  1089. if (object.ReferenceEquals(x._dict, y._dict)) {
  1090. return true;
  1091. }
  1092. SetStorage xs = SetStorage.GetItemsWorker(x.GetEnumerator());
  1093. SetStorage ys = SetStorage.GetItemsWorker(y.GetEnumerator());
  1094. return xs.Count != ys.Count || !xs.IsSubset(ys);
  1095. }
  1096. public static bool operator >(DictionaryKeyView x, DictionaryItemView y) {
  1097. if (object.ReferenceEquals(x._dict, y._dict)) {
  1098. return true;
  1099. }
  1100. SetStorage xs = SetStorage.GetItemsWorker(x.GetEnumerator());
  1101. SetStorage ys = SetStorage.GetItemsWorker(y.GetEnumerator());
  1102. return ys.IsStrictSubset(xs);
  1103. }
  1104. public static bool operator <(DictionaryKeyView x, DictionaryItemView y) {
  1105. if (object.ReferenceEquals(x._dict, y._dict)) {
  1106. return true;
  1107. }
  1108. SetStorage xs = SetStorage.GetItemsWorker(x.GetEnumerator());
  1109. SetStorage ys = SetStorage.GetItemsWorker(y.GetEnumerator());
  1110. return xs.IsStrictSubset(ys);
  1111. }
  1112. public static bool operator >=(DictionaryKeyView x, DictionaryItemView y) {
  1113. if (object.ReferenceEquals(x._dict, y._dict)) {
  1114. return false;
  1115. }
  1116. SetStorage xs = SetStorage.GetItemsWorker(x.GetEnumerator());
  1117. SetStorage ys = SetStorage.GetItemsWorker(y.GetEnumerator());
  1118. return ys.IsSubset(xs);
  1119. }
  1120. public static bool operator <=(DictionaryKeyView x, DictionaryItemView y) {
  1121. if (object.ReferenceEquals(x._dict, y._dict)) {
  1122. return false;
  1123. }
  1124. SetStorage xs = SetStorage.GetItemsWorker(x.GetEnumerator());
  1125. SetStorage ys = SetStorage.GetItemsWorker(y.GetEnumerator());
  1126. return xs.IsSubset(ys);
  1127. }
  1128. public static bool operator ==(DictionaryKeyView x, SetCollection y) {
  1129. SetStorage xs = SetStorage.GetItemsWorker(x.GetEnumerator());
  1130. SetStorage ys = y._items;
  1131. return xs.Count == ys.Count && xs.IsSubset(ys);
  1132. }
  1133. public static bool operator !=(DictionaryKeyView x, SetCollection y) {
  1134. SetStorage xs = SetStorage.GetItemsWorker(x.GetEnumerator());
  1135. SetStorage ys = y._items;
  1136. return xs.Count != ys.Count || !xs.IsSubset(ys);
  1137. }
  1138. public static bool operator >(DictionaryKeyView x, SetCollection y) {
  1139. SetStorage xs = SetStorage.GetItemsWorker(x.GetEnumerator());
  1140. SetStorage ys = y._items;
  1141. return ys.IsStrictSubset(xs);
  1142. }
  1143. public static bool operator <(DictionaryKeyView x, SetCollection y) {
  1144. SetStorage xs = SetStorage.GetItemsWorker(x.GetEnumerator());
  1145. SetStorage ys = y._items;
  1146. return xs.IsStrictSubset(ys);
  1147. }
  1148. public static bool operator >=(DictionaryKeyView x, SetCollection y) {
  1149. SetStorage xs = SetStorage.GetItemsWorker(x.GetEnumerator());
  1150. SetStorage ys = y._items;
  1151. return ys.IsSubset(xs);
  1152. }
  1153. public static bool operator <=(DictionaryKeyView x, SetCollection y) {
  1154. SetStorage xs = SetStorage.GetItemsWorker(x.GetEnumerator());
  1155. SetStorage ys = y._items;
  1156. return xs.IsSubset(ys);
  1157. }
  1158. public static bool operator ==(DictionaryKeyView x, FrozenSetCollection y) {
  1159. SetStorage xs = SetStorage.GetItemsWorker(x.GetEnumerator());
  1160. SetStorage ys = y._items;
  1161. return xs.Count == ys.Count && xs.IsSubset(ys);
  1162. }
  1163. public static bool operator !=(DictionaryKeyView x, FrozenSetCollection y) {
  1164. SetStorage xs = SetStorage.GetItemsWorker(x.GetEnumerator());
  1165. SetStorage ys = y._items;
  1166. return xs.Count != ys.Count || !xs.IsSubset(ys);
  1167. }
  1168. public static bool operator >(DictionaryKeyView x, FrozenSetCollection y) {
  1169. SetStorage xs = SetStorage.GetItemsWorker(x.GetEnumerator());
  1170. SetStorage ys = y._items;
  1171. return ys.IsStrictSubset(xs);
  1172. }
  1173. public static bool operator <(DictionaryKeyView x, FrozenSetCollection y) {
  1174. SetStorage xs = SetStorage.GetItemsWorker(x.GetEnumerator());
  1175. SetStorage ys = y._items;
  1176. return xs.IsStrictSubset(ys);
  1177. }
  1178. public static bool operator >=(DictionaryKeyView x, FrozenSetCollection y) {
  1179. SetStorage xs = SetStorage.GetItemsWorker(x.GetEnumerator());
  1180. SetStorage ys = y._items;
  1181. return ys.IsSubset(xs);
  1182. }
  1183. public static bool operator <=(DictionaryKeyView x, FrozenSetCollection y) {
  1184. SetStorage xs = SetStorage.GetItemsWorker(x.GetEnumerator());
  1185. SetStorage ys = y._items;
  1186. return xs.IsSubset(ys);
  1187. }
  1188. // *** END GENERATED CODE ***
  1189. #endregion
  1190. #region ICodeFormattable Members
  1191. public string __repr__(CodeContext context) {
  1192. StringBuilder res = new StringBuilder(20);
  1193. res.Append("dict_keys([");
  1194. string comma = "";
  1195. foreach (object key in this) {
  1196. res.Append(comma);
  1197. comma = ", ";
  1198. res.Append(PythonOps.Repr(context, key));
  1199. }
  1200. res.Append("])");
  1201. return res.ToString();
  1202. }
  1203. #endregion
  1204. public override int GetHashCode() {
  1205. return base.GetHashCode();
  1206. }
  1207. }
  1208. [PythonType("dict_items")]
  1209. public sealed class DictionaryItemView : ICollection<object>, ICodeFormattable {
  1210. internal readonly PythonDictionary _dict;
  1211. internal DictionaryItemView(PythonDictionary/*!*/ dict) {
  1212. Debug.Assert(dict != null);
  1213. _dict = dict;
  1214. }
  1215. [PythonHidden]
  1216. public IEnumerator GetEnumerator() {
  1217. return _dict.iteritems();
  1218. }
  1219. IEnumerator<object> IEnumerable<object>.GetEnumerator() {
  1220. return new DictionaryItemEnumerator(_dict._storage);
  1221. }
  1222. #region ICollection<object> Membe

Large files files are truncated, but you can click here to view the full file