@@ -5565,31 +5565,37 @@ function _compactIri(activeCtx, iri, value, relativeTo, reverse) {
5565
5565
5566
5566
// no term or @vocab match, check for possible CURIEs
5567
5567
var choice = null ;
5568
- for ( var term in activeCtx . mappings ) {
5569
- var definition = activeCtx . mappings [ term ] ;
5570
- // skip null definitions and terms with colons, they can't be prefixes
5571
- if ( ! definition || definition . _termHasColon ) {
5572
- continue ;
5573
- }
5574
- // skip entries with @ids that are not partial matches
5575
- if ( ! ( iri . length > definition [ '@id' ] . length &&
5576
- iri . indexOf ( definition [ '@id' ] ) === 0 ) ) {
5577
- continue ;
5578
- }
5579
-
5580
- // a CURIE is usable if:
5581
- // 1. it has no mapping, OR
5582
- // 2. value is null, which means we're not compacting an @value, AND
5583
- // the mapping matches the IRI)
5584
- var curie = term + ':' + iri . substr ( definition [ '@id' ] . length ) ;
5585
- var isUsableCurie = ( ! ( curie in activeCtx . mappings ) ||
5586
- ( value === null && activeCtx . mappings [ curie ] [ '@id' ] === iri ) ) ;
5587
-
5588
- // select curie if it is shorter or the same length but lexicographically
5589
- // less than the current choice
5590
- if ( isUsableCurie && ( choice === null ||
5591
- _compareShortestLeast ( curie , choice ) < 0 ) ) {
5592
- choice = curie ;
5568
+ var idx = 0 ;
5569
+ var partialMatches = [ ] ;
5570
+ var iriMap = activeCtx . fastCurieMap ;
5571
+ // check for partial matches of against `iri`, which means look until
5572
+ // iri.length - 1, not full length
5573
+ var maxPartialLength = iri . length - 1 ;
5574
+ for ( ; idx < maxPartialLength && iri [ idx ] in iriMap ; ++ idx ) {
5575
+ iriMap = iriMap [ iri [ idx ] ] ;
5576
+ if ( '' in iriMap ) {
5577
+ partialMatches . push ( iriMap [ '' ] [ 0 ] ) ;
5578
+ }
5579
+ }
5580
+ // check partial matches in reverse order to prefer longest ones first
5581
+ for ( var i = partialMatches . length - 1 ; i >= 0 ; -- i ) {
5582
+ var entry = partialMatches [ i ] ;
5583
+ var terms = entry . terms ;
5584
+ for ( var ti = 0 ; ti < terms . length ; ++ ti ) {
5585
+ // a CURIE is usable if:
5586
+ // 1. it has no mapping, OR
5587
+ // 2. value is null, which means we're not compacting an @value, AND
5588
+ // the mapping matches the IRI
5589
+ var curie = terms [ ti ] + ':' + iri . substr ( entry . iri . length ) ;
5590
+ var isUsableCurie = ( ! ( curie in activeCtx . mappings ) ||
5591
+ ( value === null && activeCtx . mappings [ curie ] [ '@id' ] === iri ) ) ;
5592
+
5593
+ // select curie if it is shorter or the same length but lexicographically
5594
+ // less than the current choice
5595
+ if ( isUsableCurie && ( choice === null ||
5596
+ _compareShortestLeast ( curie , choice ) < 0 ) ) {
5597
+ choice = curie ;
5598
+ }
5593
5599
}
5594
5600
}
5595
5601
@@ -6212,6 +6218,10 @@ function _getInitialContext(options) {
6212
6218
}
6213
6219
var inverse = activeCtx . inverse = { } ;
6214
6220
6221
+ // variables for building fast CURIE map
6222
+ var fastCurieMap = activeCtx . fastCurieMap = { } ;
6223
+ var irisToTerms = { } ;
6224
+
6215
6225
// handle default language
6216
6226
var defaultLanguage = activeCtx [ '@language' ] || '@none' ;
6217
6227
@@ -6236,10 +6246,25 @@ function _getInitialContext(options) {
6236
6246
for ( var ii = 0 ; ii < ids . length ; ++ ii ) {
6237
6247
var iri = ids [ ii ] ;
6238
6248
var entry = inverse [ iri ] ;
6249
+ var isKeyword = _isKeyword ( iri ) ;
6239
6250
6240
- // initialize entry
6241
6251
if ( ! entry ) {
6252
+ // initialize entry
6242
6253
inverse [ iri ] = entry = { } ;
6254
+
6255
+ if ( ! isKeyword && ! mapping . _termHasColon ) {
6256
+ // init IRI to term map and fast CURIE prefixes
6257
+ irisToTerms [ iri ] = [ term ] ;
6258
+ var fastCurieEntry = { iri : iri , terms : irisToTerms [ iri ] } ;
6259
+ if ( iri [ 0 ] in fastCurieMap ) {
6260
+ fastCurieMap [ iri [ 0 ] ] . push ( fastCurieEntry ) ;
6261
+ } else {
6262
+ fastCurieMap [ iri [ 0 ] ] = [ fastCurieEntry ] ;
6263
+ }
6264
+ }
6265
+ } else if ( ! isKeyword && ! mapping . _termHasColon ) {
6266
+ // add IRI to term match
6267
+ irisToTerms [ iri ] . push ( term ) ;
6243
6268
}
6244
6269
6245
6270
// add new entry
@@ -6274,9 +6299,50 @@ function _getInitialContext(options) {
6274
6299
}
6275
6300
}
6276
6301
6302
+ // build fast CURIE map
6303
+ for ( var key in fastCurieMap ) {
6304
+ _buildIriMap ( fastCurieMap , key , 1 ) ;
6305
+ }
6306
+
6277
6307
return inverse ;
6278
6308
}
6279
6309
6310
+ /**
6311
+ * Runs a recursive algorithm to build a lookup map for quickly finding
6312
+ * potential CURIEs.
6313
+ *
6314
+ * @param iriMap the map to build.
6315
+ * @param key the current key in the map to work on.
6316
+ * @param idx the index into the IRI to compare.
6317
+ */
6318
+ function _buildIriMap ( iriMap , key , idx ) {
6319
+ var entries = iriMap [ key ] ;
6320
+ var next = iriMap [ key ] = { } ;
6321
+
6322
+ var iri ;
6323
+ var letter ;
6324
+ for ( var i = 0 ; i < entries . length ; ++ i ) {
6325
+ iri = entries [ i ] . iri ;
6326
+ if ( idx >= iri . length ) {
6327
+ letter = '' ;
6328
+ } else {
6329
+ letter = iri [ idx ] ;
6330
+ }
6331
+ if ( letter in next ) {
6332
+ next [ letter ] . push ( entries [ i ] ) ;
6333
+ } else {
6334
+ next [ letter ] = [ entries [ i ] ] ;
6335
+ }
6336
+ }
6337
+
6338
+ for ( var key in next ) {
6339
+ if ( key === '' ) {
6340
+ continue ;
6341
+ }
6342
+ _buildIriMap ( next , key , idx + 1 ) ;
6343
+ }
6344
+ }
6345
+
6280
6346
/**
6281
6347
* Adds the term for the given entry if not already added.
6282
6348
*
0 commit comments