15
15
// Refer to LICENSE for more information.
16
16
17
17
using System ;
18
+ using System . Buffers . Binary ;
18
19
using System . Numerics ;
20
+ using System . Runtime . CompilerServices ;
19
21
using Google . Protobuf ;
20
22
using Decimal = Confluent . SchemaRegistry . Serdes . Protobuf . Decimal ;
21
23
@@ -33,24 +35,35 @@ public static class DecimalExtensions
33
35
/// <returns>Protobuf decimal value</returns>
34
36
public static Decimal ToProtobufDecimal ( this decimal value )
35
37
{
36
- var bytes = GetBytesFromDecimal ( value ) ;
38
+ Span < byte > bytes = stackalloc byte [ 16 ] ;
39
+ WriteBytesFromDecimal ( value , bytes ) ;
37
40
38
41
// Copy the 12 bytes into an array of size 13 so that the last byte is 0,
39
42
// 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 ) ;
42
45
46
+ #if NET6_0_OR_GREATER
43
47
var unscaledValue = new BigInteger ( unscaledValueBytes ) ;
44
- var scale = bytes [ 14 ] ;
45
-
48
+ #else
49
+ var unscaledValue = new BigInteger ( unscaledValueBytes . ToArray ( ) ) ;
50
+ #endif
51
+
46
52
if ( bytes [ 15 ] == 128 )
47
53
{
48
54
unscaledValue *= BigInteger . MinusOne ;
49
55
}
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
51
63
var buffer = unscaledValue . ToByteArray ( ) ;
52
64
Array . Reverse ( buffer ) ;
53
-
65
+ #endif
66
+
54
67
return new Decimal {
55
68
Value = ByteString . CopyFrom ( buffer ) ,
56
69
Scale = scale ,
@@ -64,61 +77,42 @@ public static Decimal ToProtobufDecimal(this decimal value)
64
77
/// <returns>Decimal value</returns>
65
78
public static decimal ToSystemDecimal ( this Decimal value )
66
79
{
80
+ #if NET6_0_OR_GREATER
81
+ var unscaledValue = new BigInteger ( value . Value . Span , isBigEndian : true ) ;
82
+ #else
67
83
var buffer = value . Value . ToByteArray ( ) ;
68
84
Array . Reverse ( buffer ) ;
69
-
70
85
var unscaledValue = new BigInteger ( buffer ) ;
86
+ #endif
71
87
72
88
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 ) ;
75
90
76
- if ( scaledValue > new BigInteger ( decimal . MaxValue ) )
91
+ if ( quotient > new BigInteger ( decimal . MaxValue ) )
77
92
{
78
93
throw new OverflowException ( $ "The value { unscaledValue } cannot fit into decimal.") ;
79
94
}
80
95
81
- var leftOfDecimal = ( decimal ) scaledValue ;
82
- var rightOfDecimal = ( ( decimal ) remainder ) / ( ( decimal ) scaleDivisor ) ;
96
+ var leftOfDecimal = ( decimal ) quotient ;
97
+ var rightOfDecimal = ( decimal ) remainder / ( decimal ) scaleDivisor ;
83
98
84
99
return leftOfDecimal + rightOfDecimal ;
85
100
}
86
101
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 )
95
104
{
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 ] ) ;
122
116
}
123
117
}
124
118
}
0 commit comments