@@ -135,7 +135,9 @@ public object Deserialize(
135
135
}
136
136
137
137
var discriminatorConvention = _classMap . GetDiscriminatorConvention ( ) ;
138
- var fastMemberMapFinder = new FastMemberMapFinder ( _classMap ) ;
138
+ var allMemberMaps = _classMap . AllMemberMaps ;
139
+ var extraElementsMemberMapIndex = _classMap . ExtraElementsMemberMapIndex ;
140
+ var memberMapBitArray = FastMemberMapHelper . GetBitArray ( allMemberMaps . Count ) ;
139
141
140
142
bsonReader . ReadStartDocument ( ) ;
141
143
while ( bsonReader . ReadBsonType ( ) != BsonType . EndOfDocument )
@@ -147,9 +149,10 @@ public object Deserialize(
147
149
continue ;
148
150
}
149
151
150
- var memberMap = fastMemberMapFinder . GetMemberMapForElement ( elementName ) ;
151
- if ( memberMap != null )
152
+ var memberMapIndex = _classMap . GetMemberMapIndexForElement ( elementName ) ;
153
+ if ( memberMapIndex >= 0 && memberMapIndex != extraElementsMemberMapIndex )
152
154
{
155
+ var memberMap = allMemberMaps [ memberMapIndex ] ;
153
156
if ( memberMap . IsReadOnly )
154
157
{
155
158
bsonReader . SkipValue ( ) ;
@@ -158,12 +161,14 @@ public object Deserialize(
158
161
{
159
162
DeserializeMember ( bsonReader , obj , memberMap ) ;
160
163
}
164
+ memberMapBitArray [ memberMapIndex >> 5 ] |= 1U << ( memberMapIndex & 31 ) ;
161
165
}
162
166
else
163
167
{
164
- if ( _classMap . ExtraElementsMemberMap != null )
168
+ if ( extraElementsMemberMapIndex >= 0 )
165
169
{
166
170
DeserializeExtraElement ( bsonReader , obj , elementName , _classMap . ExtraElementsMemberMap ) ;
171
+ memberMapBitArray [ extraElementsMemberMapIndex >> 5 ] |= 1U << ( extraElementsMemberMapIndex & 31 ) ;
167
172
}
168
173
else if ( _classMap . IgnoreExtraElements )
169
174
{
@@ -181,25 +186,38 @@ public object Deserialize(
181
186
bsonReader . ReadEndDocument ( ) ;
182
187
183
188
// check any members left over that we didn't have elements for
184
- if ( fastMemberMapFinder . HasLeftOverMemberMaps ( ) )
189
+ for ( var bitArrayIndex = 0 ; bitArrayIndex < memberMapBitArray . Length ; ++ bitArrayIndex )
185
190
{
186
- foreach ( var memberMap in fastMemberMapFinder . GetLeftOverMemberMaps ( ) )
191
+ var memberMapIndex = bitArrayIndex << 5 ;
192
+ var memberMapBlock = ~ memberMapBitArray [ bitArrayIndex ] ;
193
+
194
+ for ( ; ; )
187
195
{
188
- if ( memberMap . IsReadOnly )
196
+ while ( ( memberMapBlock & 1 ) != 0 )
189
197
{
190
- continue ;
198
+ var memberMap = allMemberMaps [ memberMapIndex ] ;
199
+ if ( memberMap . IsRequired )
200
+ {
201
+ var fieldOrProperty = ( memberMap . MemberInfo . MemberType == MemberTypes . Field ) ? "field" : "property" ;
202
+ var message = string . Format (
203
+ "Required element '{0}' for {1} '{2}' of class {3} is missing." ,
204
+ memberMap . ElementName , fieldOrProperty , memberMap . MemberName , _classMap . ClassType . FullName ) ;
205
+ throw new FileFormatException ( message ) ;
206
+ }
207
+ memberMap . ApplyDefaultValue ( obj ) ;
208
+
209
+ ++ memberMapIndex ;
210
+ memberMapBlock >>= 1 ;
191
211
}
192
212
193
- if ( memberMap . IsRequired )
213
+ if ( memberMapBlock == 0 )
194
214
{
195
- var fieldOrProperty = ( memberMap . MemberInfo . MemberType == MemberTypes . Field ) ? "field" : "property" ;
196
- var message = string . Format (
197
- "Required element '{0}' for {1} '{2}' of class {3} is missing." ,
198
- memberMap . ElementName , fieldOrProperty , memberMap . MemberName , _classMap . ClassType . FullName ) ;
199
- throw new FileFormatException ( message ) ;
215
+ break ;
200
216
}
201
217
202
- memberMap . ApplyDefaultValue ( obj ) ;
218
+ var leastSignificantBit = FastMemberMapHelper . GetLeastSignificantBit ( memberMapBlock ) ;
219
+ memberMapIndex += leastSignificantBit ;
220
+ memberMapBlock >>= leastSignificantBit ;
203
221
}
204
222
}
205
223
@@ -359,18 +377,22 @@ public void Serialize(
359
377
}
360
378
}
361
379
362
- foreach ( var memberMap in _classMap . AllMemberMaps )
380
+ var allMemberMaps = _classMap . AllMemberMaps ;
381
+ var extraElementsMemberMapIndex = _classMap . ExtraElementsMemberMapIndex ;
382
+
383
+ for ( var memberMapIndex = 0 ; memberMapIndex < allMemberMaps . Count ; ++ memberMapIndex )
363
384
{
385
+ var memberMap = allMemberMaps [ memberMapIndex ] ;
364
386
// note: if serializeIdFirst is false then idMemberMap will be null (so no property will be skipped)
365
387
if ( memberMap != idMemberMap )
366
388
{
367
- if ( memberMap == _classMap . ExtraElementsMemberMap )
389
+ if ( memberMapIndex != extraElementsMemberMapIndex )
368
390
{
369
- SerializeExtraElements ( bsonWriter , value , memberMap ) ;
391
+ SerializeMember ( bsonWriter , value , memberMap ) ;
370
392
}
371
393
else
372
394
{
373
- SerializeMember ( bsonWriter , value , memberMap ) ;
395
+ SerializeExtraElements ( bsonWriter , value , memberMap ) ;
374
396
}
375
397
}
376
398
}
@@ -531,90 +553,35 @@ private void VerifyNominalType(Type nominalType)
531
553
}
532
554
533
555
// nested classes
534
- // helper class that implements fast linear searching of member maps by using a shrinking range
535
- // and optimized for the case when the elements occur in the same order as the maps
536
- private class FastMemberMapFinder
556
+ // helper class that implements member map bit array helper functions
557
+ private static class FastMemberMapHelper
537
558
{
538
- private BsonClassMap _classMap ;
539
- private BsonMemberMap _extraElementsMemberMap ;
540
- private BsonMemberMap [ ] _memberMaps ;
541
- private int _from ;
542
- private int _to ;
543
-
544
- public FastMemberMapFinder ( BsonClassMap classMap )
559
+ private static readonly byte [ ] __multiplyDeBruijnBitIndex =
545
560
{
546
- _classMap = classMap ;
547
- _extraElementsMemberMap = classMap . ExtraElementsMemberMap ;
548
- _memberMaps = classMap . AllMemberMaps . ToArray ( ) ;
549
- _from = 0 ;
550
- _to = _memberMaps . Length - 1 ;
551
- if ( _extraElementsMemberMap != null )
552
- {
553
- var i = Array . IndexOf ( _memberMaps , _extraElementsMemberMap ) ;
554
- _memberMaps [ i ] = null ;
555
- }
556
- }
557
-
558
- public BsonMemberMap GetMemberMapForElement ( string elementName )
559
- {
560
- // linear search should be fast because elements will normally be in the same order as the member maps
561
- for ( int i = _from ; i <= _to ; i ++ )
562
- {
563
- var memberMap = _memberMaps [ i ] ;
564
- if ( memberMap == null )
565
- {
566
- if ( i == _from )
567
- {
568
- _from ++ ; // shrink the range from the left
569
- }
570
- continue ;
571
- }
561
+ 0 , 1 , 28 , 2 , 29 , 14 , 24 , 3 ,
562
+ 30 , 22 , 20 , 15 , 25 , 17 , 4 , 8 ,
563
+ 31 , 27 , 13 , 23 , 21 , 19 , 16 , 7 ,
564
+ 26 , 12 , 18 , 6 , 11 , 5 , 10 , 9 ,
565
+ } ;
572
566
573
- if ( memberMap . ElementName == elementName )
574
- {
575
- if ( i == _from )
576
- {
577
- _from ++ ; // shrink the range from the left
578
- }
579
- else if ( i == _to )
580
- {
581
- _to -- ; // shrink the range from the right
582
- }
583
- else
584
- {
585
- _memberMaps [ i ] = null ; // set to null so we don't think it's missing
586
- }
587
- return memberMap ;
588
- }
589
- }
590
-
591
- // fall back to the class map in case it's a duplicate element name that we've already null'ed out
592
- // but make sure not to return the extraElementsMemberMap
593
- if ( _extraElementsMemberMap == null || elementName != _extraElementsMemberMap . ElementName )
594
- {
595
- return _classMap . GetMemberMapForElement ( elementName ) ;
596
- }
597
- else
598
- {
599
- return null ;
600
- }
601
- }
602
-
603
- public bool HasLeftOverMemberMaps ( )
567
+ public static uint [ ] GetBitArray ( int memberCount )
604
568
{
605
- for ( int i = _from ; i <= _to ; i ++ )
569
+ var bitArrayOffset = memberCount & 31 ;
570
+ var bitArrayLength = memberCount >> 5 ;
571
+ if ( bitArrayOffset == 0 )
606
572
{
607
- if ( _memberMaps [ i ] != null )
608
- {
609
- return true ;
610
- }
573
+ return new uint [ bitArrayLength ] ;
611
574
}
612
- return false ;
575
+ var bitArray = new uint [ bitArrayLength + 1 ] ;
576
+ bitArray [ bitArrayLength ] = ~ 0U << bitArrayOffset ; // set unused bits to 1
577
+ return bitArray ;
613
578
}
614
579
615
- public IEnumerable < BsonMemberMap > GetLeftOverMemberMaps ( )
580
+ // see http://graphics.stanford.edu/~seander/bithacks.html#ZerosOnRightMultLookup
581
+ // also returns 0 if no bits are set; caller must check this case
582
+ public static int GetLeastSignificantBit ( uint bitBlock )
616
583
{
617
- return _memberMaps . Where ( ( m , i ) => ( i >= _from ) && ( i <= _to ) && ( m != null ) ) ;
584
+ return __multiplyDeBruijnBitIndex [ ( ( uint ) ( ( bitBlock & - bitBlock ) * 0x077cb531U ) ) >> 27 ] ;
618
585
}
619
586
}
620
587
}
0 commit comments