PageRenderTime 35ms CodeModel.GetById 4ms RepoModel.GetById 0ms app.codeStats 0ms

/DICK.B1/IronPython.Modules/IterTools.cs

https://bitbucket.org/williamybs/uidipythontool
C# | 980 lines | 769 code | 176 blank | 35 comment | 165 complexity | 8c0c81784c4a9b88606a09d39c1e25b1 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 Microsoft.Scripting;
  19. using Microsoft.Scripting.Runtime;
  20. using Microsoft.Scripting.Utils;
  21. using IronPython.Runtime;
  22. using IronPython.Runtime.Exceptions;
  23. using IronPython.Runtime.Operations;
  24. using IronPython.Runtime.Types;
  25. #if CLR2
  26. using Microsoft.Scripting.Math;
  27. #else
  28. using System.Numerics;
  29. #endif
  30. [assembly: PythonModule("itertools", typeof(IronPython.Modules.PythonIterTools))]
  31. namespace IronPython.Modules {
  32. public static class PythonIterTools {
  33. public const string __doc__ = "Provides functions and classes for working with iterable objects.";
  34. public static object tee(object iterable) {
  35. return tee(iterable, 2);
  36. }
  37. public static object tee(object iterable, int n) {
  38. if (n < 0) throw PythonOps.ValueError("n cannot be negative");
  39. object[] res = new object[n];
  40. if (!(iterable is TeeIterator)) {
  41. IEnumerator iter = PythonOps.GetEnumerator(iterable);
  42. List dataList = new List();
  43. for (int i = 0; i < n; i++) {
  44. res[i] = new TeeIterator(iter, dataList);
  45. }
  46. } else if (n != 0) {
  47. // if you pass in a tee you get back the original tee
  48. // and other iterators that share the same data.
  49. TeeIterator ti = iterable as TeeIterator;
  50. res[0] = ti;
  51. for (int i = 1; i < n; i++) {
  52. res[1] = new TeeIterator(ti._iter, ti._data);
  53. }
  54. }
  55. return PythonTuple.MakeTuple(res);
  56. }
  57. /// <summary>
  58. /// Base class used for iterator wrappers.
  59. /// </summary>
  60. [PythonType, PythonHidden]
  61. public class IterBase : IEnumerator {
  62. private IEnumerator _inner;
  63. internal IEnumerator InnerEnumerator {
  64. set { _inner = value; }
  65. }
  66. #region IEnumerator Members
  67. object IEnumerator.Current {
  68. get { return _inner.Current; }
  69. }
  70. bool IEnumerator.MoveNext() {
  71. return _inner.MoveNext();
  72. }
  73. void IEnumerator.Reset() {
  74. _inner.Reset();
  75. }
  76. public object __iter__() {
  77. return this;
  78. }
  79. #endregion
  80. }
  81. [PythonType]
  82. public class chain : IterBase {
  83. private chain() {
  84. }
  85. public chain(params object[] iterables) {
  86. InnerEnumerator = LazyYielder(iterables);
  87. }
  88. [ClassMethod]
  89. public static chain from_iterable(CodeContext/*!*/ context, PythonType cls, object iterables) {
  90. chain res;
  91. if (cls == DynamicHelpers.GetPythonTypeFromType(typeof(chain))) {
  92. res = new chain();
  93. res.InnerEnumerator = LazyYielder(iterables);
  94. } else {
  95. res = (chain)cls.CreateInstance(context);
  96. res.InnerEnumerator = LazyYielder(iterables);
  97. }
  98. return res;
  99. }
  100. private static IEnumerator<object> LazyYielder(object iterables) {
  101. IEnumerator ie = PythonOps.GetEnumerator(iterables);
  102. while (ie.MoveNext()) {
  103. IEnumerator inner = PythonOps.GetEnumerator(ie.Current);
  104. while (inner.MoveNext()) {
  105. yield return inner.Current;
  106. }
  107. }
  108. }
  109. }
  110. [PythonType]
  111. public class count : IEnumerator, ICodeFormattable {
  112. private BigInteger _cur, _start;
  113. public count() {
  114. _cur = _start = -1;
  115. }
  116. public count([NotNull]BigInteger n) {
  117. _cur = _start = n - 1;
  118. }
  119. #region IEnumerator Members
  120. object IEnumerator.Current {
  121. get {
  122. int res;
  123. if (_cur.AsInt32(out res)) {
  124. return ScriptingRuntimeHelpers.Int32ToObject(res);
  125. }
  126. return _cur;
  127. }
  128. }
  129. bool IEnumerator.MoveNext() {
  130. _cur += 1;
  131. return true;
  132. }
  133. void IEnumerator.Reset() {
  134. _cur = _start;
  135. }
  136. public object __iter__() {
  137. return this;
  138. }
  139. #endregion
  140. #region ICodeFormattable Members
  141. public string/*!*/ __repr__(CodeContext/*!*/ context) {
  142. int res;
  143. if ((_cur + 1).AsInt32(out res)) {
  144. return String.Format("{0}({1})", PythonOps.GetPythonTypeName(this), _cur + 1);
  145. } else {
  146. return String.Format("{0}({1}L)", PythonOps.GetPythonTypeName(this), _cur + 1);
  147. }
  148. }
  149. #endregion
  150. }
  151. [PythonType]
  152. public class cycle : IterBase {
  153. public cycle(object iterable) {
  154. InnerEnumerator = Yielder(PythonOps.GetEnumerator(iterable));
  155. }
  156. private IEnumerator<object> Yielder(IEnumerator iter) {
  157. List result = new List();
  158. while (MoveNextHelper(iter)) {
  159. result.AddNoLock(iter.Current);
  160. yield return iter.Current;
  161. }
  162. if (result.__len__() != 0) {
  163. for (; ; ) {
  164. for (int i = 0; i < result.__len__(); i++) {
  165. yield return result[i];
  166. }
  167. }
  168. }
  169. }
  170. }
  171. [PythonType]
  172. public class dropwhile : IterBase {
  173. private readonly CodeContext/*!*/ _context;
  174. public dropwhile(CodeContext/*!*/ context, object predicate, object iterable) {
  175. _context = context;
  176. InnerEnumerator = Yielder(predicate, PythonOps.GetEnumerator(iterable));
  177. }
  178. private IEnumerator<object> Yielder(object predicate, IEnumerator iter) {
  179. PythonContext pc = PythonContext.GetContext(_context);
  180. while (MoveNextHelper(iter)) {
  181. if (!Converter.ConvertToBoolean(pc.CallSplat(predicate, iter.Current))) {
  182. yield return iter.Current;
  183. break;
  184. }
  185. }
  186. while (MoveNextHelper(iter)) {
  187. yield return iter.Current;
  188. }
  189. }
  190. }
  191. [PythonType]
  192. public class groupby : IterBase {
  193. private static readonly object _starterKey = new object();
  194. private bool _fFinished = false;
  195. private object _key;
  196. private readonly CodeContext/*!*/ _context;
  197. public groupby(CodeContext/*!*/ context, object iterable) {
  198. InnerEnumerator = Yielder(PythonOps.GetEnumerator(iterable));
  199. _context = context;
  200. }
  201. public groupby(CodeContext/*!*/ context, object iterable, object key) {
  202. InnerEnumerator = Yielder(PythonOps.GetEnumerator(iterable));
  203. _context = context;
  204. if (key != null) {
  205. _key = key;
  206. }
  207. }
  208. private IEnumerator<object> Yielder(IEnumerator iter) {
  209. object curKey = _starterKey;
  210. if (MoveNextHelper(iter)) {
  211. while (!_fFinished) {
  212. while (PythonContext.Equal(GetKey(iter.Current), curKey)) {
  213. if (!MoveNextHelper(iter)) {
  214. _fFinished = true;
  215. yield break;
  216. }
  217. }
  218. curKey = GetKey(iter.Current);
  219. yield return PythonTuple.MakeTuple(curKey, Grouper(iter, curKey));
  220. }
  221. }
  222. }
  223. private IEnumerator<object> Grouper(IEnumerator iter, object curKey) {
  224. while (PythonContext.Equal(GetKey(iter.Current), curKey)) {
  225. yield return iter.Current;
  226. if (!MoveNextHelper(iter)) {
  227. _fFinished = true;
  228. yield break;
  229. }
  230. }
  231. }
  232. private object GetKey(object val) {
  233. if (_key == null) return val;
  234. return PythonContext.GetContext(_context).CallSplat(_key, val);
  235. }
  236. }
  237. [PythonType]
  238. public class ifilter : IterBase {
  239. private readonly CodeContext/*!*/ _context;
  240. public ifilter(CodeContext/*!*/ context, object predicate, object iterable) {
  241. _context = context;
  242. InnerEnumerator = Yielder(predicate, PythonOps.GetEnumerator(iterable));
  243. }
  244. private IEnumerator<object> Yielder(object predicate, IEnumerator iter) {
  245. while (MoveNextHelper(iter)) {
  246. if (ShouldYield(predicate, iter.Current)) {
  247. yield return iter.Current;
  248. }
  249. }
  250. }
  251. private bool ShouldYield(object predicate, object current) {
  252. if (predicate == null) return PythonOps.IsTrue(current);
  253. return Converter.ConvertToBoolean(PythonContext.GetContext(_context).CallSplat(predicate, current));
  254. }
  255. }
  256. [PythonType]
  257. public class ifilterfalse : IterBase {
  258. private readonly CodeContext/*!*/ _context;
  259. public ifilterfalse(CodeContext/*!*/ context, object predicate, object iterable) {
  260. _context = context;
  261. InnerEnumerator = Yielder(predicate, PythonOps.GetEnumerator(iterable));
  262. }
  263. private IEnumerator<object> Yielder(object predicate, IEnumerator iter) {
  264. while (MoveNextHelper(iter)) {
  265. if (ShouldYield(predicate, iter.Current)) {
  266. yield return iter.Current;
  267. }
  268. }
  269. }
  270. private bool ShouldYield(object predicate, object current) {
  271. if (predicate == null) return !PythonOps.IsTrue(current);
  272. return !Converter.ConvertToBoolean(
  273. PythonContext.GetContext(_context).CallSplat(predicate, current)
  274. );
  275. }
  276. }
  277. [PythonType]
  278. public class imap : IEnumerator {
  279. private object _function;
  280. private IEnumerator[] _iterables;
  281. private readonly CodeContext/*!*/ _context;
  282. public imap(CodeContext/*!*/ context, object function, params object[] iterables) {
  283. if (iterables.Length < 1) {
  284. throw PythonOps.TypeError("imap() must have at least two arguments");
  285. }
  286. _function = function;
  287. _context = context;
  288. _iterables = new IEnumerator[iterables.Length];
  289. for (int i = 0; i < iterables.Length; i++) {
  290. _iterables[i] = PythonOps.GetEnumerator(iterables[i]);
  291. }
  292. }
  293. #region IEnumerator Members
  294. object IEnumerator.Current {
  295. get {
  296. object[] args = new object[_iterables.Length];
  297. for (int i = 0; i < args.Length; i++) {
  298. args[i] = _iterables[i].Current;
  299. }
  300. if (_function == null) {
  301. return PythonTuple.MakeTuple(args);
  302. } else {
  303. return PythonContext.GetContext(_context).CallSplat(_function, args);
  304. }
  305. }
  306. }
  307. bool IEnumerator.MoveNext() {
  308. for (int i = 0; i < _iterables.Length; i++) {
  309. if (!MoveNextHelper(_iterables[i])) return false;
  310. }
  311. return true;
  312. }
  313. void IEnumerator.Reset() {
  314. for (int i = 0; i < _iterables.Length; i++) {
  315. _iterables[i].Reset();
  316. }
  317. }
  318. public object __iter__() {
  319. return this;
  320. }
  321. #endregion
  322. }
  323. [PythonType]
  324. public class islice : IterBase {
  325. public islice(object iterable, object stop)
  326. : this(iterable, 0, stop, 1) {
  327. }
  328. public islice(object iterable, object start, object stop)
  329. : this(iterable, start, stop, 1) {
  330. }
  331. public islice(object iterable, object start, object stop, object step) {
  332. int startInt = 0, stopInt = -1;
  333. if (start != null && !Converter.TryConvertToInt32(start, out startInt) || startInt < 0)
  334. throw PythonOps.ValueError("start argument must be non-negative integer, ({0})", start);
  335. if (stop != null) {
  336. if (!Converter.TryConvertToInt32(stop, out stopInt) || stopInt < 0)
  337. throw PythonOps.ValueError("stop argument must be non-negative integer ({0})", stop);
  338. }
  339. int stepInt = 1;
  340. if (step != null && !Converter.TryConvertToInt32(step, out stepInt) || stepInt <= 0) {
  341. throw PythonOps.ValueError("step must be 1 or greater for islice");
  342. }
  343. InnerEnumerator = Yielder(PythonOps.GetEnumerator(iterable), startInt, stopInt, stepInt);
  344. }
  345. private IEnumerator<object> Yielder(IEnumerator iter, int start, int stop, int step) {
  346. if (!MoveNextHelper(iter)) yield break;
  347. int cur = 0;
  348. while (cur < start) {
  349. if (!MoveNextHelper(iter)) yield break;
  350. cur++;
  351. }
  352. while (cur < stop || stop == -1) {
  353. yield return iter.Current;
  354. if ((cur + step) < 0) yield break; // early out if we'll overflow.
  355. for (int i = 0; i < step; i++) {
  356. if ((stop != -1 && ++cur >= stop) || !MoveNextHelper(iter)) {
  357. yield break;
  358. }
  359. }
  360. }
  361. }
  362. }
  363. [PythonType]
  364. public class izip : IEnumerator {
  365. private readonly IEnumerator[]/*!*/ _iters;
  366. private PythonTuple _current;
  367. public izip(params object[] iterables) {
  368. _iters = new IEnumerator[iterables.Length];
  369. for (int i = 0; i < iterables.Length; i++) {
  370. _iters[i] = PythonOps.GetEnumerator(iterables[i]);
  371. }
  372. }
  373. #region IEnumerator Members
  374. object IEnumerator.Current {
  375. get {
  376. return _current;
  377. }
  378. }
  379. bool IEnumerator.MoveNext() {
  380. if (_iters.Length == 0) return false;
  381. object[] current = new object[_iters.Length];
  382. for (int i = 0; i < _iters.Length; i++) {
  383. if (!MoveNextHelper(_iters[i])) return false;
  384. // values need to be extraced and saved as we move incase
  385. // the user passed the same iterable multiple times.
  386. current[i] = _iters[i].Current;
  387. }
  388. _current = PythonTuple.MakeTuple(current);
  389. return true;
  390. }
  391. void IEnumerator.Reset() {
  392. throw new NotImplementedException("The method or operation is not implemented.");
  393. }
  394. public object __iter__() {
  395. return this;
  396. }
  397. #endregion
  398. }
  399. [PythonType]
  400. public class izip_longest : IEnumerator {
  401. private readonly IEnumerator[]/*!*/ _iters;
  402. private readonly object _fill;
  403. private PythonTuple _current;
  404. public izip_longest(params object[] iterables) {
  405. _iters = new IEnumerator[iterables.Length];
  406. for (int i = 0; i < iterables.Length; i++) {
  407. _iters[i] = PythonOps.GetEnumerator(iterables[i]);
  408. }
  409. }
  410. public izip_longest([ParamDictionary]IDictionary<object, object> paramDict, params object[] iterables) {
  411. object fill;
  412. if (paramDict.TryGetValue("fillvalue", out fill)) {
  413. _fill = fill;
  414. if (paramDict.Count != 1) {
  415. paramDict.Remove("fillvalue");
  416. throw UnexpectedKeywordArgument(paramDict);
  417. }
  418. } else if (paramDict.Count != 0) {
  419. throw UnexpectedKeywordArgument(paramDict);
  420. }
  421. _iters = new IEnumerator[iterables.Length];
  422. for (int i = 0; i < iterables.Length; i++) {
  423. _iters[i] = PythonOps.GetEnumerator(iterables[i]);
  424. }
  425. }
  426. #region IEnumerator Members
  427. object IEnumerator.Current {
  428. get {
  429. return _current;
  430. }
  431. }
  432. bool IEnumerator.MoveNext() {
  433. if (_iters.Length == 0) return false;
  434. object[] current = new object[_iters.Length];
  435. bool gotValue = false;
  436. for (int i = 0; i < _iters.Length; i++) {
  437. if (!MoveNextHelper(_iters[i])) {
  438. current[i] = _fill;
  439. } else {
  440. // values need to be extraced and saved as we move incase
  441. // the user passed the same iterable multiple times.
  442. gotValue = true;
  443. current[i] = _iters[i].Current;
  444. }
  445. }
  446. if (gotValue) {
  447. _current = PythonTuple.MakeTuple(current);
  448. return true;
  449. }
  450. return false;
  451. }
  452. void IEnumerator.Reset() {
  453. throw new NotImplementedException("The method or operation is not implemented.");
  454. }
  455. public object __iter__() {
  456. return this;
  457. }
  458. #endregion
  459. }
  460. private static Exception UnexpectedKeywordArgument(IDictionary<object, object> paramDict) {
  461. foreach (object name in paramDict.Keys) {
  462. return PythonOps.TypeError("got unexpected keyword argument {0}", name);
  463. }
  464. throw new InvalidOperationException();
  465. }
  466. [PythonType]
  467. public class product : IterBase {
  468. public product(params object[] iterables) {
  469. InnerEnumerator = Yielder(ArrayUtils.ConvertAll(iterables, x => new List(PythonOps.GetEnumerator(x))));
  470. }
  471. public product([ParamDictionary]IDictionary<object, object> paramDict, params object[] iterables) {
  472. object repeat;
  473. int iRepeat = 1;
  474. if (paramDict.TryGetValue("repeat", out repeat)) {
  475. if (repeat is int) {
  476. iRepeat = (int)repeat;
  477. } else {
  478. throw PythonOps.TypeError("an integer is required");
  479. }
  480. if (paramDict.Count != 1) {
  481. paramDict.Remove("repeat");
  482. throw UnexpectedKeywordArgument(paramDict);
  483. }
  484. } else if (paramDict.Count != 0) {
  485. throw UnexpectedKeywordArgument(paramDict);
  486. }
  487. List[] finalIterables = new List[iterables.Length * iRepeat];
  488. for (int i = 0; i < iRepeat; i++) {
  489. for (int j = 0; j < iterables.Length; j++) {
  490. finalIterables[i * iterables.Length + j] = new List(iterables[j]);
  491. }
  492. }
  493. InnerEnumerator = Yielder(finalIterables);
  494. }
  495. private IEnumerator<object> Yielder(List[] iterables) {
  496. if (iterables.Length > 0) {
  497. IEnumerator[] enums = new IEnumerator[iterables.Length];
  498. enums[0] = iterables[0].GetEnumerator();
  499. int curDepth = 0;
  500. do {
  501. if (enums[curDepth].MoveNext()) {
  502. if (curDepth == enums.Length - 1) {
  503. // create a new array so we don't mutate previous tuples
  504. object[] final = new object[enums.Length];
  505. for (int j = 0; j < enums.Length; j++) {
  506. final[j] = enums[j].Current;
  507. }
  508. yield return PythonTuple.MakeTuple(final);
  509. } else {
  510. // going to the next depth, get a new enumerator
  511. curDepth++;
  512. enums[curDepth] = iterables[curDepth].GetEnumerator();
  513. }
  514. } else {
  515. // current depth exhausted, go to the previous iterator
  516. curDepth--;
  517. }
  518. } while (curDepth != -1);
  519. } else {
  520. yield return PythonTuple.EMPTY;
  521. }
  522. }
  523. }
  524. [PythonType]
  525. public class combinations : IterBase {
  526. private readonly List _data;
  527. public combinations(object iterable, object r) {
  528. _data = new List(iterable);
  529. InnerEnumerator = Yielder(GetR(r, _data));
  530. }
  531. private IEnumerator<object> Yielder(int r) {
  532. IEnumerator[] enums = new IEnumerator[r];
  533. if (r > 0) {
  534. enums[0] = _data.GetEnumerator();
  535. int curDepth = 0;
  536. int[] curIndicies = new int[enums.Length];
  537. do {
  538. if (enums[curDepth].MoveNext()) {
  539. curIndicies[curDepth]++;
  540. int curIndex = curIndicies[curDepth];
  541. bool shouldSkip = false;
  542. for (int i = 0; i < curDepth; i++) {
  543. if (curIndicies[i] >= curIndicies[curDepth]) {
  544. // skip if we've already seen this index or a higher
  545. // index elsewhere
  546. shouldSkip = true;
  547. break;
  548. }
  549. }
  550. if (!shouldSkip) {
  551. if (curDepth == enums.Length - 1) {
  552. // create a new array so we don't mutate previous tuples
  553. object[] final = new object[r];
  554. for (int j = 0; j < enums.Length; j++) {
  555. final[j] = enums[j].Current;
  556. }
  557. yield return PythonTuple.MakeTuple(final);
  558. } else {
  559. // going to the next depth, get a new enumerator
  560. curDepth++;
  561. enums[curDepth] = _data.GetEnumerator();
  562. curIndicies[curDepth] = 0;
  563. }
  564. }
  565. } else {
  566. // current depth exhausted, go to the previous iterator
  567. curDepth--;
  568. }
  569. } while (curDepth != -1);
  570. } else {
  571. yield return PythonTuple.EMPTY;
  572. }
  573. }
  574. }
  575. [PythonType]
  576. public class permutations : IterBase {
  577. private readonly List _data;
  578. public permutations(object iterable) {
  579. _data = new List(iterable);
  580. InnerEnumerator = Yielder(_data.Count);
  581. }
  582. public permutations(object iterable, object r) {
  583. _data = new List(iterable);
  584. InnerEnumerator = Yielder(GetR(r, _data));
  585. }
  586. private IEnumerator<object> Yielder(int r) {
  587. if (r > 0) {
  588. IEnumerator[] enums = new IEnumerator[r];
  589. enums[0] = _data.GetEnumerator();
  590. int curDepth = 0;
  591. int[] curIndicies = new int[enums.Length];
  592. do {
  593. if (enums[curDepth].MoveNext()) {
  594. curIndicies[curDepth]++;
  595. int curIndex = curIndicies[curDepth];
  596. bool shouldSkip = false;
  597. for (int i = 0; i < curDepth; i++) {
  598. if (curIndicies[i] == curIndicies[curDepth]) {
  599. // skip if we're already using this index elsewhere
  600. shouldSkip = true;
  601. break;
  602. }
  603. }
  604. if (!shouldSkip) {
  605. if (curDepth == enums.Length - 1) {
  606. // create a new array so we don't mutate previous tuples
  607. object[] final = new object[r];
  608. for (int j = 0; j < enums.Length; j++) {
  609. final[j] = enums[j].Current;
  610. }
  611. yield return PythonTuple.MakeTuple(final);
  612. } else {
  613. // going to the next depth, get a new enumerator
  614. curDepth++;
  615. enums[curDepth] = _data.GetEnumerator();
  616. curIndicies[curDepth] = 0;
  617. }
  618. }
  619. } else {
  620. // current depth exhausted, go to the previous iterator
  621. curDepth--;
  622. }
  623. } while (curDepth != -1);
  624. } else {
  625. yield return PythonTuple.EMPTY;
  626. }
  627. }
  628. }
  629. private static int GetR(object r, List data) {
  630. int ri;
  631. if (r != null) {
  632. ri = Converter.ConvertToInt32(r);
  633. if (ri < 0) {
  634. throw PythonOps.ValueError("r cannot be negative");
  635. }
  636. } else {
  637. ri = data.Count;
  638. }
  639. return ri;
  640. }
  641. [PythonType, DontMapICollectionToLen]
  642. public class repeat : IterBase, ICodeFormattable, ICollection {
  643. private int _remaining;
  644. private bool _fInfinite;
  645. private object _obj;
  646. public repeat(object @object) {
  647. _obj = @object;
  648. InnerEnumerator = Yielder();
  649. _fInfinite = true;
  650. }
  651. public repeat(object @object, int times) {
  652. _obj = @object;
  653. InnerEnumerator = Yielder();
  654. _remaining = times;
  655. }
  656. private IEnumerator<object> Yielder() {
  657. while (_fInfinite || _remaining > 0) {
  658. _remaining--;
  659. yield return _obj;
  660. }
  661. }
  662. public int __length_hint__() {
  663. if (_fInfinite) throw PythonOps.TypeError("len() of unsized object");
  664. return Math.Max(_remaining, 0);
  665. }
  666. #region ICodeFormattable Members
  667. public virtual string/*!*/ __repr__(CodeContext/*!*/ context) {
  668. if (_fInfinite) {
  669. return String.Format("{0}({1})", PythonOps.GetPythonTypeName(this), PythonOps.Repr(context, _obj));
  670. }
  671. return String.Format("{0}({1}, {2})", PythonOps.GetPythonTypeName(this), PythonOps.Repr(context, _obj), _remaining);
  672. }
  673. #endregion
  674. #region ICollection Members
  675. void ICollection.CopyTo(Array array, int index) {
  676. if (_fInfinite) throw new InvalidOperationException();
  677. if (_remaining > array.Length - index) {
  678. throw new IndexOutOfRangeException();
  679. }
  680. for (int i = 0; i < _remaining; i++) {
  681. array.SetValue(_obj, index + i);
  682. }
  683. _remaining = 0;
  684. }
  685. int ICollection.Count {
  686. get { return __length_hint__(); }
  687. }
  688. bool ICollection.IsSynchronized {
  689. get { return false; }
  690. }
  691. object ICollection.SyncRoot {
  692. get { return this; }
  693. }
  694. #endregion
  695. #region IEnumerable Members
  696. IEnumerator IEnumerable.GetEnumerator() {
  697. while (_fInfinite || _remaining > 0) {
  698. _remaining--;
  699. yield return _obj;
  700. }
  701. }
  702. #endregion
  703. }
  704. [PythonType]
  705. public class starmap : IterBase {
  706. public starmap(CodeContext context, object function, object iterable) {
  707. InnerEnumerator = Yielder(context, function, PythonOps.GetEnumerator(iterable));
  708. }
  709. private IEnumerator<object> Yielder(CodeContext context, object function, IEnumerator iter) {
  710. PythonContext pc = PythonContext.GetContext(context);
  711. while (MoveNextHelper(iter)) {
  712. PythonTuple args = iter.Current as PythonTuple;
  713. object[] objargs;
  714. if (args != null) {
  715. objargs = new object[args.__len__()];
  716. for (int i = 0; i < objargs.Length; i++) {
  717. objargs[i] = args[i];
  718. }
  719. } else {
  720. List argsList = new List(PythonOps.GetEnumerator(iter.Current));
  721. objargs = ArrayUtils.ToArray(argsList);
  722. }
  723. yield return pc.CallSplat(function, objargs);
  724. }
  725. }
  726. }
  727. [PythonType]
  728. public class takewhile : IterBase {
  729. private readonly CodeContext/*!*/ _context;
  730. public takewhile(CodeContext/*!*/ context, object predicate, object iterable) {
  731. _context = context;
  732. InnerEnumerator = Yielder(predicate, PythonOps.GetEnumerator(iterable));
  733. }
  734. private IEnumerator<object> Yielder(object predicate, IEnumerator iter) {
  735. while (MoveNextHelper(iter)) {
  736. if(!Converter.ConvertToBoolean(
  737. PythonContext.GetContext(_context).CallSplat(predicate, iter.Current)
  738. )) {
  739. break;
  740. }
  741. yield return iter.Current;
  742. }
  743. }
  744. }
  745. [PythonHidden]
  746. public class TeeIterator : IEnumerator, IWeakReferenceable {
  747. internal IEnumerator _iter;
  748. internal List _data;
  749. private int _curIndex = -1;
  750. private WeakRefTracker _weakRef;
  751. public TeeIterator(object iterable) {
  752. TeeIterator other = iterable as TeeIterator;
  753. if (other != null) {
  754. this._iter = other._iter;
  755. this._data = other._data;
  756. } else {
  757. this._iter = PythonOps.GetEnumerator(iterable);
  758. _data = new List();
  759. }
  760. }
  761. public TeeIterator(IEnumerator iter, List dataList) {
  762. this._iter = iter;
  763. this._data = dataList;
  764. }
  765. #region IEnumerator Members
  766. object IEnumerator.Current {
  767. get {
  768. return _data[_curIndex];
  769. }
  770. }
  771. bool IEnumerator.MoveNext() {
  772. lock (_data) {
  773. _curIndex++;
  774. if (_curIndex >= _data.__len__() && MoveNextHelper(_iter)) {
  775. _data.append(_iter.Current);
  776. }
  777. return _curIndex < _data.__len__();
  778. }
  779. }
  780. void IEnumerator.Reset() {
  781. throw new NotImplementedException("The method or operation is not implemented.");
  782. }
  783. public object __iter__() {
  784. return this;
  785. }
  786. #endregion
  787. #region IWeakReferenceable Members
  788. WeakRefTracker IWeakReferenceable.GetWeakRef() {
  789. return (_weakRef);
  790. }
  791. bool IWeakReferenceable.SetWeakRef(WeakRefTracker value) {
  792. _weakRef = value;
  793. return true;
  794. }
  795. void IWeakReferenceable.SetFinalizer(WeakRefTracker value) {
  796. _weakRef = value;
  797. }
  798. #endregion
  799. }
  800. private static bool MoveNextHelper(IEnumerator move) {
  801. try { return move.MoveNext(); } catch (IndexOutOfRangeException) { return false; } catch (StopIterationException) { return false; }
  802. }
  803. }
  804. }