testing/mochitest/MochiKit/Iter.js

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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

mercurial