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

/DICK.B1/IronPython/Runtime/PythonDictionary.cs

https://bitbucket.org/williamybs/uidipythontool
C# | 1153 lines | 873 code | 223 blank | 57 comment | 101 complexity | 9449deecbed83f2d6f4217273a4e8e08 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 System.Security;
  20. using IronPython.Runtime.Operations;
  21. using IronPython.Runtime.Types;
  22. using Microsoft.Scripting;
  23. using Microsoft.Scripting.Runtime;
  24. namespace IronPython.Runtime {
  25. [PythonType("dict"), Serializable, DebuggerTypeProxy(typeof(PythonDictionary.DebugProxy)), DebuggerDisplay("dict, {Count} items")]
  26. public class PythonDictionary : IDictionary<object, object>, IDictionary, IAttributesCollection,
  27. #if CLR2
  28. IValueEquality,
  29. #endif
  30. ICodeFormattable, IStructuralEquatable {
  31. [MultiRuntimeAware]
  32. private static object DefaultGetItem; // our cached __getitem__ method
  33. internal readonly DictionaryStorage _storage;
  34. internal static object MakeDict(CodeContext/*!*/ context, PythonType cls) {
  35. if (cls == TypeCache.Dict) {
  36. return new PythonDictionary();
  37. }
  38. return PythonCalls.Call(context, cls);
  39. }
  40. #region Constructors
  41. public PythonDictionary() {
  42. _storage = new CommonDictionaryStorage();
  43. }
  44. internal PythonDictionary(DictionaryStorage storage) {
  45. _storage = storage;
  46. }
  47. internal PythonDictionary(IDictionary dict) {
  48. _storage = new CommonDictionaryStorage();
  49. lock (_storage) {
  50. foreach (DictionaryEntry de in dict) {
  51. _storage.AddNoLock(de.Key, de.Value);
  52. }
  53. }
  54. }
  55. internal PythonDictionary(PythonDictionary dict) {
  56. _storage = dict._storage.Clone();
  57. }
  58. internal PythonDictionary(CodeContext/*!*/ context, object o)
  59. : this() {
  60. update(context, o);
  61. }
  62. internal PythonDictionary(int size) {
  63. _storage = new CommonDictionaryStorage();
  64. }
  65. internal static PythonDictionary FromIAC(CodeContext context, PythonDictionary iac) {
  66. return iac.GetType() == typeof(PythonDictionary) ? (PythonDictionary)iac : MakeDictFromIAC(context, iac);
  67. }
  68. private static PythonDictionary MakeDictFromIAC(CodeContext context, PythonDictionary iac) {
  69. return new PythonDictionary(new ObjectAttributesAdapter(context, iac));
  70. }
  71. internal static PythonDictionary MakeSymbolDictionary() {
  72. return new PythonDictionary(new StringDictionaryStorage());
  73. }
  74. internal static PythonDictionary MakeSymbolDictionary(int count) {
  75. return new PythonDictionary(new StringDictionaryStorage(count));
  76. }
  77. public void __init__(CodeContext/*!*/ context, object o, [ParamDictionary]IDictionary<object, object> kwArgs) {
  78. update(context, o);
  79. update(context, kwArgs);
  80. }
  81. public void __init__(CodeContext/*!*/ context, [ParamDictionary]IDictionary<object, object> kwArgs) {
  82. update(context, kwArgs);
  83. }
  84. public void __init__(CodeContext/*!*/ context, object o) {
  85. update(context, o);
  86. }
  87. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
  88. public void __init__() {
  89. }
  90. #endregion
  91. #region IDictionary<object,object> Members
  92. [PythonHidden]
  93. public void Add(object key, object value) {
  94. _storage.Add(key, value);
  95. }
  96. [PythonHidden]
  97. public bool ContainsKey(object key) {
  98. return _storage.Contains(key);
  99. }
  100. public ICollection<object> Keys {
  101. [PythonHidden]
  102. get { return keys(); }
  103. }
  104. [PythonHidden]
  105. public bool Remove(object key) {
  106. try {
  107. __delitem__(key);
  108. return true;
  109. } catch (KeyNotFoundException) {
  110. ExceptionHelpers.DynamicStackFrames = null;
  111. return false;
  112. }
  113. }
  114. [PythonHidden]
  115. public bool TryGetValue(object key, out object value) {
  116. if (_storage.TryGetValue(key, out value)) {
  117. return true;
  118. }
  119. // we need to manually look up a slot to get the correct behavior when
  120. // the __missing__ function is declared on a sub-type which is an old-class
  121. if (GetType() != typeof(PythonDictionary) &&
  122. PythonTypeOps.TryInvokeBinaryOperator(DefaultContext.Default,
  123. this,
  124. key,
  125. "__missing__",
  126. out value)) {
  127. return true;
  128. }
  129. return false;
  130. }
  131. internal bool TryGetValueNoMissing(object key, out object value) {
  132. return _storage.TryGetValue(key, out value);
  133. }
  134. public ICollection<object> Values {
  135. [PythonHidden]
  136. get { return values(); }
  137. }
  138. #endregion
  139. #region ICollection<KeyValuePair<object,object>> Members
  140. [PythonHidden]
  141. public void Add(KeyValuePair<object, object> item) {
  142. _storage.Add(item.Key, item.Value);
  143. }
  144. [PythonHidden]
  145. public void Clear() {
  146. _storage.Clear();
  147. }
  148. [PythonHidden]
  149. public bool Contains(KeyValuePair<object, object> item) {
  150. return _storage.Contains(item.Key);
  151. }
  152. [PythonHidden]
  153. public void CopyTo(KeyValuePair<object, object>[] array, int arrayIndex) {
  154. _storage.GetItems().CopyTo(array, arrayIndex);
  155. }
  156. public int Count {
  157. [PythonHidden]
  158. get { return _storage.Count; }
  159. }
  160. bool ICollection<KeyValuePair<object, object>>.IsReadOnly {
  161. get { return false; }
  162. }
  163. [PythonHidden]
  164. public bool Remove(KeyValuePair<object, object> item) {
  165. return _storage.Remove(item.Key);
  166. }
  167. #endregion
  168. #region IEnumerable<KeyValuePair<object,object>> Members
  169. [PythonHidden]
  170. public IEnumerator<KeyValuePair<object, object>> GetEnumerator() {
  171. foreach (KeyValuePair<object, object> kvp in _storage.GetItems()) {
  172. yield return kvp;
  173. }
  174. }
  175. #endregion
  176. #region IEnumerable Members
  177. IEnumerator IEnumerable.GetEnumerator() {
  178. return Converter.ConvertToIEnumerator(__iter__());
  179. }
  180. public virtual object __iter__() {
  181. return new DictionaryKeyEnumerator(_storage);
  182. }
  183. #endregion
  184. #region IMapping Members
  185. public object get(object key) {
  186. return DictionaryOps.get(this, key);
  187. }
  188. public object get(object key, object defaultValue) {
  189. return DictionaryOps.get(this, key, defaultValue);
  190. }
  191. public virtual object this[params object[] key] {
  192. get {
  193. if (key == null) {
  194. return GetItem(null);
  195. }
  196. if (key.Length == 0) {
  197. throw PythonOps.TypeError("__getitem__() takes exactly one argument (0 given)");
  198. }
  199. return this[PythonTuple.MakeTuple(key)];
  200. }
  201. set {
  202. if (key == null) {
  203. SetItem(null, value);
  204. return;
  205. }
  206. if (key.Length == 0) {
  207. throw PythonOps.TypeError("__setitem__() takes exactly two argument (1 given)");
  208. }
  209. this[PythonTuple.MakeTuple(key)] = value;
  210. }
  211. }
  212. public virtual object this[object key] {
  213. get {
  214. return GetItem(key);
  215. }
  216. set {
  217. SetItem(key, value);
  218. }
  219. }
  220. private void SetItem(object key, object value) {
  221. _storage.Add(key, value);
  222. }
  223. private object GetItem(object key) {
  224. object ret;
  225. if (TryGetValue(key, out ret)) {
  226. return ret;
  227. }
  228. throw PythonOps.KeyError(key);
  229. }
  230. public virtual void __delitem__(object key) {
  231. if (!_storage.Remove(key)) {
  232. throw PythonOps.KeyError(key);
  233. }
  234. }
  235. public virtual void __delitem__(params object[] key) {
  236. if (key == null) {
  237. __delitem__((object)null);
  238. } else if (key.Length > 0) {
  239. __delitem__(PythonTuple.MakeTuple(key));
  240. } else {
  241. throw PythonOps.TypeError("__delitem__() takes exactly one argument (0 given)");
  242. }
  243. }
  244. #endregion
  245. #region IPythonContainer Members
  246. public virtual int __len__() {
  247. return Count;
  248. }
  249. #endregion
  250. #region Python dict implementation
  251. public void clear() {
  252. _storage.Clear();
  253. }
  254. public bool has_key(object key) {
  255. return DictionaryOps.has_key(this, key);
  256. }
  257. public object pop(object key) {
  258. return DictionaryOps.pop(this, key);
  259. }
  260. public object pop(object key, object defaultValue) {
  261. return DictionaryOps.pop(this, key, defaultValue);
  262. }
  263. public PythonTuple popitem() {
  264. return DictionaryOps.popitem(this);
  265. }
  266. public object setdefault(object key) {
  267. return DictionaryOps.setdefault(this, key);
  268. }
  269. public object setdefault(object key, object defaultValue) {
  270. return DictionaryOps.setdefault(this, key, defaultValue);
  271. }
  272. public virtual List keys() {
  273. List res = new List();
  274. foreach (KeyValuePair<object, object> kvp in _storage.GetItems()) {
  275. res.append(kvp.Key);
  276. }
  277. return res;
  278. }
  279. public virtual List values() {
  280. List res = new List();
  281. foreach (KeyValuePair<object, object> kvp in _storage.GetItems()) {
  282. res.append(kvp.Value);
  283. }
  284. return res;
  285. }
  286. public virtual List items() {
  287. List res = new List();
  288. foreach (KeyValuePair<object, object> kvp in _storage.GetItems()) {
  289. res.append(PythonTuple.MakeTuple(kvp.Key, kvp.Value));
  290. }
  291. return res;
  292. }
  293. public IEnumerator iteritems() {
  294. return new DictionaryItemEnumerator(_storage);
  295. }
  296. public IEnumerator iterkeys() {
  297. return new DictionaryKeyEnumerator(_storage);
  298. }
  299. public IEnumerator itervalues() {
  300. return new DictionaryValueEnumerator(_storage);
  301. }
  302. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
  303. public void update() {
  304. }
  305. public void update(CodeContext/*!*/ context, [ParamDictionary]IDictionary<object, object> b) {
  306. DictionaryOps.update(context, this, b);
  307. }
  308. public void update(CodeContext/*!*/ context, object b) {
  309. DictionaryOps.update(context, this, b);
  310. }
  311. public void update(CodeContext/*!*/ context, object b, [ParamDictionary]IDictionary<object, object> f) {
  312. DictionaryOps.update(context, this, b);
  313. DictionaryOps.update(context, this, f);
  314. }
  315. private static object fromkeysAny(CodeContext/*!*/ context, PythonType cls, object o, object value) {
  316. PythonDictionary pyDict;
  317. object dict;
  318. if (cls == TypeCache.Dict) {
  319. string str;
  320. ICollection ic = o as ICollection;
  321. // creating our own dict, try and get the ideal size and add w/o locks
  322. if (ic != null) {
  323. pyDict = new PythonDictionary(new CommonDictionaryStorage(ic.Count));
  324. } else if ((str = o as string) != null) {
  325. pyDict = new PythonDictionary(str.Length);
  326. } else {
  327. pyDict = new PythonDictionary();
  328. }
  329. IEnumerator i = PythonOps.GetEnumerator(o);
  330. while (i.MoveNext()) {
  331. pyDict._storage.AddNoLock(i.Current, value);
  332. }
  333. return pyDict;
  334. } else {
  335. // call the user type constructor
  336. dict = MakeDict(context, cls);
  337. pyDict = dict as PythonDictionary;
  338. }
  339. if (pyDict != null) {
  340. // then store all the keys with their associated value
  341. IEnumerator i = PythonOps.GetEnumerator(o);
  342. while (i.MoveNext()) {
  343. pyDict[i.Current] = value;
  344. }
  345. } else {
  346. // slow path, cls.__new__ returned a user defined dictionary instead of a PythonDictionary.
  347. PythonContext pc = PythonContext.GetContext(context);
  348. IEnumerator i = PythonOps.GetEnumerator(o);
  349. while (i.MoveNext()) {
  350. pc.SetIndex(dict, i.Current, value);
  351. }
  352. }
  353. return dict;
  354. }
  355. [ClassMethod]
  356. public static object fromkeys(CodeContext context, PythonType cls, object seq) {
  357. return fromkeys(context, cls, seq, null);
  358. }
  359. [ClassMethod]
  360. public static object fromkeys(CodeContext context, PythonType cls, object seq, object value) {
  361. XRange xr = seq as XRange;
  362. if (xr != null) {
  363. int n = xr.__len__();
  364. object ret = PythonContext.GetContext(context).CallSplat(cls);
  365. if (ret.GetType() == typeof(PythonDictionary)) {
  366. PythonDictionary dr = ret as PythonDictionary;
  367. for (int i = 0; i < n; i++) {
  368. dr[xr[i]] = value;
  369. }
  370. } else {
  371. // slow path, user defined dict
  372. PythonContext pc = PythonContext.GetContext(context);
  373. for (int i = 0; i < n; i++) {
  374. pc.SetIndex(ret, xr[i], value);
  375. }
  376. }
  377. return ret;
  378. }
  379. return fromkeysAny(context, cls, seq, value);
  380. }
  381. public virtual PythonDictionary copy(CodeContext/*!*/ context) {
  382. return new PythonDictionary(_storage.Clone());
  383. }
  384. public virtual bool __contains__(object key) {
  385. return _storage.Contains(key);
  386. }
  387. // Dictionary has an odd not-implemented check to support custom dictionaries and therefore
  388. // needs a custom __eq__ / __ne__ implementation.
  389. [return: MaybeNotImplemented]
  390. public object __eq__(CodeContext/*!*/ context, object other) {
  391. if (!(other is PythonDictionary || other is IDictionary<object, object>))
  392. return NotImplementedType.Value;
  393. return ScriptingRuntimeHelpers.BooleanToObject(
  394. ((IStructuralEquatable)this).Equals(other, PythonContext.GetContext(context).EqualityComparerNonGeneric)
  395. );
  396. }
  397. [return: MaybeNotImplemented]
  398. public object __ne__(CodeContext/*!*/ context, object other) {
  399. if (!(other is PythonDictionary || other is IDictionary<object, object>))
  400. return NotImplementedType.Value;
  401. return ScriptingRuntimeHelpers.BooleanToObject(
  402. !((IStructuralEquatable)this).Equals(other, PythonContext.GetContext(context).EqualityComparerNonGeneric)
  403. );
  404. }
  405. [return: MaybeNotImplemented]
  406. public object __cmp__(CodeContext context, object other) {
  407. IDictionary<object, object> oth = other as IDictionary<object, object>;
  408. // CompareTo is allowed to throw (string, int, etc... all do it if they don't get a matching type)
  409. if (oth == null) {
  410. object len, iteritems;
  411. if (!PythonOps.TryGetBoundAttr(context, other, "__len__", out len) ||
  412. !PythonOps.TryGetBoundAttr(context, other, "iteritems", out iteritems)) {
  413. return NotImplementedType.Value;
  414. }
  415. // user-defined dictionary...
  416. int lcnt = Count;
  417. int rcnt = PythonContext.GetContext(context).ConvertToInt32(PythonOps.CallWithContext(context, len));
  418. if (lcnt != rcnt) return lcnt > rcnt ? 1 : -1;
  419. return DictionaryOps.CompareToWorker(context, this, new List(PythonOps.CallWithContext(context, iteritems)));
  420. }
  421. CompareUtil.Push(this, oth);
  422. try {
  423. return DictionaryOps.CompareTo(context, this, oth);
  424. } finally {
  425. CompareUtil.Pop(this, oth);
  426. }
  427. }
  428. public int __cmp__(CodeContext/*!*/ context, [NotNull]PythonDictionary/*!*/ other) {
  429. CompareUtil.Push(this, other);
  430. try {
  431. return DictionaryOps.CompareTo(context, this, other);
  432. } finally {
  433. CompareUtil.Pop(this, other);
  434. }
  435. }
  436. // these are present in CPython but always return NotImplemented.
  437. [return: MaybeNotImplemented]
  438. [Python3Warning("dict inequality comparisons not supported in 3.x")]
  439. public static NotImplementedType operator > (PythonDictionary self, PythonDictionary other) {
  440. return PythonOps.NotImplemented;
  441. }
  442. [return: MaybeNotImplemented]
  443. [Python3Warning("dict inequality comparisons not supported in 3.x")]
  444. public static NotImplementedType operator <(PythonDictionary self, PythonDictionary other) {
  445. return PythonOps.NotImplemented;
  446. }
  447. [return: MaybeNotImplemented]
  448. [Python3Warning("dict inequality comparisons not supported in 3.x")]
  449. public static NotImplementedType operator >=(PythonDictionary self, PythonDictionary other) {
  450. return PythonOps.NotImplemented;
  451. }
  452. [return: MaybeNotImplemented]
  453. [Python3Warning("dict inequality comparisons not supported in 3.x")]
  454. public static NotImplementedType operator <=(PythonDictionary self, PythonDictionary other) {
  455. return PythonOps.NotImplemented;
  456. }
  457. #endregion
  458. #region IValueEquality Members
  459. #if CLR2
  460. int IValueEquality.GetValueHashCode() {
  461. throw PythonOps.TypeErrorForUnhashableType("dict");
  462. }
  463. bool IValueEquality.ValueEquals(object other) {
  464. return EqualsWorker(other, null);
  465. }
  466. #endif
  467. #endregion
  468. #region IStructuralEquatable Members
  469. public const object __hash__ = null;
  470. int IStructuralEquatable.GetHashCode(IEqualityComparer comparer) {
  471. if (CompareUtil.Check(this)) {
  472. return 0;
  473. }
  474. int res;
  475. ISet pairs = new FrozenSetCollection();
  476. foreach (KeyValuePair<object, object> kvp in _storage.GetItems()) {
  477. pairs.PrivAdd(PythonTuple.MakeTuple(kvp.Key, kvp.Value));
  478. }
  479. CompareUtil.Push(this);
  480. try {
  481. res = pairs.GetHashCode(comparer);
  482. } finally {
  483. CompareUtil.Pop(this);
  484. }
  485. return res;
  486. }
  487. bool IStructuralEquatable.Equals(object other, IEqualityComparer comparer) {
  488. return EqualsWorker(other, comparer);
  489. }
  490. private bool EqualsWorker(object other, IEqualityComparer comparer) {
  491. if (Object.ReferenceEquals(this, other)) return true;
  492. IDictionary<object, object> oth = other as IDictionary<object, object>;
  493. if (oth == null) return false;
  494. if (oth.Count != Count) return false;
  495. PythonDictionary pd = other as PythonDictionary;
  496. if (pd != null) {
  497. return ValueEqualsPythonDict(pd, comparer);
  498. }
  499. // we cannot call Compare here and compare against zero because Python defines
  500. // value equality even if the keys/values are unordered.
  501. List myKeys = keys();
  502. foreach (object o in myKeys) {
  503. object res;
  504. if (!oth.TryGetValue(o, out res)) return false;
  505. CompareUtil.Push(res);
  506. try {
  507. if (comparer == null) {
  508. if (!PythonOps.EqualRetBool(res, this[o])) return false;
  509. } else {
  510. if (!comparer.Equals(res, this[o])) return false;
  511. }
  512. } finally {
  513. CompareUtil.Pop(res);
  514. }
  515. }
  516. return true;
  517. }
  518. private bool ValueEqualsPythonDict(PythonDictionary pd, IEqualityComparer comparer) {
  519. List myKeys = keys();
  520. foreach (object o in myKeys) {
  521. object res;
  522. if (!pd.TryGetValueNoMissing(o, out res)) return false;
  523. CompareUtil.Push(res);
  524. try {
  525. if (comparer == null) {
  526. if (!PythonOps.EqualRetBool(res, this[o])) return false;
  527. } else {
  528. if (!comparer.Equals(res, this[o])) return false;
  529. }
  530. } finally {
  531. CompareUtil.Pop(res);
  532. }
  533. }
  534. return true;
  535. }
  536. #endregion
  537. #region IDictionary Members
  538. [PythonHidden]
  539. public bool Contains(object key) {
  540. return __contains__(key);
  541. }
  542. internal class DictEnumerator : IDictionaryEnumerator {
  543. private IEnumerator<KeyValuePair<object, object>> _enumerator;
  544. private bool _moved;
  545. public DictEnumerator(IEnumerator<KeyValuePair<object, object>> enumerator) {
  546. _enumerator = enumerator;
  547. }
  548. #region IDictionaryEnumerator Members
  549. public DictionaryEntry Entry {
  550. get {
  551. // List<T> enumerator doesn't throw, so we need to.
  552. if (!_moved) throw new InvalidOperationException();
  553. return new DictionaryEntry(_enumerator.Current.Key, _enumerator.Current.Value);
  554. }
  555. }
  556. public object Key {
  557. get { return Entry.Key; }
  558. }
  559. public object Value {
  560. get { return Entry.Value; }
  561. }
  562. #endregion
  563. #region IEnumerator Members
  564. public object Current {
  565. get { return Entry; }
  566. }
  567. public bool MoveNext() {
  568. if (_enumerator.MoveNext()) {
  569. _moved = true;
  570. return true;
  571. }
  572. _moved = false;
  573. return false;
  574. }
  575. public void Reset() {
  576. _enumerator.Reset();
  577. _moved = false;
  578. }
  579. #endregion
  580. }
  581. IDictionaryEnumerator IDictionary.GetEnumerator() {
  582. return new DictEnumerator(_storage.GetItems().GetEnumerator());
  583. }
  584. bool IDictionary.IsFixedSize {
  585. get { return false; }
  586. }
  587. bool IDictionary.IsReadOnly {
  588. get { return false; }
  589. }
  590. ICollection IDictionary.Keys {
  591. get { return this.keys(); }
  592. }
  593. ICollection IDictionary.Values {
  594. get { return values(); }
  595. }
  596. void IDictionary.Remove(object key) {
  597. ((IDictionary<object, object>)this).Remove(key);
  598. }
  599. #endregion
  600. #region ICollection Members
  601. void ICollection.CopyTo(Array array, int index) {
  602. throw new NotImplementedException("The method or operation is not implemented.");
  603. }
  604. bool ICollection.IsSynchronized {
  605. get { return false; }
  606. }
  607. object ICollection.SyncRoot {
  608. get { return null; }
  609. }
  610. #endregion
  611. #region ICodeFormattable Members
  612. public virtual string/*!*/ __repr__(CodeContext/*!*/ context) {
  613. return DictionaryOps.__repr__(context, this);
  614. }
  615. #endregion
  616. #region Fast Attribute Access Support
  617. /* IAttributesDictionary is implemented on our built-in
  618. * dictionaries to allow users to assign dictionaries into
  619. * classes. These dictionaries will resolve their key via
  620. * the field table, but only get used when the user does
  621. * explicit dictionary assignment.
  622. *
  623. */
  624. #region IAttributesCollection Members
  625. void IAttributesCollection.Add(SymbolId name, object value) {
  626. this[SymbolTable.IdToString(name)] = value;
  627. }
  628. bool IAttributesCollection.ContainsKey(SymbolId name) {
  629. return __contains__(SymbolTable.IdToString(name));
  630. }
  631. bool IAttributesCollection.Remove(SymbolId name) {
  632. return ((IDictionary<object, object>)this).Remove(SymbolTable.IdToString(name));
  633. }
  634. ICollection<object> IAttributesCollection.Keys {
  635. get { return keys(); }
  636. }
  637. int IAttributesCollection.Count {
  638. get {
  639. return Count;
  640. }
  641. }
  642. bool IAttributesCollection.TryGetValue(SymbolId name, out object value) {
  643. if (GetType() != typeof(PythonDictionary) &&
  644. DictionaryOps.TryGetValueVirtual(DefaultContext.Default, this, SymbolTable.IdToString(name), ref DefaultGetItem, out value)) {
  645. return true;
  646. }
  647. // call Dict.TryGetValue to get the real value.
  648. return _storage.TryGetValue(SymbolTable.IdToString(name), out value);
  649. }
  650. object IAttributesCollection.this[SymbolId name] {
  651. get {
  652. return this[name];
  653. }
  654. set {
  655. if (GetType() == typeof(PythonDictionary)) {
  656. // no need to call virtual version
  657. _storage.Add(SymbolTable.IdToString(name), value);
  658. } else {
  659. this[SymbolTable.IdToString(name)] = value;
  660. }
  661. }
  662. }
  663. IDictionary<SymbolId, object> IAttributesCollection.SymbolAttributes {
  664. get {
  665. Dictionary<SymbolId, object> d = new Dictionary<SymbolId, object>();
  666. foreach (KeyValuePair<object, object> name in _storage.GetItems()) {
  667. string stringKey = name.Key as string;
  668. if (stringKey == null) continue;
  669. d.Add(SymbolTable.StringToId(stringKey), name.Value);
  670. }
  671. return d;
  672. }
  673. }
  674. void IAttributesCollection.AddObjectKey(object name, object value) { this[name] = value; }
  675. bool IAttributesCollection.TryGetObjectValue(object name, out object value) { return ((IDictionary<object, object>)this).TryGetValue(name, out value); }
  676. bool IAttributesCollection.RemoveObjectKey(object name) { return ((IDictionary<object, object>)this).Remove(name); }
  677. bool IAttributesCollection.ContainsObjectKey(object name) { return __contains__(name); }
  678. IDictionary<object, object> IAttributesCollection.AsObjectKeyedDictionary() { return this; }
  679. #endregion
  680. internal bool TryRemoveValue(object key, out object value) {
  681. return _storage.TryRemoveValue(key, out value);
  682. }
  683. #endregion
  684. #region Debugger View
  685. internal class DebugProxy {
  686. private readonly PythonDictionary _dict;
  687. public DebugProxy(PythonDictionary dict) {
  688. _dict = dict;
  689. }
  690. [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
  691. public List<KeyValueDebugView> Members {
  692. get {
  693. var res = new List<KeyValueDebugView>();
  694. foreach (var v in _dict) {
  695. res.Add(new KeyValueDebugView(v.Key, v.Value));
  696. }
  697. return res;
  698. }
  699. }
  700. }
  701. [DebuggerDisplay("{Value}", Name = "{Key,nq}", Type = "{TypeInfo,nq}")]
  702. internal class KeyValueDebugView {
  703. public readonly object Key;
  704. public readonly object Value;
  705. public KeyValueDebugView(object key, object value) {
  706. Key = key;
  707. Value = value;
  708. }
  709. [DebuggerBrowsable(DebuggerBrowsableState.Never)]
  710. public string TypeInfo {
  711. get {
  712. return "Key: " + PythonTypeOps.GetName(Key) + ", " + "Value: " + PythonTypeOps.GetName(Value);
  713. }
  714. }
  715. }
  716. #endregion
  717. }
  718. #if !SILVERLIGHT // environment variables not available
  719. [Serializable]
  720. internal sealed class EnvironmentDictionaryStorage : DictionaryStorage {
  721. private readonly CommonDictionaryStorage/*!*/ _storage = new CommonDictionaryStorage();
  722. public EnvironmentDictionaryStorage() {
  723. AddEnvironmentVars();
  724. }
  725. private void AddEnvironmentVars() {
  726. try {
  727. foreach (DictionaryEntry de in Environment.GetEnvironmentVariables()) {
  728. Add(de.Key, de.Value);
  729. }
  730. } catch (SecurityException) {
  731. // environment isn't available under partial trust
  732. }
  733. }
  734. public override void Add(object key, object value) {
  735. _storage.Add(key, value);
  736. string s1 = key as string;
  737. string s2 = value as string;
  738. if (s1 != null && s2 != null) {
  739. Environment.SetEnvironmentVariable(s1, s2);
  740. }
  741. }
  742. public override bool Remove(object key) {
  743. bool res = _storage.Remove(key);
  744. string s = key as string;
  745. if (s != null) {
  746. Environment.SetEnvironmentVariable(s, string.Empty);
  747. }
  748. return res;
  749. }
  750. public override bool Contains(object key) {
  751. return _storage.Contains(key);
  752. }
  753. public override bool TryGetValue(object key, out object value) {
  754. return _storage.TryGetValue(key, out value);
  755. }
  756. public override int Count {
  757. get { return _storage.Count; }
  758. }
  759. public override void Clear() {
  760. foreach (var x in GetItems()) {
  761. string key = x.Key as string;
  762. if (key != null) {
  763. Environment.SetEnvironmentVariable(key, string.Empty);
  764. }
  765. }
  766. _storage.Clear();
  767. }
  768. public override List<KeyValuePair<object, object>> GetItems() {
  769. return _storage.GetItems();
  770. }
  771. }
  772. #endif
  773. /// <summary>
  774. /// Note:
  775. /// IEnumerator innerEnum = Dictionary&lt;K,V&gt;.KeysCollections.GetEnumerator();
  776. /// innerEnum.MoveNext() will throw InvalidOperation even if the values get changed,
  777. /// which is supported in python
  778. /// </summary>
  779. [PythonType("dictionary-keyiterator")]
  780. public sealed class DictionaryKeyEnumerator : IEnumerator, IEnumerator<object> {
  781. private readonly int _size;
  782. private readonly DictionaryStorage _dict;
  783. private readonly IEnumerator<object> _keys;
  784. private int _pos;
  785. internal DictionaryKeyEnumerator(DictionaryStorage dict) {
  786. _dict = dict;
  787. _size = dict.Count;
  788. _keys = dict.GetKeys().GetEnumerator();
  789. _pos = -1;
  790. }
  791. bool IEnumerator.MoveNext() {
  792. if (_size != _dict.Count) {
  793. _pos = _size - 1; // make the length 0
  794. throw PythonOps.RuntimeError("dictionary changed size during iteration");
  795. }
  796. if (_keys.MoveNext()) {
  797. _pos++;
  798. return true;
  799. } else {
  800. return false;
  801. }
  802. }
  803. void IEnumerator.Reset() {
  804. _keys.Reset();
  805. _pos = -1;
  806. }
  807. object IEnumerator.Current {
  808. get {
  809. return _keys.Current;
  810. }
  811. }
  812. object IEnumerator<object>.Current {
  813. get {
  814. return _keys.Current;
  815. }
  816. }
  817. void IDisposable.Dispose() {
  818. }
  819. public object __iter__() {
  820. return this;
  821. }
  822. public int __length_hint__() {
  823. return _size - _pos - 1;
  824. }
  825. }
  826. /// <summary>
  827. /// Note:
  828. /// IEnumerator innerEnum = Dictionary&lt;K,V&gt;.KeysCollections.GetEnumerator();
  829. /// innerEnum.MoveNext() will throw InvalidOperation even if the values get changed,
  830. /// which is supported in python
  831. /// </summary>
  832. [PythonType("dictionary-valueiterator")]
  833. public sealed class DictionaryValueEnumerator : IEnumerator, IEnumerator<object> {
  834. private readonly int _size;
  835. DictionaryStorage _dict;
  836. private readonly object[] _values;
  837. private int _pos;
  838. internal DictionaryValueEnumerator(DictionaryStorage dict) {
  839. _dict = dict;
  840. _size = dict.Count;
  841. _values = new object[_size];
  842. int i = 0;
  843. foreach (KeyValuePair<object, object> kvp in dict.GetItems()) {
  844. _values[i++] = kvp.Value;
  845. }
  846. _pos = -1;
  847. }
  848. public bool MoveNext() {
  849. if (_size != _dict.Count) {
  850. _pos = _size - 1; // make the length 0
  851. throw PythonOps.RuntimeError("dictionary changed size during iteration");
  852. }
  853. if (_pos + 1 < _size) {
  854. _pos++;
  855. return true;
  856. } else {
  857. return false;
  858. }
  859. }
  860. public void Reset() {
  861. _pos = -1;
  862. }
  863. public object Current {
  864. get {
  865. return _values[_pos];
  866. }
  867. }
  868. public void Dispose() {
  869. }
  870. public object __iter__() {
  871. return this;
  872. }
  873. public int __len__() {
  874. return _size - _pos - 1;
  875. }
  876. }
  877. /// <summary>
  878. /// Note:
  879. /// IEnumerator innerEnum = Dictionary&lt;K,V&gt;.KeysCollections.GetEnumerator();
  880. /// innerEnum.MoveNext() will throw InvalidOperation even if the values get changed,
  881. /// which is supported in python
  882. /// </summary>
  883. [PythonType("dictionary-itemiterator")]
  884. public sealed class DictionaryItemEnumerator : IEnumerator, IEnumerator<object> {
  885. private readonly int _size;
  886. private readonly DictionaryStorage _dict;
  887. private readonly List<object> _keys;
  888. private readonly List<object> _values;
  889. private int _pos;
  890. internal DictionaryItemEnumerator(DictionaryStorage dict) {
  891. _dict = dict;
  892. _keys = new List<object>(dict.Count);
  893. _values = new List<object>(dict.Count);
  894. foreach (KeyValuePair<object, object> kvp in dict.GetItems()) {
  895. _keys.Add(kvp.Key);
  896. _values.Add(kvp.Value);
  897. }
  898. _size = _values.Count;
  899. _pos = -1;
  900. }
  901. public bool MoveNext() {
  902. if (_size != _dict.Count) {
  903. _pos = _size - 1; // make the length 0
  904. throw PythonOps.RuntimeError("dictionary changed size during iteration");
  905. }
  906. if (_pos + 1 < _size) {
  907. _pos++;
  908. return true;
  909. } else {
  910. return false;
  911. }
  912. }
  913. public void Reset() {
  914. _pos = -1;
  915. }
  916. public object Current {
  917. get {
  918. return PythonOps.MakeTuple(_keys[_pos], _values[_pos]);
  919. }
  920. }
  921. public void Dispose() {
  922. }
  923. public object __iter__() {
  924. return this;
  925. }
  926. public int __len__() {
  927. return _size - _pos - 1;
  928. }
  929. }
  930. }