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