-
Notifications
You must be signed in to change notification settings - Fork 5.1k
Added examples for Memory<T> guidance #343
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
using System; | ||
using System.Buffers; | ||
|
||
class Example | ||
{ | ||
static void Main() | ||
{ | ||
using (IMemoryOwner<char> owner = MemoryPool<char>.Shared.Rent()) | ||
{ | ||
Console.Write("Enter a number: "); | ||
try { | ||
var value = Int32.Parse(Console.ReadLine()); | ||
|
||
var memory = owner.Memory; | ||
WriteInt32ToBuffer(value, memory); | ||
DisplayBufferToConsole(memory.Slice(0, value.ToString().Length)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If you use |
||
} | ||
catch (FormatException) { | ||
Console.WriteLine("You did not enter a valid number."); | ||
} | ||
catch (OverflowException) { | ||
Console.WriteLine($"You entered a number less than {Int32.MinValue:N0} or greater than {Int32.MaxValue:N0}."); | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How are these |
||
} | ||
} | ||
|
||
static void WriteInt32ToBuffer(int value, Memory<char> buffer) | ||
{ | ||
var strValue = value.ToString(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shouldn't this use |
||
|
||
var span = buffer.Slice(0, strValue.Length).Span; | ||
strValue.AsSpan().CopyTo(span); | ||
} | ||
|
||
static void DisplayBufferToConsole(Memory<char> buffer) => | ||
Console.WriteLine($"Contents of the buffer: '{buffer}'"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Similarly, I think it would be better if this code didn't allocate, but I can't think of a reasonable way to achieve that here. |
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<OutputType>Exe</OutputType> | ||
<TargetFramework>netcoreapp2.1</TargetFramework> | ||
<RootNamespace>Visual_Studio_Projects</RootNamespace> | ||
</PropertyGroup> | ||
|
||
</Project> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
using System; | ||
using System.Buffers; | ||
|
||
class Example | ||
{ | ||
static void Main() | ||
{ | ||
IMemoryOwner<char> owner = MemoryPool<char>.Shared.Rent(); | ||
|
||
Console.Write("Enter a number: "); | ||
try { | ||
var value = Int32.Parse(Console.ReadLine()); | ||
|
||
var memory = owner.Memory; | ||
|
||
WriteInt32ToBuffer(value, memory); | ||
|
||
DisplayBufferToConsole(owner.Memory.Slice(0, value.ToString().Length)); | ||
} | ||
catch (FormatException) { | ||
Console.WriteLine("You did not enter a valid number."); | ||
} | ||
catch (OverflowException) { | ||
Console.WriteLine($"You entered a number less than {Int32.MinValue:N0} or greater than {Int32.MaxValue:N0}."); | ||
} | ||
finally { | ||
owner?.Dispose(); | ||
} | ||
} | ||
|
||
static void WriteInt32ToBuffer(int value, Memory<char> buffer) | ||
{ | ||
var strValue = value.ToString(); | ||
|
||
var span = buffer.Span; | ||
for (int ctr = 0; ctr < strValue.Length; ctr++) | ||
span[ctr] = strValue[ctr]; | ||
} | ||
|
||
static void DisplayBufferToConsole(Memory<char> buffer) => | ||
Console.WriteLine($"Contents of the buffer: '{buffer}'"); | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<OutputType>Exe</OutputType> | ||
<TargetFramework>netcoreapp2.1</TargetFramework> | ||
<RootNamespace>Visual_Studio_Projects</RootNamespace> | ||
</PropertyGroup> | ||
|
||
</Project> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
using System; | ||
|
||
class Example | ||
{ | ||
static void Main() | ||
{ | ||
Memory<char> memory = new char[64]; | ||
|
||
Console.Write("Enter a number: "); | ||
var value = Int32.Parse(Console.ReadLine()); | ||
|
||
WriteInt32ToBuffer(value, memory); | ||
DisplayBufferToConsole(memory); | ||
} | ||
|
||
static void WriteInt32ToBuffer(int value, Memory<char> buffer) | ||
{ | ||
var strValue = value.ToString(); | ||
strValue.AsSpan().CopyTo(buffer.Slice(0, strValue.Length).Span); | ||
} | ||
|
||
static void DisplayBufferToConsole(Memory<char> buffer) => | ||
Console.WriteLine($"Contents of the buffer: '{buffer}'"); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<OutputType>Exe</OutputType> | ||
<TargetFramework>netcoreapp2.1</TargetFramework> | ||
<RootNamespace>Visual_Studio_Projects</RootNamespace> | ||
</PropertyGroup> | ||
|
||
</Project> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
// <Snippet1> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why does this file have two separate |
||
using System; | ||
using System.Buffers; | ||
using System.IO; | ||
using System.Threading.Tasks; | ||
|
||
public class Example | ||
{ | ||
// <Snippet1> | ||
// An acceptable implementation. | ||
static void Log(ReadOnlyMemory<char> message) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd prefer seeing this method return the Unless, what you're showing is how |
||
{ | ||
// Run in the background so that we don't block the main thread while performing IO. | ||
Task.Run(() => { | ||
StreamWriter sw = File.AppendText(@".\input-numbers.dat"); | ||
sw.WriteLine(message); | ||
sw.Flush(); | ||
}); | ||
} | ||
// </Snippet1> | ||
|
||
// user code | ||
public static void Main() | ||
{ | ||
using (var owner = MemoryPool<char>.Shared.Rent()) | ||
{ | ||
var memory = owner.Memory; | ||
var span = memory.Span; | ||
while (true) | ||
{ | ||
int value = Int32.Parse(Console.ReadLine()); | ||
if (value < 0) | ||
return; | ||
|
||
int numCharsWritten = ToBuffer(value, span); | ||
Log(memory.Slice(0, numCharsWritten)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If |
||
} | ||
} | ||
} | ||
|
||
private static int ToBuffer(int value, Span<char> span) | ||
{ | ||
string strValue = value.ToString(); | ||
int length = strValue.Length; | ||
strValue.AsSpan().CopyTo(span.Slice(0, length)); | ||
return length; | ||
} | ||
} | ||
// </Snippet1> | ||
|
||
// Possible implementation of Log: | ||
// private static void Log(ReadOnlyMemory<char> message) | ||
// { | ||
// Console.WriteLine(message); | ||
// } |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<OutputType>Exe</OutputType> | ||
<TargetFramework>netcoreapp2.1</TargetFramework> | ||
<RootNamespace>void_returning</RootNamespace> | ||
</PropertyGroup> | ||
|
||
</Project> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
using System; | ||
using System.Buffers; | ||
using System.IO; | ||
using System.Threading.Tasks; | ||
|
||
public class Example | ||
{ | ||
// <Snippet1> | ||
// An acceptable implementation. | ||
static Task Log(ReadOnlyMemory<char> message) | ||
{ | ||
// Run in the background so that we don't block the main thread while performing IO. | ||
return Task.Run(() => { | ||
StreamWriter sw = File.AppendText(@".\input-numbers.dat"); | ||
sw.WriteLine(message); | ||
sw.Flush(); | ||
}); | ||
} | ||
// </Snippet1> | ||
|
||
// user code | ||
public static void Main() | ||
{ | ||
using (var owner = MemoryPool<char>.Shared.Rent()) | ||
{ | ||
var memory = owner.Memory; | ||
var span = memory.Span; | ||
while (true) | ||
{ | ||
int value = Int32.Parse(Console.ReadLine()); | ||
if (value < 0) | ||
return; | ||
|
||
int numCharsWritten = ToBuffer(value, span); | ||
Log(memory.Slice(0, numCharsWritten)); | ||
} | ||
} | ||
} | ||
|
||
private static int ToBuffer(int value, Span<char> span) | ||
{ | ||
string strValue = value.ToString(); | ||
int length = strValue.Length; | ||
strValue.AsSpan().CopyTo(span.Slice(0, length)); | ||
return length; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<OutputType>Exe</OutputType> | ||
<TargetFramework>netcoreapp2.1</TargetFramework> | ||
<RootNamespace>void_returning</RootNamespace> | ||
<LangVersion>latest</LangVersion> | ||
</PropertyGroup> | ||
|
||
</Project> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
// <Snippet1> | ||
using System; | ||
using System.Buffers; | ||
using System.IO; | ||
using System.Threading.Tasks; | ||
|
||
public class Example | ||
{ | ||
// <Snippet1> | ||
// An acceptable implementation. | ||
static void Log(ReadOnlyMemory<char> message) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same comment on async as the previous samples. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That won't work, since spans aren't allowed in async methods. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @rpetrusha @BillWagner does the code use this There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @pkulikov You are right. I read Ron's related PR in dotnet/docs and yes, Memory and ReadonlyMemory are not ref structs. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh, I see: though the |
||
{ | ||
// Run in the background so that we don't block the main thread while performing IO. | ||
Task.Run(() => { | ||
string defensiveCopy = message.ToString(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this defensive copy is too late. The The defensive copy should happen before the |
||
StreamWriter sw = File.AppendText(@".\input-numbers.dat"); | ||
sw.WriteLine(defensiveCopy); | ||
sw.Flush(); | ||
}); | ||
} | ||
// </Snippet1> | ||
|
||
// user code | ||
public static void Main() | ||
{ | ||
using (var owner = MemoryPool<char>.Shared.Rent()) | ||
{ | ||
var memory = owner.Memory; | ||
var span = memory.Span; | ||
while (true) | ||
{ | ||
int value = Int32.Parse(Console.ReadLine()); | ||
if (value < 0) | ||
return; | ||
|
||
int numCharsWritten = ToBuffer(value, span); | ||
Log(memory.Slice(0, numCharsWritten)); | ||
} | ||
} | ||
} | ||
|
||
private static int ToBuffer(int value, Span<char> span) | ||
{ | ||
string strValue = value.ToString(); | ||
int length = strValue.Length; | ||
strValue.AsSpan().CopyTo(span.Slice(0, length)); | ||
return length; | ||
} | ||
} | ||
// </Snippet1> | ||
|
||
// Possible implementation of Log: | ||
// private static void Log(ReadOnlyMemory<char> message) | ||
// { | ||
// Console.WriteLine(message); | ||
// } |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<OutputType>Exe</OutputType> | ||
<TargetFramework>netcoreapp2.1</TargetFramework> | ||
<RootNamespace>void_returning</RootNamespace> | ||
</PropertyGroup> | ||
|
||
</Project> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
// <Snippet1> | ||
using System; | ||
using System.Buffers; | ||
|
||
public class Example | ||
{ | ||
// implementation provided by third party | ||
static extern void Log(ReadOnlyMemory<char> message); | ||
|
||
// user code | ||
public static void Main() | ||
{ | ||
using (var owner = MemoryPool<char>.Shared.Rent()) | ||
{ | ||
var memory = owner.Memory; | ||
var span = memory.Span; | ||
while (true) | ||
{ | ||
int value = Int32.Parse(Console.ReadLine()); | ||
if (value < 0) | ||
return; | ||
|
||
int numCharsWritten = ToBuffer(value, span); | ||
Log(memory.Slice(0, numCharsWritten)); | ||
} | ||
} | ||
} | ||
|
||
private static int ToBuffer(int value, Span<char> span) | ||
{ | ||
string strValue = value.ToString(); | ||
int length = strValue.Length; | ||
strValue.AsSpan().CopyTo(span.Slice(0, length)); | ||
return length; | ||
} | ||
} | ||
// </Snippet1> | ||
|
||
// Possible implementation of Log: | ||
// private static void Log(ReadOnlyMemory<char> message) | ||
// { | ||
// Console.WriteLine(message); | ||
// } |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<OutputType>Exe</OutputType> | ||
<TargetFramework>netcoreapp2.1</TargetFramework> | ||
<RootNamespace>void_returning</RootNamespace> | ||
</PropertyGroup> | ||
|
||
</Project> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What are the guarantees about the size of the returned buffer when you don't specify
minBufferSize
, like here? The documentation forMemoryPool<T>
is missing, so that doesn't help.WriteInt32ToBuffer
relies on the fact that it's at least ~11 bytes, which is almost certainly nowhere near the limit. But mostMemory
-related code will have to deal with the possibility of a too small buffer somehow, so maybe it's worth handling here?