File: Base\MS\Internal\IO\Packaging\TrackingMemoryStream.cs
Project: wpf\src\WindowsBase.csproj (WindowsBase)
//-----------------------------------------------------------------------------
//
// <copyright file="TrackingMemoryStream.cs" company="Microsoft">
//    Copyright (C) Microsoft Corporation.  All rights reserved.
// </copyright>
//
// Description:
//  This is a stream that is capable of reporting data usage up to the registered
//  owner 
//
// History:
//  05/24/2005: IgorBel: Initial creation.
//  11/08/2005: BruceMac: Change namespace
//
//-----------------------------------------------------------------------------
 
using System;
using System.Diagnostics;
using System.IO;
 
namespace MS.Internal.IO.Packaging
{
    // making this class sealed as it is taking advantage of some Virtual methods 
    // in MemoryStream(Capacity); therefore, there is a danger of subclass overriding those and unexpected 
    // behavior changes. Consider calls from Constructor->ReportIfNecessary->Capacity 
    // prior to unsealing this class (they would be marked as FxCop violations) 
    internal sealed class TrackingMemoryStream : MemoryStream
    {
        // other constructors can be added later, as we need them, for now we only use the following 2  
        internal TrackingMemoryStream(ITrackingMemoryStreamFactory memoryStreamFactory): base()
        {
            // although we could have implemented this constructor in terms of the other constructor; we shouldn't. 
            // It seems safer to always call the equivalent base class constructor, as we might be ignorant about 
            // some minor differences between various MemoryStream constructors
            Debug.Assert(memoryStreamFactory != null);            
            _memoryStreamFactory = memoryStreamFactory;
            ReportIfNeccessary();
        }
            
        internal TrackingMemoryStream (ITrackingMemoryStreamFactory memoryStreamFactory, Int32 capacity) : base(capacity)
        {
            Debug.Assert(memoryStreamFactory != null);
            _memoryStreamFactory = memoryStreamFactory;
            ReportIfNeccessary();
        }
 
 
        // Here are the overrides for members that could possible result in changes in the allocated memory 
        public override int Read(byte[] buffer, int offset, int count)
        {
            int result = base.Read(buffer, offset, count);
 
            ReportIfNeccessary();
            return result;
        }
 
        public override void Write(byte[] buffer, int offset, int count)
        {
            base.Write(buffer, offset, count);
 
            ReportIfNeccessary();
        }
 
        public override void SetLength(long value)
        {
            base.SetLength(value);
 
            ReportIfNeccessary();
        }
 
        protected override void Dispose(bool disposing)
        {
            try
            {
                if (disposing)
                {
                    if (_memoryStreamFactory != null)
                    {
                        // release all the memory, and report it to the TrackingMemoryStreamFactory 
                        SetLength(0);
                        Capacity = 0;
                        ReportIfNeccessary();
                        _memoryStreamFactory = null;
                    }
                }
            }
            finally
            {
                base.Dispose(disposing);
            }
        }
 
        private void ReportIfNeccessary ()        
        {
            if (this.Capacity !=_lastReportedHighWaterMark)
            {
                // we need to report the new memory being allocated as a part of the constructor  
                _memoryStreamFactory.ReportMemoryUsageDelta(checked(this.Capacity - _lastReportedHighWaterMark));
                _lastReportedHighWaterMark = this.Capacity;
            }
        }
        
        private ITrackingMemoryStreamFactory _memoryStreamFactory;
        private int _lastReportedHighWaterMark;
    }
}