11using System ;
2+ using System . Buffers ;
3+ using System . Runtime . CompilerServices ;
24using DuckDB . NET . Native ;
35
46namespace DuckDB . NET . Data . Extensions ;
57
68internal static class GuidConverter
79{
10+ #if ! NET6_0_OR_GREATER
811 private const string GuidFormat = "D" ;
912 private static readonly char [ ] HexDigits = "0123456789abcdef" . ToCharArray ( ) ;
1013
@@ -45,52 +48,112 @@ public static Guid ConvertToGuid(this DuckDBHugeInt input)
4548 ByteToHex ( buffer , ref position , ( input . Lower >> 8 ) & 0xFF ) ;
4649 ByteToHex ( buffer , ref position , input . Lower & 0xFF ) ;
4750
48- #if NET6_0_OR_GREATER
49- return Guid . ParseExact ( buffer , GuidFormat ) ;
50- #else
5151 return Guid . ParseExact ( new string ( buffer . ToArray ( ) ) , GuidFormat ) ;
52- #endif
53-
52+
5453 static void ByteToHex ( Span < char > buffer , ref int position , ulong value )
5554 {
5655 buffer [ position ++ ] = HexDigits [ ( value >> 4 ) & 0xF ] ;
5756 buffer [ position ++ ] = HexDigits [ value & 0xF ] ;
5857 }
5958 }
59+ #else
60+ public static Guid ConvertToGuid ( this DuckDBHugeInt input )
61+ {
62+ var bytes = ArrayPool < byte > . Shared . Rent ( 32 ) ;
63+ try
64+ {
65+ // Reverse the bit flip on the upper 64 bits
66+ long upper = input . Upper ^ ( ( long ) 1 << 63 ) ;
67+
68+ // Write upper 64 bits (bytes 0-7)
69+ BitConverter . TryWriteBytes ( bytes . AsSpan ( 16 ) , upper ) ;
70+
71+ // Write lower 64 bits (bytes 8-15)
72+ BitConverter . TryWriteBytes ( bytes . AsSpan ( 16 + 8 ) , input . Lower ) ;
73+
74+ // Reconstruct the Guid bytes (reverse the original byte reordering)
75+ ReorderBytesForGuid ( ) ;
76+
77+ // Create Guid from the first 16 bytes
78+ return new Guid ( bytes . AsSpan ( 0 , 16 ) ) ;
79+ }
80+ finally
81+ {
82+ ArrayPool < byte > . Shared . Return ( bytes ) ;
83+ }
84+
85+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
86+ void ReorderBytesForGuid ( )
87+ {
88+ // First 4 bytes (little-endian)
89+ bytes [ 6 ] = bytes [ 16 + 0 ] ;
90+ bytes [ 7 ] = bytes [ 16 + 1 ] ;
91+ bytes [ 4 ] = bytes [ 16 + 2 ] ;
92+ bytes [ 5 ] = bytes [ 16 + 3 ] ;
93+
94+ // Next 4 bytes (little-endian)
95+ bytes [ 0 ] = bytes [ 16 + 4 ] ;
96+ bytes [ 1 ] = bytes [ 16 + 5 ] ;
97+ bytes [ 2 ] = bytes [ 16 + 6 ] ;
98+ bytes [ 3 ] = bytes [ 16 + 7 ] ;
99+
100+ // Last 8 bytes (big-endian)
101+ bytes [ 15 ] = bytes [ 16 + 8 ] ;
102+ bytes [ 14 ] = bytes [ 16 + 9 ] ;
103+ bytes [ 13 ] = bytes [ 16 + 10 ] ;
104+ bytes [ 12 ] = bytes [ 16 + 11 ] ;
105+ bytes [ 11 ] = bytes [ 16 + 12 ] ;
106+ bytes [ 10 ] = bytes [ 16 + 13 ] ;
107+ bytes [ 9 ] = bytes [ 16 + 14 ] ;
108+ bytes [ 8 ] = bytes [ 16 + 15 ] ;
109+ }
110+ }
111+ #endif
60112
61113 //https://github.com/duckdb/duckdb/blob/9c91b3a329073ea1767b0aaff94b51da98dd03e2/src/common/types/uuid.cpp#L6
62114 public static DuckDBHugeInt ToHugeInt ( this Guid guid )
63115 {
64- char HexToChar ( char ch )
116+ var bytes = ArrayPool < byte > . Shared . Rent ( 32 ) ;
117+
118+ try
65119 {
66- return ch switch
67- {
68- >= '0' and <= '9' => ( char ) ( ch - '0' ) ,
69- >= 'a' and <= 'f' => ( char ) ( 10 + ch - 'a' ) ,
70- >= 'A' and <= 'F' => ( char ) ( 10 + ch - 'A' ) ,
71- _ => ( char ) 0
72- } ;
73- }
120+ #if NET6_0_OR_GREATER
121+ guid . TryWriteBytes ( bytes ) ;
122+ #else
123+ Buffer . BlockCopy ( guid . ToByteArray ( ) , 0 , bytes , 0 , 16 ) ;
124+ #endif
125+ bytes [ 16 + 0 ] = bytes [ 6 ] ; // First 4 bytes (little-endian)
126+ bytes [ 16 + 1 ] = bytes [ 7 ] ;
127+ bytes [ 16 + 2 ] = bytes [ 4 ] ;
128+ bytes [ 16 + 3 ] = bytes [ 5 ] ;
129+ bytes [ 16 + 4 ] = bytes [ 0 ] ; // Next 4 bytes (little-endian)
130+ bytes [ 16 + 5 ] = bytes [ 1 ] ;
131+ bytes [ 16 + 6 ] = bytes [ 2 ] ;
132+ bytes [ 16 + 7 ] = bytes [ 3 ] ;
74133
75- ulong lower = 0 ;
76- long upper = 0 ;
134+ bytes [ 16 + 8 ] = bytes [ 15 ] ; // Big endian
135+ bytes [ 16 + 9 ] = bytes [ 14 ] ;
136+ bytes [ 16 + 10 ] = bytes [ 13 ] ;
137+ bytes [ 16 + 11 ] = bytes [ 12 ] ;
138+ bytes [ 16 + 12 ] = bytes [ 11 ] ;
139+ bytes [ 16 + 13 ] = bytes [ 10 ] ;
140+ bytes [ 16 + 14 ] = bytes [ 9 ] ;
141+ bytes [ 16 + 15 ] = bytes [ 8 ] ;
77142
78- var str = guid . ToString ( "N" ) ;
143+ // Upper 64 bits (bytes 0-7)
144+ long upper = BitConverter . ToInt64 ( bytes , 16 + 0 ) ;
79145
80- for ( var index = 0 ; index < str . Length ; index ++ )
146+ // Lower 64 bits (bytes 8-15)
147+ ulong lower = BitConverter . ToUInt64 ( bytes , 16 + 8 ) ;
148+
149+ // Flip the first bit to make `order by uuid` same as `order by uuid::varchar`
150+ upper ^= ( ( long ) 1 << 63 ) ;
151+
152+ return new DuckDBHugeInt ( lower , upper ) ;
153+ }
154+ finally
81155 {
82- if ( index >= 16 )
83- {
84- lower = ( lower << 4 ) | HexToChar ( str [ index ] ) ;
85- }
86- else
87- {
88- upper = ( upper << 4 ) | HexToChar ( str [ index ] ) ;
89- }
156+ ArrayPool < byte > . Shared . Return ( bytes ) ;
90157 }
91-
92- // Flip the first bit to make `order by uuid` same as `order by uuid::varchar`
93- upper ^= ( ( long ) 1 << 63 ) ;
94- return new DuckDBHugeInt ( lower , upper ) ;
95158 }
96159}
0 commit comments