You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

808 lines
23 KiB

/***
MochiKit.Iter 1.4
See <http://mochikit.com/> for documentation, downloads, license, etc.
(c) 2005 Bob Ippolito. All rights Reserved.
***/
if (typeof(dojo) != 'undefined') {
dojo.provide('MochiKit.Iter');
dojo.require('MochiKit.Base');
}
if (typeof(JSAN) != 'undefined') {
JSAN.use("MochiKit.Base", []);
}
try {
if (typeof(MochiKit.Base) == 'undefined') {
throw "";
}
} catch (e) {
throw "MochiKit.Iter depends on MochiKit.Base!";
}
if (typeof(MochiKit.Iter) == 'undefined') {
MochiKit.Iter = {};
}
MochiKit.Iter.NAME = "MochiKit.Iter";
MochiKit.Iter.VERSION = "1.4";
MochiKit.Base.update(MochiKit.Iter, {
__repr__: function () {
return "[" + this.NAME + " " + this.VERSION + "]";
},
toString: function () {
return this.__repr__();
},
registerIteratorFactory: function (name, check, iterfactory, /* optional */ override) {
MochiKit.Iter.iteratorRegistry.register(name, check, iterfactory, override);
},
iter: function (iterable, /* optional */ sentinel) {
var self = MochiKit.Iter;
if (arguments.length == 2) {
return self.takewhile(
function (a) { return a != sentinel; },
iterable
);
}
if (typeof(iterable.next) == 'function') {
return iterable;
} else if (typeof(iterable.iter) == 'function') {
return iterable.iter();
/*
} else if (typeof(iterable.__iterator__) == 'function') {
//
// XXX: We can't support JavaScript 1.7 __iterator__ directly
// because of Object.prototype.__iterator__
//
return iterable.__iterator__();
*/
}
try {
return self.iteratorRegistry.match(iterable);
} catch (e) {
var m = MochiKit.Base;
if (e == m.NotFound) {
e = new TypeError(typeof(iterable) + ": " + m.repr(iterable) + " is not iterable");
}
throw e;
}
},
// count: function (n) {
// if (!n) {
// n = 0;
// }
// var m = MochiKit.Base;
// return {
// repr: function () { return "count(" + n + ")"; },
// toString: m.forwardCall("repr"),
// next: m.counter(n)
// };
// },
// cycle: function (p) {
// var self = MochiKit.Iter;
// var m = MochiKit.Base;
// var lst = [];
// var iterator = self.iter(p);
// return {
// repr: function () { return "cycle(...)"; },
// toString: m.forwardCall("repr"),
// next: function () {
// try {
// var rval = iterator.next();
// lst.push(rval);
// return rval;
// } catch (e) {
// if (e != self.StopIteration) {
// throw e;
// }
// if (lst.length === 0) {
// this.next = function () {
// throw self.StopIteration;
// };
// } else {
// var i = -1;
// this.next = function () {
// i = (i + 1) % lst.length;
// return lst[i];
// };
// }
// return this.next();
// }
// }
// };
// },
repeat: function (elem, /* optional */n) {
var m = MochiKit.Base;
if (typeof(n) == 'undefined') {
return {
repr: function () {
return "repeat(" + m.repr(elem) + ")";
},
toString: m.forwardCall("repr"),
next: function () {
return elem;
}
};
}
return {
repr: function () {
return "repeat(" + m.repr(elem) + ", " + n + ")";
},
toString: m.forwardCall("repr"),
next: function () {
if (n <= 0) {
throw MochiKit.Iter.StopIteration;
}
n -= 1;
return elem;
}
};
},
next: function (iterator) {
return iterator.next();
},
// izip: function (p, q/*, ...*/) {
// var m = MochiKit.Base;
// var self = MochiKit.Iter;
// var next = self.next;
// var iterables = m.map(self.iter, arguments);
// return {
// repr: function () { return "izip(...)"; },
// toString: m.forwardCall("repr"),
// next: function () { return m.map(next, iterables); }
// };
// },
ifilter: function (pred, seq) {
var m = MochiKit.Base;
seq = MochiKit.Iter.iter(seq);
if (pred === null) {
pred = m.operator.truth;
}
return {
repr: function () { return "ifilter(...)"; },
toString: m.forwardCall("repr"),
next: function () {
while (true) {
var rval = seq.next();
if (pred(rval)) {
return rval;
}
}
// mozilla warnings aren't too bright
return undefined;
}
};
},
ifilterfalse: function (pred, seq) {
var m = MochiKit.Base;
seq = MochiKit.Iter.iter(seq);
if (pred === null) {
pred = m.operator.truth;
}
return {
repr: function () { return "ifilterfalse(...)"; },
toString: m.forwardCall("repr"),
next: function () {
while (true) {
var rval = seq.next();
if (!pred(rval)) {
return rval;
}
}
// mozilla warnings aren't too bright
return undefined;
}
};
},
// islice: function (seq/*, [start,] stop[, step] */) {
// var self = MochiKit.Iter;
// var m = MochiKit.Base;
// seq = self.iter(seq);
// var start = 0;
// var stop = 0;
// var step = 1;
// var i = -1;
// if (arguments.length == 2) {
// stop = arguments[1];
// } else if (arguments.length == 3) {
// start = arguments[1];
// stop = arguments[2];
// } else {
// start = arguments[1];
// stop = arguments[2];
// step = arguments[3];
// }
// return {
// repr: function () {
// return "islice(" + ["...", start, stop, step].join(", ") + ")";
// },
// toString: m.forwardCall("repr"),
// next: function () {
// var rval;
// while (i < start) {
// rval = seq.next();
// i++;
// }
// if (start >= stop) {
// throw self.StopIteration;
// }
// start += step;
// return rval;
// }
// };
// },
imap: function (fun, p, q/*, ...*/) {
var m = MochiKit.Base;
var self = MochiKit.Iter;
var iterables = m.map(self.iter, m.extend(null, arguments, 1));
var map = m.map;
var next = self.next;
return {
repr: function () { return "imap(...)"; },
toString: m.forwardCall("repr"),
next: function () {
return fun.apply(this, map(next, iterables));
}
};
},
// applymap: function (fun, seq, self) {
// seq = MochiKit.Iter.iter(seq);
// var m = MochiKit.Base;
// return {
// repr: function () { return "applymap(...)"; },
// toString: m.forwardCall("repr"),
// next: function () {
// return fun.apply(self, seq.next());
// }
// };
// },
// chain: function (p, q/*, ...*/) {
// // dumb fast path
// var self = MochiKit.Iter;
// var m = MochiKit.Base;
// if (arguments.length == 1) {
// return self.iter(arguments[0]);
// }
// var argiter = m.map(self.iter, arguments);
// return {
// repr: function () { return "chain(...)"; },
// toString: m.forwardCall("repr"),
// next: function () {
// while (argiter.length > 1) {
// try {
// return argiter[0].next();
// } catch (e) {
// if (e != self.StopIteration) {
// throw e;
// }
// argiter.shift();
// }
// }
// if (argiter.length == 1) {
// // optimize last element
// var arg = argiter.shift();
// this.next = m.bind("next", arg);
// return this.next();
// }
// throw self.StopIteration;
// }
// };
// },
// takewhile: function (pred, seq) {
// var self = MochiKit.Iter;
// seq = self.iter(seq);
// return {
// repr: function () { return "takewhile(...)"; },
// toString: MochiKit.Base.forwardCall("repr"),
// next: function () {
// var rval = seq.next();
// if (!pred(rval)) {
// this.next = function () {
// throw self.StopIteration;
// };
// this.next();
// }
// return rval;
// }
// };
// },
// dropwhile: function (pred, seq) {
// seq = MochiKit.Iter.iter(seq);
// var m = MochiKit.Base;
// var bind = m.bind;
// return {
// "repr": function () { return "dropwhile(...)"; },
// "toString": m.forwardCall("repr"),
// "next": function () {
// while (true) {
// var rval = seq.next();
// if (!pred(rval)) {
// break;
// }
// }
// this.next = bind("next", seq);
// return rval;
// }
// };
// },
// _tee: function (ident, sync, iterable) {
// sync.pos[ident] = -1;
// var m = MochiKit.Base;
// var listMin = m.listMin;
// return {
// repr: function () { return "tee(" + ident + ", ...)"; },
// toString: m.forwardCall("repr"),
// next: function () {
// var rval;
// var i = sync.pos[ident];
//
// if (i == sync.max) {
// rval = iterable.next();
// sync.deque.push(rval);
// sync.max += 1;
// sync.pos[ident] += 1;
// } else {
// rval = sync.deque[i - sync.min];
// sync.pos[ident] += 1;
// if (i == sync.min && listMin(sync.pos) != sync.min) {
// sync.min += 1;
// sync.deque.shift();
// }
// }
// return rval;
// }
// };
// },
// tee: function (iterable, n/* = 2 */) {
// var rval = [];
// var sync = {
// "pos": [],
// "deque": [],
// "max": -1,
// "min": -1
// };
// if (arguments.length == 1 || typeof(n) == "undefined" || n === null) {
// n = 2;
// }
// var self = MochiKit.Iter;
// iterable = self.iter(iterable);
// var _tee = self._tee;
// for (var i = 0; i < n; i++) {
// rval.push(_tee(i, sync, iterable));
// }
// return rval;
// },
list: function (iterable) {
// Fast-path for Array and Array-like
var m = MochiKit.Base;
if (typeof(iterable.slice) == 'function') {
return iterable.slice();
} else if (m.isArrayLike(iterable)) {
return m.concat(iterable);
}
var self = MochiKit.Iter;
iterable = self.iter(iterable);
var rval = [];
try {
while (true) {
rval.push(iterable.next());
}
} catch (e) {
if (e != self.StopIteration) {
throw e;
}
return rval;
}
// mozilla warnings aren't too bright
return undefined;
},
// reduce: function (fn, iterable, /* optional */initial) {
// var i = 0;
// var x = initial;
// var self = MochiKit.Iter;
// iterable = self.iter(iterable);
// if (arguments.length < 3) {
// try {
// x = iterable.next();
// } catch (e) {
// if (e == self.StopIteration) {
// e = new TypeError("reduce() of empty sequence with no initial value");
// }
// throw e;
// }
// i++;
// }
// try {
// while (true) {
// x = fn(x, iterable.next());
// }
// } catch (e) {
// if (e != self.StopIteration) {
// throw e;
// }
// }
// return x;
// },
// range: function (/* [start,] stop[, step] */) {
// var start = 0;
// var stop = 0;
// var step = 1;
// if (arguments.length == 1) {
// stop = arguments[0];
// } else if (arguments.length == 2) {
// start = arguments[0];
// stop = arguments[1];
// } else if (arguments.length == 3) {
// start = arguments[0];
// stop = arguments[1];
// step = arguments[2];
// } else {
// throw new TypeError("range() takes 1, 2, or 3 arguments!");
// }
// if (step === 0) {
// throw new TypeError("range() step must not be 0");
// }
// return {
// next: function () {
// if ((step > 0 && start >= stop) || (step < 0 && start <= stop)) {
// throw MochiKit.Iter.StopIteration;
// }
// var rval = start;
// start += step;
// return rval;
// },
// repr: function () {
// return "range(" + [start, stop, step].join(", ") + ")";
// },
// toString: MochiKit.Base.forwardCall("repr")
// };
// },
//
// sum: function (iterable, start/* = 0 */) {
// if (typeof(start) == "undefined" || start === null) {
// start = 0;
// }
// var x = start;
// var self = MochiKit.Iter;
// iterable = self.iter(iterable);
// try {
// while (true) {
// x += iterable.next();
// }
// } catch (e) {
// if (e != self.StopIteration) {
// throw e;
// }
// }
// return x;
// },
// exhaust: function (iterable) {
// var self = MochiKit.Iter;
// iterable = self.iter(iterable);
// try {
// while (true) {
// iterable.next();
// }
// } catch (e) {
// if (e != self.StopIteration) {
// throw e;
// }
// }
// },
forEach: function (iterable, func, /* optional */self) {
var m = MochiKit.Base;
if (arguments.length > 2) {
func = m.bind(func, self);
}
// fast path for array
if (m.isArrayLike(iterable)) {
try {
for (var i = 0; i < iterable.length; i++) {
func(iterable[i]);
}
} catch (e) {
if (e != MochiKit.Iter.StopIteration) {
throw e;
}
}
} else {
self = MochiKit.Iter;
self.exhaust(self.imap(func, iterable));
}
},
every: function (iterable, func) {
var self = MochiKit.Iter;
try {
self.ifilterfalse(func, iterable).next();
return false;
} catch (e) {
if (e != self.StopIteration) {
throw e;
}
return true;
}
},
// sorted: function (iterable, /* optional */cmp) {
// var rval = MochiKit.Iter.list(iterable);
// if (arguments.length == 1) {
// cmp = MochiKit.Base.compare;
// }
// rval.sort(cmp);
// return rval;
// },
// reversed: function (iterable) {
// var rval = MochiKit.Iter.list(iterable);
// rval.reverse();
// return rval;
// },
//
// some: function (iterable, func) {
// var self = MochiKit.Iter;
// try {
// self.ifilter(func, iterable).next();
// return true;
// } catch (e) {
// if (e != self.StopIteration) {
// throw e;
// }
// return false;
// }
// },
//
// iextend: function (lst, iterable) {
// if (MochiKit.Base.isArrayLike(iterable)) {
// // fast-path for array-like
// for (var i = 0; i < iterable.length; i++) {
// lst.push(iterable[i]);
// }
// } else {
// var self = MochiKit.Iter;
// iterable = self.iter(iterable);
// try {
// while (true) {
// lst.push(iterable.next());
// }
// } catch (e) {
// if (e != self.StopIteration) {
// throw e;
// }
// }
// }
// return lst;
// },
// groupby: function(iterable, /* optional */ keyfunc) {
// var m = MochiKit.Base;
// var self = MochiKit.Iter;
// if (arguments.length < 2) {
// keyfunc = m.operator.identity;
// }
// iterable = self.iter(iterable);
//
// // shared
// var pk = undefined;
// var k = undefined;
// var v;
//
// function fetch() {
// v = iterable.next();
// k = keyfunc(v);
// };
//
// function eat() {
// var ret = v;
// v = undefined;
// return ret;
// };
//
// var first = true;
// return {
// repr: function () { return "groupby(...)"; },
// next: function() {
// // iterator-next
//
// // iterate until meet next group
// while (k == pk) {
// fetch();
// if (first) {
// first = false;
// break;
// }
// }
// pk = k;
// return [k, {
// next: function() {
// // subiterator-next
// if (v == undefined) { // Is there something to eat?
// fetch();
// }
// if (k != pk) {
// throw self.StopIteration;
// }
// return eat();
// }
// }];
// }
// };
// },
// groupby_as_array: function (iterable, /* optional */ keyfunc) {
// var m = MochiKit.Base;
// var self = MochiKit.Iter;
// if (arguments.length < 2) {
// keyfunc = m.operator.identity;
// }
//
// iterable = self.iter(iterable);
// var result = [];
// var first = true;
// var prev_key;
// while (true) {
// try {
// var value = iterable.next();
// var key = keyfunc(value);
// } catch (e) {
// if (e == self.StopIteration) {
// break;
// }
// throw e;
// }
// if (first || key != prev_key) {
// var values = [];
// result.push([key, values]);
// }
// values.push(value);
// first = false;
// prev_key = key;
// }
// return result;
// },
arrayLikeIter: function (iterable) {
var i = 0;
return {
repr: function () { return "arrayLikeIter(...)"; },
toString: MochiKit.Base.forwardCall("repr"),
next: function () {
if (i >= iterable.length) {
throw MochiKit.Iter.StopIteration;
}
return iterable[i++];
}
};
},
hasIterateNext: function (iterable) {
return (iterable && typeof(iterable.iterateNext) == "function");
},
iterateNextIter: function (iterable) {
return {
repr: function () { return "iterateNextIter(...)"; },
toString: MochiKit.Base.forwardCall("repr"),
next: function () {
var rval = iterable.iterateNext();
if (rval === null || rval === undefined) {
throw MochiKit.Iter.StopIteration;
}
return rval;
}
};
}
});
MochiKit.Iter.EXPORT_OK = [
"iteratorRegistry",
"arrayLikeIter",
"hasIterateNext",
"iterateNextIter",
];
MochiKit.Iter.EXPORT = [
"StopIteration",
"registerIteratorFactory",
"iter",
"count",
"cycle",
"repeat",
"next",
"izip",
"ifilter",
"ifilterfalse",
"islice",
"imap",
"applymap",
"chain",
"takewhile",
"dropwhile",
"tee",
"list",
"reduce",
"range",
"sum",
"exhaust",
"forEach",
"every",
"sorted",
"reversed",
"some",
"iextend",
"groupby",
"groupby_as_array"
];
MochiKit.Iter.__new__ = function () {
var m = MochiKit.Base;
// Re-use StopIteration if exists (e.g. SpiderMonkey)
if (typeof(StopIteration) != "undefined") {
this.StopIteration = StopIteration;
} else {
this.StopIteration = new m.NamedError("StopIteration");
}
this.iteratorRegistry = new m.AdapterRegistry();
// Register the iterator factory for arrays
this.registerIteratorFactory(
"arrayLike",
m.isArrayLike,
this.arrayLikeIter
);
this.registerIteratorFactory(
"iterateNext",
this.hasIterateNext,
this.iterateNextIter
);
this.EXPORT_TAGS = {
":common": this.EXPORT,
":all": m.concat(this.EXPORT, this.EXPORT_OK)
};
m.nameFunctions(this);
};
MochiKit.Iter.__new__();
//
// XXX: Internet Explorer blows
//
if (MochiKit.__export__) {
reduce = MochiKit.Iter.reduce;
}
MochiKit.Base._exportSymbols(this, MochiKit.Iter);