Skip to content

Commit a093b2b

Browse files
authored
Merge pull request #19 from rameel/memory-marshal-extensions
Add TryGetStringView and TryGetArrayView extensions to MemoryMarshal
2 parents 6abe41c + 3c618e7 commit a093b2b

2 files changed

Lines changed: 140 additions & 0 deletions

File tree

Ramstack.Structures.Tests/InteropServices/MemoryMarshalTests.cs

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,4 +44,99 @@ public void CreateArrayView()
4444
MemoryMarshal.CreateArrayView(array, 0, 5).Length,
4545
Is.EqualTo(5));
4646
}
47+
48+
[Test]
49+
public static void ReadOnlyMemory_TryGetStringView()
50+
{
51+
const string Input = "0123456789";
52+
53+
var memory = Input.AsMemory();
54+
Assert.That(memory.IsEmpty, Is.False);
55+
56+
Assert.That(MemoryMarshal.TryGetStringView(memory, out var view), Is.True);
57+
Assert.That(view, Is.EqualTo(Input));
58+
59+
memory = memory[1..];
60+
Assert.That(MemoryMarshal.TryGetStringView(memory, out view), Is.True);
61+
Assert.That(view, Is.EqualTo(Input[1..]));
62+
Assert.That(view.Length, Is.EqualTo(Input.Length - 1));
63+
64+
memory = memory[1..];
65+
Assert.That(MemoryMarshal.TryGetStringView(memory, out view), Is.True);
66+
Assert.That(view, Is.EqualTo(Input[2..]));
67+
Assert.That(view.Length, Is.EqualTo(Input.Length - 2));
68+
69+
memory = memory.Slice(3, 2);
70+
Assert.That(MemoryMarshal.TryGetStringView(memory, out view), Is.True);
71+
Assert.That(view, Is.EqualTo(Input[5..7]));
72+
Assert.That(view.Length, Is.EqualTo(2));
73+
74+
memory = memory[memory.Length..];
75+
Assert.That(MemoryMarshal.TryGetStringView(memory, out view), Is.True);
76+
Assert.That(view.Length, Is.Zero);
77+
78+
memory = memory[..];
79+
Assert.That(MemoryMarshal.TryGetStringView(memory, out view), Is.True);
80+
Assert.That(view.Length, Is.Zero);
81+
82+
memory = memory[..0];
83+
Assert.That(MemoryMarshal.TryGetStringView(memory, out view), Is.True);
84+
Assert.That(view.Length, Is.Zero);
85+
86+
Assert.That(memory.IsEmpty, Is.True);
87+
}
88+
89+
[Test]
90+
public static void ReadOnlyMemory_TryGetStringView_Array_ReturnsFalse()
91+
{
92+
var memory = new char[10].AsMemory();
93+
Assert.That(MemoryMarshal.TryGetStringView(memory, out var view), Is.False);
94+
Assert.That(view.IsDefault, Is.True);
95+
}
96+
97+
[Test]
98+
public static void ReadOnlyMemory_TryGetArrayView()
99+
{
100+
var buffer = Enumerable.Range(0, 10).ToArray();
101+
var memory = buffer.AsMemory();
102+
103+
Assert.That(MemoryMarshal.TryGetArrayView<int>(memory, out var view), Is.True);
104+
Assert.That(view, Is.EquivalentTo(buffer));
105+
}
106+
107+
[Test]
108+
public static void ReadOnlyMemory_TryGetArrayView_EmptyArray()
109+
{
110+
var buffer = Array.Empty<int>();
111+
var memory = buffer.AsMemory();
112+
113+
Assert.That(MemoryMarshal.TryGetArrayView<int>(memory, out var view), Is.True);
114+
Assert.That(view, Is.EquivalentTo(buffer));
115+
}
116+
117+
[Test]
118+
public static void ReadOnlyMemory_TryGetArrayView_Default()
119+
{
120+
var memory = default(ReadOnlyMemory<int>);
121+
122+
Assert.That(MemoryMarshal.TryGetArrayView(memory, out var view), Is.True);
123+
Assert.That(view, Is.EquivalentTo(Array.Empty<int>()));
124+
}
125+
126+
[Test]
127+
public static void ReadOnlyMemory_TryGetArrayView_Empty()
128+
{
129+
var memory = ReadOnlyMemory<int>.Empty;
130+
131+
Assert.That(MemoryMarshal.TryGetArrayView(memory, out var view), Is.True);
132+
Assert.That(view, Is.EquivalentTo(Array.Empty<int>()));
133+
}
134+
135+
[Test]
136+
public static void ReadOnlyMemory_TryGetArrayView_String_ReturnsFalse()
137+
{
138+
var memory = "0123456789".AsMemory();
139+
Assert.That(MemoryMarshal.TryGetArrayView(memory, out var view), Is.False);
140+
Assert.That(view.IsDefault, Is.True);
141+
}
47142
}

Ramstack.Structures/InteropServices/MemoryMarshalExtensions.cs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,5 +119,50 @@ public static ArrayView<T> CreateArrayView<T>(T[] array, int index, int length)
119119

120120
return new ArrayView<T>(array, index, length, unused: 0);
121121
}
122+
123+
/// <summary>
124+
/// Attempts to get a <see cref="StringView"/> from the underlying memory buffer.
125+
/// </summary>
126+
/// <param name="memory">Read-only memory containing a block of characters.</param>
127+
/// <param name="view">When this method returns, contains the <see cref="StringView"/>
128+
/// retrieved from the underlying read-only memory buffer.</param>
129+
/// <returns>
130+
/// <see langword="true"/> if the method successfully retrieves the underlying string;
131+
/// otherwise, <see langword="false"/>.
132+
/// </returns>
133+
public static bool TryGetStringView(ReadOnlyMemory<char> memory, out StringView view)
134+
{
135+
if (MemoryMarshal.TryGetString(memory, out var value, out var start, out var length))
136+
{
137+
view = new StringView(value, start, length, unused: 0);
138+
return true;
139+
}
140+
141+
view = default;
142+
return false;
143+
}
144+
145+
/// <summary>
146+
/// Attempts to get a <see cref="StringView"/> from the underlying memory buffer.
147+
/// </summary>
148+
/// <typeparam name="T">The type of elements in the read-only memory buffer.</typeparam>
149+
/// <param name="memory">Read-only memory buffer.</param>
150+
/// <param name="view">When this method returns, contains the <see cref="ArrayView{T}"/>
151+
/// retrieved from the underlying read-only memory buffer.</param>
152+
/// <returns>
153+
/// <see langword="true"/> if the underlying memory buffer represents an array segment;
154+
/// otherwise, <see langword="false"/>.
155+
/// </returns>
156+
public static bool TryGetArrayView<T>(ReadOnlyMemory<T> memory, out ArrayView<T> view)
157+
{
158+
if (MemoryMarshal.TryGetArray(memory, out var segment))
159+
{
160+
view = segment;
161+
return true;
162+
}
163+
164+
view = default;
165+
return false;
166+
}
122167
}
123168
}

0 commit comments

Comments
 (0)