singrdk/base/Libraries/System.Net/Sockets/TrackedBytesBuffer.sg

162 lines
5.0 KiB
Plaintext
Raw Permalink Normal View History

2008-03-05 09:52:00 -05:00
////////////////////////////////////////////////////////////////////////////////
//
// Microsoft Research Singularity
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Note:
// A utility class that can store vectors of bytes from the shared heap without
// duplicating them, then copy them out later as though they were a single
// uninterrupted array of bytes.
//
using Microsoft.SingSharp;
using Microsoft.SingSharp.Runtime;
using Microsoft.Singularity;
using Microsoft.Singularity.Channels;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
namespace System.Net.Sockets
{
internal class TrackedBytesBuffer
{
private class BytesPlusCount : ITracked
{
int nextOffset; // Offset of the next byte to use
byte[]! in ExHeap bytes; // The bytes
public BytesPlusCount([Claims]byte[]! in ExHeap data)
{
bytes = data;
nextOffset = 0;
base();
}
#region ITracked members
void ITracked.Release() {}
void ITracked.Acquire() {}
public void Dispose()
{
delete bytes;
}
void ITracked.Expose() {}
void ITracked.UnExpose() {}
#endregion
public int Length
{
get {
expose(this) {
return bytes.Length - nextOffset;
}
}
}
public bool Empty
{
get {
expose(this) {
return nextOffset >= bytes.Length;
}
}
}
// Copy out as many bytes as possible
public int CopyOut(byte[]! buff, int offset, int length, bool fPeek)
{
if (Length <= 0) {
return 0;
}
int numToCopy = Math.Min(length, Length);
expose (this) {
2008-11-17 18:29:00 -05:00
for (int i = 0; i < numToCopy; ++i) {
2008-03-05 09:52:00 -05:00
buff[offset + i] = bytes[nextOffset + i];
}
}
if (!fPeek) {
nextOffset += numToCopy;
}
// else it's as if the copy never happened
return numToCopy;
}
}
// Contains TContainer<BytesPlusCount>
private Queue m_DataQueue;
// Count of the total bytes that we (logically) contain
private int m_Count;
public TrackedBytesBuffer()
{
m_DataQueue = new Queue();
m_Count = 0;
}
public void AddToTail([Claims] byte[]! in ExHeap bytes)
{
m_Count += bytes.Length;
BytesPlusCount! holder = new BytesPlusCount(bytes);
m_DataQueue.Enqueue(new TContainer<BytesPlusCount>(holder));
}
// Copy data out into a supplied buffer. If fPeek is true, it means we
// would copy out the exact same bytes if called again.
public int CopyFromHead(byte[]! buffer, int offset, int length, bool fPeek)
{
int bytesCopied = 0;
2008-11-17 18:29:00 -05:00
while ((m_DataQueue.Count > 0) && (bytesCopied < length)) {
2008-03-05 09:52:00 -05:00
// Don't dequeue just yet, just peek
TContainer<BytesPlusCount> wrapper = (TContainer<BytesPlusCount>)m_DataQueue.Peek();
assert wrapper != null; // Because we checked the count
BytesPlusCount! topChunk = wrapper.Acquire();
int copied = topChunk.CopyOut(buffer, offset + bytesCopied,
length - bytesCopied, fPeek);
bytesCopied += copied;
if ((!fPeek) && (topChunk.Empty)) {
// We want to throw away the top chunk. To take pressure off
// the finalizer, we'll explicitly free the ExHeap data vector.
topChunk.Dispose();
m_DataQueue.Dequeue();
}
else if ((!fPeek) && (!topChunk.Empty)) {
// This should only happen because we filled up the
// caller's buffer
Debug.Assert(bytesCopied == length);
// Put the data back into its wrapper
wrapper.Release(topChunk);
}
else {
// Release topChunk back
wrapper.Release(topChunk);
}
}
if (!fPeek) {
m_Count -= bytesCopied;
Debug.Assert(m_Count >= 0);
}
return bytesCopied;
}
public int Count
{
get { return m_Count; }
}
}
}