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 using System.Runtime.CompilerServices;
8 using System.Runtime.InteropServices;
10 using Internal.Runtime.CompilerServices;
13 using nuint = System.UInt64;
15 using nuint = System.UInt32;
21 /// Extension methods and non-generic helpers for Span, ReadOnlySpan, Memory, and ReadOnlyMemory.
23 public static class Span
25 /// <summary>Creates a new <see cref="ReadOnlyMemory{char}"/> over the portion of the target string.</summary>
26 /// <param name="text">The target string.</param>
27 /// <exception cref="System.ArgumentNullException">Thrown when <paramref name="text"/> is a null reference (Nothing in Visual Basic).</exception>
28 public static ReadOnlyMemory<char> AsReadOnlyMemory(this string text)
31 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.text);
33 return new ReadOnlyMemory<char>(text, 0, text.Length);
36 /// <summary>Creates a new <see cref="ReadOnlyMemory{char}"/> over the portion of the target string.</summary>
37 /// <param name="text">The target string.</param>
38 /// <exception cref="System.ArgumentNullException">Thrown when <paramref name="text"/> is a null reference (Nothing in Visual Basic).</exception>
39 /// <exception cref="System.ArgumentOutOfRangeException">
40 /// Thrown when the specified <paramref name="start"/> index is not in range (<0 or >text.Length).
42 public static ReadOnlyMemory<char> AsReadOnlyMemory(this string text, int start)
45 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.text);
47 if ((uint)start > (uint)text.Length)
48 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
50 return new ReadOnlyMemory<char>(text, start, text.Length - start);
53 /// <summary>Creates a new <see cref="ReadOnlyMemory{char}"/> over the portion of the target string.</summary>
54 /// <param name="text">The target string.</param>
55 /// <exception cref="System.ArgumentNullException">Thrown when <paramref name="text"/> is a null reference (Nothing in Visual Basic).</exception>
56 /// <exception cref="System.ArgumentOutOfRangeException">
57 /// Thrown when the specified <paramref name="start"/> index or <paramref name="length"/> is not in range.
59 public static ReadOnlyMemory<char> AsReadOnlyMemory(this string text, int start, int length)
62 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.text);
64 if ((uint)start > (uint)text.Length || (uint)length > (uint)(text.Length - start))
65 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
67 return new ReadOnlyMemory<char>(text, start, length);
70 /// <summary>Attempts to get the underlying <see cref="string"/> from a <see cref="ReadOnlyMemory{T}"/>.</summary>
71 /// <param name="readOnlyMemory">The memory that may be wrapping a <see cref="string"/> object.</param>
72 /// <param name="text">The string.</param>
73 /// <param name="start">The starting location in <paramref name="text"/>.</param>
74 /// <param name="length">The number of items in <paramref name="text"/>.</param>
75 /// <returns></returns>
76 public static bool TryGetString(this ReadOnlyMemory<char> readOnlyMemory, out string text, out int start, out int length)
78 if (readOnlyMemory.GetObjectStartLength(out int offset, out int count) is string s)
95 /// Casts a Span of one primitive type <typeparamref name="T"/> to Span of bytes.
96 /// That type may not contain pointers or references. This is checked at runtime in order to preserve type safety.
98 /// <param name="source">The source slice, of type <typeparamref name="T"/>.</param>
99 /// <exception cref="System.ArgumentException">
100 /// Thrown when <typeparamref name="T"/> contains pointers.
102 [MethodImpl(MethodImplOptions.AggressiveInlining)]
103 public static Span<byte> AsBytes<T>(this Span<T> source)
106 if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
107 ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(T));
109 return new Span<byte>(
110 ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(source)),
111 checked(source.Length * Unsafe.SizeOf<T>()));
115 /// Casts a ReadOnlySpan of one primitive type <typeparamref name="T"/> to ReadOnlySpan of bytes.
116 /// That type may not contain pointers or references. This is checked at runtime in order to preserve type safety.
118 /// <param name="source">The source slice, of type <typeparamref name="T"/>.</param>
119 /// <exception cref="System.ArgumentException">
120 /// Thrown when <typeparamref name="T"/> contains pointers.
122 [MethodImpl(MethodImplOptions.AggressiveInlining)]
123 public static ReadOnlySpan<byte> AsBytes<T>(this ReadOnlySpan<T> source)
126 if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
127 ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(T));
129 return new ReadOnlySpan<byte>(
130 ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(source)),
131 checked(source.Length * Unsafe.SizeOf<T>()));
135 /// Casts a Span of one primitive type <typeparamref name="TFrom"/> to another primitive type <typeparamref name="TTo"/>.
136 /// These types may not contain pointers or references. This is checked at runtime in order to preserve type safety.
139 /// Supported only for platforms that support misaligned memory access.
141 /// <param name="source">The source slice, of type <typeparamref name="TFrom"/>.</param>
142 /// <exception cref="System.ArgumentException">
143 /// Thrown when <typeparamref name="TFrom"/> or <typeparamref name="TTo"/> contains pointers.
145 [MethodImpl(MethodImplOptions.AggressiveInlining)]
146 public static Span<TTo> NonPortableCast<TFrom, TTo>(this Span<TFrom> source)
150 if (RuntimeHelpers.IsReferenceOrContainsReferences<TFrom>())
151 ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(TFrom));
152 if (RuntimeHelpers.IsReferenceOrContainsReferences<TTo>())
153 ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(TTo));
155 return new Span<TTo>(
156 ref Unsafe.As<TFrom, TTo>(ref source.DangerousGetPinnableReference()),
157 checked((int)((long)source.Length * Unsafe.SizeOf<TFrom>() / Unsafe.SizeOf<TTo>())));
161 /// Casts a ReadOnlySpan of one primitive type <typeparamref name="TFrom"/> to another primitive type <typeparamref name="TTo"/>.
162 /// These types may not contain pointers or references. This is checked at runtime in order to preserve type safety.
165 /// Supported only for platforms that support misaligned memory access.
167 /// <param name="source">The source slice, of type <typeparamref name="TFrom"/>.</param>
168 /// <exception cref="System.ArgumentException">
169 /// Thrown when <typeparamref name="TFrom"/> or <typeparamref name="TTo"/> contains pointers.
171 [MethodImpl(MethodImplOptions.AggressiveInlining)]
172 public static ReadOnlySpan<TTo> NonPortableCast<TFrom, TTo>(this ReadOnlySpan<TFrom> source)
176 if (RuntimeHelpers.IsReferenceOrContainsReferences<TFrom>())
177 ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(TFrom));
178 if (RuntimeHelpers.IsReferenceOrContainsReferences<TTo>())
179 ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(TTo));
181 return new ReadOnlySpan<TTo>(
182 ref Unsafe.As<TFrom, TTo>(ref MemoryMarshal.GetReference(source)),
183 checked((int)((long)source.Length * Unsafe.SizeOf<TFrom>() / Unsafe.SizeOf<TTo>())));
187 /// Creates a new readonly span over the portion of the target string.
189 /// <param name="text">The target string.</param>
190 /// <exception cref="System.ArgumentNullException">Thrown when <paramref name="text"/> is a null
191 /// reference (Nothing in Visual Basic).</exception>
192 [MethodImpl(MethodImplOptions.AggressiveInlining)]
193 public static ReadOnlySpan<char> AsReadOnlySpan(this string text)
196 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.text);
198 return new ReadOnlySpan<char>(ref text.GetRawStringData(), text.Length);
202 /// Creates a new readonly span over the portion of the target string.
204 /// <param name="text">The target string.</param>
205 /// <exception cref="System.ArgumentNullException">Thrown when <paramref name="text"/> is a null
206 /// reference (Nothing in Visual Basic).
208 /// <exception cref="System.ArgumentOutOfRangeException">
209 /// Thrown when the specified <paramref name="start"/> index is not in range (<0 or >text.Length).
211 [MethodImpl(MethodImplOptions.AggressiveInlining)]
212 public static ReadOnlySpan<char> AsReadOnlySpan(this string text, int start)
215 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.text);
217 if ((uint)start > (uint)text.Length)
218 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
220 return new ReadOnlySpan<char>(ref Unsafe.Add(ref text.GetRawStringData(), start), text.Length - start);
224 /// Creates a new readonly span over the portion of the target string.
226 /// <param name="text">The target string.</param>
227 /// <exception cref="System.ArgumentNullException">Thrown when <paramref name="text"/> is a null
228 /// reference (Nothing in Visual Basic).
230 /// <exception cref="System.ArgumentOutOfRangeException">
231 /// Thrown when the specified <paramref name="start"/> index or <paramref name="length"/> is not in range.
233 [MethodImpl(MethodImplOptions.AggressiveInlining)]
234 public static ReadOnlySpan<char> AsReadOnlySpan(this string text, int start, int length)
237 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.text);
239 if ((uint)start > (uint)text.Length || (uint)length > (uint)(text.Length - start))
240 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
242 return new ReadOnlySpan<char>(ref Unsafe.Add(ref text.GetRawStringData(), start), length);
245 internal static unsafe void CopyTo<T>(ref T destination, ref T source, int elementsCount)
247 if (Unsafe.AreSame(ref destination, ref source))
250 if (elementsCount <= 1)
252 if (elementsCount == 1)
254 destination = source;
259 nuint byteCount = (nuint)elementsCount * (nuint)Unsafe.SizeOf<T>();
260 if (!RuntimeHelpers.IsReferenceOrContainsReferences<T>())
262 fixed (byte* pDestination = &Unsafe.As<T, byte>(ref destination))
264 fixed (byte* pSource = &Unsafe.As<T, byte>(ref source))
266 Buffer.Memmove(pDestination, pSource, byteCount);
272 RuntimeImports.RhBulkMoveWithWriteBarrier(
273 ref Unsafe.As<T, byte>(ref destination),
274 ref Unsafe.As<T, byte>(ref source),
279 internal static unsafe void ClearWithoutReferences(ref byte b, nuint byteLength)
284 #if CORECLR && (AMD64 || ARM64)
285 if (byteLength > 4096) goto PInvoke;
286 Unsafe.InitBlockUnaligned(ref b, 0, (uint)byteLength);
289 // TODO: Optimize other platforms to be on par with AMD64 CoreCLR
290 // Note: It's important that this switch handles lengths at least up to 22.
291 // See notes below near the main loop for why.
293 // The switch will be very fast since it can be implemented using a jump
294 // table in assembly. See http://stackoverflow.com/a/449297/4077294 for more info.
302 Unsafe.As<byte, short>(ref b) = 0;
305 Unsafe.As<byte, short>(ref b) = 0;
306 Unsafe.Add<byte>(ref b, 2) = 0;
309 Unsafe.As<byte, int>(ref b) = 0;
312 Unsafe.As<byte, int>(ref b) = 0;
313 Unsafe.Add<byte>(ref b, 4) = 0;
316 Unsafe.As<byte, int>(ref b) = 0;
317 Unsafe.As<byte, short>(ref Unsafe.Add<byte>(ref b, 4)) = 0;
320 Unsafe.As<byte, int>(ref b) = 0;
321 Unsafe.As<byte, short>(ref Unsafe.Add<byte>(ref b, 4)) = 0;
322 Unsafe.Add<byte>(ref b, 6) = 0;
326 Unsafe.As<byte, long>(ref b) = 0;
328 Unsafe.As<byte, int>(ref b) = 0;
329 Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 4)) = 0;
334 Unsafe.As<byte, long>(ref b) = 0;
336 Unsafe.As<byte, int>(ref b) = 0;
337 Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 4)) = 0;
339 Unsafe.Add<byte>(ref b, 8) = 0;
343 Unsafe.As<byte, long>(ref b) = 0;
345 Unsafe.As<byte, int>(ref b) = 0;
346 Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 4)) = 0;
348 Unsafe.As<byte, short>(ref Unsafe.Add<byte>(ref b, 8)) = 0;
352 Unsafe.As<byte, long>(ref b) = 0;
354 Unsafe.As<byte, int>(ref b) = 0;
355 Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 4)) = 0;
357 Unsafe.As<byte, short>(ref Unsafe.Add<byte>(ref b, 8)) = 0;
358 Unsafe.Add<byte>(ref b, 10) = 0;
362 Unsafe.As<byte, long>(ref b) = 0;
364 Unsafe.As<byte, int>(ref b) = 0;
365 Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 4)) = 0;
367 Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 8)) = 0;
371 Unsafe.As<byte, long>(ref b) = 0;
373 Unsafe.As<byte, int>(ref b) = 0;
374 Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 4)) = 0;
376 Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 8)) = 0;
377 Unsafe.Add<byte>(ref b, 12) = 0;
381 Unsafe.As<byte, long>(ref b) = 0;
383 Unsafe.As<byte, int>(ref b) = 0;
384 Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 4)) = 0;
386 Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 8)) = 0;
387 Unsafe.As<byte, short>(ref Unsafe.Add<byte>(ref b, 12)) = 0;
391 Unsafe.As<byte, long>(ref b) = 0;
393 Unsafe.As<byte, int>(ref b) = 0;
394 Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 4)) = 0;
396 Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 8)) = 0;
397 Unsafe.As<byte, short>(ref Unsafe.Add<byte>(ref b, 12)) = 0;
398 Unsafe.Add<byte>(ref b, 14) = 0;
402 Unsafe.As<byte, long>(ref b) = 0;
403 Unsafe.As<byte, long>(ref Unsafe.Add<byte>(ref b, 8)) = 0;
405 Unsafe.As<byte, int>(ref b) = 0;
406 Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 4)) = 0;
407 Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 8)) = 0;
408 Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 12)) = 0;
413 Unsafe.As<byte, long>(ref b) = 0;
414 Unsafe.As<byte, long>(ref Unsafe.Add<byte>(ref b, 8)) = 0;
416 Unsafe.As<byte, int>(ref b) = 0;
417 Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 4)) = 0;
418 Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 8)) = 0;
419 Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 12)) = 0;
421 Unsafe.Add<byte>(ref b, 16) = 0;
425 Unsafe.As<byte, long>(ref b) = 0;
426 Unsafe.As<byte, long>(ref Unsafe.Add<byte>(ref b, 8)) = 0;
428 Unsafe.As<byte, int>(ref b) = 0;
429 Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 4)) = 0;
430 Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 8)) = 0;
431 Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 12)) = 0;
433 Unsafe.As<byte, short>(ref Unsafe.Add<byte>(ref b, 16)) = 0;
437 Unsafe.As<byte, long>(ref b) = 0;
438 Unsafe.As<byte, long>(ref Unsafe.Add<byte>(ref b, 8)) = 0;
440 Unsafe.As<byte, int>(ref b) = 0;
441 Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 4)) = 0;
442 Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 8)) = 0;
443 Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 12)) = 0;
445 Unsafe.As<byte, short>(ref Unsafe.Add<byte>(ref b, 16)) = 0;
446 Unsafe.Add<byte>(ref b, 18) = 0;
450 Unsafe.As<byte, long>(ref b) = 0;
451 Unsafe.As<byte, long>(ref Unsafe.Add<byte>(ref b, 8)) = 0;
453 Unsafe.As<byte, int>(ref b) = 0;
454 Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 4)) = 0;
455 Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 8)) = 0;
456 Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 12)) = 0;
458 Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 16)) = 0;
462 Unsafe.As<byte, long>(ref b) = 0;
463 Unsafe.As<byte, long>(ref Unsafe.Add<byte>(ref b, 8)) = 0;
465 Unsafe.As<byte, int>(ref b) = 0;
466 Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 4)) = 0;
467 Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 8)) = 0;
468 Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 12)) = 0;
470 Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 16)) = 0;
471 Unsafe.Add<byte>(ref b, 20) = 0;
475 Unsafe.As<byte, long>(ref b) = 0;
476 Unsafe.As<byte, long>(ref Unsafe.Add<byte>(ref b, 8)) = 0;
478 Unsafe.As<byte, int>(ref b) = 0;
479 Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 4)) = 0;
480 Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 8)) = 0;
481 Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 12)) = 0;
483 Unsafe.As<byte, int>(ref Unsafe.Add<byte>(ref b, 16)) = 0;
484 Unsafe.As<byte, short>(ref Unsafe.Add<byte>(ref b, 20)) = 0;
488 // P/Invoke into the native version for large lengths
489 if (byteLength >= 512) goto PInvoke;
491 nuint i = 0; // byte offset at which we're copying
493 if ((Unsafe.As<byte, int>(ref b) & 3) != 0)
495 if ((Unsafe.As<byte, int>(ref b) & 1) != 0)
497 Unsafe.AddByteOffset<byte>(ref b, i) = 0;
499 if ((Unsafe.As<byte, int>(ref b) & 2) != 0)
502 Unsafe.As<byte, short>(ref Unsafe.AddByteOffset<byte>(ref b, i)) = 0;
508 // On 64-bit IntPtr.Size == 8, so we want to advance to the next 8-aligned address. If
509 // (int)b % 8 is 0, 5, 6, or 7, we will already have advanced by 0, 3, 2, or 1
510 // bytes to the next aligned address (respectively), so do nothing. On the other hand,
511 // if it is 1, 2, 3, or 4 we will want to copy-and-advance another 4 bytes until
513 // The thing 1, 2, 3, and 4 have in common that the others don't is that if you
514 // subtract one from them, their 3rd lsb will not be set. Hence, the below check.
516 if (((Unsafe.As<byte, int>(ref b) - 1) & 4) == 0)
518 Unsafe.As<byte, int>(ref Unsafe.AddByteOffset<byte>(ref b, i)) = 0;
522 nuint end = byteLength - 16;
523 byteLength -= i; // lower 4 bits of byteLength represent how many bytes are left *after* the unrolled loop
525 // We know due to the above switch-case that this loop will always run 1 iteration; max
526 // bytes we clear before checking is 23 (7 to align the pointers, 16 for 1 iteration) so
527 // the switch handles lengths 0-22.
528 Debug.Assert(end >= 7 && i <= end);
530 // This is separated out into a different variable, so the i + 16 addition can be
531 // performed at the start of the pipeline and the loop condition does not have
532 // a dependency on the writes.
539 // This loop looks very costly since there appear to be a bunch of temporary values
540 // being created with the adds, but the jit (for x86 anyways) will convert each of
541 // these to use memory addressing operands.
543 // So the only cost is a bit of code size, which is made up for by the fact that
544 // we save on writes to b.
547 Unsafe.As<byte, long>(ref Unsafe.AddByteOffset<byte>(ref b, i)) = 0;
548 Unsafe.As<byte, long>(ref Unsafe.AddByteOffset<byte>(ref b, i + 8)) = 0;
550 Unsafe.As<byte, int>(ref Unsafe.AddByteOffset<byte>(ref b, i)) = 0;
551 Unsafe.As<byte, int>(ref Unsafe.AddByteOffset<byte>(ref b, i + 4)) = 0;
552 Unsafe.As<byte, int>(ref Unsafe.AddByteOffset<byte>(ref b, i + 8)) = 0;
553 Unsafe.As<byte, int>(ref Unsafe.AddByteOffset<byte>(ref b, i + 12)) = 0;
558 // See notes above for why this wasn't used instead
561 while (counter <= end);
563 if ((byteLength & 8) != 0)
566 Unsafe.As<byte, long>(ref Unsafe.AddByteOffset<byte>(ref b, i)) = 0;
568 Unsafe.As<byte, int>(ref Unsafe.AddByteOffset<byte>(ref b, i)) = 0;
569 Unsafe.As<byte, int>(ref Unsafe.AddByteOffset<byte>(ref b, i + 4)) = 0;
573 if ((byteLength & 4) != 0)
575 Unsafe.As<byte, int>(ref Unsafe.AddByteOffset<byte>(ref b, i)) = 0;
578 if ((byteLength & 2) != 0)
580 Unsafe.As<byte, short>(ref Unsafe.AddByteOffset<byte>(ref b, i)) = 0;
583 if ((byteLength & 1) != 0)
585 Unsafe.AddByteOffset<byte>(ref b, i) = 0;
586 // We're not using i after this, so not needed
594 RuntimeImports.RhZeroMemory(ref b, byteLength);
597 internal static unsafe void ClearWithReferences(ref IntPtr ip, nuint pointerSizeLength)
599 if (pointerSizeLength == 0)
602 // TODO: Perhaps do switch casing to improve small size perf
606 while ((n = i + 8) <= (pointerSizeLength))
608 Unsafe.AddByteOffset<IntPtr>(ref ip, (i + 0) * (nuint)sizeof(IntPtr)) = default(IntPtr);
609 Unsafe.AddByteOffset<IntPtr>(ref ip, (i + 1) * (nuint)sizeof(IntPtr)) = default(IntPtr);
610 Unsafe.AddByteOffset<IntPtr>(ref ip, (i + 2) * (nuint)sizeof(IntPtr)) = default(IntPtr);
611 Unsafe.AddByteOffset<IntPtr>(ref ip, (i + 3) * (nuint)sizeof(IntPtr)) = default(IntPtr);
612 Unsafe.AddByteOffset<IntPtr>(ref ip, (i + 4) * (nuint)sizeof(IntPtr)) = default(IntPtr);
613 Unsafe.AddByteOffset<IntPtr>(ref ip, (i + 5) * (nuint)sizeof(IntPtr)) = default(IntPtr);
614 Unsafe.AddByteOffset<IntPtr>(ref ip, (i + 6) * (nuint)sizeof(IntPtr)) = default(IntPtr);
615 Unsafe.AddByteOffset<IntPtr>(ref ip, (i + 7) * (nuint)sizeof(IntPtr)) = default(IntPtr);
618 if ((n = i + 4) <= (pointerSizeLength))
620 Unsafe.AddByteOffset<IntPtr>(ref ip, (i + 0) * (nuint)sizeof(IntPtr)) = default(IntPtr);
621 Unsafe.AddByteOffset<IntPtr>(ref ip, (i + 1) * (nuint)sizeof(IntPtr)) = default(IntPtr);
622 Unsafe.AddByteOffset<IntPtr>(ref ip, (i + 2) * (nuint)sizeof(IntPtr)) = default(IntPtr);
623 Unsafe.AddByteOffset<IntPtr>(ref ip, (i + 3) * (nuint)sizeof(IntPtr)) = default(IntPtr);
626 if ((n = i + 2) <= (pointerSizeLength))
628 Unsafe.AddByteOffset<IntPtr>(ref ip, (i + 0) * (nuint)sizeof(IntPtr)) = default(IntPtr);
629 Unsafe.AddByteOffset<IntPtr>(ref ip, (i + 1) * (nuint)sizeof(IntPtr)) = default(IntPtr);
632 if ((i + 1) <= (pointerSizeLength))
634 Unsafe.AddByteOffset<IntPtr>(ref ip, (i + 0) * (nuint)sizeof(IntPtr)) = default(IntPtr);