Team Ai
Datasetpublic

MegaBites-AI/Windows-powershell

sourceHugging Facemitupdated 6mo agoView on Hugging Face
0likes372downloads
OutputQueue.cs334 linesDownload Raw Back to common
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4using System;5using System.Collections.Generic;6using System.Diagnostics;7 8namespace Microsoft.PowerShell.Commands.Internal.Format9{10    /// <summary>11    /// Queue to provide sliding window capabilities for auto size functionality12    /// It provides caching capabilities (either the first N objects in a group13    /// or all the objects in a group)14    /// </summary>15    internal sealed class OutputGroupQueue16    {17        /// <summary>18        /// Create a grouping cache.19        /// </summary>20        /// <param name="callBack">Notification callback to be called when the desired number of objects is reached.</param>21        /// <param name="objectCount">Max number of objects to be cached.</param>22        internal OutputGroupQueue(FormattedObjectsCache.ProcessCachedGroupNotification callBack, int objectCount)23        {24            _notificationCallBack = callBack;25            _objectCount = objectCount;26        }27 28        /// <summary>29        /// Create a time-bounded grouping cache.30        /// </summary>31        /// <param name="callBack">Notification callback to be called when the desired number of objects is reached.</param>32        /// <param name="groupingDuration">Max amount of time to cache of objects.</param>33        internal OutputGroupQueue(FormattedObjectsCache.ProcessCachedGroupNotification callBack, TimeSpan groupingDuration)34        {35            _notificationCallBack = callBack;36            _groupingDuration = groupingDuration;37        }38 39        /// <summary>40        /// Add an object to the cache.41        /// </summary>42        /// <param name="o">Object to add.</param>43        /// <returns>Objects the cache needs to return. It can be null.</returns>44        internal List<PacketInfoData> Add(PacketInfoData o)45        {46            if (o is FormatStartData fsd)47            {48                // just cache the reference (used during the notification call)49                _formatStartData = fsd;50            }51 52            UpdateObjectCount(o);53 54            // STATE TRANSITION: we are not processing and we start55            if (!_processingGroup && (o is GroupStartData))56            {57                // just set the flag and start caching58                _processingGroup = true;59                _currentObjectCount = 0;60 61                if (_groupingDuration > TimeSpan.MinValue)62                {63                    _groupingTimer = Stopwatch.StartNew();64                }65 66                _queue.Enqueue(o);67                return null;68            }69 70            // STATE TRANSITION: we are processing and we stop71            if (_processingGroup &&72                ((o is GroupEndData) ||73                (_objectCount > 0) && (_currentObjectCount >= _objectCount)) ||74                ((_groupingTimer != null) && (_groupingTimer.Elapsed > _groupingDuration))75                )76            {77                // reset the object count78                _currentObjectCount = 0;79 80                if (_groupingTimer != null)81                {82                    _groupingTimer.Stop();83                    _groupingTimer = null;84                }85 86                // add object to queue, to be picked up87                _queue.Enqueue(o);88 89                // we are at the end of a group, drain the queue90                Notify();91                _processingGroup = false;92 93                List<PacketInfoData> retVal = new List<PacketInfoData>();94 95                while (_queue.Count > 0)96                {97                    retVal.Add(_queue.Dequeue());98                }99 100                return retVal;101            }102 103            // NO STATE TRANSITION: check the state we are in104            if (_processingGroup)105            {106                // we are in the caching state107                _queue.Enqueue(o);108                return null;109            }110 111            // we are not processing, so just return it112            List<PacketInfoData> ret = new List<PacketInfoData>();113 114            ret.Add(o);115            return ret;116        }117 118        private void UpdateObjectCount(PacketInfoData o)119        {120            // add only of it's not a control message121            // and it's not out of band122            if (o is FormatEntryData fed && !fed.outOfBand)123            {124                _currentObjectCount++;125            }126        }127 128        private void Notify()129        {130            if (_notificationCallBack == null)131                return;132 133            // filter out the out of band data, since they do not participate in the134            // auto resize algorithm135            List<PacketInfoData> validObjects = new List<PacketInfoData>();136 137            foreach (PacketInfoData x in _queue)138            {139                if (x is FormatEntryData fed && fed.outOfBand)140                    continue;141 142                validObjects.Add(x);143            }144 145            _notificationCallBack(_formatStartData, validObjects);146        }147 148        /// <summary>149        /// Remove a single object from the queue.150        /// </summary>151        /// <returns>Object retrieved, null if queue is empty.</returns>152        internal PacketInfoData Dequeue()153        {154            if (_queue.Count == 0)155                return null;156 157            return _queue.Dequeue();158        }159 160        /// <summary>161        /// Queue to store the currently cached objects.162        /// </summary>163        private readonly Queue<PacketInfoData> _queue = new Queue<PacketInfoData>();164 165        /// <summary>166        /// Number of objects to compute the best fit.167        /// Zero: all the objects168        /// a positive number N: use the first N.169        /// </summary>170        private readonly int _objectCount = 0;171 172        /// <summary>173        /// Maximum amount of time for record processing to compute the best fit.174        /// MaxValue: all the objects.175        /// A positive timespan: use all objects that have been processed within the timeframe.176        /// </summary>177        private readonly TimeSpan _groupingDuration = TimeSpan.MinValue;178        private Stopwatch _groupingTimer = null;179 180        /// <summary>181        /// Notification callback to be called when we have accumulated enough182        /// data to compute a hint.183        /// </summary>184        private readonly FormattedObjectsCache.ProcessCachedGroupNotification _notificationCallBack = null;185 186        /// <summary>187        /// Reference kept to be used during notification.188        /// </summary>189        private FormatStartData _formatStartData = null;190 191        /// <summary>192        /// State flag to signal we are queuing.193        /// </summary>194        private bool _processingGroup = false;195 196        /// <summary>197        /// Current object count.198        /// </summary>199        private int _currentObjectCount = 0;200    }201 202    /// <summary>203    /// Facade class managing the front end and the autosize cache.204    /// </summary>205    internal sealed class FormattedObjectsCache206    {207        /// <summary>208        /// Delegate to allow notifications when the autosize queue is about to be drained.209        /// </summary>210        /// <param name="formatStartData">Current Fs control message.</param>211        /// <param name="objects">Enumeration of PacketInfoData objects.</param>212        internal delegate void ProcessCachedGroupNotification(FormatStartData formatStartData, List<PacketInfoData> objects);213 214        /// <summary>215        /// Decide right away if we need a front end cache (e.g. printing)216        /// </summary>217        /// <param name="cacheFrontEnd">If true, create a front end cache object.</param>218        internal FormattedObjectsCache(bool cacheFrontEnd)219        {220            if (cacheFrontEnd)221                _frontEndQueue = new Queue<PacketInfoData>();222        }223 224        /// <summary>225        /// If needed, add a back end autosize (grouping) cache.226        /// </summary>227        /// <param name="callBack">Notification callback to be called when the desired number of objects is reached.</param>228        /// <param name="objectCount">Max number of objects to be cached.</param>229        internal void EnableGroupCaching(ProcessCachedGroupNotification callBack, int objectCount)230        {231            if (callBack != null)232                _groupQueue = new OutputGroupQueue(callBack, objectCount);233        }234 235        /// <summary>236        /// If needed, add a back end autosize (grouping) cache.237        /// </summary>238        /// <param name="callBack">Notification callback to be called when the desired number of objects is reached.</param>239        /// <param name="groupingDuration">Max amount of time to cache of objects.</param>240        internal void EnableGroupCaching(ProcessCachedGroupNotification callBack, TimeSpan groupingDuration)241        {242            if (callBack != null)243                _groupQueue = new OutputGroupQueue(callBack, groupingDuration);244        }245 246        /// <summary>247        /// Add an object to the cache. the behavior depends on the object added, the248        /// objects already in the cache and the cache settings.249        /// </summary>250        /// <param name="o">Object to add.</param>251        /// <returns>List of objects the cache is flushing.</returns>252        internal List<PacketInfoData> Add(PacketInfoData o)253        {254            // if neither there, pass thru255            if (_frontEndQueue == null && _groupQueue == null)256            {257                List<PacketInfoData> retVal = new List<PacketInfoData>();258                retVal.Add(o);259                return retVal;260            }261 262            // if front present, add to front263            if (_frontEndQueue != null)264            {265                _frontEndQueue.Enqueue(o);266                return null;267            }268 269            // if back only, add to back270            return _groupQueue.Add(o);271        }272 273        /// <summary>274        /// Remove all the objects from the cache.275        /// </summary>276        /// <returns>All the objects that were in the cache.</returns>277        internal List<PacketInfoData> Drain()278        {279            // if neither there,we did not cache at all280            if (_frontEndQueue == null && _groupQueue == null)281            {282                return null;283            }284 285            List<PacketInfoData> retVal = new List<PacketInfoData>();286 287            if (_frontEndQueue != null)288            {289                if (_groupQueue == null)290                {291                    // drain the front queue and return the data292                    while (_frontEndQueue.Count > 0)293                        retVal.Add(_frontEndQueue.Dequeue());294 295                    return retVal;296                }297 298                // move from the front to the back queue299                while (_frontEndQueue.Count > 0)300                {301                    List<PacketInfoData> groupQueueOut = _groupQueue.Add(_frontEndQueue.Dequeue());302 303                    if (groupQueueOut != null)304                        foreach (PacketInfoData x in groupQueueOut)305                            retVal.Add(x);306                }307            }308 309            // drain the back queue310            while (true)311            {312                PacketInfoData obj = _groupQueue.Dequeue();313 314                if (obj == null)315                    break;316 317                retVal.Add(obj);318            }319 320            return retVal;321        }322 323        /// <summary>324        /// Front end queue (if present, cache ALL, if not, bypass)325        /// </summary>326        private readonly Queue<PacketInfoData> _frontEndQueue;327 328        /// <summary>329        /// Back end grouping queue.330        /// </summary>331        private OutputGroupQueue _groupQueue = null;332    }333}334