11using System ;
22using System . Buffers ;
33using System . Runtime . CompilerServices ;
4+ using System . Runtime . InteropServices ;
45using System . Threading ;
56
67namespace StackExchange . Redis
@@ -16,7 +17,7 @@ public sealed class Lease<T> : IMemoryOwner<T>
1617 /// </summary>
1718 public static Lease < T > Empty { get ; } = new Lease < T > ( System . Array . Empty < T > ( ) , 0 ) ;
1819
19- private T [ ] ? _arr ;
20+ private object ? _buffer ;
2021
2122 /// <summary>
2223 /// Gets whether this lease is empty.
@@ -41,9 +42,29 @@ public static Lease<T> Create(int length, bool clear = true)
4142 return new Lease < T > ( arr , length ) ;
4243 }
4344
45+ /// <summary>
46+ /// Create a new lease.
47+ /// </summary>
48+ /// <param name="length">The size required.</param>
49+ /// <param name="memoryOwner">Buffer.</param>
50+ public static Lease < T > Create ( int length , IMemoryOwner < T > memoryOwner )
51+ {
52+ if ( length == 0 ) return Empty ;
53+ if ( ( uint ) length > memoryOwner . Memory . Length )
54+ throw new ArgumentOutOfRangeException ( nameof ( length ) ) ;
55+
56+ return new Lease < T > ( memoryOwner , length ) ;
57+ }
58+
4459 private Lease ( T [ ] arr , int length )
4560 {
46- _arr = arr ;
61+ _buffer = arr ;
62+ Length = length ;
63+ }
64+
65+ private Lease ( IMemoryOwner < T > memoryOwner , int length )
66+ {
67+ _buffer = memoryOwner ;
4768 Length = length ;
4869 }
4970
@@ -54,33 +75,50 @@ public void Dispose()
5475 {
5576 if ( Length != 0 )
5677 {
57- var arr = Interlocked . Exchange ( ref _arr , null ) ;
58- if ( arr != null ) ArrayPool < T > . Shared . Return ( arr ) ;
78+ var buffer = Interlocked . Exchange ( ref _buffer , null ) ;
79+ if ( buffer != null )
80+ {
81+ if ( buffer is T [ ] arr )
82+ ArrayPool < T > . Shared . Return ( arr ) ;
83+ else
84+ ( ( IMemoryOwner < T > ) buffer ) . Dispose ( ) ;
85+ }
5986 }
6087 }
6188
6289 [ MethodImpl ( MethodImplOptions . NoInlining ) ]
6390 private static T [ ] ThrowDisposed ( ) => throw new ObjectDisposedException ( nameof ( Lease < T > ) ) ;
6491
65- private T [ ] Array
66- {
67- [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
68- get => _arr ?? ThrowDisposed ( ) ;
69- }
70-
7192 /// <summary>
7293 /// The data as a <see cref="Memory{T}"/>.
7394 /// </summary>
74- public Memory < T > Memory => new Memory < T > ( Array , 0 , Length ) ;
95+ public Memory < T > Memory => _buffer is IMemoryOwner < T > memoryOwner
96+ ? memoryOwner . Memory . Slice ( 0 , Length )
97+ : new Memory < T > ( ( T [ ] ? ) _buffer ?? ThrowDisposed ( ) , 0 , Length ) ;
7598
7699 /// <summary>
77100 /// The data as a <see cref="Span{T}"/>.
78101 /// </summary>
79- public Span < T > Span => new Span < T > ( Array , 0 , Length ) ;
102+ public Span < T > Span => _buffer is IMemoryOwner < T > memoryOwner
103+ ? memoryOwner . Memory . Span . Slice ( 0 , Length )
104+ : new Span < T > ( ( T [ ] ? ) _buffer ?? ThrowDisposed ( ) , 0 , Length ) ;
80105
81106 /// <summary>
82107 /// The data as an <see cref="ArraySegment{T}"/>.
83108 /// </summary>
84- public ArraySegment < T > ArraySegment => new ArraySegment < T > ( Array , 0 , Length ) ;
109+ public ArraySegment < T > ArraySegment
110+ {
111+ get
112+ {
113+ if ( _buffer is IMemoryOwner < T > memoryOwner )
114+ {
115+ if ( ! MemoryMarshal . TryGetArray ( ( ReadOnlyMemory < T > ) memoryOwner . Memory , out var segment ) )
116+ throw new NotSupportedException ( "Only array-backed buffers are supported" ) ;
117+
118+ return new ArraySegment < T > ( segment . Array ! , segment . Offset , Length ) ;
119+ }
120+ return new ArraySegment < T > ( ( T [ ] ? ) _buffer ?? ThrowDisposed ( ) , 0 , Length ) ;
121+ }
122+ }
85123 }
86124}
0 commit comments