Iter.js 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807
  1. /***
  2. MochiKit.Iter 1.4
  3. See <http://mochikit.com/> for documentation, downloads, license, etc.
  4. (c) 2005 Bob Ippolito. All rights Reserved.
  5. ***/
  6. if (typeof(dojo) != 'undefined') {
  7. dojo.provide('MochiKit.Iter');
  8. dojo.require('MochiKit.Base');
  9. }
  10. if (typeof(JSAN) != 'undefined') {
  11. JSAN.use("MochiKit.Base", []);
  12. }
  13. try {
  14. if (typeof(MochiKit.Base) == 'undefined') {
  15. throw "";
  16. }
  17. } catch (e) {
  18. throw "MochiKit.Iter depends on MochiKit.Base!";
  19. }
  20. if (typeof(MochiKit.Iter) == 'undefined') {
  21. MochiKit.Iter = {};
  22. }
  23. MochiKit.Iter.NAME = "MochiKit.Iter";
  24. MochiKit.Iter.VERSION = "1.4";
  25. MochiKit.Base.update(MochiKit.Iter, {
  26. __repr__: function () {
  27. return "[" + this.NAME + " " + this.VERSION + "]";
  28. },
  29. toString: function () {
  30. return this.__repr__();
  31. },
  32. registerIteratorFactory: function (name, check, iterfactory, /* optional */ override) {
  33. MochiKit.Iter.iteratorRegistry.register(name, check, iterfactory, override);
  34. },
  35. iter: function (iterable, /* optional */ sentinel) {
  36. var self = MochiKit.Iter;
  37. if (arguments.length == 2) {
  38. return self.takewhile(
  39. function (a) { return a != sentinel; },
  40. iterable
  41. );
  42. }
  43. if (typeof(iterable.next) == 'function') {
  44. return iterable;
  45. } else if (typeof(iterable.iter) == 'function') {
  46. return iterable.iter();
  47. /*
  48. } else if (typeof(iterable.__iterator__) == 'function') {
  49. //
  50. // XXX: We can't support JavaScript 1.7 __iterator__ directly
  51. // because of Object.prototype.__iterator__
  52. //
  53. return iterable.__iterator__();
  54. */
  55. }
  56. try {
  57. return self.iteratorRegistry.match(iterable);
  58. } catch (e) {
  59. var m = MochiKit.Base;
  60. if (e == m.NotFound) {
  61. e = new TypeError(typeof(iterable) + ": " + m.repr(iterable) + " is not iterable");
  62. }
  63. throw e;
  64. }
  65. },
  66. count: function (n) {
  67. if (!n) {
  68. n = 0;
  69. }
  70. var m = MochiKit.Base;
  71. return {
  72. repr: function () { return "count(" + n + ")"; },
  73. toString: m.forwardCall("repr"),
  74. next: m.counter(n)
  75. };
  76. },
  77. cycle: function (p) {
  78. var self = MochiKit.Iter;
  79. var m = MochiKit.Base;
  80. var lst = [];
  81. var iterator = self.iter(p);
  82. return {
  83. repr: function () { return "cycle(...)"; },
  84. toString: m.forwardCall("repr"),
  85. next: function () {
  86. try {
  87. var rval = iterator.next();
  88. lst.push(rval);
  89. return rval;
  90. } catch (e) {
  91. if (e != self.StopIteration) {
  92. throw e;
  93. }
  94. if (lst.length === 0) {
  95. this.next = function () {
  96. throw self.StopIteration;
  97. };
  98. } else {
  99. var i = -1;
  100. this.next = function () {
  101. i = (i + 1) % lst.length;
  102. return lst[i];
  103. };
  104. }
  105. return this.next();
  106. }
  107. }
  108. };
  109. },
  110. repeat: function (elem, /* optional */n) {
  111. var m = MochiKit.Base;
  112. if (typeof(n) == 'undefined') {
  113. return {
  114. repr: function () {
  115. return "repeat(" + m.repr(elem) + ")";
  116. },
  117. toString: m.forwardCall("repr"),
  118. next: function () {
  119. return elem;
  120. }
  121. };
  122. }
  123. return {
  124. repr: function () {
  125. return "repeat(" + m.repr(elem) + ", " + n + ")";
  126. },
  127. toString: m.forwardCall("repr"),
  128. next: function () {
  129. if (n <= 0) {
  130. throw MochiKit.Iter.StopIteration;
  131. }
  132. n -= 1;
  133. return elem;
  134. }
  135. };
  136. },
  137. next: function (iterator) {
  138. return iterator.next();
  139. },
  140. izip: function (p, q/*, ...*/) {
  141. var m = MochiKit.Base;
  142. var self = MochiKit.Iter;
  143. var next = self.next;
  144. var iterables = m.map(self.iter, arguments);
  145. return {
  146. repr: function () { return "izip(...)"; },
  147. toString: m.forwardCall("repr"),
  148. next: function () { return m.map(next, iterables); }
  149. };
  150. },
  151. ifilter: function (pred, seq) {
  152. var m = MochiKit.Base;
  153. seq = MochiKit.Iter.iter(seq);
  154. if (pred === null) {
  155. pred = m.operator.truth;
  156. }
  157. return {
  158. repr: function () { return "ifilter(...)"; },
  159. toString: m.forwardCall("repr"),
  160. next: function () {
  161. while (true) {
  162. var rval = seq.next();
  163. if (pred(rval)) {
  164. return rval;
  165. }
  166. }
  167. // mozilla warnings aren't too bright
  168. return undefined;
  169. }
  170. };
  171. },
  172. ifilterfalse: function (pred, seq) {
  173. var m = MochiKit.Base;
  174. seq = MochiKit.Iter.iter(seq);
  175. if (pred === null) {
  176. pred = m.operator.truth;
  177. }
  178. return {
  179. repr: function () { return "ifilterfalse(...)"; },
  180. toString: m.forwardCall("repr"),
  181. next: function () {
  182. while (true) {
  183. var rval = seq.next();
  184. if (!pred(rval)) {
  185. return rval;
  186. }
  187. }
  188. // mozilla warnings aren't too bright
  189. return undefined;
  190. }
  191. };
  192. },
  193. islice: function (seq/*, [start,] stop[, step] */) {
  194. var self = MochiKit.Iter;
  195. var m = MochiKit.Base;
  196. seq = self.iter(seq);
  197. var start = 0;
  198. var stop = 0;
  199. var step = 1;
  200. var i = -1;
  201. if (arguments.length == 2) {
  202. stop = arguments[1];
  203. } else if (arguments.length == 3) {
  204. start = arguments[1];
  205. stop = arguments[2];
  206. } else {
  207. start = arguments[1];
  208. stop = arguments[2];
  209. step = arguments[3];
  210. }
  211. return {
  212. repr: function () {
  213. return "islice(" + ["...", start, stop, step].join(", ") + ")";
  214. },
  215. toString: m.forwardCall("repr"),
  216. next: function () {
  217. var rval;
  218. while (i < start) {
  219. rval = seq.next();
  220. i++;
  221. }
  222. if (start >= stop) {
  223. throw self.StopIteration;
  224. }
  225. start += step;
  226. return rval;
  227. }
  228. };
  229. },
  230. imap: function (fun, p, q/*, ...*/) {
  231. var m = MochiKit.Base;
  232. var self = MochiKit.Iter;
  233. var iterables = m.map(self.iter, m.extend(null, arguments, 1));
  234. var map = m.map;
  235. var next = self.next;
  236. return {
  237. repr: function () { return "imap(...)"; },
  238. toString: m.forwardCall("repr"),
  239. next: function () {
  240. return fun.apply(this, map(next, iterables));
  241. }
  242. };
  243. },
  244. applymap: function (fun, seq, self) {
  245. seq = MochiKit.Iter.iter(seq);
  246. var m = MochiKit.Base;
  247. return {
  248. repr: function () { return "applymap(...)"; },
  249. toString: m.forwardCall("repr"),
  250. next: function () {
  251. return fun.apply(self, seq.next());
  252. }
  253. };
  254. },
  255. chain: function (p, q/*, ...*/) {
  256. // dumb fast path
  257. var self = MochiKit.Iter;
  258. var m = MochiKit.Base;
  259. if (arguments.length == 1) {
  260. return self.iter(arguments[0]);
  261. }
  262. var argiter = m.map(self.iter, arguments);
  263. return {
  264. repr: function () { return "chain(...)"; },
  265. toString: m.forwardCall("repr"),
  266. next: function () {
  267. while (argiter.length > 1) {
  268. try {
  269. return argiter[0].next();
  270. } catch (e) {
  271. if (e != self.StopIteration) {
  272. throw e;
  273. }
  274. argiter.shift();
  275. }
  276. }
  277. if (argiter.length == 1) {
  278. // optimize last element
  279. var arg = argiter.shift();
  280. this.next = m.bind("next", arg);
  281. return this.next();
  282. }
  283. throw self.StopIteration;
  284. }
  285. };
  286. },
  287. takewhile: function (pred, seq) {
  288. var self = MochiKit.Iter;
  289. seq = self.iter(seq);
  290. return {
  291. repr: function () { return "takewhile(...)"; },
  292. toString: MochiKit.Base.forwardCall("repr"),
  293. next: function () {
  294. var rval = seq.next();
  295. if (!pred(rval)) {
  296. this.next = function () {
  297. throw self.StopIteration;
  298. };
  299. this.next();
  300. }
  301. return rval;
  302. }
  303. };
  304. },
  305. dropwhile: function (pred, seq) {
  306. seq = MochiKit.Iter.iter(seq);
  307. var m = MochiKit.Base;
  308. var bind = m.bind;
  309. return {
  310. "repr": function () { return "dropwhile(...)"; },
  311. "toString": m.forwardCall("repr"),
  312. "next": function () {
  313. while (true) {
  314. var rval = seq.next();
  315. if (!pred(rval)) {
  316. break;
  317. }
  318. }
  319. this.next = bind("next", seq);
  320. return rval;
  321. }
  322. };
  323. },
  324. _tee: function (ident, sync, iterable) {
  325. sync.pos[ident] = -1;
  326. var m = MochiKit.Base;
  327. var listMin = m.listMin;
  328. return {
  329. repr: function () { return "tee(" + ident + ", ...)"; },
  330. toString: m.forwardCall("repr"),
  331. next: function () {
  332. var rval;
  333. var i = sync.pos[ident];
  334. if (i == sync.max) {
  335. rval = iterable.next();
  336. sync.deque.push(rval);
  337. sync.max += 1;
  338. sync.pos[ident] += 1;
  339. } else {
  340. rval = sync.deque[i - sync.min];
  341. sync.pos[ident] += 1;
  342. if (i == sync.min && listMin(sync.pos) != sync.min) {
  343. sync.min += 1;
  344. sync.deque.shift();
  345. }
  346. }
  347. return rval;
  348. }
  349. };
  350. },
  351. tee: function (iterable, n/* = 2 */) {
  352. var rval = [];
  353. var sync = {
  354. "pos": [],
  355. "deque": [],
  356. "max": -1,
  357. "min": -1
  358. };
  359. if (arguments.length == 1 || typeof(n) == "undefined" || n === null) {
  360. n = 2;
  361. }
  362. var self = MochiKit.Iter;
  363. iterable = self.iter(iterable);
  364. var _tee = self._tee;
  365. for (var i = 0; i < n; i++) {
  366. rval.push(_tee(i, sync, iterable));
  367. }
  368. return rval;
  369. },
  370. list: function (iterable) {
  371. // Fast-path for Array and Array-like
  372. var m = MochiKit.Base;
  373. if (typeof(iterable.slice) == 'function') {
  374. return iterable.slice();
  375. } else if (m.isArrayLike(iterable)) {
  376. return m.concat(iterable);
  377. }
  378. var self = MochiKit.Iter;
  379. iterable = self.iter(iterable);
  380. var rval = [];
  381. try {
  382. while (true) {
  383. rval.push(iterable.next());
  384. }
  385. } catch (e) {
  386. if (e != self.StopIteration) {
  387. throw e;
  388. }
  389. return rval;
  390. }
  391. // mozilla warnings aren't too bright
  392. return undefined;
  393. },
  394. reduce: function (fn, iterable, /* optional */initial) {
  395. var i = 0;
  396. var x = initial;
  397. var self = MochiKit.Iter;
  398. iterable = self.iter(iterable);
  399. if (arguments.length < 3) {
  400. try {
  401. x = iterable.next();
  402. } catch (e) {
  403. if (e == self.StopIteration) {
  404. e = new TypeError("reduce() of empty sequence with no initial value");
  405. }
  406. throw e;
  407. }
  408. i++;
  409. }
  410. try {
  411. while (true) {
  412. x = fn(x, iterable.next());
  413. }
  414. } catch (e) {
  415. if (e != self.StopIteration) {
  416. throw e;
  417. }
  418. }
  419. return x;
  420. },
  421. range: function (/* [start,] stop[, step] */) {
  422. var start = 0;
  423. var stop = 0;
  424. var step = 1;
  425. if (arguments.length == 1) {
  426. stop = arguments[0];
  427. } else if (arguments.length == 2) {
  428. start = arguments[0];
  429. stop = arguments[1];
  430. } else if (arguments.length == 3) {
  431. start = arguments[0];
  432. stop = arguments[1];
  433. step = arguments[2];
  434. } else {
  435. throw new TypeError("range() takes 1, 2, or 3 arguments!");
  436. }
  437. if (step === 0) {
  438. throw new TypeError("range() step must not be 0");
  439. }
  440. return {
  441. next: function () {
  442. if ((step > 0 && start >= stop) || (step < 0 && start <= stop)) {
  443. throw MochiKit.Iter.StopIteration;
  444. }
  445. var rval = start;
  446. start += step;
  447. return rval;
  448. },
  449. repr: function () {
  450. return "range(" + [start, stop, step].join(", ") + ")";
  451. },
  452. toString: MochiKit.Base.forwardCall("repr")
  453. };
  454. },
  455. sum: function (iterable, start/* = 0 */) {
  456. if (typeof(start) == "undefined" || start === null) {
  457. start = 0;
  458. }
  459. var x = start;
  460. var self = MochiKit.Iter;
  461. iterable = self.iter(iterable);
  462. try {
  463. while (true) {
  464. x += iterable.next();
  465. }
  466. } catch (e) {
  467. if (e != self.StopIteration) {
  468. throw e;
  469. }
  470. }
  471. return x;
  472. },
  473. exhaust: function (iterable) {
  474. var self = MochiKit.Iter;
  475. iterable = self.iter(iterable);
  476. try {
  477. while (true) {
  478. iterable.next();
  479. }
  480. } catch (e) {
  481. if (e != self.StopIteration) {
  482. throw e;
  483. }
  484. }
  485. },
  486. forEach: function (iterable, func, /* optional */self) {
  487. var m = MochiKit.Base;
  488. if (arguments.length > 2) {
  489. func = m.bind(func, self);
  490. }
  491. // fast path for array
  492. if (m.isArrayLike(iterable)) {
  493. try {
  494. for (var i = 0; i < iterable.length; i++) {
  495. func(iterable[i]);
  496. }
  497. } catch (e) {
  498. if (e != MochiKit.Iter.StopIteration) {
  499. throw e;
  500. }
  501. }
  502. } else {
  503. self = MochiKit.Iter;
  504. self.exhaust(self.imap(func, iterable));
  505. }
  506. },
  507. every: function (iterable, func) {
  508. var self = MochiKit.Iter;
  509. try {
  510. self.ifilterfalse(func, iterable).next();
  511. return false;
  512. } catch (e) {
  513. if (e != self.StopIteration) {
  514. throw e;
  515. }
  516. return true;
  517. }
  518. },
  519. sorted: function (iterable, /* optional */cmp) {
  520. var rval = MochiKit.Iter.list(iterable);
  521. if (arguments.length == 1) {
  522. cmp = MochiKit.Base.compare;
  523. }
  524. rval.sort(cmp);
  525. return rval;
  526. },
  527. reversed: function (iterable) {
  528. var rval = MochiKit.Iter.list(iterable);
  529. rval.reverse();
  530. return rval;
  531. },
  532. some: function (iterable, func) {
  533. var self = MochiKit.Iter;
  534. try {
  535. self.ifilter(func, iterable).next();
  536. return true;
  537. } catch (e) {
  538. if (e != self.StopIteration) {
  539. throw e;
  540. }
  541. return false;
  542. }
  543. },
  544. iextend: function (lst, iterable) {
  545. if (MochiKit.Base.isArrayLike(iterable)) {
  546. // fast-path for array-like
  547. for (var i = 0; i < iterable.length; i++) {
  548. lst.push(iterable[i]);
  549. }
  550. } else {
  551. var self = MochiKit.Iter;
  552. iterable = self.iter(iterable);
  553. try {
  554. while (true) {
  555. lst.push(iterable.next());
  556. }
  557. } catch (e) {
  558. if (e != self.StopIteration) {
  559. throw e;
  560. }
  561. }
  562. }
  563. return lst;
  564. },
  565. groupby: function(iterable, /* optional */ keyfunc) {
  566. var m = MochiKit.Base;
  567. var self = MochiKit.Iter;
  568. if (arguments.length < 2) {
  569. keyfunc = m.operator.identity;
  570. }
  571. iterable = self.iter(iterable);
  572. // shared
  573. var pk = undefined;
  574. var k = undefined;
  575. var v;
  576. function fetch() {
  577. v = iterable.next();
  578. k = keyfunc(v);
  579. };
  580. function eat() {
  581. var ret = v;
  582. v = undefined;
  583. return ret;
  584. };
  585. var first = true;
  586. return {
  587. repr: function () { return "groupby(...)"; },
  588. next: function() {
  589. // iterator-next
  590. // iterate until meet next group
  591. while (k == pk) {
  592. fetch();
  593. if (first) {
  594. first = false;
  595. break;
  596. }
  597. }
  598. pk = k;
  599. return [k, {
  600. next: function() {
  601. // subiterator-next
  602. if (v == undefined) { // Is there something to eat?
  603. fetch();
  604. }
  605. if (k != pk) {
  606. throw self.StopIteration;
  607. }
  608. return eat();
  609. }
  610. }];
  611. }
  612. };
  613. },
  614. groupby_as_array: function (iterable, /* optional */ keyfunc) {
  615. var m = MochiKit.Base;
  616. var self = MochiKit.Iter;
  617. if (arguments.length < 2) {
  618. keyfunc = m.operator.identity;
  619. }
  620. iterable = self.iter(iterable);
  621. var result = [];
  622. var first = true;
  623. var prev_key;
  624. while (true) {
  625. try {
  626. var value = iterable.next();
  627. var key = keyfunc(value);
  628. } catch (e) {
  629. if (e == self.StopIteration) {
  630. break;
  631. }
  632. throw e;
  633. }
  634. if (first || key != prev_key) {
  635. var values = [];
  636. result.push([key, values]);
  637. }
  638. values.push(value);
  639. first = false;
  640. prev_key = key;
  641. }
  642. return result;
  643. },
  644. arrayLikeIter: function (iterable) {
  645. var i = 0;
  646. return {
  647. repr: function () { return "arrayLikeIter(...)"; },
  648. toString: MochiKit.Base.forwardCall("repr"),
  649. next: function () {
  650. if (i >= iterable.length) {
  651. throw MochiKit.Iter.StopIteration;
  652. }
  653. return iterable[i++];
  654. }
  655. };
  656. },
  657. hasIterateNext: function (iterable) {
  658. return (iterable && typeof(iterable.iterateNext) == "function");
  659. },
  660. iterateNextIter: function (iterable) {
  661. return {
  662. repr: function () { return "iterateNextIter(...)"; },
  663. toString: MochiKit.Base.forwardCall("repr"),
  664. next: function () {
  665. var rval = iterable.iterateNext();
  666. if (rval === null || rval === undefined) {
  667. throw MochiKit.Iter.StopIteration;
  668. }
  669. return rval;
  670. }
  671. };
  672. }
  673. });
  674. MochiKit.Iter.EXPORT_OK = [
  675. "iteratorRegistry",
  676. "arrayLikeIter",
  677. "hasIterateNext",
  678. "iterateNextIter",
  679. ];
  680. MochiKit.Iter.EXPORT = [
  681. "StopIteration",
  682. "registerIteratorFactory",
  683. "iter",
  684. "count",
  685. "cycle",
  686. "repeat",
  687. "next",
  688. "izip",
  689. "ifilter",
  690. "ifilterfalse",
  691. "islice",
  692. "imap",
  693. "applymap",
  694. "chain",
  695. "takewhile",
  696. "dropwhile",
  697. "tee",
  698. "list",
  699. "reduce",
  700. "range",
  701. "sum",
  702. "exhaust",
  703. "forEach",
  704. "every",
  705. "sorted",
  706. "reversed",
  707. "some",
  708. "iextend",
  709. "groupby",
  710. "groupby_as_array"
  711. ];
  712. MochiKit.Iter.__new__ = function () {
  713. var m = MochiKit.Base;
  714. // Re-use StopIteration if exists (e.g. SpiderMonkey)
  715. if (typeof(StopIteration) != "undefined") {
  716. this.StopIteration = StopIteration;
  717. } else {
  718. this.StopIteration = new m.NamedError("StopIteration");
  719. }
  720. this.iteratorRegistry = new m.AdapterRegistry();
  721. // Register the iterator factory for arrays
  722. this.registerIteratorFactory(
  723. "arrayLike",
  724. m.isArrayLike,
  725. this.arrayLikeIter
  726. );
  727. this.registerIteratorFactory(
  728. "iterateNext",
  729. this.hasIterateNext,
  730. this.iterateNextIter
  731. );
  732. this.EXPORT_TAGS = {
  733. ":common": this.EXPORT,
  734. ":all": m.concat(this.EXPORT, this.EXPORT_OK)
  735. };
  736. m.nameFunctions(this);
  737. };
  738. MochiKit.Iter.__new__();
  739. //
  740. // XXX: Internet Explorer blows
  741. //
  742. if (MochiKit.__export__) {
  743. reduce = MochiKit.Iter.reduce;
  744. }
  745. MochiKit.Base._exportSymbols(this, MochiKit.Iter);