Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 41 additions & 34 deletions spec/unsafe-code.md
Original file line number Diff line number Diff line change
Expand Up @@ -1040,75 +1040,79 @@ Except for the `stackalloc` operator, C# provides no predefined constructs for m
using System;
using System.Runtime.InteropServices;

public unsafe class Memory
public static unsafe class Memory
{
// Handle for the process heap. This handle is used in all calls to the
// HeapXXX APIs in the methods below.
static int ph = GetProcessHeap();

// Private instance constructor to prevent instantiation.
private Memory() {}
private static readonly IntPtr s_heap = GetProcessHeap();

// Allocates a memory block of the given size. The allocated memory is
// automatically initialized to zero.
public static void* Alloc(int size) {
void* result = HeapAlloc(ph, HEAP_ZERO_MEMORY, size);
public static void* Alloc(int size)
{
void* result = HeapAlloc(s_heap, HEAP_ZERO_MEMORY, (UIntPtr)size);
if (result == null) throw new OutOfMemoryException();
return result;
}

// Copies count bytes from src to dst. The source and destination
// blocks are permitted to overlap.
public static void Copy(void* src, void* dst, int count) {
public static void Copy(void* src, void* dst, int count)
{
byte* ps = (byte*)src;
byte* pd = (byte*)dst;
if (ps > pd) {
if (ps > pd)
{
for (; count != 0; count--) *pd++ = *ps++;
}
else if (ps < pd) {
else if (ps < pd)
{
for (ps += count, pd += count; count != 0; count--) *--pd = *--ps;
}
}

// Frees a memory block.
public static void Free(void* block) {
if (!HeapFree(ph, 0, block)) throw new InvalidOperationException();
public static void Free(void* block)
{
if (!HeapFree(s_heap, 0, block)) throw new InvalidOperationException();
}

// Re-allocates a memory block. If the reallocation request is for a
// larger size, the additional region of memory is automatically
// initialized to zero.
public static void* ReAlloc(void* block, int size) {
void* result = HeapReAlloc(ph, HEAP_ZERO_MEMORY, block, size);
public static void* ReAlloc(void* block, int size)
{
void* result = HeapReAlloc(s_heap, HEAP_ZERO_MEMORY, block, (UIntPtr)size);
if (result == null) throw new OutOfMemoryException();
return result;
}

// Returns the size of a memory block.
public static int SizeOf(void* block) {
int result = HeapSize(ph, 0, block);
public static int SizeOf(void* block)
{
int result = (int)HeapSize(s_heap, 0, block);
if (result == -1) throw new InvalidOperationException();
return result;
}

// Heap API flags
const int HEAP_ZERO_MEMORY = 0x00000008;
private const int HEAP_ZERO_MEMORY = 0x00000008;

// Heap API functions
[DllImport("kernel32")]
static extern int GetProcessHeap();
private static extern IntPtr GetProcessHeap();

[DllImport("kernel32")]
static extern void* HeapAlloc(int hHeap, int flags, int size);
private static extern void* HeapAlloc(IntPtr hHeap, int flags, UIntPtr size);

[DllImport("kernel32")]
static extern bool HeapFree(int hHeap, int flags, void* block);
private static extern bool HeapFree(IntPtr hHeap, int flags, void* block);

[DllImport("kernel32")]
static extern void* HeapReAlloc(int hHeap, int flags, void* block, int size);
private static extern void* HeapReAlloc(IntPtr hHeap, int flags, void* block, UIntPtr size);

[DllImport("kernel32")]
static extern int HeapSize(int hHeap, int flags, void* block);
private static extern UIntPtr HeapSize(IntPtr hHeap, int flags, void* block);
}
```

Expand All @@ -1117,18 +1121,21 @@ An example that uses the `Memory` class is given below:
```csharp
class Test
{
static void Main() {
unsafe {
byte* buffer = (byte*)Memory.Alloc(256);
try {
for (int i = 0; i < 256; i++) buffer[i] = (byte)i;
byte[] array = new byte[256];
fixed (byte* p = array) Memory.Copy(buffer, p, 256);
}
finally {
Memory.Free(buffer);
}
for (int i = 0; i < 256; i++) Console.WriteLine(array[i]);
static unsafe void Main()
{
byte* buffer = null;
try
{
const int Size = 256;
buffer = (byte*)Memory.Alloc(Size);
for (int i = 0; i < Size; i++) buffer[i] = (byte)i;
byte[] array = new byte[Size];
fixed (byte* p = array) Memory.Copy(buffer, p, Size);
for (int i = 0; i < Size; i++) Console.WriteLine(array[i]);
}
finally
{
if (buffer != null) Memory.Free(buffer);
}
}
}
Expand Down