More Corelib cleanup (dotnet/coreclr#26872)
[mono-project.git] / netcore / System.Private.CoreLib / shared / System / MemoryExtensions.Trim.cs
blob236a5e3fa2171d9b87d2ca770099a8082d609627
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
5 using System.Diagnostics;
7 namespace System
9 public static partial class MemoryExtensions
11 /// <summary>
12 /// Removes all leading and trailing occurrences of a specified element from the memory.
13 /// </summary>
14 /// <param name="memory">The source memory from which the element is removed.</param>
15 /// <param name="trimElement">The specified element to look for and remove.</param>
16 public static Memory<T> Trim<T>(this Memory<T> memory, T trimElement)
17 #nullable disable // to enable use with both T and T? for reference types due to IEquatable<T> being invariant
18 where T : IEquatable<T>
19 #nullable restore
21 ReadOnlySpan<T> span = memory.Span;
22 int start = ClampStart(span, trimElement);
23 int length = ClampEnd(span, start, trimElement);
24 return memory.Slice(start, length);
27 /// <summary>
28 /// Removes all leading occurrences of a specified element from the memory.
29 /// </summary>
30 /// <param name="memory">The source memory from which the element is removed.</param>
31 /// <param name="trimElement">The specified element to look for and remove.</param>
32 public static Memory<T> TrimStart<T>(this Memory<T> memory, T trimElement)
33 #nullable disable // to enable use with both T and T? for reference types due to IEquatable<T> being invariant
34 where T : IEquatable<T>
35 #nullable restore
36 => memory.Slice(ClampStart(memory.Span, trimElement));
38 /// <summary>
39 /// Removes all trailing occurrences of a specified element from the memory.
40 /// </summary>
41 /// <param name="memory">The source memory from which the element is removed.</param>
42 /// <param name="trimElement">The specified element to look for and remove.</param>
43 public static Memory<T> TrimEnd<T>(this Memory<T> memory, T trimElement)
44 #nullable disable // to enable use with both T and T? for reference types due to IEquatable<T> being invariant
45 where T : IEquatable<T>
46 #nullable restore
47 => memory.Slice(0, ClampEnd(memory.Span, 0, trimElement));
49 /// <summary>
50 /// Removes all leading and trailing occurrences of a specified element from the memory.
51 /// </summary>
52 /// <param name="memory">The source memory from which the element is removed.</param>
53 /// <param name="trimElement">The specified element to look for and remove.</param>
54 public static ReadOnlyMemory<T> Trim<T>(this ReadOnlyMemory<T> memory, T trimElement)
55 #nullable disable // to enable use with both T and T? for reference types due to IEquatable<T> being invariant
56 where T : IEquatable<T>
57 #nullable restore
59 ReadOnlySpan<T> span = memory.Span;
60 int start = ClampStart(span, trimElement);
61 int length = ClampEnd(span, start, trimElement);
62 return memory.Slice(start, length);
65 /// <summary>
66 /// Removes all leading occurrences of a specified element from the memory.
67 /// </summary>
68 /// <param name="memory">The source memory from which the element is removed.</param>
69 /// <param name="trimElement">The specified element to look for and remove.</param>
70 public static ReadOnlyMemory<T> TrimStart<T>(this ReadOnlyMemory<T> memory, T trimElement)
71 #nullable disable // to enable use with both T and T? for reference types due to IEquatable<T> being invariant
72 where T : IEquatable<T>
73 #nullable restore
74 => memory.Slice(ClampStart(memory.Span, trimElement));
76 /// <summary>
77 /// Removes all trailing occurrences of a specified element from the memory.
78 /// </summary>
79 /// <param name="memory">The source memory from which the element is removed.</param>
80 /// <param name="trimElement">The specified element to look for and remove.</param>
81 public static ReadOnlyMemory<T> TrimEnd<T>(this ReadOnlyMemory<T> memory, T trimElement)
82 #nullable disable // to enable use with both T and T? for reference types due to IEquatable<T> being invariant
83 where T : IEquatable<T>
84 #nullable restore
85 => memory.Slice(0, ClampEnd(memory.Span, 0, trimElement));
87 /// <summary>
88 /// Removes all leading and trailing occurrences of a specified element from the span.
89 /// </summary>
90 /// <param name="span">The source span from which the element is removed.</param>
91 /// <param name="trimElement">The specified element to look for and remove.</param>
92 public static Span<T> Trim<T>(this Span<T> span, T trimElement)
93 #nullable disable // to enable use with both T and T? for reference types due to IEquatable<T> being invariant
94 where T : IEquatable<T>
95 #nullable restore
97 int start = ClampStart(span, trimElement);
98 int length = ClampEnd(span, start, trimElement);
99 return span.Slice(start, length);
102 /// <summary>
103 /// Removes all leading occurrences of a specified element from the span.
104 /// </summary>
105 /// <param name="span">The source span from which the element is removed.</param>
106 /// <param name="trimElement">The specified element to look for and remove.</param>
107 public static Span<T> TrimStart<T>(this Span<T> span, T trimElement)
108 #nullable disable // to enable use with both T and T? for reference types due to IEquatable<T> being invariant
109 where T : IEquatable<T>
110 #nullable restore
111 => span.Slice(ClampStart(span, trimElement));
113 /// <summary>
114 /// Removes all trailing occurrences of a specified element from the span.
115 /// </summary>
116 /// <param name="span">The source span from which the element is removed.</param>
117 /// <param name="trimElement">The specified element to look for and remove.</param>
118 public static Span<T> TrimEnd<T>(this Span<T> span, T trimElement)
119 #nullable disable // to enable use with both T and T? for reference types due to IEquatable<T> being invariant
120 where T : IEquatable<T>
121 #nullable restore
122 => span.Slice(0, ClampEnd(span, 0, trimElement));
124 /// <summary>
125 /// Removes all leading and trailing occurrences of a specified element from the span.
126 /// </summary>
127 /// <param name="span">The source span from which the element is removed.</param>
128 /// <param name="trimElement">The specified element to look for and remove.</param>
129 public static ReadOnlySpan<T> Trim<T>(this ReadOnlySpan<T> span, T trimElement)
130 #nullable disable // to enable use with both T and T? for reference types due to IEquatable<T> being invariant
131 where T : IEquatable<T>
132 #nullable restore
134 int start = ClampStart(span, trimElement);
135 int length = ClampEnd(span, start, trimElement);
136 return span.Slice(start, length);
139 /// <summary>
140 /// Removes all leading occurrences of a specified element from the span.
141 /// </summary>
142 /// <param name="span">The source span from which the element is removed.</param>
143 /// <param name="trimElement">The specified element to look for and remove.</param>
144 public static ReadOnlySpan<T> TrimStart<T>(this ReadOnlySpan<T> span, T trimElement)
145 #nullable disable // to enable use with both T and T? for reference types due to IEquatable<T> being invariant
146 where T : IEquatable<T>
147 #nullable restore
148 => span.Slice(ClampStart(span, trimElement));
150 /// <summary>
151 /// Removes all trailing occurrences of a specified element from the span.
152 /// </summary>
153 /// <param name="span">The source span from which the element is removed.</param>
154 /// <param name="trimElement">The specified element to look for and remove.</param>
155 public static ReadOnlySpan<T> TrimEnd<T>(this ReadOnlySpan<T> span, T trimElement)
156 #nullable disable // to enable use with both T and T? for reference types due to IEquatable<T> being invariant
157 where T : IEquatable<T>
158 #nullable restore
159 => span.Slice(0, ClampEnd(span, 0, trimElement));
161 /// <summary>
162 /// Delimits all leading occurrences of a specified element from the span.
163 /// </summary>
164 /// <param name="span">The source span from which the element is removed.</param>
165 /// <param name="trimElement">The specified element to look for and remove.</param>
166 private static int ClampStart<T>(ReadOnlySpan<T> span, T trimElement)
167 #nullable disable // to enable use with both T and T? for reference types due to IEquatable<T> being invariant
168 where T : IEquatable<T>
169 #nullable restore
171 int start = 0;
173 if (trimElement != null)
175 for (; start < span.Length; start++)
177 if (!trimElement.Equals(span[start]))
179 break;
183 else
185 for (; start < span.Length; start++)
187 if (span[start] != null)
189 break;
194 return start;
197 /// <summary>
198 /// Delimits all trailing occurrences of a specified element from the span.
199 /// </summary>
200 /// <param name="span">The source span from which the element is removed.</param>
201 /// <param name="start">The start index from which to being searching.</param>
202 /// <param name="trimElement">The specified element to look for and remove.</param>
203 private static int ClampEnd<T>(ReadOnlySpan<T> span, int start, T trimElement)
204 #nullable disable // to enable use with both T and T? for reference types due to IEquatable<T> being invariant
205 where T : IEquatable<T>
206 #nullable restore
208 // Initially, start==len==0. If ClampStart trims all, start==len
209 Debug.Assert((uint)start <= span.Length);
211 int end = span.Length - 1;
213 if (trimElement != null)
215 for (; end >= start; end--)
217 if (!trimElement.Equals(span[end]))
219 break;
223 else
225 for (; end >= start; end--)
227 if (span[end] != null)
229 break;
234 return end - start + 1;
237 /// <summary>
238 /// Removes all leading and trailing occurrences of a set of elements specified
239 /// in a readonly span from the memory.
240 /// </summary>
241 /// <param name="memory">The source memory from which the elements are removed.</param>
242 /// <param name="trimElements">The span which contains the set of elements to remove.</param>
243 /// <remarks>If <paramref name="trimElements"/> is empty, the memory is returned unaltered.</remarks>
244 public static Memory<T> Trim<T>(this Memory<T> memory, ReadOnlySpan<T> trimElements)
245 #nullable disable // to enable use with both T and T? for reference types due to IEquatable<T> being invariant
246 where T : IEquatable<T>
247 #nullable restore
249 if (trimElements.Length > 1)
251 ReadOnlySpan<T> span = memory.Span;
252 int start = ClampStart(span, trimElements);
253 int length = ClampEnd(span, start, trimElements);
254 return memory.Slice(start, length);
257 if (trimElements.Length == 1)
259 return Trim(memory, trimElements[0]);
262 return memory;
265 /// <summary>
266 /// Removes all leading occurrences of a set of elements specified
267 /// in a readonly span from the memory.
268 /// </summary>
269 /// <param name="memory">The source memory from which the elements are removed.</param>
270 /// <param name="trimElements">The span which contains the set of elements to remove.</param>
271 /// <remarks>If <paramref name="trimElements"/> is empty, the memory is returned unaltered.</remarks>
272 public static Memory<T> TrimStart<T>(this Memory<T> memory, ReadOnlySpan<T> trimElements)
273 #nullable disable // to enable use with both T and T? for reference types due to IEquatable<T> being invariant
274 where T : IEquatable<T>
275 #nullable restore
277 if (trimElements.Length > 1)
279 return memory.Slice(ClampStart(memory.Span, trimElements));
282 if (trimElements.Length == 1)
284 return TrimStart(memory, trimElements[0]);
287 return memory;
290 /// <summary>
291 /// Removes all trailing occurrences of a set of elements specified
292 /// in a readonly span from the memory.
293 /// </summary>
294 /// <param name="memory">The source memory from which the elements are removed.</param>
295 /// <param name="trimElements">The span which contains the set of elements to remove.</param>
296 /// <remarks>If <paramref name="trimElements"/> is empty, the memory is returned unaltered.</remarks>
297 public static Memory<T> TrimEnd<T>(this Memory<T> memory, ReadOnlySpan<T> trimElements)
298 #nullable disable // to enable use with both T and T? for reference types due to IEquatable<T> being invariant
299 where T : IEquatable<T>
300 #nullable restore
302 if (trimElements.Length > 1)
304 return memory.Slice(0, ClampEnd(memory.Span, 0, trimElements));
307 if (trimElements.Length == 1)
309 return TrimEnd(memory, trimElements[0]);
312 return memory;
315 /// <summary>
316 /// Removes all leading and trailing occurrences of a set of elements specified
317 /// in a readonly span from the memory.
318 /// </summary>
319 /// <param name="memory">The source memory from which the elements are removed.</param>
320 /// <param name="trimElements">The span which contains the set of elements to remove.</param>
321 /// <remarks>If <paramref name="trimElements"/> is empty, the memory is returned unaltered.</remarks>
322 public static ReadOnlyMemory<T> Trim<T>(this ReadOnlyMemory<T> memory, ReadOnlySpan<T> trimElements)
323 #nullable disable // to enable use with both T and T? for reference types due to IEquatable<T> being invariant
324 where T : IEquatable<T>
325 #nullable restore
327 if (trimElements.Length > 1)
329 ReadOnlySpan<T> span = memory.Span;
330 int start = ClampStart(span, trimElements);
331 int length = ClampEnd(span, start, trimElements);
332 return memory.Slice(start, length);
335 if (trimElements.Length == 1)
337 return Trim(memory, trimElements[0]);
340 return memory;
343 /// <summary>
344 /// Removes all leading occurrences of a set of elements specified
345 /// in a readonly span from the memory.
346 /// </summary>
347 /// <param name="memory">The source memory from which the elements are removed.</param>
348 /// <param name="trimElements">The span which contains the set of elements to remove.</param>
349 /// <remarks>If <paramref name="trimElements"/> is empty, the memory is returned unaltered.</remarks>
350 public static ReadOnlyMemory<T> TrimStart<T>(this ReadOnlyMemory<T> memory, ReadOnlySpan<T> trimElements)
351 #nullable disable // to enable use with both T and T? for reference types due to IEquatable<T> being invariant
352 where T : IEquatable<T>
353 #nullable restore
355 if (trimElements.Length > 1)
357 return memory.Slice(ClampStart(memory.Span, trimElements));
360 if (trimElements.Length == 1)
362 return TrimStart(memory, trimElements[0]);
365 return memory;
368 /// <summary>
369 /// Removes all trailing occurrences of a set of elements specified
370 /// in a readonly span from the memory.
371 /// </summary>
372 /// <param name="memory">The source memory from which the elements are removed.</param>
373 /// <param name="trimElements">The span which contains the set of elements to remove.</param>
374 /// <remarks>If <paramref name="trimElements"/> is empty, the memory is returned unaltered.</remarks>
375 public static ReadOnlyMemory<T> TrimEnd<T>(this ReadOnlyMemory<T> memory, ReadOnlySpan<T> trimElements)
376 #nullable disable // to enable use with both T and T? for reference types due to IEquatable<T> being invariant
377 where T : IEquatable<T>
378 #nullable restore
380 if (trimElements.Length > 1)
382 return memory.Slice(0, ClampEnd(memory.Span, 0, trimElements));
385 if (trimElements.Length == 1)
387 return TrimEnd(memory, trimElements[0]);
390 return memory;
393 /// <summary>
394 /// Removes all leading and trailing occurrences of a set of elements specified
395 /// in a readonly span from the span.
396 /// </summary>
397 /// <param name="span">The source span from which the elements are removed.</param>
398 /// <param name="trimElements">The span which contains the set of elements to remove.</param>
399 /// <remarks>If <paramref name="trimElements"/> is empty, the span is returned unaltered.</remarks>
400 public static Span<T> Trim<T>(this Span<T> span, ReadOnlySpan<T> trimElements)
401 #nullable disable // to enable use with both T and T? for reference types due to IEquatable<T> being invariant
402 where T : IEquatable<T>
403 #nullable restore
405 if (trimElements.Length > 1)
407 int start = ClampStart(span, trimElements);
408 int length = ClampEnd(span, start, trimElements);
409 return span.Slice(start, length);
412 if (trimElements.Length == 1)
414 return Trim(span, trimElements[0]);
417 return span;
420 /// <summary>
421 /// Removes all leading occurrences of a set of elements specified
422 /// in a readonly span from the span.
423 /// </summary>
424 /// <param name="span">The source span from which the elements are removed.</param>
425 /// <param name="trimElements">The span which contains the set of elements to remove.</param>
426 /// <remarks>If <paramref name="trimElements"/> is empty, the span is returned unaltered.</remarks>
427 public static Span<T> TrimStart<T>(this Span<T> span, ReadOnlySpan<T> trimElements)
428 #nullable disable // to enable use with both T and T? for reference types due to IEquatable<T> being invariant
429 where T : IEquatable<T>
430 #nullable restore
432 if (trimElements.Length > 1)
434 return span.Slice(ClampStart(span, trimElements));
437 if (trimElements.Length == 1)
439 return TrimStart(span, trimElements[0]);
442 return span;
445 /// <summary>
446 /// Removes all trailing occurrences of a set of elements specified
447 /// in a readonly span from the span.
448 /// </summary>
449 /// <param name="span">The source span from which the elements are removed.</param>
450 /// <param name="trimElements">The span which contains the set of elements to remove.</param>
451 /// <remarks>If <paramref name="trimElements"/> is empty, the span is returned unaltered.</remarks>
452 public static Span<T> TrimEnd<T>(this Span<T> span, ReadOnlySpan<T> trimElements)
453 #nullable disable // to enable use with both T and T? for reference types due to IEquatable<T> being invariant
454 where T : IEquatable<T>
455 #nullable restore
457 if (trimElements.Length > 1)
459 return span.Slice(0, ClampEnd(span, 0, trimElements));
462 if (trimElements.Length == 1)
464 return TrimEnd(span, trimElements[0]);
467 return span;
470 /// <summary>
471 /// Removes all leading and trailing occurrences of a set of elements specified
472 /// in a readonly span from the span.
473 /// </summary>
474 /// <param name="span">The source span from which the elements are removed.</param>
475 /// <param name="trimElements">The span which contains the set of elements to remove.</param>
476 /// <remarks>If <paramref name="trimElements"/> is empty, the span is returned unaltered.</remarks>
477 public static ReadOnlySpan<T> Trim<T>(this ReadOnlySpan<T> span, ReadOnlySpan<T> trimElements)
478 #nullable disable // to enable use with both T and T? for reference types due to IEquatable<T> being invariant
479 where T : IEquatable<T>
480 #nullable restore
482 if (trimElements.Length > 1)
484 int start = ClampStart(span, trimElements);
485 int length = ClampEnd(span, start, trimElements);
486 return span.Slice(start, length);
489 if (trimElements.Length == 1)
491 return Trim(span, trimElements[0]);
494 return span;
497 /// <summary>
498 /// Removes all leading occurrences of a set of elements specified
499 /// in a readonly span from the span.
500 /// </summary>
501 /// <param name="span">The source span from which the elements are removed.</param>
502 /// <param name="trimElements">The span which contains the set of elements to remove.</param>
503 /// <remarks>If <paramref name="trimElements"/> is empty, the span is returned unaltered.</remarks>
504 public static ReadOnlySpan<T> TrimStart<T>(this ReadOnlySpan<T> span, ReadOnlySpan<T> trimElements)
505 #nullable disable // to enable use with both T and T? for reference types due to IEquatable<T> being invariant
506 where T : IEquatable<T>
507 #nullable restore
509 if (trimElements.Length > 1)
511 return span.Slice(ClampStart(span, trimElements));
514 if (trimElements.Length == 1)
516 return TrimStart(span, trimElements[0]);
519 return span;
522 /// <summary>
523 /// Removes all trailing occurrences of a set of elements specified
524 /// in a readonly span from the span.
525 /// </summary>
526 /// <param name="span">The source span from which the elements are removed.</param>
527 /// <param name="trimElements">The span which contains the set of elements to remove.</param>
528 /// <remarks>If <paramref name="trimElements"/> is empty, the span is returned unaltered.</remarks>
529 public static ReadOnlySpan<T> TrimEnd<T>(this ReadOnlySpan<T> span, ReadOnlySpan<T> trimElements)
530 #nullable disable // to enable use with both T and T? for reference types due to IEquatable<T> being invariant
531 where T : IEquatable<T>
532 #nullable restore
534 if (trimElements.Length > 1)
536 return span.Slice(0, ClampEnd(span, 0, trimElements));
539 if (trimElements.Length == 1)
541 return TrimEnd(span, trimElements[0]);
544 return span;
547 /// <summary>
548 /// Delimits all leading occurrences of a set of elements specified
549 /// in a readonly span from the span.
550 /// </summary>
551 /// <param name="span">The source span from which the elements are removed.</param>
552 /// <param name="trimElements">The span which contains the set of elements to remove.</param>
553 private static int ClampStart<T>(ReadOnlySpan<T> span, ReadOnlySpan<T> trimElements)
554 #nullable disable // to enable use with both T and T? for reference types due to IEquatable<T> being invariant
555 where T : IEquatable<T>
556 #nullable restore
558 int start = 0;
559 for (; start < span.Length; start++)
561 if (!trimElements.Contains(span[start]))
563 break;
567 return start;
570 /// <summary>
571 /// Delimits all trailing occurrences of a set of elements specified
572 /// in a readonly span from the span.
573 /// </summary>
574 /// <param name="span">The source span from which the elements are removed.</param>
575 /// <param name="start">The start index from which to being searching.</param>
576 /// <param name="trimElements">The span which contains the set of elements to remove.</param>
577 private static int ClampEnd<T>(ReadOnlySpan<T> span, int start, ReadOnlySpan<T> trimElements)
578 #nullable disable // to enable use with both T and T? for reference types due to IEquatable<T> being invariant
579 where T : IEquatable<T>
580 #nullable restore
582 // Initially, start==len==0. If ClampStart trims all, start==len
583 Debug.Assert((uint)start <= span.Length);
585 int end = span.Length - 1;
586 for (; end >= start; end--)
588 if (!trimElements.Contains(span[end]))
590 break;
594 return end - start + 1;
597 /// <summary>
598 /// Removes all leading and trailing white-space characters from the memory.
599 /// </summary>
600 /// <param name="memory">The source memory from which the characters are removed.</param>
601 public static Memory<char> Trim(this Memory<char> memory)
603 ReadOnlySpan<char> span = memory.Span;
604 int start = ClampStart(span);
605 int length = ClampEnd(span, start);
606 return memory.Slice(start, length);
609 /// <summary>
610 /// Removes all leading white-space characters from the memory.
611 /// </summary>
612 /// <param name="memory">The source memory from which the characters are removed.</param>
613 public static Memory<char> TrimStart(this Memory<char> memory)
614 => memory.Slice(ClampStart(memory.Span));
616 /// <summary>
617 /// Removes all trailing white-space characters from the memory.
618 /// </summary>
619 /// <param name="memory">The source memory from which the characters are removed.</param>
620 public static Memory<char> TrimEnd(this Memory<char> memory)
621 => memory.Slice(0, ClampEnd(memory.Span, 0));
623 /// <summary>
624 /// Removes all leading and trailing white-space characters from the memory.
625 /// </summary>
626 /// <param name="memory">The source memory from which the characters are removed.</param>
627 public static ReadOnlyMemory<char> Trim(this ReadOnlyMemory<char> memory)
629 ReadOnlySpan<char> span = memory.Span;
630 int start = ClampStart(span);
631 int length = ClampEnd(span, start);
632 return memory.Slice(start, length);
635 /// <summary>
636 /// Removes all leading white-space characters from the memory.
637 /// </summary>
638 /// <param name="memory">The source memory from which the characters are removed.</param>
639 public static ReadOnlyMemory<char> TrimStart(this ReadOnlyMemory<char> memory)
640 => memory.Slice(ClampStart(memory.Span));
642 /// <summary>
643 /// Removes all trailing white-space characters from the memory.
644 /// </summary>
645 /// <param name="memory">The source memory from which the characters are removed.</param>
646 public static ReadOnlyMemory<char> TrimEnd(this ReadOnlyMemory<char> memory)
647 => memory.Slice(0, ClampEnd(memory.Span, 0));
649 /// <summary>
650 /// Removes all leading and trailing white-space characters from the span.
651 /// </summary>
652 /// <param name="span">The source span from which the characters are removed.</param>
653 public static ReadOnlySpan<char> Trim(this ReadOnlySpan<char> span)
655 int start = 0;
656 for (; start < span.Length; start++)
658 if (!char.IsWhiteSpace(span[start]))
660 break;
664 int end = span.Length - 1;
665 for (; end > start; end--)
667 if (!char.IsWhiteSpace(span[end]))
669 break;
673 return span.Slice(start, end - start + 1);
676 /// <summary>
677 /// Removes all leading white-space characters from the span.
678 /// </summary>
679 /// <param name="span">The source span from which the characters are removed.</param>
680 public static ReadOnlySpan<char> TrimStart(this ReadOnlySpan<char> span)
682 int start = 0;
683 for (; start < span.Length; start++)
685 if (!char.IsWhiteSpace(span[start]))
687 break;
691 return span.Slice(start);
694 /// <summary>
695 /// Removes all trailing white-space characters from the span.
696 /// </summary>
697 /// <param name="span">The source span from which the characters are removed.</param>
698 public static ReadOnlySpan<char> TrimEnd(this ReadOnlySpan<char> span)
700 int end = span.Length - 1;
701 for (; end >= 0; end--)
703 if (!char.IsWhiteSpace(span[end]))
705 break;
709 return span.Slice(0, end + 1);
712 /// <summary>
713 /// Removes all leading and trailing occurrences of a specified character from the span.
714 /// </summary>
715 /// <param name="span">The source span from which the character is removed.</param>
716 /// <param name="trimChar">The specified character to look for and remove.</param>
717 public static ReadOnlySpan<char> Trim(this ReadOnlySpan<char> span, char trimChar)
719 int start = 0;
720 for (; start < span.Length; start++)
722 if (span[start] != trimChar)
724 break;
728 int end = span.Length - 1;
729 for (; end > start; end--)
731 if (span[end] != trimChar)
733 break;
737 return span.Slice(start, end - start + 1);
740 /// <summary>
741 /// Removes all leading occurrences of a specified character from the span.
742 /// </summary>
743 /// <param name="span">The source span from which the character is removed.</param>
744 /// <param name="trimChar">The specified character to look for and remove.</param>
745 public static ReadOnlySpan<char> TrimStart(this ReadOnlySpan<char> span, char trimChar)
747 int start = 0;
748 for (; start < span.Length; start++)
750 if (span[start] != trimChar)
752 break;
756 return span.Slice(start);
759 /// <summary>
760 /// Removes all trailing occurrences of a specified character from the span.
761 /// </summary>
762 /// <param name="span">The source span from which the character is removed.</param>
763 /// <param name="trimChar">The specified character to look for and remove.</param>
764 public static ReadOnlySpan<char> TrimEnd(this ReadOnlySpan<char> span, char trimChar)
766 int end = span.Length - 1;
767 for (; end >= 0; end--)
769 if (span[end] != trimChar)
771 break;
775 return span.Slice(0, end + 1);
778 /// <summary>
779 /// Removes all leading and trailing occurrences of a set of characters specified
780 /// in a readonly span from the span.
781 /// </summary>
782 /// <param name="span">The source span from which the characters are removed.</param>
783 /// <param name="trimChars">The span which contains the set of characters to remove.</param>
784 /// <remarks>If <paramref name="trimChars"/> is empty, white-space characters are removed instead.</remarks>
785 public static ReadOnlySpan<char> Trim(this ReadOnlySpan<char> span, ReadOnlySpan<char> trimChars)
786 => span.TrimStart(trimChars).TrimEnd(trimChars);
788 /// <summary>
789 /// Removes all leading occurrences of a set of characters specified
790 /// in a readonly span from the span.
791 /// </summary>
792 /// <param name="span">The source span from which the characters are removed.</param>
793 /// <param name="trimChars">The span which contains the set of characters to remove.</param>
794 /// <remarks>If <paramref name="trimChars"/> is empty, white-space characters are removed instead.</remarks>
795 public static ReadOnlySpan<char> TrimStart(this ReadOnlySpan<char> span, ReadOnlySpan<char> trimChars)
797 if (trimChars.IsEmpty)
799 return span.TrimStart();
802 int start = 0;
803 for (; start < span.Length; start++)
805 for (int i = 0; i < trimChars.Length; i++)
807 if (span[start] == trimChars[i])
809 goto Next;
813 break;
814 Next:
818 return span.Slice(start);
821 /// <summary>
822 /// Removes all trailing occurrences of a set of characters specified
823 /// in a readonly span from the span.
824 /// </summary>
825 /// <param name="span">The source span from which the characters are removed.</param>
826 /// <param name="trimChars">The span which contains the set of characters to remove.</param>
827 /// <remarks>If <paramref name="trimChars"/> is empty, white-space characters are removed instead.</remarks>
828 public static ReadOnlySpan<char> TrimEnd(this ReadOnlySpan<char> span, ReadOnlySpan<char> trimChars)
830 if (trimChars.IsEmpty)
832 return span.TrimEnd();
835 int end = span.Length - 1;
836 for (; end >= 0; end--)
838 for (int i = 0; i < trimChars.Length; i++)
840 if (span[end] == trimChars[i])
842 goto Next;
846 break;
847 Next:
851 return span.Slice(0, end + 1);
854 /// <summary>
855 /// Removes all leading and trailing white-space characters from the span.
856 /// </summary>
857 /// <param name="span">The source span from which the characters are removed.</param>
858 public static Span<char> Trim(this Span<char> span)
860 int start = ClampStart(span);
861 int length = ClampEnd(span, start);
862 return span.Slice(start, length);
865 /// <summary>
866 /// Removes all leading white-space characters from the span.
867 /// </summary>
868 /// <param name="span">The source span from which the characters are removed.</param>
869 public static Span<char> TrimStart(this Span<char> span)
870 => span.Slice(ClampStart(span));
872 /// <summary>
873 /// Removes all trailing white-space characters from the span.
874 /// </summary>
875 /// <param name="span">The source span from which the characters are removed.</param>
876 public static Span<char> TrimEnd(this Span<char> span)
877 => span.Slice(0, ClampEnd(span, 0));
879 /// <summary>
880 /// Delimits all leading occurrences of whitespace charecters from the span.
881 /// </summary>
882 /// <param name="span">The source span from which the characters are removed.</param>
883 private static int ClampStart(ReadOnlySpan<char> span)
885 int start = 0;
887 for (; start < span.Length; start++)
889 if (!char.IsWhiteSpace(span[start]))
891 break;
895 return start;
898 /// <summary>
899 /// Delimits all trailing occurrences of whitespace charecters from the span.
900 /// </summary>
901 /// <param name="span">The source span from which the characters are removed.</param>
902 /// <param name="start">The start index from which to being searching.</param>
903 private static int ClampEnd(ReadOnlySpan<char> span, int start)
905 // Initially, start==len==0. If ClampStart trims all, start==len
906 Debug.Assert((uint)start <= span.Length);
908 int end = span.Length - 1;
910 for (; end >= start; end--)
912 if (!char.IsWhiteSpace(span[end]))
914 break;
918 return end - start + 1;