164 lines
5.0 KiB
Plaintext
164 lines
5.0 KiB
Plaintext
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Microsoft Research Singularity
|
|
//
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//
|
|
// File: TrackedBytesBuffer.sg
|
|
//
|
|
// 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) {
|
|
for(int i = 0; i < numToCopy; ++i) {
|
|
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;
|
|
|
|
while((m_DataQueue.Count > 0) && (bytesCopied < length)) {
|
|
// 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; }
|
|
}
|
|
}
|
|
}
|