mirror of
https://github.com/chylex/.NET-Community-Toolkit.git
synced 2025-08-16 05:31:46 +02:00
.github
CommunityToolkit.Common
CommunityToolkit.Diagnostics
CommunityToolkit.HighPerformance
Attributes
Buffers
Enumerables
Extensions
ArrayExtensions.1D.cs
ArrayExtensions.2D.cs
ArrayExtensions.3D.cs
ArrayPoolBufferWriterExtensions.cs
ArrayPoolExtensions.cs
BoolExtensions.cs
HashCodeExtensions.cs
IBufferWriterExtensions.cs
IMemoryOwnerExtensions.cs
ListExtensions.cs
MemoryExtensions.cs
NullableExtensions.cs
ReadOnlyMemoryExtensions.cs
ReadOnlySpanExtensions.cs
SpanExtensions.cs
SpinLockExtensions.cs
StreamExtensions.cs
StringExtensions.cs
Helpers
Memory
Properties
Streams
Box{T}.cs
CommunityToolkit.HighPerformance.csproj
NullableReadOnlyRef{T}.cs
NullableRef{T}.cs
ReadOnlyRef{T}.cs
Ref{T}.cs
CommunityToolkit.Mvvm
CommunityToolkit.Mvvm.SourceGenerators
build
tests
.editorconfig
.git-blame-ignore-revs
.gitattributes
.gitignore
.runsettings
CODE_OF_CONDUCT.md
Contributing.md
Directory.Build.props
Directory.Build.targets
License.md
README.md
ThirdPartyNotices.txt
azure-pipelines.yml
dotnet Community Toolkit.sln
toolkit.snk
version.json
134 lines
5.7 KiB
C#
134 lines
5.7 KiB
C#
// Licensed to the .NET Foundation under one or more agreements.
|
|
// The .NET Foundation licenses this file to you under the MIT license.
|
|
// See the LICENSE file in the project root for more information.
|
|
|
|
using System;
|
|
using System.Buffers;
|
|
using System.IO;
|
|
using System.Runtime.CompilerServices;
|
|
using System.Runtime.InteropServices;
|
|
using CommunityToolkit.HighPerformance.Buffers;
|
|
using CommunityToolkit.HighPerformance.Streams;
|
|
|
|
namespace CommunityToolkit.HighPerformance;
|
|
|
|
/// <summary>
|
|
/// Helpers for working with the <see cref="IBufferWriter{T}"/> type.
|
|
/// </summary>
|
|
public static class IBufferWriterExtensions
|
|
{
|
|
/// <summary>
|
|
/// Returns a <see cref="Stream"/> that can be used to write to a target an <see cref="IBufferWriter{T}"/> of <see cref="byte"/> instance.
|
|
/// </summary>
|
|
/// <param name="writer">The target <see cref="IBufferWriter{T}"/> instance.</param>
|
|
/// <returns>A <see cref="Stream"/> wrapping <paramref name="writer"/> and writing data to its underlying buffer.</returns>
|
|
/// <remarks>The returned <see cref="Stream"/> can only be written to and does not support seeking.</remarks>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Stream AsStream(this IBufferWriter<byte> writer)
|
|
{
|
|
if (writer.GetType() == typeof(ArrayPoolBufferWriter<byte>))
|
|
{
|
|
// If the input writer is of type ArrayPoolBufferWriter<byte>, we can use the type
|
|
// specific buffer writer owner to let the JIT elide callvirts when accessing it.
|
|
ArrayPoolBufferWriter<byte>? internalWriter = Unsafe.As<ArrayPoolBufferWriter<byte>>(writer)!;
|
|
|
|
return new IBufferWriterStream<ArrayBufferWriterOwner>(new ArrayBufferWriterOwner(internalWriter));
|
|
}
|
|
|
|
return new IBufferWriterStream<IBufferWriterOwner>(new IBufferWriterOwner(writer));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Writes a value of a specified type into a target <see cref="IBufferWriter{T}"/> instance.
|
|
/// </summary>
|
|
/// <typeparam name="T">The type of value to write.</typeparam>
|
|
/// <param name="writer">The target <see cref="IBufferWriter{T}"/> instance to write to.</param>
|
|
/// <param name="value">The input value to write to <paramref name="writer"/>.</param>
|
|
/// <exception cref="ArgumentOutOfRangeException">Thrown if <paramref name="writer"/> reaches the end.</exception>
|
|
public static void Write<T>(this IBufferWriter<byte> writer, T value)
|
|
where T : unmanaged
|
|
{
|
|
int length = Unsafe.SizeOf<T>();
|
|
Span<byte> span = writer.GetSpan(1);
|
|
|
|
if (span.Length < length)
|
|
{
|
|
ThrowArgumentExceptionForEndOfBuffer();
|
|
}
|
|
|
|
ref byte r0 = ref MemoryMarshal.GetReference(span);
|
|
|
|
Unsafe.WriteUnaligned(ref r0, value);
|
|
|
|
writer.Advance(length);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Writes a value of a specified type into a target <see cref="IBufferWriter{T}"/> instance.
|
|
/// </summary>
|
|
/// <typeparam name="T">The type of value to write.</typeparam>
|
|
/// <param name="writer">The target <see cref="IBufferWriter{T}"/> instance to write to.</param>
|
|
/// <param name="value">The input value to write to <paramref name="writer"/>.</param>
|
|
/// <exception cref="ArgumentOutOfRangeException">Thrown if <paramref name="writer"/> reaches the end.</exception>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static void Write<T>(this IBufferWriter<T> writer, T value)
|
|
{
|
|
Span<T> span = writer.GetSpan(1);
|
|
|
|
if (span.Length < 1)
|
|
{
|
|
ThrowArgumentExceptionForEndOfBuffer();
|
|
}
|
|
|
|
MemoryMarshal.GetReference(span) = value;
|
|
|
|
writer.Advance(1);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Writes a series of items of a specified type into a target <see cref="IBufferWriter{T}"/> instance.
|
|
/// </summary>
|
|
/// <typeparam name="T">The type of value to write.</typeparam>
|
|
/// <param name="writer">The target <see cref="IBufferWriter{T}"/> instance to write to.</param>
|
|
/// <param name="span">The input <see cref="ReadOnlySpan{T}"/> to write to <paramref name="writer"/>.</param>
|
|
/// <exception cref="ArgumentOutOfRangeException">Thrown if <paramref name="writer"/> reaches the end.</exception>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static void Write<T>(this IBufferWriter<byte> writer, ReadOnlySpan<T> span)
|
|
where T : unmanaged
|
|
{
|
|
ReadOnlySpan<byte> source = MemoryMarshal.AsBytes(span);
|
|
Span<byte> destination = writer.GetSpan(source.Length);
|
|
|
|
source.CopyTo(destination);
|
|
|
|
writer.Advance(source.Length);
|
|
}
|
|
|
|
#if !NETSTANDARD2_1_OR_GREATER
|
|
/// <summary>
|
|
/// Writes a series of items of a specified type into a target <see cref="IBufferWriter{T}"/> instance.
|
|
/// </summary>
|
|
/// <typeparam name="T">The type of value to write.</typeparam>
|
|
/// <param name="writer">The target <see cref="IBufferWriter{T}"/> instance to write to.</param>
|
|
/// <param name="span">The input <see cref="ReadOnlySpan{T}"/> to write to <paramref name="writer"/>.</param>
|
|
/// <exception cref="ArgumentOutOfRangeException">Thrown if <paramref name="writer"/> reaches the end.</exception>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static void Write<T>(this IBufferWriter<T> writer, ReadOnlySpan<T> span)
|
|
{
|
|
Span<T> destination = writer.GetSpan(span.Length);
|
|
|
|
span.CopyTo(destination);
|
|
|
|
writer.Advance(span.Length);
|
|
}
|
|
#endif
|
|
|
|
/// <summary>
|
|
/// Throws an <see cref="ArgumentException"/> when trying to write too many bytes to the target writer.
|
|
/// </summary>
|
|
private static void ThrowArgumentExceptionForEndOfBuffer()
|
|
{
|
|
throw new ArgumentException("The current buffer writer can't contain the requested input data.");
|
|
}
|
|
}
|