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

/Languages/IronPython/IronPython/Runtime/DictionaryOps.cs

http://github.com/IronLanguages/main
C# | 270 lines | 199 code | 39 blank | 32 comment | 40 complexity | 7eef5ae33d97fe4b508e5efa8b0a77ce 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. using System;
  16. using System.Collections;
  17. using System.Collections.Generic;
  18. using System.Diagnostics;
  19. using System.Runtime.CompilerServices;
  20. using Microsoft.Scripting;
  21. using Microsoft.Scripting.Runtime;
  22. using System.Text;
  23. using IronPython.Runtime.Binding;
  24. using IronPython.Runtime.Operations;
  25. using IronPython.Runtime.Types;
  26. namespace IronPython.Runtime {
  27. /// <summary>
  28. /// Provides both helpers for implementing Python dictionaries as well
  29. /// as providing public methods that should be exposed on all dictionary types.
  30. ///
  31. /// Currently these are published on IDictionary&lt;object, object&gt;
  32. /// </summary>
  33. public static class DictionaryOps {
  34. #region Dictionary Public API Surface
  35. // Dictionary has an odd not-implemented check to support custom dictionaries and therefore
  36. // needs a custom __eq__ / __ne__ implementation.
  37. public static string/*!*/ __repr__(CodeContext/*!*/ context, IDictionary<object, object> self) {
  38. List<object> infinite = PythonOps.GetAndCheckInfinite(self);
  39. if (infinite == null) {
  40. return "{...}";
  41. }
  42. int index = infinite.Count;
  43. infinite.Add(self);
  44. try {
  45. StringBuilder buf = new StringBuilder();
  46. buf.Append("{");
  47. bool first = true;
  48. foreach (KeyValuePair<object, object> kv in self) {
  49. if (first) first = false;
  50. else buf.Append(", ");
  51. if (CustomStringDictionary.IsNullObject(kv.Key))
  52. buf.Append("None");
  53. else
  54. buf.Append(PythonOps.Repr(context, kv.Key));
  55. buf.Append(": ");
  56. buf.Append(PythonOps.Repr(context, kv.Value));
  57. }
  58. buf.Append("}");
  59. return buf.ToString();
  60. } finally {
  61. System.Diagnostics.Debug.Assert(index == infinite.Count - 1);
  62. infinite.RemoveAt(index);
  63. }
  64. }
  65. public static object get(PythonDictionary self, object key) {
  66. return get(self, key, null);
  67. }
  68. public static object get(PythonDictionary self, object key, object defaultValue) {
  69. object ret;
  70. if (self.TryGetValueNoMissing(key, out ret)) return ret;
  71. return defaultValue;
  72. }
  73. public static bool has_key(IDictionary<object, object> self, object key) {
  74. return self.ContainsKey(key);
  75. }
  76. public static List items(IDictionary<object, object> self) {
  77. List ret = PythonOps.MakeEmptyList(self.Count);
  78. foreach (KeyValuePair<object, object> kv in self) {
  79. ret.AddNoLock(PythonTuple.MakeTuple(kv.Key, kv.Value));
  80. }
  81. return ret;
  82. }
  83. public static IEnumerator iteritems(IDictionary<object, object> self) {
  84. return ((IEnumerable)items(self)).GetEnumerator();
  85. }
  86. public static IEnumerator iterkeys(IDictionary<object, object> self) {
  87. return ((IEnumerable)keys(self)).GetEnumerator();
  88. }
  89. public static List keys(IDictionary<object, object> self) {
  90. return PythonOps.MakeListFromSequence(self.Keys);
  91. }
  92. public static object pop(PythonDictionary self, object key) {
  93. //??? perf won't match expected Python perf
  94. object ret;
  95. if (self.TryGetValueNoMissing(key, out ret)) {
  96. self.RemoveDirect(key);
  97. return ret;
  98. } else {
  99. throw PythonOps.KeyError(key);
  100. }
  101. }
  102. public static object pop(PythonDictionary self, object key, object defaultValue) {
  103. //??? perf won't match expected Python perf
  104. object ret;
  105. if (self.TryGetValueNoMissing(key, out ret)) {
  106. self.RemoveDirect(key);
  107. return ret;
  108. } else {
  109. return defaultValue;
  110. }
  111. }
  112. public static PythonTuple popitem(IDictionary<object, object> self) {
  113. IEnumerator<KeyValuePair<object, object>> ie = self.GetEnumerator();
  114. if (ie.MoveNext()) {
  115. object key = ie.Current.Key;
  116. object val = ie.Current.Value;
  117. self.Remove(key);
  118. return PythonTuple.MakeTuple(key, val);
  119. }
  120. throw PythonOps.KeyError("dictionary is empty");
  121. }
  122. public static object setdefault(PythonDictionary self, object key) {
  123. return setdefault(self, key, null);
  124. }
  125. public static object setdefault(PythonDictionary self, object key, object defaultValue) {
  126. object ret;
  127. if (self.TryGetValueNoMissing(key, out ret)) return ret;
  128. self.SetItem(key, defaultValue);
  129. return defaultValue;
  130. }
  131. public static void update(CodeContext/*!*/ context, PythonDictionary/*!*/ self, object other) {
  132. PythonDictionary pyDict;
  133. if ((pyDict = other as PythonDictionary) != null) {
  134. pyDict._storage.CopyTo(ref self._storage);
  135. } else {
  136. SlowUpdate(context, self, other);
  137. }
  138. }
  139. private static void SlowUpdate(CodeContext/*!*/ context, PythonDictionary/*!*/ self, object other) {
  140. object keysFunc;
  141. DictProxy dictProxy;
  142. IDictionary dict;
  143. if ((dictProxy = other as DictProxy) != null) {
  144. update(context, self, dictProxy.Type.GetMemberDictionary(context, false));
  145. } else if ((dict = other as IDictionary) != null) {
  146. IDictionaryEnumerator e = dict.GetEnumerator();
  147. while (e.MoveNext()) {
  148. self._storage.Add(ref self._storage, e.Key, e.Value);
  149. }
  150. } else if (PythonOps.TryGetBoundAttr(other, "keys", out keysFunc)) {
  151. // user defined dictionary
  152. IEnumerator i = PythonOps.GetEnumerator(PythonCalls.Call(context, keysFunc));
  153. while (i.MoveNext()) {
  154. self._storage.Add(ref self._storage, i.Current, PythonOps.GetIndex(context, other, i.Current));
  155. }
  156. } else {
  157. // list of lists (key/value pairs), list of tuples,
  158. // tuple of tuples, etc...
  159. IEnumerator i = PythonOps.GetEnumerator(other);
  160. int index = 0;
  161. while (i.MoveNext()) {
  162. if (!AddKeyValue(self, i.Current)) {
  163. throw PythonOps.ValueError("dictionary update sequence element #{0} has bad length; 2 is required", index);
  164. }
  165. index++;
  166. }
  167. }
  168. }
  169. #endregion
  170. #region Dictionary Helper APIs
  171. internal static bool TryGetValueVirtual(CodeContext context, PythonDictionary self, object key, ref object DefaultGetItem, out object value) {
  172. IPythonObject sdo = self as IPythonObject;
  173. if (sdo != null) {
  174. Debug.Assert(sdo != null);
  175. PythonType myType = sdo.PythonType;
  176. object ret;
  177. PythonTypeSlot dts;
  178. if (DefaultGetItem == null) {
  179. // lazy init our cached DefaultGetItem
  180. TypeCache.Dict.TryLookupSlot(context, "__getitem__", out dts);
  181. bool res = dts.TryGetValue(context, self, TypeCache.Dict, out DefaultGetItem);
  182. Debug.Assert(res);
  183. }
  184. // check and see if it's overridden
  185. if (myType.TryLookupSlot(context, "__getitem__", out dts)) {
  186. dts.TryGetValue(context, self, myType, out ret);
  187. if (ret != DefaultGetItem) {
  188. // subtype of dict that has overridden __getitem__
  189. // we need to call the user's versions, and handle
  190. // any exceptions.
  191. try {
  192. value = self[key];
  193. return true;
  194. } catch (KeyNotFoundException) {
  195. value = null;
  196. return false;
  197. }
  198. }
  199. }
  200. }
  201. value = null;
  202. return false;
  203. }
  204. internal static bool AddKeyValue(PythonDictionary self, object o) {
  205. IEnumerator i = PythonOps.GetEnumerator(o); //c.GetEnumerator();
  206. if (i.MoveNext()) {
  207. object key = i.Current;
  208. if (i.MoveNext()) {
  209. object value = i.Current;
  210. self._storage.Add(ref self._storage, key, value);
  211. return !i.MoveNext();
  212. }
  213. }
  214. return false;
  215. }
  216. internal static int CompareTo(CodeContext/*!*/ context, IDictionary<object, object> left, IDictionary<object, object> right) {
  217. int lcnt = left.Count;
  218. int rcnt = right.Count;
  219. if (lcnt != rcnt) return lcnt > rcnt ? 1 : -1;
  220. List ritems = DictionaryOps.items(right);
  221. return CompareToWorker(context, left, ritems);
  222. }
  223. internal static int CompareToWorker(CodeContext/*!*/ context, IDictionary<object, object> left, List ritems) {
  224. List litems = DictionaryOps.items(left);
  225. litems.sort(context);
  226. ritems.sort(context);
  227. return litems.CompareToWorker(ritems);
  228. }
  229. #endregion
  230. }
  231. }