5 See <http://mochikit.com/> for documentation, downloads, license, etc.
7 (c) 2005 Bob Ippolito. All rights Reserved.
11 if (typeof(dojo
) != 'undefined') {
12 dojo
.provide('MochiKit.Iter');
13 dojo
.require('MochiKit.Base');
16 if (typeof(JSAN
) != 'undefined') {
17 JSAN
.use("MochiKit.Base", []);
21 if (typeof(MochiKit
.Base
) == 'undefined') {
25 throw "MochiKit.Iter depends on MochiKit.Base!";
28 if (typeof(MochiKit
.Iter
) == 'undefined') {
32 MochiKit
.Iter
.NAME
= "MochiKit.Iter";
33 MochiKit
.Iter
.VERSION
= "1.4";
34 MochiKit
.Base
.update(MochiKit
.Iter
, {
35 __repr__: function () {
36 return "[" + this.NAME
+ " " + this.VERSION
+ "]";
38 toString: function () {
39 return this.__repr__();
42 /** @id MochiKit.Iter.registerIteratorFactory */
43 registerIteratorFactory: function (name
, check
, iterfactory
, /* optional */ override
) {
44 MochiKit
.Iter
.iteratorRegistry
.register(name
, check
, iterfactory
, override
);
47 /** @id MochiKit.Iter.iter */
48 iter: function (iterable
, /* optional */ sentinel
) {
49 var self
= MochiKit
.Iter
;
50 if (arguments
.length
== 2) {
51 return self
.takewhile(
52 function (a
) { return a
!= sentinel
; },
56 if (typeof(iterable
.next
) == 'function') {
58 } else if (typeof(iterable
.iter
) == 'function') {
59 return iterable
.iter();
61 } else if (typeof(iterable.__iterator__) == 'function') {
63 // XXX: We can't support JavaScript 1.7 __iterator__ directly
64 // because of Object.prototype.__iterator__
66 return iterable.__iterator__();
71 return self
.iteratorRegistry
.match(iterable
);
73 var m
= MochiKit
.Base
;
74 if (e
== m
.NotFound
) {
75 e
= new TypeError(typeof(iterable
) + ": " + m
.repr(iterable
) + " is not iterable");
81 /** @id MochiKit.Iter.count */
86 var m
= MochiKit
.Base
;
88 repr: function () { return "count(" + n
+ ")"; },
89 toString
: m
.forwardCall("repr"),
94 /** @id MochiKit.Iter.cycle */
96 var self
= MochiKit
.Iter
;
97 var m
= MochiKit
.Base
;
99 var iterator
= self
.iter(p
);
101 repr: function () { return "cycle(...)"; },
102 toString
: m
.forwardCall("repr"),
105 var rval
= iterator
.next();
109 if (e
!= self
.StopIteration
) {
112 if (lst
.length
=== 0) {
113 this.next = function () {
114 throw self
.StopIteration
;
118 this.next = function () {
119 i
= (i
+ 1) % lst
.length
;
129 /** @id MochiKit.Iter.repeat */
130 repeat: function (elem
, /* optional */n
) {
131 var m
= MochiKit
.Base
;
132 if (typeof(n
) == 'undefined') {
135 return "repeat(" + m
.repr(elem
) + ")";
137 toString
: m
.forwardCall("repr"),
145 return "repeat(" + m
.repr(elem
) + ", " + n
+ ")";
147 toString
: m
.forwardCall("repr"),
150 throw MochiKit
.Iter
.StopIteration
;
158 /** @id MochiKit.Iter.next */
159 next: function (iterator
) {
160 return iterator
.next();
163 /** @id MochiKit.Iter.izip */
164 izip: function (p
, q
/*, ...*/) {
165 var m
= MochiKit
.Base
;
166 var self
= MochiKit
.Iter
;
167 var next
= self
.next
;
168 var iterables
= m
.map(self
.iter
, arguments
);
170 repr: function () { return "izip(...)"; },
171 toString
: m
.forwardCall("repr"),
172 next: function () { return m
.map(next
, iterables
); }
176 /** @id MochiKit.Iter.ifilter */
177 ifilter: function (pred
, seq
) {
178 var m
= MochiKit
.Base
;
179 seq
= MochiKit
.Iter
.iter(seq
);
181 pred
= m
.operator
.truth
;
184 repr: function () { return "ifilter(...)"; },
185 toString
: m
.forwardCall("repr"),
188 var rval
= seq
.next();
193 // mozilla warnings aren't too bright
199 /** @id MochiKit.Iter.ifilterfalse */
200 ifilterfalse: function (pred
, seq
) {
201 var m
= MochiKit
.Base
;
202 seq
= MochiKit
.Iter
.iter(seq
);
204 pred
= m
.operator
.truth
;
207 repr: function () { return "ifilterfalse(...)"; },
208 toString
: m
.forwardCall("repr"),
211 var rval
= seq
.next();
216 // mozilla warnings aren't too bright
222 /** @id MochiKit.Iter.islice */
223 islice: function (seq
/*, [start,] stop[, step] */) {
224 var self
= MochiKit
.Iter
;
225 var m
= MochiKit
.Base
;
226 seq
= self
.iter(seq
);
231 if (arguments
.length
== 2) {
233 } else if (arguments
.length
== 3) {
234 start
= arguments
[1];
237 start
= arguments
[1];
243 return "islice(" + ["...", start
, stop
, step
].join(", ") + ")";
245 toString
: m
.forwardCall("repr"),
253 throw self
.StopIteration
;
261 /** @id MochiKit.Iter.imap */
262 imap: function (fun
, p
, q
/*, ...*/) {
263 var m
= MochiKit
.Base
;
264 var self
= MochiKit
.Iter
;
265 var iterables
= m
.map(self
.iter
, m
.extend(null, arguments
, 1));
267 var next
= self
.next
;
269 repr: function () { return "imap(...)"; },
270 toString
: m
.forwardCall("repr"),
272 return fun
.apply(this, map(next
, iterables
));
277 /** @id MochiKit.Iter.applymap */
278 applymap: function (fun
, seq
, self
) {
279 seq
= MochiKit
.Iter
.iter(seq
);
280 var m
= MochiKit
.Base
;
282 repr: function () { return "applymap(...)"; },
283 toString
: m
.forwardCall("repr"),
285 return fun
.apply(self
, seq
.next());
290 /** @id MochiKit.Iter.chain */
291 chain: function (p
, q
/*, ...*/) {
293 var self
= MochiKit
.Iter
;
294 var m
= MochiKit
.Base
;
295 if (arguments
.length
== 1) {
296 return self
.iter(arguments
[0]);
298 var argiter
= m
.map(self
.iter
, arguments
);
300 repr: function () { return "chain(...)"; },
301 toString
: m
.forwardCall("repr"),
303 while (argiter
.length
> 1) {
305 return argiter
[0].next();
307 if (e
!= self
.StopIteration
) {
313 if (argiter
.length
== 1) {
314 // optimize last element
315 var arg
= argiter
.shift();
316 this.next
= m
.bind("next", arg
);
319 throw self
.StopIteration
;
324 /** @id MochiKit.Iter.takewhile */
325 takewhile: function (pred
, seq
) {
326 var self
= MochiKit
.Iter
;
327 seq
= self
.iter(seq
);
329 repr: function () { return "takewhile(...)"; },
330 toString
: MochiKit
.Base
.forwardCall("repr"),
332 var rval
= seq
.next();
334 this.next = function () {
335 throw self
.StopIteration
;
344 /** @id MochiKit.Iter.dropwhile */
345 dropwhile: function (pred
, seq
) {
346 seq
= MochiKit
.Iter
.iter(seq
);
347 var m
= MochiKit
.Base
;
350 "repr": function () { return "dropwhile(...)"; },
351 "toString": m
.forwardCall("repr"),
352 "next": function () {
354 var rval
= seq
.next();
359 this.next
= bind("next", seq
);
365 _tee: function (ident
, sync
, iterable
) {
366 sync
.pos
[ident
] = -1;
367 var m
= MochiKit
.Base
;
368 var listMin
= m
.listMin
;
370 repr: function () { return "tee(" + ident
+ ", ...)"; },
371 toString
: m
.forwardCall("repr"),
374 var i
= sync
.pos
[ident
];
377 rval
= iterable
.next();
378 sync
.deque
.push(rval
);
380 sync
.pos
[ident
] += 1;
382 rval
= sync
.deque
[i
- sync
.min
];
383 sync
.pos
[ident
] += 1;
384 if (i
== sync
.min
&& listMin(sync
.pos
) != sync
.min
) {
394 /** @id MochiKit.Iter.tee */
395 tee: function (iterable
, n
/* = 2 */) {
403 if (arguments
.length
== 1 || typeof(n
) == "undefined" || n
=== null) {
406 var self
= MochiKit
.Iter
;
407 iterable
= self
.iter(iterable
);
408 var _tee
= self
._tee
;
409 for (var i
= 0; i
< n
; i
++) {
410 rval
.push(_tee(i
, sync
, iterable
));
415 /** @id MochiKit.Iter.list */
416 list: function (iterable
) {
417 // Fast-path for Array and Array-like
419 if (iterable
instanceof Array
) {
420 return iterable
.slice();
422 // this is necessary to avoid a Safari crash
423 if (typeof(iterable
) == "function" &&
424 !(iterable
instanceof Function
) &&
425 typeof(iterable
.length
) == 'number') {
427 for (var i
= 0; i
< iterable
.length
; i
++) {
428 rval
.push(iterable
[i
]);
433 var self
= MochiKit
.Iter
;
434 iterable
= self
.iter(iterable
);
438 rval
.push(iterable
.next());
441 if (e
!= self
.StopIteration
) {
446 // mozilla warnings aren't too bright
451 /** @id MochiKit.Iter.reduce */
452 reduce: function (fn
, iterable
, /* optional */initial
) {
455 var self
= MochiKit
.Iter
;
456 iterable
= self
.iter(iterable
);
457 if (arguments
.length
< 3) {
461 if (e
== self
.StopIteration
) {
462 e
= new TypeError("reduce() of empty sequence with no initial value");
470 x
= fn(x
, iterable
.next());
473 if (e
!= self
.StopIteration
) {
480 /** @id MochiKit.Iter.range */
481 range: function (/* [start,] stop[, step] */) {
485 if (arguments
.length
== 1) {
487 } else if (arguments
.length
== 2) {
488 start
= arguments
[0];
490 } else if (arguments
.length
== 3) {
491 start
= arguments
[0];
495 throw new TypeError("range() takes 1, 2, or 3 arguments!");
498 throw new TypeError("range() step must not be 0");
502 if ((step
> 0 && start
>= stop
) || (step
< 0 && start
<= stop
)) {
503 throw MochiKit
.Iter
.StopIteration
;
510 return "range(" + [start
, stop
, step
].join(", ") + ")";
512 toString
: MochiKit
.Base
.forwardCall("repr")
516 /** @id MochiKit.Iter.sum */
517 sum: function (iterable
, start
/* = 0 */) {
518 if (typeof(start
) == "undefined" || start
=== null) {
522 var self
= MochiKit
.Iter
;
523 iterable
= self
.iter(iterable
);
526 x
+= iterable
.next();
529 if (e
!= self
.StopIteration
) {
536 /** @id MochiKit.Iter.exhaust */
537 exhaust: function (iterable
) {
538 var self
= MochiKit
.Iter
;
539 iterable
= self
.iter(iterable
);
545 if (e
!= self
.StopIteration
) {
551 /** @id MochiKit.Iter.forEach */
552 forEach: function (iterable
, func
, /* optional */self
) {
553 var m
= MochiKit
.Base
;
554 if (arguments
.length
> 2) {
555 func
= m
.bind(func
, self
);
557 // fast path for array
558 if (m
.isArrayLike(iterable
)) {
560 for (var i
= 0; i
< iterable
.length
; i
++) {
564 if (e
!= MochiKit
.Iter
.StopIteration
) {
569 self
= MochiKit
.Iter
;
570 self
.exhaust(self
.imap(func
, iterable
));
574 /** @id MochiKit.Iter.every */
575 every: function (iterable
, func
) {
576 var self
= MochiKit
.Iter
;
578 self
.ifilterfalse(func
, iterable
).next();
581 if (e
!= self
.StopIteration
) {
588 /** @id MochiKit.Iter.sorted */
589 sorted: function (iterable
, /* optional */cmp
) {
590 var rval
= MochiKit
.Iter
.list(iterable
);
591 if (arguments
.length
== 1) {
592 cmp
= MochiKit
.Base
.compare
;
598 /** @id MochiKit.Iter.reversed */
599 reversed: function (iterable
) {
600 var rval
= MochiKit
.Iter
.list(iterable
);
605 /** @id MochiKit.Iter.some */
606 some: function (iterable
, func
) {
607 var self
= MochiKit
.Iter
;
609 self
.ifilter(func
, iterable
).next();
612 if (e
!= self
.StopIteration
) {
619 /** @id MochiKit.Iter.iextend */
620 iextend: function (lst
, iterable
) {
621 if (MochiKit
.Base
.isArrayLike(iterable
)) {
622 // fast-path for array-like
623 for (var i
= 0; i
< iterable
.length
; i
++) {
624 lst
.push(iterable
[i
]);
627 var self
= MochiKit
.Iter
;
628 iterable
= self
.iter(iterable
);
631 lst
.push(iterable
.next());
634 if (e
!= self
.StopIteration
) {
642 /** @id MochiKit.Iter.groupby */
643 groupby: function(iterable
, /* optional */ keyfunc
) {
644 var m
= MochiKit
.Base
;
645 var self
= MochiKit
.Iter
;
646 if (arguments
.length
< 2) {
647 keyfunc
= m
.operator
.identity
;
649 iterable
= self
.iter(iterable
);
668 var compare
= m
.compare
;
670 repr: function () { return "groupby(...)"; },
674 // iterate until meet next group
675 while (compare(k
, pk
) === 0) {
686 if (v
== undefined) { // Is there something to eat?
689 if (compare(k
, pk
) !== 0) {
690 throw self
.StopIteration
;
699 /** @id MochiKit.Iter.groupby_as_array */
700 groupby_as_array: function (iterable
, /* optional */ keyfunc
) {
701 var m
= MochiKit
.Base
;
702 var self
= MochiKit
.Iter
;
703 if (arguments
.length
< 2) {
704 keyfunc
= m
.operator
.identity
;
707 iterable
= self
.iter(iterable
);
711 var compare
= m
.compare
;
714 var value
= iterable
.next();
715 var key
= keyfunc(value
);
717 if (e
== self
.StopIteration
) {
722 if (first
|| compare(key
, prev_key
) !== 0) {
724 result
.push([key
, values
]);
733 /** @id MochiKit.Iter.arrayLikeIter */
734 arrayLikeIter: function (iterable
) {
737 repr: function () { return "arrayLikeIter(...)"; },
738 toString
: MochiKit
.Base
.forwardCall("repr"),
740 if (i
>= iterable
.length
) {
741 throw MochiKit
.Iter
.StopIteration
;
743 return iterable
[i
++];
748 /** @id MochiKit.Iter.hasIterateNext */
749 hasIterateNext: function (iterable
) {
750 return (iterable
&& typeof(iterable
.iterateNext
) == "function");
753 /** @id MochiKit.Iter.iterateNextIter */
754 iterateNextIter: function (iterable
) {
756 repr: function () { return "iterateNextIter(...)"; },
757 toString
: MochiKit
.Base
.forwardCall("repr"),
759 var rval
= iterable
.iterateNext();
760 if (rval
=== null || rval
=== undefined) {
761 throw MochiKit
.Iter
.StopIteration
;
770 MochiKit
.Iter
.EXPORT_OK
= [
777 MochiKit
.Iter
.EXPORT
= [
779 "registerIteratorFactory",
810 MochiKit
.Iter
.__new__ = function () {
811 var m
= MochiKit
.Base
;
812 // Re-use StopIteration if exists (e.g. SpiderMonkey)
813 if (typeof(StopIteration
) != "undefined") {
814 this.StopIteration
= StopIteration
;
816 /** @id MochiKit.Iter.StopIteration */
817 this.StopIteration
= new m
.NamedError("StopIteration");
819 this.iteratorRegistry
= new m
.AdapterRegistry();
820 // Register the iterator factory for arrays
821 this.registerIteratorFactory(
827 this.registerIteratorFactory(
834 ":common": this.EXPORT
,
835 ":all": m
.concat(this.EXPORT
, this.EXPORT_OK
)
838 m
.nameFunctions(this);
842 MochiKit
.Iter
.__new__();
845 // XXX: Internet Explorer blows
847 if (MochiKit
.__export__
) {
848 reduce
= MochiKit
.Iter
.reduce
;
851 MochiKit
.Base
._exportSymbols(this, MochiKit
.Iter
);