Skip to content

Commit

Permalink
Add a few more buffer related helpers and update StyleCop
Browse files Browse the repository at this point in the history
  • Loading branch information
JeremyKuhne committed Feb 3, 2024
1 parent 21b2ac4 commit d719ef3
Show file tree
Hide file tree
Showing 6 changed files with 155 additions and 1 deletion.
2 changes: 2 additions & 0 deletions src/thirtytwo/Support/BufferScope.cs
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,8 @@ public unsafe void EnsureCapacity(int capacity, bool copy = false)

public static implicit operator ReadOnlySpan<T>(BufferScope<T> scope) => scope._span;

public readonly Span<T>.Enumerator GetEnumerator() => _span.GetEnumerator();

public void Dispose()
{
if (_array is not null)
Expand Down
19 changes: 19 additions & 0 deletions src/thirtytwo/Support/SpanExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,23 @@ public static IEnumerable<string> Split(this ReadOnlySpan<char> span, char delim

return strings;
}

/// <summary>
/// Converts a span of <see cref="BSTR"/>s to an array of <see langword="string"/>;
/// </summary>
public static string[] ToStringArray(this ReadOnlySpan<BSTR> bstrs)
{
if (bstrs.IsEmpty)
{
return [];
}

string[] strings = new string[bstrs.Length];
for (int i = 0; i < bstrs.Length; i++)
{
strings[i] = bstrs[i].ToString();
}

return strings;
}
}
46 changes: 46 additions & 0 deletions src/thirtytwo/Support/StackBufferScope16.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Copyright (c) Jeremy W. Kuhne. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System.Runtime.CompilerServices;

namespace Windows.Support;

/// <summary>
/// Simple buffer that has 16 <typeparamref name="T"/>s on the stack. If the buffer needs to be larger than 16
/// elements it will be allocated on the heap.
/// </summary>
/// <remarks>
/// <para>
/// This type cannot be nested in another ref type as it will result in it getting initialized in a copy which will
/// make the data in the buffer point to random stack data.
/// </para>
/// </remarks>
public unsafe ref struct StackBufferScope16<T> where T : unmanaged
{
private const int StackSpace = 16;

private StackBuffer _stackBuffer;
private BufferScope<T> _bufferScope;

public StackBufferScope16(int length)
{
#pragma warning disable CS9084 // Struct member returns 'this' or other instance members by reference
_bufferScope = new BufferScope<T>(_stackBuffer, length);
#pragma warning restore CS9084
}

public ref T this[int i] => ref _bufferScope[i];

public readonly Span<T> this[Range range] => _bufferScope[range];
public readonly int Length => _bufferScope.Length;

public readonly Span<T>.Enumerator GetEnumerator() => _bufferScope.GetEnumerator();
public readonly ref T GetPinnableReference() => ref _bufferScope.GetPinnableReference();
public void Dispose() => _bufferScope.Dispose();

[InlineArray(StackSpace)]
private struct StackBuffer
{
internal T _element0;
}
}
58 changes: 58 additions & 0 deletions src/thirtytwo/Win32/Foundation/BstrBuffer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// Copyright (c) Jeremy W. Kuhne. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System.Runtime.CompilerServices;
using Windows.Support;

namespace Windows.Win32.Foundation;

/// <summary>
/// Buffer specficially for allocating an array of <see cref="BSTR"/>s. Disposing the buffer will free all
/// of the contained <see cref="BSTR"/>s.
/// </summary>
/// <remarks>
/// <para>
/// This type cannot be nested in another ref type as it will result in it getting initialized in a copy which will
/// make the data in the buffer point to random stack data.
/// </para>
/// </remarks>
public unsafe ref struct BstrBuffer
{
private const int StackSpace = 16;

private StackBuffer _stackBuffer;
private BufferScope<BSTR> _bufferScope;

#pragma warning disable CS9084 // Struct member returns 'this' or other instance members by reference
public BstrBuffer(int length) => _bufferScope = new(_stackBuffer, length);
#pragma warning restore CS9084

public readonly ref BSTR GetPinnableReference() => ref _bufferScope.GetPinnableReference();

public void Clear()
{
for (int i = 0; i < _bufferScope.Length; i++)
{
_bufferScope[i].Dispose();
}
}

public ref BSTR this[int i] => ref _bufferScope[i];

public readonly Span<BSTR> this[Range range] => _bufferScope[range];

public static implicit operator BSTR*(in BstrBuffer scope) =>
(BSTR*)Unsafe.AsPointer(ref Unsafe.AsRef(in scope._stackBuffer._element0));

public void Dispose()
{
Clear();
_bufferScope.Dispose();
}

[InlineArray(StackSpace)]
private struct StackBuffer
{
internal BSTR _element0;
}
}
2 changes: 1 addition & 1 deletion src/thirtytwo/thirtytwo.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.507">
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.556">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
Expand Down
29 changes: 29 additions & 0 deletions src/thirtytwo_tests/Win32/Foundation/BstrBufferTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Copyright (c) Jeremy W. Kuhne. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

namespace Windows.Win32.Foundation;

public class BstrBufferTests
{
[Fact]
public unsafe void BstrBuffer_Basics()
{
BSTR bstr = new("Foo");
using BstrBuffer buffer = new(2);
buffer[0] = bstr;
((nint)buffer[0].Value).Should().Be((nint)bstr.Value);
buffer[0].Dispose();
buffer[0].IsNull.Should().BeTrue();
}

[Fact]
public void BstrBuffer_Clear_FreesBstrs()
{
using BstrBuffer buffer = new(2);
buffer[0] = new("Foo");
buffer[1] = new("Bar");
buffer.Clear();
buffer[0].IsNull.Should().BeTrue();
buffer[1].IsNull.Should().BeTrue();
}
}

0 comments on commit d719ef3

Please sign in to comment.