11using System ;
2- using System . Collections . Generic ;
32using System . IO ;
43using System . IO . Pipelines ;
5- using System . Linq ;
64using System . Text ;
5+ using System . Threading ;
6+ using System . Threading . Tasks ;
7+ using BencodeNET . IO ;
78
89namespace BencodeNET . Objects
910{
@@ -14,7 +15,7 @@ namespace BencodeNET.Objects
1415 /// <remarks>
1516 /// The underlying value is a <see cref="byte"/> array.
1617 /// </remarks>
17- public sealed class BString : BObject < IReadOnlyList < byte > > , IComparable < BString >
18+ public sealed class BString : BObject < ReadOnlyMemory < byte > > , IComparable < BString >
1819 {
1920 /// <summary>
2021 /// The maximum number of digits that can be handled as the length part of a bencoded string.
@@ -24,13 +25,12 @@ public sealed class BString : BObject<IReadOnlyList<byte>>, IComparable<BString>
2425 /// <summary>
2526 /// The underlying bytes of the string.
2627 /// </summary>
27- public override IReadOnlyList < byte > Value => _value ;
28- private readonly byte [ ] _value ;
28+ public override ReadOnlyMemory < byte > Value { get ; }
2929
3030 /// <summary>
3131 /// Gets the length of the string in bytes.
3232 /// </summary>
33- public int Length => _value . Length ;
33+ public int Length => Value . Length ;
3434
3535 private static readonly Encoding DefaultEncoding = Encoding . UTF8 ;
3636
@@ -58,12 +58,10 @@ public BString()
5858 /// </summary>
5959 /// <param name="bytes">The bytes representing the data.</param>
6060 /// <param name="encoding">The encoding of the bytes. Defaults to <see cref="System.Text.Encoding.UTF8"/>.</param>
61- public BString ( IEnumerable < byte > bytes , Encoding encoding = null )
61+ public BString ( byte [ ] bytes , Encoding encoding = null )
6262 {
63- if ( bytes == null ) throw new ArgumentNullException ( nameof ( bytes ) ) ;
64-
63+ Value = bytes ?? throw new ArgumentNullException ( nameof ( bytes ) ) ;
6564 _encoding = encoding ?? DefaultEncoding ;
66- _value = bytes as byte [ ] ?? bytes . ToArray ( ) ;
6765 }
6866
6967 /// <summary>
@@ -75,20 +73,31 @@ public BString(IEnumerable<byte> bytes, Encoding encoding = null)
7573 public BString ( string str , Encoding encoding = null )
7674 {
7775 _encoding = encoding ?? DefaultEncoding ;
78- _value = string . IsNullOrEmpty ( str )
79- ? Array . Empty < byte > ( )
80- : _encoding . GetBytes ( str ) ;
76+
77+ if ( string . IsNullOrEmpty ( str ) )
78+ {
79+ Value = Array . Empty < byte > ( ) ;
80+ }
81+ else
82+ {
83+ var maxByteCount = _encoding . GetMaxByteCount ( str . Length ) ;
84+ var span = new byte [ maxByteCount ] . AsSpan ( ) ;
85+
86+ var length = _encoding . GetBytes ( str . AsSpan ( ) , span ) ;
87+
88+ Value = span . Slice ( 0 , length ) . ToArray ( ) ;
89+ }
8190 }
8291
8392 /// <inheritdoc/>
84- public override int GetSizeInBytes ( ) => _value . Length + 1 + _value . Length . DigitCount ( ) ;
93+ public override int GetSizeInBytes ( ) => Value . Length + 1 + Value . Length . DigitCount ( ) ;
8594
8695 /// <inheritdoc/>
8796 protected override void EncodeObject ( Stream stream )
8897 {
89- stream . Write ( _value . Length ) ;
98+ stream . Write ( Value . Length ) ;
9099 stream . Write ( ':' ) ;
91- stream . Write ( _value ) ;
100+ stream . Write ( Value . Span ) ;
92101 }
93102
94103 /// <inheritdoc/>
@@ -98,26 +107,14 @@ protected override void EncodeObject(PipeWriter writer)
98107 var size = GetSizeInBytes ( ) ;
99108 var buffer = writer . GetSpan ( size ) ;
100109
101- #if NETCOREAPP
102110 // Write length
103- var writtenBytes = Encoding . GetBytes ( _value . Length . ToString ( ) . AsSpan ( ) , buffer ) ;
111+ var writtenBytes = Encoding . GetBytes ( Value . Length . ToString ( ) . AsSpan ( ) , buffer ) ;
104112
105113 // Write ':'
106114 buffer [ writtenBytes ] = ( byte ) ':' ;
107115
108116 // Write value
109- _value . AsSpan ( ) . CopyTo ( buffer . Slice ( writtenBytes + 1 ) ) ;
110- #else
111- // Write length
112- var lengthBytes = Encoding . GetBytes ( _value . Length . ToString ( ) ) ;
113- lengthBytes . CopyTo ( buffer ) ;
114-
115- // Write ':'
116- buffer [ lengthBytes . Length ] = ( byte ) ':' ;
117-
118- // Write value
119- _value . AsSpan ( ) . CopyTo ( buffer . Slice ( lengthBytes . Length + 1 ) ) ;
120- #endif
117+ Value . Span . CopyTo ( buffer . Slice ( writtenBytes + 1 ) ) ;
121118
122119 // Commit
123120 writer . Advance ( size ) ;
@@ -128,56 +125,34 @@ protected override void EncodeObject(PipeWriter writer)
128125
129126 public static bool operator == ( BString first , BString second )
130127 {
131- if ( ReferenceEquals ( first , null ) )
132- return ReferenceEquals ( second , null ) ;
128+ if ( first is null )
129+ return second is null ;
133130
134131 return first . Equals ( second ) ;
135132 }
136133
137134 public static bool operator != ( BString first , BString second ) => ! ( first == second ) ;
138135
139- public override bool Equals ( object other ) => other is BString bstring && Value . SequenceEqual ( bstring . Value ) ;
136+ public override bool Equals ( object other ) => other is BString bstring && Value . Span . SequenceEqual ( bstring . Value . Span ) ;
140137
141- public bool Equals ( BString bstring ) => bstring != null && Value . SequenceEqual ( bstring . Value ) ;
138+ public bool Equals ( BString bstring ) => bstring != null && Value . Span . SequenceEqual ( bstring . Value . Span ) ;
142139
143140 public override int GetHashCode ( )
144141 {
145- var bytesToHash = Math . Min ( Value . Count , 32 ) ;
142+ var bytesToHash = Math . Min ( Value . Length , 32 ) ;
146143
147144 long hashValue = 0 ;
148145 for ( var i = 0 ; i < bytesToHash ; i ++ )
149146 {
150- hashValue = ( 37 * hashValue + Value [ i ] ) % int . MaxValue ;
147+ hashValue = ( 37 * hashValue + Value . Span [ i ] ) % int . MaxValue ;
151148 }
152149
153150 return ( int ) hashValue ;
154151 }
155152
156153 public int CompareTo ( BString other )
157154 {
158- if ( other == null )
159- return 1 ;
160-
161- var maxLength = Math . Max ( this . Length , other . Length ) ;
162-
163- for ( var i = 0 ; i < maxLength ; i ++ )
164- {
165- // This is shorter and thereby this is "less than" the other
166- if ( i >= this . Length )
167- return - 1 ;
168-
169- // The other is shorter and thereby this is "greater than" the other
170- if ( i >= other . Length )
171- return 1 ;
172-
173- if ( this . Value [ i ] > other . Value [ i ] )
174- return 1 ;
175-
176- if ( this . Value [ i ] < other . Value [ i ] )
177- return - 1 ;
178- }
179-
180- return 0 ;
155+ return Value . Span . SequenceCompareTo ( other . Value . Span ) ;
181156 }
182157#pragma warning restore 1591
183158
@@ -189,11 +164,7 @@ public int CompareTo(BString other)
189164 /// </returns>
190165 public override string ToString ( )
191166 {
192- #if NETCOREAPP
193- return _encoding . GetString ( _value . AsSpan ( ) ) ;
194- #else
195- return _encoding . GetString ( _value ) ;
196- #endif
167+ return _encoding . GetString ( Value . Span ) ;
197168 }
198169
199170 /// <summary>
@@ -206,11 +177,7 @@ public override string ToString()
206177 public string ToString ( Encoding encoding )
207178 {
208179 encoding = encoding ?? _encoding ;
209- #if NETCOREAPP
210- return encoding . GetString ( _value . AsSpan ( ) ) ;
211- #else
212- return encoding . GetString ( _value ) ;
213- #endif
180+ return encoding . GetString ( Value . Span ) ;
214181 }
215182 }
216183}
0 commit comments