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