@@ -36,22 +36,6 @@ private static ReadOnlySpan<char> FirstSplitSpan(ReadOnlySpan<char> rest, int i,
3636 : rest . Slice ( 0 , i ) ;
3737 }
3838
39- private static ReadOnlyMemory < char > FirstSplitMemory ( string source , int start , int i , int n , out int nextIndex )
40- {
41- Debug . Assert ( start >= 0 ) ;
42- if ( i == - 1 )
43- {
44- nextIndex = - 1 ;
45- return start == 0 ? source . AsMemory ( ) : source . AsMemory ( start ) ;
46- }
47-
48- nextIndex = i + n ;
49- int segmentLen = i - start ;
50- return segmentLen == 0
51- ? ReadOnlyMemory < char > . Empty
52- : source . AsMemory ( start , segmentLen ) ;
53- }
54-
5539 /// <summary>
5640 /// Finds the first instance of a character and returns the set of characters up to that character.
5741 /// </summary>
@@ -177,46 +161,17 @@ public static ReadOnlySpan<char> FirstSplit(this ReadOnlySpan<char> source,
177161 /// <param name="splitCharacter">The character to find.</param>
178162 /// <param name="options">Can specify to omit empty entries.</param>
179163 /// <returns>An enumerable of the segments.</returns>
180- public static IEnumerable < string > SplitToEnumerable ( this string source ,
181- char splitCharacter ,
182- StringSplitOptions options = StringSplitOptions . None )
164+ public static IEnumerable < string > SplitToEnumerable (
165+ this string source ,
166+ char splitCharacter ,
167+ StringSplitOptions options = StringSplitOptions . None )
183168 {
184169 if ( source is null ) throw new ArgumentNullException ( nameof ( source ) ) ;
185- Contract . EndContractBlock ( ) ;
186170
187- return options switch
188- {
189- StringSplitOptions . None => source . Length == 0
190- ? Enumerable . Repeat ( string . Empty , 1 )
191- : SplitAsEnumerableCore ( ) ,
192- StringSplitOptions . RemoveEmptyEntries => source . Length == 0
193- ? Enumerable . Empty < string > ( )
194- : SplitAsEnumerableCoreOmitEmpty ( ) ,
195- _ => throw new System . ComponentModel . InvalidEnumArgumentException ( ) ,
196- } ;
197-
198- IEnumerable < string > SplitAsEnumerableCore ( )
199- {
200- int startIndex = 0 ;
201- do
202- {
203- yield return source . FirstSplit ( splitCharacter , out int nextIndex , startIndex ) . ToString ( ) ;
204- startIndex = nextIndex ;
205- }
206- while ( startIndex != - 1 ) ;
207- }
208-
209- IEnumerable < string > SplitAsEnumerableCoreOmitEmpty ( )
210- {
211- int startIndex = 0 ;
212- do
213- {
214- ReadOnlySpan < char > result = source . FirstSplit ( splitCharacter , out int nextIndex , startIndex ) ;
215- if ( result . Length != 0 ) yield return result . ToString ( ) ;
216- startIndex = nextIndex ;
217- }
218- while ( startIndex != - 1 ) ;
219- }
171+ Contract . EndContractBlock ( ) ;
172+ return source . AsSegment ( )
173+ . SplitAsSegments ( splitCharacter , options )
174+ . Select ( s => s . ToString ( ) ) ;
220175 }
221176
222177 /// <summary>
@@ -229,49 +184,16 @@ IEnumerable<string> SplitAsEnumerableCoreOmitEmpty()
229184 /// <returns>An IEnumerable<string> of the segments.</returns>
230185 public static IEnumerable < string > SplitToEnumerable (
231186 this string source ,
232- string splitSequence ,
187+ StringSegment splitSequence ,
233188 StringSplitOptions options = StringSplitOptions . None ,
234189 StringComparison comparisonType = StringComparison . Ordinal )
235190 {
236191 if ( source is null ) throw new ArgumentNullException ( nameof ( source ) ) ;
237- if ( splitSequence is null ) throw new ArgumentNullException ( nameof ( splitSequence ) ) ;
238- if ( splitSequence . Length == 0 )
239- throw new ArgumentException ( "Cannot split using empty sequence." , nameof ( splitSequence ) ) ;
240192 Contract . EndContractBlock ( ) ;
241193
242- return options switch
243- {
244- StringSplitOptions . None => source . Length == 0
245- ? Enumerable . Repeat ( string . Empty , 1 )
246- : SplitAsEnumerableCore ( source , splitSequence , comparisonType ) ,
247- StringSplitOptions . RemoveEmptyEntries => source . Length == 0
248- ? Enumerable . Empty < string > ( )
249- : SplitAsEnumerableCoreOmitEmpty ( source , splitSequence , comparisonType ) ,
250- _ => throw new System . ComponentModel . InvalidEnumArgumentException ( ) ,
251- } ;
252-
253- static IEnumerable < string > SplitAsEnumerableCore ( string source , string splitSequence , StringComparison comparisonType )
254- {
255- int startIndex = 0 ;
256- do
257- {
258- yield return source . FirstSplit ( splitSequence , out int nextIndex , startIndex , comparisonType ) . ToString ( ) ;
259- startIndex = nextIndex ;
260- }
261- while ( startIndex != - 1 ) ;
262- }
263-
264- static IEnumerable < string > SplitAsEnumerableCoreOmitEmpty ( string source , string splitSequence , StringComparison comparisonType )
265- {
266- int startIndex = 0 ;
267- do
268- {
269- ReadOnlySpan < char > result = source . FirstSplit ( splitSequence , out int nextIndex , startIndex , comparisonType ) ;
270- if ( result . Length != 0 ) yield return result . ToString ( ) ;
271- startIndex = nextIndex ;
272- }
273- while ( startIndex != - 1 ) ;
274- }
194+ return source . AsSegment ( )
195+ . SplitAsSegments ( splitSequence , options , comparisonType )
196+ . Select ( s => s . ToString ( ) ) ;
275197 }
276198
277199 /// <returns>An IEnumerable<ReadOnlyMemory<char>> of the segments.</returns>
@@ -280,94 +202,18 @@ public static IEnumerable<ReadOnlyMemory<char>> SplitAsMemory(
280202 this string source ,
281203 char splitCharacter ,
282204 StringSplitOptions options = StringSplitOptions . None )
283- {
284- if ( source is null ) throw new ArgumentNullException ( nameof ( source ) ) ;
285- Contract . EndContractBlock ( ) ;
286-
287- return options switch
288- {
289- StringSplitOptions . None => source . Length == 0
290- ? Enumerable . Repeat ( ReadOnlyMemory < char > . Empty , 1 )
291- : SplitAsMemoryCore ( source , splitCharacter ) ,
292- StringSplitOptions . RemoveEmptyEntries => source . Length == 0
293- ? Enumerable . Empty < ReadOnlyMemory < char > > ( )
294- : SplitAsMemoryOmitEmpty ( source , splitCharacter ) ,
295- _ => throw new System . ComponentModel . InvalidEnumArgumentException ( ) ,
296- } ;
297-
298- static IEnumerable < ReadOnlyMemory < char > > SplitAsMemoryCore ( string source , char splitCharacter )
299- {
300- int startIndex = 0 ;
301- do
302- {
303- yield return FirstSplitMemory ( source , startIndex , source . IndexOf ( splitCharacter , startIndex ) , 1 , out int nextIndex ) ;
304- startIndex = nextIndex ;
305- }
306- while ( startIndex != - 1 ) ;
307- }
308-
309- static IEnumerable < ReadOnlyMemory < char > > SplitAsMemoryOmitEmpty ( string source , char splitCharacter )
310- {
311- int startIndex = 0 ;
312- do
313- {
314- ReadOnlyMemory < char > result = FirstSplitMemory ( source , startIndex , source . IndexOf ( splitCharacter , startIndex ) , 1 , out int nextIndex ) ;
315- if ( result . Length != 0 ) yield return result ;
316- startIndex = nextIndex ;
317- }
318- while ( startIndex != - 1 ) ;
319- }
320- }
205+ => SplitAsSegments ( source . AsSegment ( ) , splitCharacter , options )
206+ . Select ( s => s . AsMemory ( ) ) ;
321207
322208 /// <returns>An IEnumerable<ReadOnlyMemory<char>> of the segments.</returns>
323- /// <inheritdoc cref="SplitToEnumerable(string, string , StringSplitOptions, StringComparison)"/>
209+ /// <inheritdoc cref="SplitToEnumerable(string, StringSegment , StringSplitOptions, StringComparison)"/>
324210 public static IEnumerable < ReadOnlyMemory < char > > SplitAsMemory ( this string source ,
325211 string splitSequence ,
326212 StringSplitOptions options = StringSplitOptions . None ,
327213 StringComparison comparisonType = StringComparison . Ordinal )
328- {
329- if ( source is null ) throw new ArgumentNullException ( nameof ( source ) ) ;
330- if ( splitSequence is null ) throw new ArgumentNullException ( nameof ( splitSequence ) ) ;
331- if ( splitSequence . Length == 0 )
332- throw new ArgumentException ( "Cannot split using empty sequence." , nameof ( splitSequence ) ) ;
333- Contract . EndContractBlock ( ) ;
334214
335- return options switch
336- {
337- StringSplitOptions . None => source . Length == 0
338- ? Enumerable . Repeat ( ReadOnlyMemory < char > . Empty , 1 )
339- : SplitAsMemoryCore ( source , splitSequence , comparisonType ) ,
340- StringSplitOptions . RemoveEmptyEntries => source . Length == 0
341- ? Enumerable . Empty < ReadOnlyMemory < char > > ( )
342- : SplitAsMemoryOmitEmpty ( source , splitSequence , comparisonType ) ,
343- _ => throw new System . ComponentModel . InvalidEnumArgumentException ( ) ,
344- } ;
345-
346- static IEnumerable < ReadOnlyMemory < char > > SplitAsMemoryOmitEmpty ( string source , string splitSequence , StringComparison comparisonType )
347- {
348- int startIndex = 0 ;
349- int splitLen = splitSequence . Length ;
350- do
351- {
352- ReadOnlyMemory < char > result = FirstSplitMemory ( source , startIndex , source . IndexOf ( splitSequence , startIndex , comparisonType ) , splitLen , out int nextIndex ) ;
353- if ( result . Length != 0 ) yield return result ;
354- startIndex = nextIndex ;
355- }
356- while ( startIndex != - 1 ) ;
357- }
358-
359- static IEnumerable < ReadOnlyMemory < char > > SplitAsMemoryCore ( string source , string splitSequence , StringComparison comparisonType )
360- {
361- int startIndex = 0 ;
362- int splitLen = splitSequence . Length ;
363- do
364- {
365- yield return FirstSplitMemory ( source , startIndex , source . IndexOf ( splitSequence , startIndex , comparisonType ) , splitLen , out int nextIndex ) ;
366- startIndex = nextIndex ;
367- }
368- while ( startIndex != - 1 ) ;
369- }
370- }
215+ => SplitAsSegments ( source . AsSegment ( ) , splitSequence , options , comparisonType )
216+ . Select ( s => s . AsMemory ( ) ) ;
371217
372218 /// <summary>
373219 /// Splits a sequence of characters into strings using the character provided.
@@ -376,42 +222,46 @@ static IEnumerable<ReadOnlyMemory<char>> SplitAsMemoryCore(string source, string
376222 /// <param name="splitCharacter">The character to split by.</param>
377223 /// <param name="options">Can specify to omit empty entries.</param>
378224 /// <returns>The resultant list of string segments.</returns>
379- public static IReadOnlyList < string > Split ( this ReadOnlySpan < char > source ,
225+ public static IReadOnlyList < string > Split (
226+ this ReadOnlySpan < char > source ,
380227 char splitCharacter ,
381228 StringSplitOptions options = StringSplitOptions . None )
382229 {
383- switch ( options )
230+ if ( source . IsEmpty )
384231 {
385- case StringSplitOptions . None when source . Length == 0 :
386- return SingleEmpty . Instance ;
387-
388- case StringSplitOptions . RemoveEmptyEntries when source . Length == 0 :
389- return Array . Empty < string > ( ) ;
390-
391- case StringSplitOptions . RemoveEmptyEntries :
392- {
393- Debug . Assert ( ! source . IsEmpty ) ;
394- var list = new List < string > ( ) ;
395-
396- loop :
397- ReadOnlySpan < char > result = source . FirstSplit ( splitCharacter , out int nextIndex ) ;
398- if ( ! result . IsEmpty ) list . Add ( result . ToString ( ) ) ;
399- if ( nextIndex == - 1 ) return list ;
400- source = source . Slice ( nextIndex ) ;
401- goto loop ;
402- }
403-
404- default :
405- {
406- Debug . Assert ( ! source . IsEmpty ) ;
407- var list = new List < string > ( ) ;
408- loop :
409- ReadOnlySpan < char > result = source . FirstSplit ( splitCharacter , out int nextIndex ) ;
410- list . Add ( result . IsEmpty ? string . Empty : result . ToString ( ) ) ;
411- if ( nextIndex == - 1 ) return list ;
412- source = source . Slice ( nextIndex ) ;
413- goto loop ;
414- }
232+ return options . HasFlag ( StringSplitOptions . RemoveEmptyEntries )
233+ ? Array . Empty < string > ( )
234+ : SingleEmpty . Instance ;
235+ }
236+
237+ var list = new List < string > ( ) ;
238+
239+ #if NET5_0_OR_GREATER
240+ bool trimEach = options . HasFlag ( StringSplitOptions . TrimEntries ) ;
241+ #endif
242+ if ( options . HasFlag ( StringSplitOptions . RemoveEmptyEntries ) )
243+ {
244+ loop :
245+ ReadOnlySpan < char > result = source . FirstSplit ( splitCharacter , out int nextIndex ) ;
246+ #if NET5_0_OR_GREATER
247+ if ( trimEach ) result = result . Trim ( ) ;
248+ #endif
249+ if ( ! result . IsEmpty ) list . Add ( result . ToString ( ) ) ;
250+ if ( nextIndex == - 1 ) return list ;
251+ source = source . Slice ( nextIndex ) ;
252+ goto loop ;
253+ }
254+
255+ {
256+ loop :
257+ ReadOnlySpan < char > result = source . FirstSplit ( splitCharacter , out int nextIndex ) ;
258+ #if NET5_0_OR_GREATER
259+ if ( trimEach ) result = result . Trim ( ) ;
260+ #endif
261+ list . Add ( result . IsEmpty ? string . Empty : result . ToString ( ) ) ;
262+ if ( nextIndex == - 1 ) return list ;
263+ source = source . Slice ( nextIndex ) ;
264+ goto loop ;
415265 }
416266 }
417267
@@ -428,38 +278,40 @@ public static IReadOnlyList<string> Split(this ReadOnlySpan<char> source,
428278 StringSplitOptions options = StringSplitOptions . None ,
429279 StringComparison comparisonType = StringComparison . Ordinal )
430280 {
431- switch ( options )
281+ if ( source . IsEmpty )
282+ {
283+ return options . HasFlag ( StringSplitOptions . RemoveEmptyEntries )
284+ ? Array . Empty < string > ( )
285+ : SingleEmpty . Instance ;
286+ }
287+
288+ var list = new List < string > ( ) ;
289+ #if NET5_0_OR_GREATER
290+ bool trimEach = options . HasFlag ( StringSplitOptions . TrimEntries ) ;
291+ #endif
292+ if ( options . HasFlag ( StringSplitOptions . RemoveEmptyEntries ) )
293+ {
294+ loop :
295+ ReadOnlySpan < char > result = source . FirstSplit ( splitSequence , out int nextIndex , comparisonType ) ;
296+ #if NET5_0_OR_GREATER
297+ if ( trimEach ) result = result . Trim ( ) ;
298+ #endif
299+ if ( ! result . IsEmpty ) list . Add ( result . ToString ( ) ) ;
300+ if ( nextIndex == - 1 ) return list ;
301+ source = source . Slice ( nextIndex ) ;
302+ goto loop ;
303+ }
304+
432305 {
433- case StringSplitOptions . None when source . IsEmpty :
434- return SingleEmpty . Instance ;
435-
436- case StringSplitOptions . RemoveEmptyEntries when source . IsEmpty :
437- return Array . Empty < string > ( ) ;
438-
439- case StringSplitOptions . RemoveEmptyEntries :
440- {
441- Debug . Assert ( ! source . IsEmpty ) ;
442- var list = new List < string > ( ) ;
443-
444- loop :
445- ReadOnlySpan < char > result = source . FirstSplit ( splitSequence , out int nextIndex , comparisonType ) ;
446- if ( ! result . IsEmpty ) list . Add ( result . ToString ( ) ) ;
447- if ( nextIndex == - 1 ) return list ;
448- source = source . Slice ( nextIndex ) ;
449- goto loop ;
450- }
451-
452- default :
453- {
454- Debug . Assert ( ! source . IsEmpty ) ;
455- var list = new List < string > ( ) ;
456- loop :
457- ReadOnlySpan < char > result = source . FirstSplit ( splitSequence , out int nextIndex , comparisonType ) ;
458- list . Add ( result . IsEmpty ? string . Empty : result . ToString ( ) ) ;
459- if ( nextIndex == - 1 ) return list ;
460- source = source . Slice ( nextIndex ) ;
461- goto loop ;
462- }
306+ loop :
307+ ReadOnlySpan < char > result = source . FirstSplit ( splitSequence , out int nextIndex , comparisonType ) ;
308+ #if NET5_0_OR_GREATER
309+ if ( trimEach ) result = result . Trim ( ) ;
310+ #endif
311+ list . Add ( result . IsEmpty ? string . Empty : result . ToString ( ) ) ;
312+ if ( nextIndex == - 1 ) return list ;
313+ source = source . Slice ( nextIndex ) ;
314+ goto loop ;
463315 }
464316 }
465317
0 commit comments