1414*/
1515
1616using System ;
17+ using System . Buffers ;
1718using System . Collections . Generic ;
1819using System . ComponentModel ;
1920using System . Reflection ;
21+ using System . Runtime . CompilerServices ;
2022using MongoDB . Bson . IO ;
2123using MongoDB . Bson . Serialization . Conventions ;
2224using MongoDB . Bson . Serialization . Serializers ;
@@ -82,7 +84,7 @@ public override TClass Deserialize(BsonDeserializationContext context, BsonDeser
8284 {
8385 var bsonReader = context . Reader ;
8486
85- if ( bsonReader . GetCurrentBsonType ( ) == Bson . BsonType . Null )
87+ if ( bsonReader . GetCurrentBsonType ( ) == BsonType . Null )
8688 {
8789 bsonReader . ReadNull ( ) ;
8890 return default ( TClass ) ;
@@ -149,7 +151,9 @@ public TClass DeserializeClass(BsonDeserializationContext context)
149151 var discriminatorConvention = _classMap . GetDiscriminatorConvention ( ) ;
150152 var allMemberMaps = _classMap . AllMemberMaps ;
151153 var extraElementsMemberMapIndex = _classMap . ExtraElementsMemberMapIndex ;
152- var memberMapBitArray = FastMemberMapHelper . GetBitArray ( allMemberMaps . Count ) ;
154+ 155+ var ( lengthInUInts , useStackAlloc ) = FastMemberMapHelper . GetLengthInUInts ( allMemberMaps . Count ) ;
156+ using var bitArray = useStackAlloc ? FastMemberMapHelper . GetMembersBitArray ( stackalloc uint [ lengthInUInts ] ) : FastMemberMapHelper . GetMembersBitArray ( lengthInUInts ) ;
153157
154158 bsonReader . ReadStartDocument ( ) ;
155159 var elementTrie = _classMap . ElementTrie ;
@@ -193,7 +197,8 @@ public TClass DeserializeClass(BsonDeserializationContext context)
193197 DeserializeExtraElementValue ( context , values , elementName , memberMap ) ;
194198 }
195199 }
196- memberMapBitArray [ memberMapIndex >> 5 ] |= 1U << ( memberMapIndex & 31 ) ;
200+ 201+ bitArray . SetMemberIndex ( memberMapIndex ) ;
197202 }
198203 else
199204 {
@@ -221,7 +226,7 @@ public TClass DeserializeClass(BsonDeserializationContext context)
221226 {
222227 DeserializeExtraElementValue ( context , values , elementName , extraElementsMemberMap ) ;
223228 }
224- memberMapBitArray [ extraElementsMemberMapIndex >> 5 ] |= 1U << ( extraElementsMemberMapIndex & 31 ) ;
229+ bitArray . SetMemberIndex ( extraElementsMemberMapIndex ) ;
225230 }
226231 else if ( _classMap . IgnoreExtraElements )
227232 {
@@ -239,51 +244,38 @@ public TClass DeserializeClass(BsonDeserializationContext context)
239244 bsonReader . ReadEndDocument ( ) ;
240245
241246 // 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 ++ )
243249 {
244250 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
246252
247253 // work through this memberMapBlock of 32 elements
248- while ( true )
254+ for ( ; memberMapBlock != 0 && memberMapIndex < allMemberMaps . Count ; memberMapIndex ++ , memberMapBlock >>= 1 )
249255 {
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 ;
267258
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 ;
276263 }
277264
278- if ( memberMapBlock == 0 )
265+ if ( memberMap . IsRequired )
279266 {
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.") ;
281269 }
282270
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+ }
287279 }
288280 }
289281
@@ -335,13 +327,11 @@ public bool GetDocumentId(
335327 idGenerator = idMemberMap . IdGenerator ;
336328 return true ;
337329 }
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 ;
345335 }
346336
347337 /// <summary>
@@ -694,48 +684,63 @@ private bool ShouldSerializeDiscriminator(Type nominalType)
694684
695685 // nested classes
696686 // helper class that implements member map bit array helper functions
697- private static class FastMemberMapHelper
687+ internal static class FastMemberMapHelper
698688 {
699- public static uint [ ] GetBitArray ( int memberCount )
689+ internal ref struct MembersBitArray ( )
700690 {
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 ;
711695
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 )
718- {
719- bitBlock >>= 16 ;
720- leastSignificantBit |= 16 ;
721- }
722- if ( ( bitBlock & 255 ) == 0 )
696+ public MembersBitArray ( Span < uint > bitArray ) : this ( )
723697 {
724- bitBlock >>= 8 ;
725- leastSignificantBit |= 8 ;
698+ _arrayPool = null ;
699+ _bitArray = bitArray ;
700+ _rentedBuffer = null ;
701+ 702+ _bitArray . Clear ( ) ;
726703 }
727- if ( ( bitBlock & 15 ) == 0 )
704+ 705+ public MembersBitArray ( int lengthInUInts , ArrayPool < uint > arrayPool ) : this ( )
728706 {
729- bitBlock >>= 4 ;
730- leastSignificantBit |= 4 ;
707+ _arrayPool = arrayPool ;
708+ _rentedBuffer = arrayPool . Rent ( lengthInUInts ) ;
709+ _bitArray = _rentedBuffer . AsSpan ( 0 , lengthInUInts ) ;
710+ 711+ _bitArray . Clear ( ) ;
731712 }
732- if ( ( bitBlock & 3 ) == 0 )
713+ 714+ public Span < uint > Span => _bitArray ;
715+ public ArrayPool < uint > ArrayPool => _arrayPool ;
716+ 717+ public void SetMemberIndex ( int memberMapIndex ) =>
718+ _bitArray [ memberMapIndex >> 5 ] |= 1U << ( memberMapIndex & 31 ) ;
719+ 720+ public void Dispose ( )
733721 {
734- bitBlock >>= 2 ;
735- leastSignificantBit |= 2 ;
722+ if ( _isDisposed )
723+ return ;
724+ 725+ if ( _rentedBuffer != null )
726+ {
727+ _arrayPool . Return ( _rentedBuffer ) ;
728+ }
729+ _isDisposed = true ;
736730 }
737- return leastSignificantBit - ( int ) ( bitBlock & 1 ) ;
738731 }
732+ 733+ public static ( int LengthInUInts , bool UseStackAlloc ) GetLengthInUInts ( int membersCount )
734+ {
735+ var lengthInUInts = ( membersCount + 31 ) >> 5 ;
736+ return ( lengthInUInts , lengthInUInts <= 8 ) ; // Use stackalloc for up to 256 members
737+ }
738+ 739+ public static MembersBitArray GetMembersBitArray ( Span < uint > span ) =>
740+ new ( span ) ;
741+ 742+ public static MembersBitArray GetMembersBitArray ( int lengthInUInts ) =>
743+ new ( lengthInUInts , ArrayPool < uint > . Shared ) ;
739744 }
740745 }
741746}
0 commit comments