14
14
*/
15
15
16
16
using System ;
17
+ using System . Buffers ;
17
18
using System . Collections . Generic ;
18
19
using System . ComponentModel ;
19
20
using System . Reflection ;
21
+ using System . Runtime . CompilerServices ;
20
22
using MongoDB . Bson . IO ;
21
23
using MongoDB . Bson . Serialization . Conventions ;
22
24
using MongoDB . Bson . Serialization . Serializers ;
@@ -82,7 +84,7 @@ public override TClass Deserialize(BsonDeserializationContext context, BsonDeser
82
84
{
83
85
var bsonReader = context . Reader ;
84
86
85
- if ( bsonReader . GetCurrentBsonType ( ) == Bson . BsonType . Null )
87
+ if ( bsonReader . GetCurrentBsonType ( ) == BsonType . Null )
86
88
{
87
89
bsonReader . ReadNull ( ) ;
88
90
return default ( TClass ) ;
@@ -149,7 +151,9 @@ public TClass DeserializeClass(BsonDeserializationContext context)
149
151
var discriminatorConvention = _classMap . GetDiscriminatorConvention ( ) ;
150
152
var allMemberMaps = _classMap . AllMemberMaps ;
151
153
var extraElementsMemberMapIndex = _classMap . ExtraElementsMemberMapIndex ;
152
- var memberMapBitArray = FastMemberMapHelper . GetBitArray ( allMemberMaps . Count ) ;
154
+
155
+ var ( bitArrayLength , useStackAlloc ) = FastMemberMapHelper . GetBitArrayLength ( _classMap . AllMemberMaps . Count ) ;
156
+ using var bitArray = useStackAlloc ? FastMemberMapHelper . GetBitArray ( stackalloc uint [ bitArrayLength ] ) : FastMemberMapHelper . GetBitArray ( bitArrayLength ) ;
153
157
154
158
bsonReader . ReadStartDocument ( ) ;
155
159
var elementTrie = _classMap . ElementTrie ;
@@ -193,7 +197,8 @@ public TClass DeserializeClass(BsonDeserializationContext context)
193
197
DeserializeExtraElementValue ( context , values , elementName , memberMap ) ;
194
198
}
195
199
}
196
- memberMapBitArray [ memberMapIndex >> 5 ] |= 1U << ( memberMapIndex & 31 ) ;
200
+
201
+ bitArray . SetMemberIndex ( memberMapIndex ) ;
197
202
}
198
203
else
199
204
{
@@ -221,7 +226,7 @@ public TClass DeserializeClass(BsonDeserializationContext context)
221
226
{
222
227
DeserializeExtraElementValue ( context , values , elementName , extraElementsMemberMap ) ;
223
228
}
224
- memberMapBitArray [ extraElementsMemberMapIndex >> 5 ] |= 1U << ( extraElementsMemberMapIndex & 31 ) ;
229
+ bitArray . SetMemberIndex ( extraElementsMemberMapIndex ) ;
225
230
}
226
231
else if ( _classMap . IgnoreExtraElements )
227
232
{
@@ -239,51 +244,38 @@ public TClass DeserializeClass(BsonDeserializationContext context)
239
244
bsonReader . ReadEndDocument ( ) ;
240
245
241
246
// check any members left over that we didn't have elements for (in blocks of 32 elements at a time)
242
- for ( var bitArrayIndex = 0 ; bitArrayIndex < memberMapBitArray . Length ; ++ bitArrayIndex )
247
+ var bitArraySpan = bitArray . Span ;
248
+ for ( var bitArrayIndex = 0 ; bitArrayIndex < bitArraySpan . Length ; bitArrayIndex ++ )
243
249
{
244
250
var memberMapIndex = bitArrayIndex << 5 ;
245
- var memberMapBlock = ~ memberMapBitArray [ bitArrayIndex ] ; // notice that bits are flipped so 1's are now the missing elements
251
+ var memberMapBlock = ~ bitArraySpan [ bitArrayIndex ] ; // notice that bits are flipped so 1's are now the missing elements
246
252
247
253
// work through this memberMapBlock of 32 elements
248
- while ( true )
254
+ for ( ; memberMapBlock != 0 && memberMapIndex < allMemberMaps . Count ; memberMapIndex ++ , memberMapBlock >>= 1 )
249
255
{
250
- // examine missing elements (memberMapBlock is shifted right as we work through the block)
251
- for ( ; ( memberMapBlock & 1 ) != 0 ; ++ memberMapIndex , memberMapBlock >>= 1 )
252
- {
253
- var memberMap = allMemberMaps [ memberMapIndex ] ;
254
- if ( memberMap . IsReadOnly )
255
- {
256
- continue ;
257
- }
258
-
259
- if ( memberMap . IsRequired )
260
- {
261
- var fieldOrProperty = ( memberMap . MemberInfo is FieldInfo ) ? "field" : "property" ;
262
- var message = string . Format (
263
- "Required element '{0}' for {1} '{2}' of class {3} is missing." ,
264
- memberMap . ElementName , fieldOrProperty , memberMap . MemberName , _classMap . ClassType . FullName ) ;
265
- throw new FormatException ( message ) ;
266
- }
256
+ if ( ( memberMapBlock & 1 ) == 0 )
257
+ continue ;
267
258
268
- if ( document != null )
269
- {
270
- memberMap . ApplyDefaultValue ( document ) ;
271
- }
272
- else if ( memberMap . IsDefaultValueSpecified && ! memberMap . IsReadOnly )
273
- {
274
- values [ memberMap . ElementName ] = memberMap . DefaultValue ;
275
- }
259
+ var memberMap = allMemberMaps [ memberMapIndex ] ;
260
+ if ( memberMap . IsReadOnly )
261
+ {
262
+ continue ;
276
263
}
277
264
278
- if ( memberMapBlock == 0 )
265
+ if ( memberMap . IsRequired )
279
266
{
280
- break ;
267
+ var fieldOrProperty = ( memberMap . MemberInfo is FieldInfo ) ? "field" : "property" ;
268
+ throw new FormatException ( $ "Required element 'memberMap.ElementName' for { fieldOrProperty } '{ memberMap . MemberName } ' of class { _classMap . ClassType . FullName } is missing.") ;
281
269
}
282
270
283
- // skip ahead to the next missing element
284
- var leastSignificantBit = FastMemberMapHelper . GetLeastSignificantBit ( memberMapBlock ) ;
285
- memberMapIndex += leastSignificantBit ;
286
- memberMapBlock >>= leastSignificantBit ;
271
+ if ( document != null )
272
+ {
273
+ memberMap . ApplyDefaultValue ( document ) ;
274
+ }
275
+ else if ( memberMap . IsDefaultValueSpecified && ! memberMap . IsReadOnly )
276
+ {
277
+ values [ memberMap . ElementName ] = memberMap . DefaultValue ;
278
+ }
287
279
}
288
280
}
289
281
@@ -335,13 +327,11 @@ public bool GetDocumentId(
335
327
idGenerator = idMemberMap . IdGenerator ;
336
328
return true ;
337
329
}
338
- else
339
- {
340
- id = null ;
341
- idNominalType = null ;
342
- idGenerator = null ;
343
- return false ;
344
- }
330
+
331
+ id = null ;
332
+ idNominalType = null ;
333
+ idGenerator = null ;
334
+ return false ;
345
335
}
346
336
347
337
/// <summary>
@@ -694,47 +684,73 @@ private bool ShouldSerializeDiscriminator(Type nominalType)
694
684
695
685
// nested classes
696
686
// helper class that implements member map bit array helper functions
697
- private static class FastMemberMapHelper
687
+ internal static class FastMemberMapHelper
698
688
{
699
- public static uint [ ] GetBitArray ( int memberCount )
689
+ internal ref struct BitArray ( )
700
690
{
701
- var bitArrayOffset = memberCount & 31 ;
702
- var bitArrayLength = memberCount >> 5 ;
703
- if ( bitArrayOffset == 0 )
704
- {
705
- return new uint [ bitArrayLength ] ;
706
- }
707
- var bitArray = new uint [ bitArrayLength + 1 ] ;
708
- bitArray [ bitArrayLength ] = ~ 0U << bitArrayOffset ; // set unused bits to 1
709
- return bitArray ;
710
- }
691
+ private readonly ArrayPool < uint > _arrayPool ;
692
+ private readonly Span < uint > _bitArray ;
693
+ private readonly uint [ ] _rentedBuffer ;
694
+ private bool _isDisposed = false ;
711
695
712
- // see http://graphics.stanford.edu/~seander/bithacks.html#ZerosOnRightBinSearch
713
- // also returns 31 if no bits are set; caller must check this case
714
- public static int GetLeastSignificantBit ( uint bitBlock )
715
- {
716
- var leastSignificantBit = 1 ;
717
- if ( ( bitBlock & 65535 ) == 0 )
696
+ public BitArray ( Span < uint > bitArray ) : this ( )
718
697
{
719
- bitBlock >>= 16 ;
720
- leastSignificantBit |= 16 ;
698
+ _arrayPool = null ;
699
+ _bitArray = bitArray ;
700
+ _rentedBuffer = null ;
721
701
}
722
- if ( ( bitBlock & 255 ) == 0 )
702
+
703
+ public BitArray ( int spanLength , uint [ ] rentedBuffer , ArrayPool < uint > arrayPool ) : this ( )
723
704
{
724
- bitBlock >>= 8 ;
725
- leastSignificantBit |= 8 ;
705
+ _arrayPool = arrayPool ;
706
+ _bitArray = rentedBuffer . AsSpan ( 0 , spanLength ) ;
707
+ _rentedBuffer = rentedBuffer ;
726
708
}
727
- if ( ( bitBlock & 15 ) == 0 )
709
+
710
+ public Span < uint > Span => _bitArray ;
711
+ public ArrayPool < uint > ArrayPool => _arrayPool ;
712
+
713
+ public void SetMemberIndex ( int memberMapIndex ) =>
714
+ _bitArray [ memberMapIndex >> 5 ] |= 1U << ( memberMapIndex & 31 ) ;
715
+
716
+ public void Dispose ( )
728
717
{
729
- bitBlock >>= 4 ;
730
- leastSignificantBit |= 4 ;
718
+ if ( _isDisposed )
719
+ return ;
720
+
721
+ if ( _rentedBuffer != null )
722
+ {
723
+ _arrayPool . Return ( _rentedBuffer ) ;
724
+ }
725
+ _isDisposed = true ;
731
726
}
732
- if ( ( bitBlock & 3 ) == 0 )
727
+ }
728
+
729
+ public static ( int BitArrayLength , bool UseStackAlloc ) GetBitArrayLength ( int membersCount )
730
+ {
731
+ var length = ( membersCount + 31 ) >> 5 ;
732
+ return ( length , length <= 8 ) ; // Use stackalloc for up to 256 members
733
+ }
734
+
735
+ public static BitArray GetBitArray ( Span < uint > span ) =>
736
+ new ( ResetSpan ( span ) ) ;
737
+
738
+ public static BitArray GetBitArray ( int length )
739
+ {
740
+ var rentedBuffer = ArrayPool < uint > . Shared . Rent ( length ) ;
741
+ ResetSpan ( rentedBuffer ) ;
742
+
743
+ return new ( length , rentedBuffer , ArrayPool < uint > . Shared ) ;
744
+ }
745
+
746
+ private static Span < uint > ResetSpan ( Span < uint > span )
747
+ {
748
+ for ( var i = 0 ; i < span . Length ; i ++ )
733
749
{
734
- bitBlock >>= 2 ;
735
- leastSignificantBit |= 2 ;
750
+ span [ i ] = 0 ;
736
751
}
737
- return leastSignificantBit - ( int ) ( bitBlock & 1 ) ;
752
+
753
+ return span ;
738
754
}
739
755
}
740
756
}
0 commit comments