[Dojo-checkins] elazutkin - r20738 - dojo/trunk/_base
dojo-checkins-admin at dojotoolkit.org
dojo-checkins-admin at dojotoolkit.org
Mon Nov 9 00:04:31 EST 2009
Author: elazutkin
Date: Sun Nov 8 21:04:29 2009
New Revision: 20738
Modified:
dojo/trunk/_base/declare.js
Log:
dojo.declare: performance improvements, minor API updates, !strict, refs #9862.
Modified: dojo/trunk/_base/declare.js
==============================================================================
--- dojo/trunk/_base/declare.js (original)
+++ dojo/trunk/_base/declare.js Sun Nov 8 21:04:29 2009
@@ -4,7 +4,7 @@
dojo.require("dojo._base.array");
(function(){
- var d = dojo, op = Object.prototype, isF = d.isFunction, mix = d._mixin,
+ var d = dojo, op = Object.prototype, mix = d._mixin, opts = op.toString,
xtor = new Function, counter = 0;
function err(msg){ throw new Error("declare: " + msg); }
@@ -82,57 +82,49 @@
return result;
}
-
+
// find the next "inherited" method using available meta-information
- function findInherited(self, caller, name){
- var meta = self.constructor._meta, bases = meta.bases,
- l = bases.length, i, f, opf, cache, currentBase, proto;
+ function findNext(meta, cache, caller, name){
+ var bases = meta.bases, chains = meta.chains, opf = op[name], f, pos, base, proto;
- name = name || caller.nom;
if(!name){
err("can't deduce a name to call inherited()");
}
// error detection
- if(name == "constructor" ? meta.chains.constructor !== "manual" :
- meta.chains.hasOwnProperty(name)){
- err("calling chained method as inherited: " + name);
- }
-
- // find our caller using simple cache and the list of base classes
- cache = self._inherited;
- currentBase = bases[cache.pos];
- meta = currentBase && currentBase._meta;
- proto = currentBase && currentBase.prototype;
- if(!currentBase || cache.name != name ||
- !(meta ?
- (meta.hidden[name] === caller ||
- proto.hasOwnProperty(name) && proto[name] === caller) :
- (proto[name] === caller))){
- // cache bust
- for(i = 0; i < l; ++i){
- currentBase = bases[i];
- meta = currentBase._meta;
- proto = currentBase.prototype;
- if(meta ?
- (meta.hidden[name] === caller ||
- proto.hasOwnProperty(name) &&
- proto[name] === caller) :
- (proto[name] === caller)){
- break;
+ if(chains && typeof chains[name] == "string"){
+ err("calling chained method with inherited: " + name);
+ }
+
+ // do we have a cache bust?
+ if(cache.c !== caller){
+ // find caller
+ cache.n = name;
+ for(pos = 0; base = bases[pos]; ++pos){ // intentional assignment
+ meta = base._meta;
+ proto = base.prototype;
+ if(meta){
+ if(proto.hasOwnProperty(name)){
+ f = proto[name];
+ if(f === caller){
+ break;
+ }
+ }
+ f = meta.hidden[name];
+ if(f === caller){
+ break;
+ }
}
}
- cache.name = name;
- cache.pos = i < l ? i : -1;
+ pos = base ? pos : -1;
+ }else{
+ pos = cache.p;
}
- i = cache.pos;
// find next
- opf = op[name];
- while(++i < l){
- currentBase = bases[i];
- proto = currentBase.prototype;
- if(currentBase._meta){
+ while(base = bases[++pos]){ // intentional assignment
+ proto = base.prototype;
+ if(base._meta){
if(proto.hasOwnProperty(name)){
f = proto[name];
break;
@@ -144,33 +136,171 @@
}
}
}
- cache.pos = i;
+ cache.c = f = base && f;
+ cache.p = pos;
// return found method, or the underlying Object method
- return i < l && f || name != "constructor" && opf;
+ return f || name != "constructor" && opf;
+ }
+
+ // find the next "inherited" constructor using available meta-information
+ function findNextConstructor(meta, cache, caller){
+ var bases = meta.bases, chains = meta.chains, f, pos, opf, base;
+
+ // error detection
+ if(!chains || chains.constructor != "manual"){
+ err("calling chained constructor with inherited");
+ }
+
+ // do we have a cache bust?
+ if(cache.c !== caller){
+ // find caller
+ cache.n = "";
+ for(pos = 0; base = bases[pos]; ++pos){ // intentional assignment
+ meta = base._meta;
+ if(meta && meta.ctor === caller){
+ break;
+ }
+ }
+ }else{
+ pos = cache.p;
+ }
+
+ // find next
+ while(base = bases[++pos]){ // intentional assignment
+ meta = base._meta;
+ if(meta){
+ f = meta.ctor;
+ if(f){
+ break;
+ }
+ }else{
+ f = base;
+ break;
+ }
+ }
+ cache.c = f = base && f;
+ cache.p = pos;
+
+ // return found method, or the underlying Object method
+ return f;
}
// implementation of getInherited()
function getInherited(args, a){
- var name;
+ var name, caller, cache = this._inherited = this._inherited || {},
+ m, meta, base, f = 0;
// crack arguments
if(typeof args == "string"){
name = args;
args = a;
}
- return findInherited(this, args.callee, name);
+ caller = args.callee;
+ name = name || caller.nom;
+ m = meta = this.constructor._meta;
+ if(name != "constructor"){
+ if(cache.c !== caller){
+ base = meta.bases[0];
+ meta = base._meta;
+ if(meta && meta.hidden[name] === caller){
+ cache.n = name;
+ cache.c = caller;
+ cache.p = 0;
+ }
+ }
+ base = meta.bases[++cache.p];
+ meta = base && base._meta;
+ f = meta && meta.hidden[name];
+ if(f){
+ cache.c = f;
+ }else{
+ --cache.p;
+ }
+ if(!f){
+ f = findNext(m, cache, caller, name);
+ }
+ }else{
+ if(cache.c !== caller){
+ base = meta.bases[0];
+ meta = base._meta;
+ if(meta && meta.ctor === caller){
+ cache.n = "";
+ cache.c = caller;
+ cache.p = 0;
+ }
+ }
+ base = meta.bases[++cache.p];
+ meta = base && base._meta;
+ f = meta && meta.ctor;
+ if(f){
+ cache.c = f;
+ }else{
+ --cache.p;
+ }
+ if(!f){
+ f = findNextConstructor(m, cache, caller);
+ }
+ }
+ // do not call the inherited at the end of the chain
+ return f ? f.apply(this, a || args) : undefined;
}
- // implementation of inherited()
function inherited(args, a, f){
- var name;
+ var name, caller, cache = this._inherited = this._inherited || {},
+ m, meta, base;
// crack arguments
if(typeof args == "string"){
name = args;
args = a;
a = f;
}
- f = findInherited(this, args.callee, name);
+ f = 0;
+ caller = args.callee;
+ name = name || caller.nom;
+ m = meta = this.constructor._meta;
+ if(name != "constructor"){
+ if(cache.c !== caller){
+ base = meta.bases[0];
+ meta = base._meta;
+ if(meta && meta.hidden[name] === caller){
+ cache.n = name;
+ cache.c = caller;
+ cache.p = 0;
+ }
+ }
+ base = meta.bases[++cache.p];
+ meta = base && base._meta;
+ f = meta && meta.hidden[name];
+ if(f){
+ cache.c = f;
+ }else{
+ --cache.p;
+ }
+ if(!f){
+ f = findNext(m, cache, caller, name);
+ }
+ }else{
+ if(cache.c !== caller){
+ base = meta.bases[0];
+ meta = base._meta;
+ if(meta && meta.ctor === caller){
+ cache.n = "";
+ cache.c = caller;
+ cache.p = 0;
+ }
+ }
+ base = meta.bases[++cache.p];
+ meta = base && base._meta;
+ f = meta && meta.ctor;
+ if(f){
+ cache.c = f;
+ }else{
+ --cache.p;
+ }
+ if(!f){
+ f = findNextConstructor(m, cache, caller);
+ }
+ }
// do not call the inherited at the end of the chain
return f ? f.apply(this, a || args) : undefined;
}
@@ -193,7 +323,7 @@
for(name in source){
t = source[name];
if((t !== op[name] || !(name in op)) && name != "constructor"){
- if(isF(t)){
+ if(opts.call(t) == "[object Function]"){
// non-trivial function method => attach its name
t.nom = name;
}
@@ -205,25 +335,27 @@
name = d._extraNames[i];
t = source[name];
if((t !== op[name] || !(name in op)) && name != "constructor"){
- if(isF(t)){
+ if(opts.call(t) == "[object Function]"){
// non-trivial function method => attach its name
t.nom = name;
}
target[name] = t;
}
}
+ return target;
}
function extend(source){
safeMixin(this.prototype, source);
+ return this;
}
// chained constructor compatible with the legacy dojo.declare()
function chainedConstructor(bases, ctorSpecial){
return function(){
- var a = arguments, args = a, a0 = a[0], f, i, m, h,
+ var a = arguments, args = a, a0 = a[0], f, i, m,
l = bases.length, preArgs;
- this._inherited = {};
+ //this._inherited = {};
// perform the shaman's rituals of the original dojo.declare()
// 1) call two types of the preamble
if(ctorSpecial && (a0 && a0.preamble || this.preamble)){
@@ -261,10 +393,7 @@
for(i = l - 1; i >= 0; --i){
f = bases[i];
m = f._meta;
- if(m){
- h = m.hidden;
- f = h.hasOwnProperty("constructor") && h.constructor;
- }
+ f = m ? m.ctor : f;
if(f){
f.apply(this, preArgs ? preArgs[i] : a);
}
@@ -277,21 +406,59 @@
};
}
+
+ // chained constructor compatible with the legacy dojo.declare()
+ function singleConstructor(ctor, ctorSpecial){
+ return function(){
+ var a = arguments, t = a, a0 = a[0], f;
+ //this._inherited = {};
+ // perform the shaman's rituals of the original dojo.declare()
+ // 1) call two types of the preamble
+ if(ctorSpecial){
+ // full blown ritual
+ if(a0){
+ // process the preamble of the 1st argument
+ f = a0.preamble;
+ if(f){
+ t = f.apply(this, t) || t;
+ }
+ }
+ if(this.preamble){
+ // process the preamble of this class
+ f = this.preamble;
+ if(f){
+ f.apply(this, t);
+ }
+ // one pecularity of the preamble:
+ // it is called even if it is not needed,
+ // e.g., there is no constructor to call
+ // let's watch for the last constructor
+ // (see ticket #9795)
+ }
+ }
+ // 2) call a constructor
+ if(ctor){
+ ctor.apply(this, a);
+ }
+ // 3) continue the original ritual: call the postscript
+ f = this.postscript;
+ if(f){
+ f.apply(this, a);
+ }
+ };
+ }
+
// plain vanilla constructor (can use inherited() to call its base constructor)
function simpleConstructor(bases){
return function(){
- var a = arguments, f, i = 0, l = bases.length;
- this._inherited = {};
+ var a = arguments, i = 0, f;
+ //this._inherited = {};
// perform the shaman's rituals of the original dojo.declare()
// 1) do not call the preamble
// 2) call the top constructor (it can use this.inherited())
- for(; i < l; ++i){
- f = bases[i];
+ for(; f = bases[i]; ++i){ // intentional assignment
m = f._meta;
- if(m){
- h = m.hidden;
- f = h.hasOwnProperty("constructor") && h.constructor;
- }
+ f = m ? m.ctor : f;
if(f){
f.apply(this, a);
break;
@@ -330,7 +497,7 @@
}
d.declare = function(className, superclass, props){
- var proto, i, t, ctor, name, bases, mixins = 1, chains = {}, parents = superclass;
+ var proto, i, t, ctor, name, bases, chains, mixins = 1, parents = superclass;
// crack parameters
if(typeof className != "string"){
@@ -341,7 +508,7 @@
props = props || {};
// build a prototype
- if(d.isArray(superclass)){
+ if(opts.call(superclass) == "[object Array]"){
// C3 MRO
bases = c3mro(superclass);
t = bases[0];
@@ -355,10 +522,6 @@
}
}
if(superclass){
- if(superclass._meta){
- xtor.prototype = superclass._meta.chains;
- chains = new xtor;
- }
for(i = mixins - 1;; --i){
// delegation
xtor.prototype = superclass.prototype;
@@ -369,12 +532,7 @@
}
// mix in properties
t = bases[i];
- if(t._meta){
- mix(chains, t._meta.chains);
- mix(proto, t._meta.hidden);
- }else{
- mix(proto, t.prototype);
- }
+ mix(proto, t._meta ? t._meta.hidden : t.prototype);
// chain in new constructor
ctor = new Function;
ctor.superclass = superclass;
@@ -395,16 +553,24 @@
xtor.prototype = 0; // cleanup
// collect chains and flags
- if(proto.hasOwnProperty("-chains-")){
- mix(chains, proto["-chains-"]);
+ for(i = mixins - 1; i; --i){ // intentional assignment
+ t = bases[i]._meta;
+ if(t && t.chains){
+ chains = mix(chains || {}, t.chains);
+ }
+ }
+ if(proto["-chains-"]){
+ chains = mix(chains || {}, proto["-chains-"]);
}
// build ctor
- bases[0] = ctor = chains.constructor === "manual" ? simpleConstructor(bases) :
- chainedConstructor(bases, !chains.hasOwnProperty("constructor"));
+ t = !chains || !chains.hasOwnProperty("constructor");
+ bases[0] = ctor = (chains && chains.constructor === "manual") ? simpleConstructor(bases) :
+ (bases.length == 1 ? singleConstructor(props.constructor, t) : chainedConstructor(bases, t));
// add meta information to the constructor
- ctor._meta = {bases: bases, hidden: props, chains: chains, parents: parents};
+ ctor._meta = {bases: bases, hidden: props, chains: chains,
+ parents: parents, ctor: props.constructor};
ctor.superclass = superclass && superclass.prototype;
ctor.extend = extend;
ctor.prototype = proto;
@@ -422,10 +588,12 @@
}
// build chains and add them to the prototype
- for(name in chains){
- if(proto[name] && typeof chains[name] == "string" && name != "constructor"){
- t = proto[name] = chain(name, bases, chains[name] === "after");
- t.nom = name;
+ if(chains){
+ for(name in chains){
+ if(proto[name] && typeof chains[name] == "string" && name != "constructor"){
+ t = proto[name] = chain(name, bases, chains[name] === "after");
+ t.nom = name;
+ }
}
}
// chained methods do not return values
More information about the Dojo-checkins
mailing list