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

/Languages/IronPython/IronPython.Modules/IterTools.cs

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