/Languages/IronPython/IronPython/Runtime/Types/DictProxy.cs

https://github.com/kumaryu/IronLanguages-main · C# · 346 lines · 253 code · 79 blank · 14 comment · 23 complexity · 734655b43c946ff953214ba85da69767 MD5 · raw 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.Runtime.InteropServices;
  20. using IronPython.Runtime.Operations;
  21. using Microsoft.Scripting.Runtime;
  22. using Microsoft.Scripting.Utils;
  23. namespace IronPython.Runtime.Types {
  24. [PythonType("dictproxy")]
  25. public class DictProxy : IDictionary, IEnumerable, IDictionary<object, object> {
  26. private readonly PythonType/*!*/ _dt;
  27. public DictProxy(PythonType/*!*/ dt) {
  28. Debug.Assert(dt != null);
  29. _dt = dt;
  30. }
  31. #region Python Public API Surface
  32. public int __len__(CodeContext context) {
  33. return _dt.GetMemberDictionary(context, false).Count;
  34. }
  35. public bool __contains__(CodeContext/*!*/ context, object value) {
  36. return has_key(context, value);
  37. }
  38. public string/*!*/ __str__(CodeContext/*!*/ context) {
  39. return DictionaryOps.__repr__(context, this);
  40. }
  41. public bool has_key(CodeContext/*!*/ context, object key) {
  42. object dummy;
  43. return TryGetValue(context, key, out dummy);
  44. }
  45. public object get(CodeContext/*!*/ context, [NotNull]object k, [DefaultParameterValue(null)]object d) {
  46. object res;
  47. if (!TryGetValue(context, k, out res)) {
  48. res = d;
  49. }
  50. return res;
  51. }
  52. public object keys(CodeContext context) {
  53. return new List(_dt.GetMemberDictionary(context, false).Keys);
  54. }
  55. public object values(CodeContext context) {
  56. List res = new List();
  57. foreach (KeyValuePair<object, object> kvp in _dt.GetMemberDictionary(context, false)) {
  58. PythonTypeUserDescriptorSlot dts = kvp.Value as PythonTypeUserDescriptorSlot;
  59. if (dts != null) {
  60. res.AddNoLock(dts.Value);
  61. } else {
  62. res.AddNoLock(kvp.Value);
  63. }
  64. }
  65. return res;
  66. }
  67. public List items(CodeContext context) {
  68. List res = new List();
  69. foreach (KeyValuePair<object, object> kvp in _dt.GetMemberDictionary(context, false)) {
  70. PythonTypeUserDescriptorSlot dts = kvp.Value as PythonTypeUserDescriptorSlot;
  71. object val;
  72. if (dts != null) {
  73. val = dts.Value;
  74. } else {
  75. val = kvp.Value;
  76. }
  77. res.append(PythonTuple.MakeTuple(kvp.Key, val));
  78. }
  79. return res;
  80. }
  81. public PythonDictionary copy(CodeContext/*!*/ context) {
  82. return new PythonDictionary(context, this);
  83. }
  84. public IEnumerator iteritems(CodeContext/*!*/ context) {
  85. return new DictionaryItemEnumerator(_dt.GetMemberDictionary(context, false)._storage);
  86. }
  87. public IEnumerator iterkeys(CodeContext/*!*/ context) {
  88. return new DictionaryKeyEnumerator(_dt.GetMemberDictionary(context, false)._storage);
  89. }
  90. public IEnumerator itervalues(CodeContext/*!*/ context) {
  91. return new DictionaryValueEnumerator(_dt.GetMemberDictionary(context, false)._storage);
  92. }
  93. #endregion
  94. #region Object overrides
  95. public override bool Equals(object obj) {
  96. DictProxy proxy = obj as DictProxy;
  97. if (proxy == null) return false;
  98. return proxy._dt == _dt;
  99. }
  100. public override int GetHashCode() {
  101. return ~_dt.GetHashCode();
  102. }
  103. #endregion
  104. #region IDictionary Members
  105. public object this[object key] {
  106. get {
  107. return GetIndex(DefaultContext.Default, key);
  108. }
  109. [PythonHidden]
  110. set {
  111. throw PythonOps.TypeError("cannot assign to dictproxy");
  112. }
  113. }
  114. bool IDictionary.Contains(object key) {
  115. return has_key(DefaultContext.Default, key);
  116. }
  117. #endregion
  118. #region IEnumerable Members
  119. System.Collections.IEnumerator IEnumerable.GetEnumerator() {
  120. return DictionaryOps.iterkeys(_dt.GetMemberDictionary(DefaultContext.Default, false));
  121. }
  122. #endregion
  123. #region IDictionary Members
  124. [PythonHidden]
  125. public void Add(object key, object value) {
  126. this[key] = value;
  127. }
  128. [PythonHidden]
  129. public void Clear() {
  130. throw new InvalidOperationException("dictproxy is read-only");
  131. }
  132. IDictionaryEnumerator IDictionary.GetEnumerator() {
  133. return new PythonDictionary.DictEnumerator(_dt.GetMemberDictionary(DefaultContext.Default, false).GetEnumerator());
  134. }
  135. bool IDictionary.IsFixedSize {
  136. get { return true; }
  137. }
  138. bool IDictionary.IsReadOnly {
  139. get { return true; }
  140. }
  141. ICollection IDictionary.Keys {
  142. get {
  143. ICollection<object> res = _dt.GetMemberDictionary(DefaultContext.Default, false).Keys;
  144. ICollection coll = res as ICollection;
  145. if (coll != null) {
  146. return coll;
  147. }
  148. return new List<object>(res);
  149. }
  150. }
  151. void IDictionary.Remove(object key) {
  152. throw new InvalidOperationException("dictproxy is read-only");
  153. }
  154. ICollection IDictionary.Values {
  155. get {
  156. List<object> res = new List<object>();
  157. foreach (KeyValuePair<object, object> kvp in _dt.GetMemberDictionary(DefaultContext.Default, false)) {
  158. res.Add(kvp.Value);
  159. }
  160. return res;
  161. }
  162. }
  163. #endregion
  164. #region ICollection Members
  165. void ICollection.CopyTo(Array array, int index) {
  166. foreach (DictionaryEntry de in (IDictionary)this) {
  167. array.SetValue(de, index++);
  168. }
  169. }
  170. int ICollection.Count {
  171. get { return __len__(DefaultContext.Default); }
  172. }
  173. bool ICollection.IsSynchronized {
  174. get { return false; }
  175. }
  176. object ICollection.SyncRoot {
  177. get { return this; }
  178. }
  179. #endregion
  180. #region IDictionary<object,object> Members
  181. bool IDictionary<object, object>.ContainsKey(object key) {
  182. return has_key(DefaultContext.Default, key);
  183. }
  184. ICollection<object> IDictionary<object, object>.Keys {
  185. get {
  186. return _dt.GetMemberDictionary(DefaultContext.Default, false).Keys;
  187. }
  188. }
  189. bool IDictionary<object, object>.Remove(object key) {
  190. throw new InvalidOperationException("dictproxy is read-only");
  191. }
  192. bool IDictionary<object, object>.TryGetValue(object key, out object value) {
  193. return TryGetValue(DefaultContext.Default, key, out value);
  194. }
  195. ICollection<object> IDictionary<object, object>.Values {
  196. get {
  197. return _dt.GetMemberDictionary(DefaultContext.Default, false).Values;
  198. }
  199. }
  200. #endregion
  201. #region ICollection<KeyValuePair<object,object>> Members
  202. void ICollection<KeyValuePair<object, object>>.Add(KeyValuePair<object, object> item) {
  203. this[item.Key] = item.Value;
  204. }
  205. bool ICollection<KeyValuePair<object, object>>.Contains(KeyValuePair<object, object> item) {
  206. return has_key(DefaultContext.Default, item.Key);
  207. }
  208. void ICollection<KeyValuePair<object, object>>.CopyTo(KeyValuePair<object, object>[] array, int arrayIndex) {
  209. foreach (KeyValuePair<object, object> de in (IEnumerable<KeyValuePair<object, object>>)this) {
  210. array.SetValue(de, arrayIndex++);
  211. }
  212. }
  213. int ICollection<KeyValuePair<object, object>>.Count {
  214. get { return __len__(DefaultContext.Default); }
  215. }
  216. bool ICollection<KeyValuePair<object, object>>.IsReadOnly {
  217. get { return true; }
  218. }
  219. bool ICollection<KeyValuePair<object, object>>.Remove(KeyValuePair<object, object> item) {
  220. return ((IDictionary<object, object>)this).Remove(item.Key);
  221. }
  222. #endregion
  223. #region IEnumerable<KeyValuePair<object,object>> Members
  224. IEnumerator<KeyValuePair<object, object>> IEnumerable<KeyValuePair<object, object>>.GetEnumerator() {
  225. return _dt.GetMemberDictionary(DefaultContext.Default, false).GetEnumerator();
  226. }
  227. #endregion
  228. #region Internal implementation details
  229. private object GetIndex(CodeContext context, object index) {
  230. string strIndex = index as string;
  231. if (strIndex != null) {
  232. PythonTypeSlot dts;
  233. if (_dt.TryLookupSlot(context, strIndex, out dts)) {
  234. PythonTypeUserDescriptorSlot uds = dts as PythonTypeUserDescriptorSlot;
  235. if (uds != null) {
  236. return uds.Value;
  237. }
  238. return dts;
  239. }
  240. }
  241. throw PythonOps.KeyError(index.ToString());
  242. }
  243. private bool TryGetValue(CodeContext/*!*/ context, object key, out object value) {
  244. string strIndex = key as string;
  245. if (strIndex != null) {
  246. PythonTypeSlot dts;
  247. if (_dt.TryLookupSlot(context, strIndex, out dts)) {
  248. PythonTypeUserDescriptorSlot uds = dts as PythonTypeUserDescriptorSlot;
  249. if (uds != null) {
  250. value = uds.Value;
  251. return true;
  252. }
  253. value = dts;
  254. return true;
  255. }
  256. }
  257. value = null;
  258. return false;
  259. }
  260. internal PythonType Type {
  261. get {
  262. return _dt;
  263. }
  264. }
  265. #endregion
  266. }
  267. }