1515// Refer to LICENSE for more information.
1616
1717using System ;
18+ using System . Buffers . Binary ;
1819using System . Numerics ;
20+ using System . Runtime . CompilerServices ;
1921using Google . Protobuf ;
2022using Decimal = Confluent . SchemaRegistry . Serdes . Protobuf . Decimal ;
2123
@@ -33,24 +35,35 @@ public static class DecimalExtensions
3335 /// <returns>Protobuf decimal value</returns>
3436 public static Decimal ToProtobufDecimal ( this decimal value )
3537 {
36- var bytes = GetBytesFromDecimal ( value ) ;
38+ Span < byte > bytes = stackalloc byte [ 16 ] ;
39+ WriteBytesFromDecimal ( value , bytes ) ;
3740
3841 // Copy the 12 bytes into an array of size 13 so that the last byte is 0,
3942 // which will ensure that the unscaled value is positive.
40- var unscaledValueBytes = new byte [ 13 ] ;
41- Array . Copy ( bytes , unscaledValueBytes , 12 ) ;
43+ Span < byte > unscaledValueBytes = stackalloc byte [ 13 ] ;
44+ bytes . Slice ( 0 , 12 ) . CopyTo ( unscaledValueBytes ) ;
4245
46+ #if NET6_0_OR_GREATER
4347 var unscaledValue = new BigInteger ( unscaledValueBytes ) ;
44- var scale = bytes [ 14 ] ;
45-
48+ #else
49+ var unscaledValue = new BigInteger ( unscaledValueBytes . ToArray ( ) ) ;
50+ #endif
51+
4652 if ( bytes [ 15 ] == 128 )
4753 {
4854 unscaledValue *= BigInteger . MinusOne ;
4955 }
50-
56+ var scale = bytes [ 14 ] ;
57+
58+ #if NET6_0_OR_GREATER
59+ Span < byte > buffer = stackalloc byte [ 16 ] ;
60+ unscaledValue . TryWriteBytes ( buffer , out var bytesWritten , isBigEndian : true ) ;
61+ buffer = buffer . Slice ( 0 , bytesWritten ) ;
62+ #else
5163 var buffer = unscaledValue . ToByteArray ( ) ;
5264 Array . Reverse ( buffer ) ;
53-
65+ #endif
66+
5467 return new Decimal {
5568 Value = ByteString . CopyFrom ( buffer ) ,
5669 Scale = scale ,
@@ -64,61 +77,42 @@ public static Decimal ToProtobufDecimal(this decimal value)
6477 /// <returns>Decimal value</returns>
6578 public static decimal ToSystemDecimal ( this Decimal value )
6679 {
80+ #if NET6_0_OR_GREATER
81+ var unscaledValue = new BigInteger ( value . Value . Span , isBigEndian : true ) ;
82+ #else
6783 var buffer = value . Value . ToByteArray ( ) ;
6884 Array . Reverse ( buffer ) ;
69-
7085 var unscaledValue = new BigInteger ( buffer ) ;
86+ #endif
7187
7288 var scaleDivisor = BigInteger . Pow ( new BigInteger ( 10 ) , value . Scale ) ;
73- var remainder = BigInteger . Remainder ( unscaledValue , scaleDivisor ) ;
74- var scaledValue = BigInteger . Divide ( unscaledValue , scaleDivisor ) ;
89+ var quotient = BigInteger . DivRem ( unscaledValue , scaleDivisor , out var remainder ) ;
7590
76- if ( scaledValue > new BigInteger ( decimal . MaxValue ) )
91+ if ( quotient > new BigInteger ( decimal . MaxValue ) )
7792 {
7893 throw new OverflowException ( $ "The value { unscaledValue } cannot fit into decimal.") ;
7994 }
8095
81- var leftOfDecimal = ( decimal ) scaledValue ;
82- var rightOfDecimal = ( ( decimal ) remainder ) / ( ( decimal ) scaleDivisor ) ;
96+ var leftOfDecimal = ( decimal ) quotient ;
97+ var rightOfDecimal = ( decimal ) remainder / ( decimal ) scaleDivisor ;
8398
8499 return leftOfDecimal + rightOfDecimal ;
85100 }
86101
87- /// <summary>
88- /// Gets the bytes from decimal.
89- /// </summary>
90- /// <param name="d">The <see cref="decimal" />.</param>
91- /// <returns>
92- /// A byte array.
93- /// </returns>
94- private static byte [ ] GetBytesFromDecimal ( decimal d )
102+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
103+ private static void WriteBytesFromDecimal ( decimal value , Span < byte > destination )
95104 {
96- byte [ ] bytes = new byte [ 16 ] ;
97-
98- int [ ] bits = decimal . GetBits ( d ) ;
99- int lo = bits [ 0 ] ;
100- int mid = bits [ 1 ] ;
101- int hi = bits [ 2 ] ;
102- int flags = bits [ 3 ] ;
103-
104- bytes [ 0 ] = ( byte ) lo ;
105- bytes [ 1 ] = ( byte ) ( lo >> 8 ) ;
106- bytes [ 2 ] = ( byte ) ( lo >> 0x10 ) ;
107- bytes [ 3 ] = ( byte ) ( lo >> 0x18 ) ;
108- bytes [ 4 ] = ( byte ) mid ;
109- bytes [ 5 ] = ( byte ) ( mid >> 8 ) ;
110- bytes [ 6 ] = ( byte ) ( mid >> 0x10 ) ;
111- bytes [ 7 ] = ( byte ) ( mid >> 0x18 ) ;
112- bytes [ 8 ] = ( byte ) hi ;
113- bytes [ 9 ] = ( byte ) ( hi >> 8 ) ;
114- bytes [ 10 ] = ( byte ) ( hi >> 0x10 ) ;
115- bytes [ 11 ] = ( byte ) ( hi >> 0x18 ) ;
116- bytes [ 12 ] = ( byte ) flags ;
117- bytes [ 13 ] = ( byte ) ( flags >> 8 ) ;
118- bytes [ 14 ] = ( byte ) ( flags >> 0x10 ) ;
119- bytes [ 15 ] = ( byte ) ( flags >> 0x18 ) ;
120-
121- return bytes ;
105+ #if NET6_0_OR_GREATER
106+ Span < int > bits = stackalloc int [ 4 ] ;
107+ _ = decimal . GetBits ( value , bits ) ;
108+ #else
109+ var bits = decimal . GetBits ( value ) ;
110+ #endif
111+
112+ BinaryPrimitives . WriteInt32LittleEndian ( destination , bits [ 0 ] ) ;
113+ BinaryPrimitives . WriteInt32LittleEndian ( destination . Slice ( 4 ) , bits [ 1 ] ) ;
114+ BinaryPrimitives . WriteInt32LittleEndian ( destination . Slice ( 8 ) , bits [ 2 ] ) ;
115+ BinaryPrimitives . WriteInt32LittleEndian ( destination . Slice ( 12 ) , bits [ 3 ] ) ;
122116 }
123117 }
124118}
0 commit comments