PageRenderTime 55ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/CoolEngine/IronPython/Src/IronPython/Runtime/Enumerate.cs

#
C# | 439 lines | 326 code | 90 blank | 23 comment | 32 complexity | 2a8f8ac30c7897563758da8e9a69995e 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.Runtime.CompilerServices;
  20. using IronPython.Runtime.Exceptions;
  21. using IronPython.Runtime.Operations;
  22. using IronPython.Runtime.Types;
  23. using Microsoft.Scripting.Runtime;
  24. namespace IronPython.Runtime {
  25. /*
  26. * Enumeraters exposed to Python code directly
  27. *
  28. */
  29. [PythonSystemType("enumerate")]
  30. [Documentation("enumerate(iterable) -> iterator for index, value of iterable")]
  31. public class Enumerate : IEnumerator, IEnumerator<object> {
  32. private readonly IEnumerator _iter;
  33. private int _index;
  34. public Enumerate(object iter) {
  35. this._iter = PythonOps.GetEnumerator(iter);
  36. }
  37. #region IEnumerator Members
  38. void IEnumerator.Reset() {
  39. throw new NotImplementedException();
  40. }
  41. object IEnumerator.Current {
  42. get {
  43. return PythonTuple.MakeTuple(_index++, _iter.Current);
  44. }
  45. }
  46. object IEnumerator<object>.Current {
  47. get {
  48. return ((IEnumerator)this).Current;
  49. }
  50. }
  51. bool IEnumerator.MoveNext() {
  52. return _iter.MoveNext();
  53. }
  54. #endregion
  55. #region IDisposable Members
  56. void IDisposable.Dispose() {
  57. Dispose(true);
  58. GC.SuppressFinalize(this);
  59. }
  60. protected virtual void Dispose(bool notFinalizing) {
  61. }
  62. #endregion
  63. }
  64. [PythonSystemType("ReversedEnumerator")]
  65. public class ReversedEnumerator : IEnumerator, IEnumerator<object> {
  66. private readonly object _getItemMethod;
  67. private object _current;
  68. private int _index;
  69. private int _savedIndex;
  70. public ReversedEnumerator(int length, object getitem) {
  71. this._index = this._savedIndex = length;
  72. this._getItemMethod = getitem;
  73. }
  74. public int __len__() { return _index; }
  75. #region IEnumerator implementation
  76. object IEnumerator.Current {
  77. get {
  78. return _current;
  79. }
  80. }
  81. object IEnumerator<object>.Current {
  82. get {
  83. return ((IEnumerator)this).Current;
  84. }
  85. }
  86. bool IEnumerator.MoveNext() {
  87. if (_index > 0) {
  88. _index--;
  89. _current = PythonCalls.Call(_getItemMethod, _index);
  90. return true;
  91. } else return false;
  92. }
  93. void IEnumerator.Reset() {
  94. _index = _savedIndex;
  95. }
  96. #endregion
  97. #region IDisposable Members
  98. void IDisposable.Dispose() {
  99. Dispose(true);
  100. GC.SuppressFinalize(this);
  101. }
  102. protected virtual void Dispose(bool disposing) {
  103. }
  104. #endregion
  105. }
  106. [PythonSystemType("SentinelIterator")]
  107. public sealed class SentinelIterator : IEnumerator, IEnumerator<object> {
  108. private readonly object _target;
  109. private readonly object _sentinel;
  110. private object _current;
  111. private bool _sinkState;
  112. public SentinelIterator(object target, object sentinel) {
  113. this._target = target;
  114. this._sentinel = sentinel;
  115. this._current = null;
  116. this._sinkState = false;
  117. }
  118. public object __iter__() {
  119. return this;
  120. }
  121. public object next() {
  122. if (((IEnumerator)this).MoveNext()) {
  123. return ((IEnumerator)this).Current;
  124. } else {
  125. throw PythonOps.StopIteration();
  126. }
  127. }
  128. #region IEnumerator implementation
  129. object IEnumerator.Current {
  130. get {
  131. return _current;
  132. }
  133. }
  134. object IEnumerator<object>.Current {
  135. get {
  136. return _current;
  137. }
  138. }
  139. bool IEnumerator.MoveNext() {
  140. if (_sinkState) return false;
  141. _current = PythonCalls.Call(_target);
  142. bool hit = PythonOps.EqualRetBool(_sentinel, _current);
  143. if (hit) _sinkState = true;
  144. return !hit;
  145. }
  146. void IEnumerator.Reset() {
  147. throw new NotImplementedException();
  148. }
  149. #endregion
  150. #region IDisposable Members
  151. void IDisposable.Dispose() {
  152. }
  153. #endregion
  154. }
  155. /*
  156. * Enumeraters exposed to .NET code
  157. *
  158. */
  159. [PythonSystemType("enumerator")]
  160. public class PythonEnumerator : IEnumerator {
  161. private readonly object _baseObject;
  162. private object _nextMethod;
  163. private object _current;
  164. public static bool TryCreate(object baseEnumerator, out IEnumerator enumerator) {
  165. object iter;
  166. if (baseEnumerator is IEnumerator) {
  167. enumerator = (IEnumerator)baseEnumerator;
  168. return true;
  169. }
  170. if (baseEnumerator is IEnumerable) {
  171. enumerator = ((IEnumerable)baseEnumerator).GetEnumerator();
  172. return true;
  173. }
  174. if (PythonOps.TryGetBoundAttr(baseEnumerator, Symbols.Iterator, out iter)) {
  175. object iterator = PythonCalls.Call(iter);
  176. // don't re-wrap if we don't need to (common case is PythonGenerator).
  177. IEnumerable enumerale = iterator as IEnumerable;
  178. if (enumerale != null) {
  179. enumerator = enumerale.GetEnumerator();
  180. } else {
  181. enumerator = new PythonEnumerator(iterator);
  182. }
  183. return true;
  184. } else {
  185. enumerator = null;
  186. return false;
  187. }
  188. }
  189. public static IEnumerator Create(object baseObject) {
  190. IEnumerator res;
  191. if (!TryCreate(baseObject, out res)) {
  192. throw PythonOps.TypeError("cannot convert {0} to IEnumerator", PythonTypeOps.GetName(baseObject));
  193. }
  194. return res;
  195. }
  196. public PythonEnumerator(object iter) {
  197. Debug.Assert(!(iter is PythonGenerator));
  198. this._baseObject = iter;
  199. }
  200. #region IEnumerator Members
  201. public void Reset() {
  202. throw new NotImplementedException();
  203. }
  204. public object Current {
  205. get {
  206. return _current;
  207. }
  208. }
  209. public bool MoveNext() {
  210. if (_nextMethod == null) {
  211. if (!PythonOps.TryGetBoundAttr(_baseObject, Symbols.GeneratorNext, out _nextMethod) || _nextMethod == null) {
  212. throw PythonOps.TypeError("instance has no next() method");
  213. }
  214. }
  215. try {
  216. _current = PythonCalls.Call(_nextMethod);
  217. return true;
  218. } catch (StopIterationException) {
  219. return false;
  220. }
  221. }
  222. #endregion
  223. public object __iter__() {
  224. return this;
  225. }
  226. }
  227. [PythonSystemType("enumerable")]
  228. public class PythonEnumerable : IEnumerable {
  229. private object _iterator;
  230. public static bool TryCreate(object baseEnumerator, out IEnumerable enumerator) {
  231. Debug.Assert(!(baseEnumerator is IEnumerable) || baseEnumerator is IPythonObject); // we shouldn't re-wrap things that don't need it
  232. object iter;
  233. if (PythonOps.TryGetBoundAttr(baseEnumerator, Symbols.Iterator, out iter)) {
  234. object iterator = PythonCalls.Call(iter);
  235. if (iterator is IEnumerable) {
  236. enumerator = (IEnumerable)iterator;
  237. } else {
  238. enumerator = new PythonEnumerable(iterator);
  239. }
  240. return true;
  241. } else {
  242. enumerator = null;
  243. return false;
  244. }
  245. }
  246. public static IEnumerable Create(object baseObject) {
  247. IEnumerable res;
  248. if (!TryCreate(baseObject, out res)) {
  249. throw PythonOps.TypeError("cannot convert {0} to IEnumerable", PythonTypeOps.GetName(baseObject));
  250. }
  251. return res;
  252. }
  253. private PythonEnumerable(object iterator) {
  254. this._iterator = iterator;
  255. }
  256. #region IEnumerable Members
  257. IEnumerator IEnumerable.GetEnumerator() {
  258. return new PythonEnumerator(_iterator);
  259. }
  260. #endregion
  261. }
  262. [PythonSystemType("item-enumerator")]
  263. public class ItemEnumerator : IEnumerator {
  264. private readonly object _getItemMethod;
  265. private object _current;
  266. private int _index;
  267. internal static bool TryCreate(object baseObject, out IEnumerator enumerator) {
  268. object getitem;
  269. if (PythonOps.TryGetBoundAttr(baseObject, Symbols.GetItem, out getitem)) {
  270. enumerator = new ItemEnumerator(getitem);
  271. return true;
  272. } else {
  273. enumerator = null;
  274. return false;
  275. }
  276. }
  277. internal static IEnumerator Create(object baseObject) {
  278. IEnumerator res;
  279. if (!TryCreate(baseObject, out res)) {
  280. throw PythonOps.TypeError("cannot convert {0} to IEnumerator", PythonTypeOps.GetName(baseObject));
  281. }
  282. return res;
  283. }
  284. internal ItemEnumerator(object getItemMethod) {
  285. this._getItemMethod = getItemMethod;
  286. }
  287. #region IEnumerator members
  288. object IEnumerator.Current {
  289. get {
  290. return _current;
  291. }
  292. }
  293. bool IEnumerator.MoveNext() {
  294. if (_index < 0) {
  295. return false;
  296. }
  297. try {
  298. _current = PythonCalls.Call(_getItemMethod, _index);
  299. _index++;
  300. return true;
  301. } catch (IndexOutOfRangeException) {
  302. _current = null;
  303. _index = -1; // this is the end
  304. return false;
  305. } catch (StopIterationException) {
  306. _current = null;
  307. _index = -1; // this is the end
  308. return false;
  309. }
  310. }
  311. void IEnumerator.Reset() {
  312. _index = 0;
  313. _current = null;
  314. }
  315. #endregion
  316. }
  317. [PythonSystemType("item-enumerable")]
  318. public class ItemEnumerable : IEnumerable {
  319. private object _getitem;
  320. internal static bool TryCreate(object baseObject, out ItemEnumerable ie) {
  321. object getitem;
  322. if (PythonOps.TryGetBoundAttr(baseObject, Symbols.GetItem, out getitem)) {
  323. ie = new ItemEnumerable(getitem);
  324. return true;
  325. } else {
  326. ie = null;
  327. return false;
  328. }
  329. }
  330. internal static ItemEnumerable Create(object baseObject) {
  331. ItemEnumerable res;
  332. if (!TryCreate(baseObject, out res)) {
  333. throw PythonOps.TypeError("cannot convert {0} to IEnumerable", PythonTypeOps.GetName(baseObject));
  334. }
  335. return res;
  336. }
  337. private ItemEnumerable(object getitem) {
  338. this._getitem = getitem;
  339. }
  340. public IEnumerator __iter__() {
  341. return ((IEnumerable)this).GetEnumerator();
  342. }
  343. #region IEnumerable Members
  344. IEnumerator IEnumerable.GetEnumerator() {
  345. return new ItemEnumerator(_getitem);
  346. }
  347. #endregion
  348. }
  349. }