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
;
6 using System
.Globalization
;
7 using System
.Runtime
.CompilerServices
;
8 using System
.Runtime
.InteropServices
;
10 using Internal
.Runtime
.CompilerServices
;
15 /// Extension methods for Span{T}, Memory{T}, and friends.
17 public static partial class MemoryExtensions
20 /// Returns a value indicating whether the specified <paramref name="value"/> occurs within the <paramref name="span"/>.
21 /// <param name="span">The source span.</param>
22 /// <param name="value">The value to seek within the source span.</param>
23 /// <param name="comparisonType">One of the enumeration values that determines how the <paramref name="span"/> and <paramref name="value"/> are compared.</param>
25 public static bool Contains(this ReadOnlySpan
<char> span
, ReadOnlySpan
<char> value, StringComparison comparisonType
)
27 return IndexOf(span
, value, comparisonType
) >= 0;
31 /// Determines whether this <paramref name="span"/> and the specified <paramref name="other"/> span have the same characters
32 /// when compared using the specified <paramref name="comparisonType"/> option.
33 /// <param name="span">The source span.</param>
34 /// <param name="other">The value to compare with the source span.</param>
35 /// <param name="comparisonType">One of the enumeration values that determines how the <paramref name="span"/> and <paramref name="other"/> are compared.</param>
37 public static bool Equals(this ReadOnlySpan
<char> span
, ReadOnlySpan
<char> other
, StringComparison comparisonType
)
39 string.CheckStringComparison(comparisonType
);
41 switch (comparisonType
)
43 case StringComparison
.CurrentCulture
:
44 return CultureInfo
.CurrentCulture
.CompareInfo
.CompareOptionNone(span
, other
) == 0;
46 case StringComparison
.CurrentCultureIgnoreCase
:
47 return CultureInfo
.CurrentCulture
.CompareInfo
.CompareOptionIgnoreCase(span
, other
) == 0;
49 case StringComparison
.InvariantCulture
:
50 return CompareInfo
.Invariant
.CompareOptionNone(span
, other
) == 0;
52 case StringComparison
.InvariantCultureIgnoreCase
:
53 return CompareInfo
.Invariant
.CompareOptionIgnoreCase(span
, other
) == 0;
55 case StringComparison
.Ordinal
:
56 return EqualsOrdinal(span
, other
);
58 case StringComparison
.OrdinalIgnoreCase
:
59 return EqualsOrdinalIgnoreCase(span
, other
);
62 Debug
.Fail("StringComparison outside range");
66 [MethodImpl(MethodImplOptions
.AggressiveInlining
)]
67 internal static bool EqualsOrdinal(this ReadOnlySpan
<char> span
, ReadOnlySpan
<char> value)
69 if (span
.Length
!= value.Length
)
71 if (value.Length
== 0) // span.Length == value.Length == 0
73 return span
.SequenceEqual(value);
76 [MethodImpl(MethodImplOptions
.AggressiveInlining
)]
77 internal static bool EqualsOrdinalIgnoreCase(this ReadOnlySpan
<char> span
, ReadOnlySpan
<char> value)
79 if (span
.Length
!= value.Length
)
81 if (value.Length
== 0) // span.Length == value.Length == 0
83 return CompareInfo
.EqualsOrdinalIgnoreCase(ref MemoryMarshal
.GetReference(span
), ref MemoryMarshal
.GetReference(value), span
.Length
);
87 /// Compares the specified <paramref name="span"/> and <paramref name="other"/> using the specified <paramref name="comparisonType"/>,
88 /// and returns an integer that indicates their relative position in the sort order.
89 /// <param name="span">The source span.</param>
90 /// <param name="other">The value to compare with the source span.</param>
91 /// <param name="comparisonType">One of the enumeration values that determines how the <paramref name="span"/> and <paramref name="other"/> are compared.</param>
93 public static int CompareTo(this ReadOnlySpan
<char> span
, ReadOnlySpan
<char> other
, StringComparison comparisonType
)
95 string.CheckStringComparison(comparisonType
);
97 switch (comparisonType
)
99 case StringComparison
.CurrentCulture
:
100 return CultureInfo
.CurrentCulture
.CompareInfo
.CompareOptionNone(span
, other
);
102 case StringComparison
.CurrentCultureIgnoreCase
:
103 return CultureInfo
.CurrentCulture
.CompareInfo
.CompareOptionIgnoreCase(span
, other
);
105 case StringComparison
.InvariantCulture
:
106 return CompareInfo
.Invariant
.CompareOptionNone(span
, other
);
108 case StringComparison
.InvariantCultureIgnoreCase
:
109 return CompareInfo
.Invariant
.CompareOptionIgnoreCase(span
, other
);
111 case StringComparison
.Ordinal
:
112 if (span
.Length
== 0 || other
.Length
== 0)
113 return span
.Length
- other
.Length
;
114 return string.CompareOrdinal(span
, other
);
116 case StringComparison
.OrdinalIgnoreCase
:
117 return CompareInfo
.CompareOrdinalIgnoreCase(span
, other
);
120 Debug
.Fail("StringComparison outside range");
125 /// Reports the zero-based index of the first occurrence of the specified <paramref name="value"/> in the current <paramref name="span"/>.
126 /// <param name="span">The source span.</param>
127 /// <param name="value">The value to seek within the source span.</param>
128 /// <param name="comparisonType">One of the enumeration values that determines how the <paramref name="span"/> and <paramref name="value"/> are compared.</param>
130 public static int IndexOf(this ReadOnlySpan
<char> span
, ReadOnlySpan
<char> value, StringComparison comparisonType
)
132 string.CheckStringComparison(comparisonType
);
134 if (value.Length
== 0)
139 if (span
.Length
== 0)
144 if (comparisonType
== StringComparison
.Ordinal
)
146 return SpanHelpers
.IndexOf(
147 ref MemoryMarshal
.GetReference(span
),
149 ref MemoryMarshal
.GetReference(value),
153 if (GlobalizationMode
.Invariant
)
155 return CompareInfo
.InvariantIndexOf(span
, value, string.GetCaseCompareOfComparisonCulture(comparisonType
) != CompareOptions
.None
);
158 switch (comparisonType
)
160 case StringComparison
.CurrentCulture
:
161 case StringComparison
.CurrentCultureIgnoreCase
:
162 return CultureInfo
.CurrentCulture
.CompareInfo
.IndexOf(span
, value, string.GetCaseCompareOfComparisonCulture(comparisonType
));
164 case StringComparison
.InvariantCulture
:
165 case StringComparison
.InvariantCultureIgnoreCase
:
166 return CompareInfo
.Invariant
.IndexOf(span
, value, string.GetCaseCompareOfComparisonCulture(comparisonType
));
169 Debug
.Assert(comparisonType
== StringComparison
.OrdinalIgnoreCase
);
170 return CompareInfo
.Invariant
.IndexOfOrdinalIgnoreCase(span
, value);
175 /// Reports the zero-based index of the last occurrence of the specified <paramref name="value"/> in the current <paramref name="span"/>.
176 /// <param name="span">The source span.</param>
177 /// <param name="value">The value to seek within the source span.</param>
178 /// <param name="comparisonType">One of the enumeration values that determines how the <paramref name="span"/> and <paramref name="value"/> are compared.</param>
180 public static int LastIndexOf(this ReadOnlySpan
<char> span
, ReadOnlySpan
<char> value, StringComparison comparisonType
)
182 string.CheckStringComparison(comparisonType
);
184 if (value.Length
== 0)
186 return span
.Length
> 0 ? span
.Length
- 1 : 0;
189 if (span
.Length
== 0)
194 if (GlobalizationMode
.Invariant
)
196 return CompareInfo
.InvariantIndexOf(span
, value, string.GetCaseCompareOfComparisonCulture(comparisonType
) != CompareOptions
.None
, fromBeginning
: false);
199 switch (comparisonType
)
201 case StringComparison
.CurrentCulture
:
202 case StringComparison
.CurrentCultureIgnoreCase
:
203 return CultureInfo
.CurrentCulture
.CompareInfo
.LastIndexOf(span
, value, string.GetCaseCompareOfComparisonCulture(comparisonType
));
205 case StringComparison
.InvariantCulture
:
206 case StringComparison
.InvariantCultureIgnoreCase
:
207 return CompareInfo
.Invariant
.LastIndexOf(span
, value, string.GetCaseCompareOfComparisonCulture(comparisonType
));
210 Debug
.Assert(comparisonType
== StringComparison
.Ordinal
|| comparisonType
== StringComparison
.OrdinalIgnoreCase
);
211 return CompareInfo
.Invariant
.LastIndexOfOrdinal(span
, value, string.GetCaseCompareOfComparisonCulture(comparisonType
) != CompareOptions
.None
);
216 /// Copies the characters from the source span into the destination, converting each character to lowercase,
217 /// using the casing rules of the specified culture.
219 /// <param name="source">The source span.</param>
220 /// <param name="destination">The destination span which contains the transformed characters.</param>
221 /// <param name="culture">An object that supplies culture-specific casing rules.</param>
222 /// <remarks>If <paramref name="culture"/> is null, <see cref="System.Globalization.CultureInfo.CurrentCulture"/> will be used.</remarks>
223 /// <returns>The number of characters written into the destination span. If the destination is too small, returns -1.</returns>
224 /// <exception cref="InvalidOperationException">The source and destination buffers overlap.</exception>
225 public static int ToLower(this ReadOnlySpan
<char> source
, Span
<char> destination
, CultureInfo
? culture
)
227 if (source
.Overlaps(destination
))
228 throw new InvalidOperationException(SR
.InvalidOperation_SpanOverlappedOperation
);
230 culture
??= CultureInfo
.CurrentCulture
;
232 // Assuming that changing case does not affect length
233 if (destination
.Length
< source
.Length
)
236 if (GlobalizationMode
.Invariant
)
237 TextInfo
.ToLowerAsciiInvariant(source
, destination
);
239 culture
.TextInfo
.ChangeCaseToLower(source
, destination
);
240 return source
.Length
;
244 /// Copies the characters from the source span into the destination, converting each character to lowercase,
245 /// using the casing rules of the invariant culture.
247 /// <param name="source">The source span.</param>
248 /// <param name="destination">The destination span which contains the transformed characters.</param>
249 /// <returns>The number of characters written into the destination span. If the destination is too small, returns -1.</returns>
250 /// <exception cref="InvalidOperationException">The source and destination buffers overlap.</exception>
251 public static int ToLowerInvariant(this ReadOnlySpan
<char> source
, Span
<char> destination
)
253 if (source
.Overlaps(destination
))
254 throw new InvalidOperationException(SR
.InvalidOperation_SpanOverlappedOperation
);
256 // Assuming that changing case does not affect length
257 if (destination
.Length
< source
.Length
)
260 if (GlobalizationMode
.Invariant
)
261 TextInfo
.ToLowerAsciiInvariant(source
, destination
);
263 CultureInfo
.InvariantCulture
.TextInfo
.ChangeCaseToLower(source
, destination
);
264 return source
.Length
;
268 /// Copies the characters from the source span into the destination, converting each character to uppercase,
269 /// using the casing rules of the specified culture.
271 /// <param name="source">The source span.</param>
272 /// <param name="destination">The destination span which contains the transformed characters.</param>
273 /// <param name="culture">An object that supplies culture-specific casing rules.</param>
274 /// <remarks>If <paramref name="culture"/> is null, <see cref="System.Globalization.CultureInfo.CurrentCulture"/> will be used.</remarks>
275 /// <returns>The number of characters written into the destination span. If the destination is too small, returns -1.</returns>
276 /// <exception cref="InvalidOperationException">The source and destination buffers overlap.</exception>
277 public static int ToUpper(this ReadOnlySpan
<char> source
, Span
<char> destination
, CultureInfo
? culture
)
279 if (source
.Overlaps(destination
))
280 throw new InvalidOperationException(SR
.InvalidOperation_SpanOverlappedOperation
);
282 culture
??= CultureInfo
.CurrentCulture
;
284 // Assuming that changing case does not affect length
285 if (destination
.Length
< source
.Length
)
288 if (GlobalizationMode
.Invariant
)
289 TextInfo
.ToUpperAsciiInvariant(source
, destination
);
291 culture
.TextInfo
.ChangeCaseToUpper(source
, destination
);
292 return source
.Length
;
296 /// Copies the characters from the source span into the destination, converting each character to uppercase
297 /// using the casing rules of the invariant culture.
299 /// <param name="source">The source span.</param>
300 /// <param name="destination">The destination span which contains the transformed characters.</param>
301 /// <returns>The number of characters written into the destination span. If the destination is too small, returns -1.</returns>
302 /// <exception cref="InvalidOperationException">The source and destination buffers overlap.</exception>
303 public static int ToUpperInvariant(this ReadOnlySpan
<char> source
, Span
<char> destination
)
305 if (source
.Overlaps(destination
))
306 throw new InvalidOperationException(SR
.InvalidOperation_SpanOverlappedOperation
);
308 // Assuming that changing case does not affect length
309 if (destination
.Length
< source
.Length
)
312 if (GlobalizationMode
.Invariant
)
313 TextInfo
.ToUpperAsciiInvariant(source
, destination
);
315 CultureInfo
.InvariantCulture
.TextInfo
.ChangeCaseToUpper(source
, destination
);
316 return source
.Length
;
320 /// Determines whether the end of the <paramref name="span"/> matches the specified <paramref name="value"/> when compared using the specified <paramref name="comparisonType"/> option.
322 /// <param name="span">The source span.</param>
323 /// <param name="value">The sequence to compare to the end of the source span.</param>
324 /// <param name="comparisonType">One of the enumeration values that determines how the <paramref name="span"/> and <paramref name="value"/> are compared.</param>
325 public static bool EndsWith(this ReadOnlySpan
<char> span
, ReadOnlySpan
<char> value, StringComparison comparisonType
)
327 string.CheckStringComparison(comparisonType
);
329 if (value.Length
== 0)
334 if (comparisonType
>= StringComparison
.Ordinal
|| GlobalizationMode
.Invariant
)
336 if (string.GetCaseCompareOfComparisonCulture(comparisonType
) == CompareOptions
.None
)
337 return span
.EndsWith(value);
339 return (span
.Length
>= value.Length
) ? (CompareInfo
.CompareOrdinalIgnoreCase(span
.Slice(span
.Length
- value.Length
), value) == 0) : false;
342 if (span
.Length
== 0)
347 return (comparisonType
>= StringComparison
.InvariantCulture
) ?
348 CompareInfo
.Invariant
.IsSuffix(span
, value, string.GetCaseCompareOfComparisonCulture(comparisonType
)) :
349 CultureInfo
.CurrentCulture
.CompareInfo
.IsSuffix(span
, value, string.GetCaseCompareOfComparisonCulture(comparisonType
));
353 /// Determines whether the beginning of the <paramref name="span"/> matches the specified <paramref name="value"/> when compared using the specified <paramref name="comparisonType"/> option.
355 /// <param name="span">The source span.</param>
356 /// <param name="value">The sequence to compare to the beginning of the source span.</param>
357 /// <param name="comparisonType">One of the enumeration values that determines how the <paramref name="span"/> and <paramref name="value"/> are compared.</param>
358 public static bool StartsWith(this ReadOnlySpan
<char> span
, ReadOnlySpan
<char> value, StringComparison comparisonType
)
360 string.CheckStringComparison(comparisonType
);
362 if (value.Length
== 0)
367 if (comparisonType
>= StringComparison
.Ordinal
|| GlobalizationMode
.Invariant
)
369 if (string.GetCaseCompareOfComparisonCulture(comparisonType
) == CompareOptions
.None
)
370 return span
.StartsWith(value);
372 return (span
.Length
>= value.Length
) ? (CompareInfo
.CompareOrdinalIgnoreCase(span
.Slice(0, value.Length
), value) == 0) : false;
375 if (span
.Length
== 0)
380 return (comparisonType
>= StringComparison
.InvariantCulture
) ?
381 CompareInfo
.Invariant
.IsPrefix(span
, value, string.GetCaseCompareOfComparisonCulture(comparisonType
)) :
382 CultureInfo
.CurrentCulture
.CompareInfo
.IsPrefix(span
, value, string.GetCaseCompareOfComparisonCulture(comparisonType
));
386 /// Creates a new span over the portion of the target array.
388 [MethodImpl(MethodImplOptions
.AggressiveInlining
)]
389 public static Span
<T
> AsSpan
<T
>(this T
[]? array
, int start
)
394 ThrowHelper
.ThrowArgumentOutOfRangeException();
397 if (default(T
)! == null && array
.GetType() != typeof(T
[])) // TODO-NULLABLE: default(T) == null warning (https://github.com/dotnet/roslyn/issues/34757)
398 ThrowHelper
.ThrowArrayTypeMismatchException();
399 if ((uint)start
> (uint)array
.Length
)
400 ThrowHelper
.ThrowArgumentOutOfRangeException();
402 return new Span
<T
>(ref Unsafe
.Add(ref Unsafe
.As
<byte, T
>(ref array
.GetRawSzArrayData()), start
), array
.Length
- start
);
406 /// Creates a new span over the portion of the target array.
408 [MethodImpl(MethodImplOptions
.AggressiveInlining
)]
409 public static Span
<T
> AsSpan
<T
>(this T
[]? array
, Index startIndex
)
413 if (!startIndex
.Equals(Index
.Start
))
414 ThrowHelper
.ThrowArgumentNullException(ExceptionArgument
.array
);
419 if (default(T
)! == null && array
.GetType() != typeof(T
[])) // TODO-NULLABLE: default(T) == null warning (https://github.com/dotnet/roslyn/issues/34757)
420 ThrowHelper
.ThrowArrayTypeMismatchException();
422 int actualIndex
= startIndex
.GetOffset(array
.Length
);
423 if ((uint)actualIndex
> (uint)array
.Length
)
424 ThrowHelper
.ThrowArgumentOutOfRangeException();
426 return new Span
<T
>(ref Unsafe
.Add(ref Unsafe
.As
<byte, T
>(ref array
.GetRawSzArrayData()), actualIndex
), array
.Length
- actualIndex
);
430 /// Creates a new span over the portion of the target array.
432 [MethodImpl(MethodImplOptions
.AggressiveInlining
)]
433 public static Span
<T
> AsSpan
<T
>(this T
[]? array
, Range range
)
437 Index startIndex
= range
.Start
;
438 Index endIndex
= range
.End
;
440 if (!startIndex
.Equals(Index
.Start
) || !endIndex
.Equals(Index
.Start
))
441 ThrowHelper
.ThrowArgumentNullException(ExceptionArgument
.array
);
446 if (default(T
)! == null && array
.GetType() != typeof(T
[])) // TODO-NULLABLE: default(T) == null warning (https://github.com/dotnet/roslyn/issues/34757)
447 ThrowHelper
.ThrowArrayTypeMismatchException();
449 (int start
, int length
) = range
.GetOffsetAndLength(array
.Length
);
450 return new Span
<T
>(ref Unsafe
.Add(ref Unsafe
.As
<byte, T
>(ref array
.GetRawSzArrayData()), start
), length
);
454 /// Creates a new readonly span over the portion of the target string.
456 /// <param name="text">The target string.</param>
457 /// <remarks>Returns default when <paramref name="text"/> is null.</remarks>
458 [MethodImpl(MethodImplOptions
.AggressiveInlining
)]
459 public static ReadOnlySpan
<char> AsSpan(this string? text
)
464 return new ReadOnlySpan
<char>(ref text
.GetRawStringData(), text
.Length
);
468 /// Creates a new readonly span over the portion of the target string.
470 /// <param name="text">The target string.</param>
471 /// <param name="start">The index at which to begin this slice.</param>
472 /// <exception cref="System.ArgumentNullException">Thrown when <paramref name="text"/> is null.</exception>
473 /// <exception cref="System.ArgumentOutOfRangeException">
474 /// Thrown when the specified <paramref name="start"/> index is not in range (<0 or >text.Length).
476 [MethodImpl(MethodImplOptions
.AggressiveInlining
)]
477 public static ReadOnlySpan
<char> AsSpan(this string? text
, int start
)
482 ThrowHelper
.ThrowArgumentOutOfRangeException(ExceptionArgument
.start
);
486 if ((uint)start
> (uint)text
.Length
)
487 ThrowHelper
.ThrowArgumentOutOfRangeException(ExceptionArgument
.start
);
489 return new ReadOnlySpan
<char>(ref Unsafe
.Add(ref text
.GetRawStringData(), start
), text
.Length
- start
);
493 /// Creates a new readonly span over the portion of the target string.
495 /// <param name="text">The target string.</param>
496 /// <param name="start">The index at which to begin this slice.</param>
497 /// <param name="length">The desired length for the slice (exclusive).</param>
498 /// <remarks>Returns default when <paramref name="text"/> is null.</remarks>
499 /// <exception cref="System.ArgumentOutOfRangeException">
500 /// Thrown when the specified <paramref name="start"/> index or <paramref name="length"/> is not in range.
502 [MethodImpl(MethodImplOptions
.AggressiveInlining
)]
503 public static ReadOnlySpan
<char> AsSpan(this string? text
, int start
, int length
)
507 if (start
!= 0 || length
!= 0)
508 ThrowHelper
.ThrowArgumentOutOfRangeException(ExceptionArgument
.start
);
513 // See comment in Span<T>.Slice for how this works.
514 if ((ulong)(uint)start
+ (ulong)(uint)length
> (ulong)(uint)text
.Length
)
515 ThrowHelper
.ThrowArgumentOutOfRangeException(ExceptionArgument
.start
);
517 if ((uint)start
> (uint)text
.Length
|| (uint)length
> (uint)(text
.Length
- start
))
518 ThrowHelper
.ThrowArgumentOutOfRangeException(ExceptionArgument
.start
);
521 return new ReadOnlySpan
<char>(ref Unsafe
.Add(ref text
.GetRawStringData(), start
), length
);
524 /// <summary>Creates a new <see cref="ReadOnlyMemory{T}"/> over the portion of the target string.</summary>
525 /// <param name="text">The target string.</param>
526 /// <remarks>Returns default when <paramref name="text"/> is null.</remarks>
527 public static ReadOnlyMemory
<char> AsMemory(this string? text
)
532 return new ReadOnlyMemory
<char>(text
, 0, text
.Length
);
535 /// <summary>Creates a new <see cref="ReadOnlyMemory{T}"/> over the portion of the target string.</summary>
536 /// <param name="text">The target string.</param>
537 /// <param name="start">The index at which to begin this slice.</param>
538 /// <remarks>Returns default when <paramref name="text"/> is null.</remarks>
539 /// <exception cref="System.ArgumentOutOfRangeException">
540 /// Thrown when the specified <paramref name="start"/> index is not in range (<0 or >text.Length).
542 public static ReadOnlyMemory
<char> AsMemory(this string? text
, int start
)
547 ThrowHelper
.ThrowArgumentOutOfRangeException(ExceptionArgument
.start
);
551 if ((uint)start
> (uint)text
.Length
)
552 ThrowHelper
.ThrowArgumentOutOfRangeException(ExceptionArgument
.start
);
554 return new ReadOnlyMemory
<char>(text
, start
, text
.Length
- start
);
557 /// <summary>Creates a new <see cref="ReadOnlyMemory{T}"/> over the portion of the target string.</summary>
558 /// <param name="text">The target string.</param>
559 /// <param name="startIndex">The index at which to begin this slice.</param>
560 public static ReadOnlyMemory
<char> AsMemory(this string? text
, Index startIndex
)
564 if (!startIndex
.Equals(Index
.Start
))
565 ThrowHelper
.ThrowArgumentNullException(ExceptionArgument
.text
);
570 int actualIndex
= startIndex
.GetOffset(text
.Length
);
571 if ((uint)actualIndex
> (uint)text
.Length
)
572 ThrowHelper
.ThrowArgumentOutOfRangeException();
574 return new ReadOnlyMemory
<char>(text
, actualIndex
, text
.Length
- actualIndex
);
577 /// <summary>Creates a new <see cref="ReadOnlyMemory{T}"/> over the portion of the target string.</summary>
578 /// <param name="text">The target string.</param>
579 /// <param name="start">The index at which to begin this slice.</param>
580 /// <param name="length">The desired length for the slice (exclusive).</param>
581 /// <remarks>Returns default when <paramref name="text"/> is null.</remarks>
582 /// <exception cref="System.ArgumentOutOfRangeException">
583 /// Thrown when the specified <paramref name="start"/> index or <paramref name="length"/> is not in range.
585 public static ReadOnlyMemory
<char> AsMemory(this string? text
, int start
, int length
)
589 if (start
!= 0 || length
!= 0)
590 ThrowHelper
.ThrowArgumentOutOfRangeException(ExceptionArgument
.start
);
595 // See comment in Span<T>.Slice for how this works.
596 if ((ulong)(uint)start
+ (ulong)(uint)length
> (ulong)(uint)text
.Length
)
597 ThrowHelper
.ThrowArgumentOutOfRangeException(ExceptionArgument
.start
);
599 if ((uint)start
> (uint)text
.Length
|| (uint)length
> (uint)(text
.Length
- start
))
600 ThrowHelper
.ThrowArgumentOutOfRangeException(ExceptionArgument
.start
);
603 return new ReadOnlyMemory
<char>(text
, start
, length
);
606 /// <summary>Creates a new <see cref="ReadOnlyMemory{T}"/> over the portion of the target string.</summary>
607 /// <param name="text">The target string.</param>
608 /// <param name="range">The range used to indicate the start and length of the sliced string.</param>
609 public static ReadOnlyMemory
<char> AsMemory(this string? text
, Range range
)
613 Index startIndex
= range
.Start
;
614 Index endIndex
= range
.End
;
616 if (!startIndex
.Equals(Index
.Start
) || !endIndex
.Equals(Index
.Start
))
617 ThrowHelper
.ThrowArgumentNullException(ExceptionArgument
.text
);
622 (int start
, int length
) = range
.GetOffsetAndLength(text
.Length
);
623 return new ReadOnlyMemory
<char>(text
, start
, length
);