@@ -108,10 +108,33 @@ function Namespace(name, options) {
108
108
* @private
109
109
*/
110
110
this . _nestedArray = null ;
111
+
112
+ /**
113
+ * Cache lookup calls for any objects contains anywhere under this namespace.
114
+ * This drastically speeds up resolve for large cross-linked protos where the same
115
+ * types are looked up repeatedly.
116
+ * @type {Object.<string,ReflectionObject|null> }
117
+ * @private
118
+ */
119
+ this . _lookupCache = { } ;
120
+
121
+ /**
122
+ * Whether or not objects contained in this namespace need feature resolution.
123
+ * @type {boolean }
124
+ * @protected
125
+ */
126
+ this . _needsRecursiveFeatureResolution = true ;
111
127
}
112
128
113
129
function clearCache ( namespace ) {
114
130
namespace . _nestedArray = null ;
131
+ namespace . _lookupCache = { } ;
132
+
133
+ // Also clear parent caches, since they include nested lookups.
134
+ var parent = namespace ;
135
+ while ( parent = parent . parent ) {
136
+ parent . _lookupCache = { } ;
137
+ }
115
138
return namespace ;
116
139
}
117
140
@@ -249,6 +272,14 @@ Namespace.prototype.add = function add(object) {
249
272
}
250
273
}
251
274
275
+ this . _needsRecursiveFeatureResolution = true ;
276
+
277
+ // Also clear parent caches, since they need to recurse down.
278
+ var parent = this ;
279
+ while ( parent = parent . parent ) {
280
+ parent . _needsRecursiveFeatureResolution = true ;
281
+ }
282
+
252
283
object . onAdd ( this ) ;
253
284
return clearCache ( this ) ;
254
285
} ;
@@ -324,6 +355,9 @@ Namespace.prototype.resolveAll = function resolveAll() {
324
355
* @override
325
356
*/
326
357
Namespace . prototype . _resolveFeaturesRecursive = function _resolveFeaturesRecursive ( edition ) {
358
+ if ( ! this . _needsRecursiveFeatureResolution ) return this ;
359
+ this . _needsRecursiveFeatureResolution = false ;
360
+
327
361
edition = this . _edition || edition ;
328
362
329
363
ReflectionObject . prototype . _resolveFeaturesRecursive . call ( this , edition ) ;
@@ -341,7 +375,6 @@ Namespace.prototype._resolveFeaturesRecursive = function _resolveFeaturesRecursi
341
375
* @returns {ReflectionObject|null } Looked up object or `null` if none could be found
342
376
*/
343
377
Namespace . prototype . lookup = function lookup ( path , filterTypes , parentAlreadyChecked ) {
344
-
345
378
/* istanbul ignore next */
346
379
if ( typeof filterTypes === "boolean" ) {
347
380
parentAlreadyChecked = filterTypes ;
@@ -360,25 +393,48 @@ Namespace.prototype.lookup = function lookup(path, filterTypes, parentAlreadyChe
360
393
if ( path [ 0 ] === "" )
361
394
return this . root . lookup ( path . slice ( 1 ) , filterTypes ) ;
362
395
396
+ var found = this . _lookupImpl ( path ) ;
397
+ if ( found && ( ! filterTypes || filterTypes . indexOf ( found . constructor ) > - 1 ) ) {
398
+ return found ;
399
+ }
400
+
401
+ // If there hasn't been a match, try again at the parent
402
+ if ( this . parent === null || parentAlreadyChecked )
403
+ return null ;
404
+ return this . parent . lookup ( path , filterTypes ) ;
405
+ } ;
406
+
407
+ /**
408
+ * Internal helper for lookup that handles searching just at this namespace and below along with caching.
409
+ * @param {string[] } path Path to look up
410
+ * @returns {ReflectionObject|null } Looked up object or `null` if none could be found
411
+ * @private
412
+ */
413
+ Namespace . prototype . _lookupImpl = function lookup ( path ) {
414
+ var flatPath = path . join ( "." ) ;
415
+ if ( Object . prototype . hasOwnProperty . call ( this . _lookupCache , flatPath ) ) {
416
+ return this . _lookupCache [ flatPath ] ;
417
+ }
418
+
363
419
// Test if the first part matches any nested object, and if so, traverse if path contains more
364
420
var found = this . get ( path [ 0 ] ) ;
421
+ var exact = null ;
365
422
if ( found ) {
366
423
if ( path . length === 1 ) {
367
- if ( ! filterTypes || filterTypes . indexOf ( found . constructor ) > - 1 )
368
- return found ;
369
- } else if ( found instanceof Namespace && ( found = found . lookup ( path . slice ( 1 ) , filterTypes , true ) ) )
370
- return found ;
424
+ exact = found ;
425
+ } else if ( found instanceof Namespace && ( found = found . _lookupImpl ( path . slice ( 1 ) ) ) )
426
+ exact = found ;
371
427
372
428
// Otherwise try each nested namespace
373
- } else
429
+ } else {
374
430
for ( var i = 0 ; i < this . nestedArray . length ; ++ i )
375
- if ( this . _nestedArray [ i ] instanceof Namespace && ( found = this . _nestedArray [ i ] . lookup ( path , filterTypes , true ) ) )
376
- return found ;
431
+ if ( this . _nestedArray [ i ] instanceof Namespace && ( found = this . _nestedArray [ i ] . _lookupImpl ( path ) ) )
432
+ exact = found ;
433
+ }
377
434
378
- // If there hasn't been a match, try again at the parent
379
- if ( this . parent === null || parentAlreadyChecked )
380
- return null ;
381
- return this . parent . lookup ( path , filterTypes ) ;
435
+ // Set this even when null, so that when we walk up the tree we can quickly bail on repeated checks back down.
436
+ this . _lookupCache [ flatPath ] = exact ;
437
+ return exact ;
382
438
} ;
383
439
384
440
/**
0 commit comments