mirror of
https://github.com/aphrody-labs/PowerShell.git
synced 2026-10-16 06:39:25 +00:00
435 lines
12 KiB
C#
435 lines
12 KiB
C#
/********************************************************************++
|
|
Copyright (c) Microsoft Corporation. All rights reserved.
|
|
--********************************************************************/
|
|
|
|
#pragma warning disable 1634, 1691
|
|
#pragma warning disable 56517
|
|
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Collections.ObjectModel;
|
|
using Dbg = System.Management.Automation.Diagnostics;
|
|
|
|
namespace System.Management.Automation.Runspaces
|
|
{
|
|
internal delegate void RunspaceConfigurationEntryUpdateEventHandler();
|
|
|
|
/// <summary>
|
|
/// Define class for runspace configuration entry collection.
|
|
/// </summary>
|
|
/// <!--
|
|
/// Runspace configuration entry collection is used for handling following
|
|
/// problems for runspace configuration entries.
|
|
///
|
|
/// 1. synchronization. Since multiple runspaces may be sharing the same
|
|
/// runspace configuration, it is essential all the entry collections
|
|
/// (cmdlets, providers, assemblies, types, formats) are thread-safe.
|
|
/// 2. prepending/appending. Data for types and formats are order
|
|
/// sensitive. It is required for supporting prepending/appending to
|
|
/// the list and ability to remove the prepended/appended items.
|
|
/// 3. update. Update to the data needs to be communicated to other monad
|
|
/// components. For example, if cmdlets/providers list is updated, it
|
|
/// has to be communicated to engine.
|
|
/// -->
|
|
#if CORECLR
|
|
internal
|
|
#else
|
|
public
|
|
#endif
|
|
sealed class RunspaceConfigurationEntryCollection<T> : IEnumerable<T> where T : RunspaceConfigurationEntry
|
|
{
|
|
/// <summary>
|
|
/// Constructor
|
|
/// </summary>
|
|
public RunspaceConfigurationEntryCollection()
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Constructor
|
|
/// </summary>
|
|
/// <param name="items"></param>
|
|
public RunspaceConfigurationEntryCollection(IEnumerable<T> items)
|
|
{
|
|
if (items == null)
|
|
{
|
|
throw PSTraceSource.NewArgumentNullException("item");
|
|
}
|
|
AddBuiltInItem(items);
|
|
}
|
|
|
|
private Collection<T> _data = new Collection<T>();
|
|
private int _builtInEnd = 0; // this is the index of first after item.
|
|
|
|
private Collection<T> _updateList = new Collection<T>();
|
|
internal Collection<T> UpdateList
|
|
{
|
|
get
|
|
{
|
|
return _updateList;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get items at a index position.
|
|
/// </summary>
|
|
/// <param name="index"></param>
|
|
/// <returns></returns>
|
|
public T this[int index]
|
|
{
|
|
get
|
|
{
|
|
lock (_syncObject)
|
|
{
|
|
return _data[index];
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get number of items in the collection.
|
|
/// </summary>
|
|
public int Count
|
|
{
|
|
get
|
|
{
|
|
lock (_syncObject)
|
|
{
|
|
return _data.Count;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Reset items in the collection
|
|
/// </summary>
|
|
public void Reset()
|
|
{
|
|
lock (_syncObject)
|
|
{
|
|
for (int i = _data.Count - 1; i >= 0; i--)
|
|
{
|
|
if (!_data[i].BuiltIn)
|
|
{
|
|
RecordRemove(_data[i]);
|
|
|
|
_data.RemoveAt(i);
|
|
}
|
|
}
|
|
|
|
_builtInEnd = _data.Count;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Remove one item from the collection
|
|
/// </summary>
|
|
/// <param name="index"></param>
|
|
/// <exception cref="PSArgumentOutOfRangeException">when <paramref name="index"/> is out of range.</exception>
|
|
public void RemoveItem(int index)
|
|
{
|
|
lock (_syncObject)
|
|
{
|
|
if (index < 0 || index >= _data.Count)
|
|
{
|
|
throw PSTraceSource.NewArgumentOutOfRangeException("index", index);
|
|
}
|
|
|
|
RecordRemove(_data[index]);
|
|
|
|
_data.RemoveAt(index);
|
|
|
|
if (index < _builtInEnd)
|
|
_builtInEnd--;
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Remove multiple items in the collection.
|
|
/// </summary>
|
|
/// <param name="index"></param>
|
|
/// <param name="count"></param>
|
|
/// <exception cref="PSArgumentOutOfRangeException">when <paramref name="index"/> is out of range.</exception>
|
|
public void RemoveItem(int index, int count)
|
|
{
|
|
lock (_syncObject)
|
|
{
|
|
if (index < 0 || index + count > _data.Count)
|
|
{
|
|
throw PSTraceSource.NewArgumentOutOfRangeException("index", index);
|
|
}
|
|
|
|
for (int i = index + count - 1; i >= index; i--)
|
|
{
|
|
RecordRemove(_data[i]);
|
|
|
|
_data.RemoveAt(i);
|
|
}
|
|
|
|
int _numBeforeBuiltInEnd = Math.Min(count, _builtInEnd - index);
|
|
|
|
if (_numBeforeBuiltInEnd > 0)
|
|
_builtInEnd -= _numBeforeBuiltInEnd;
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Remove one item from the collection
|
|
/// </summary>
|
|
/// <param name="item"></param>
|
|
internal void Remove(T item)
|
|
{
|
|
lock (_syncObject)
|
|
{
|
|
int index = _data.IndexOf(item);
|
|
|
|
if (index < 0 || index >= _data.Count)
|
|
{
|
|
Dbg.Assert(false, "Index from which to remove the item is out of range.");
|
|
throw PSTraceSource.NewArgumentOutOfRangeException("index", index);
|
|
}
|
|
|
|
RecordRemove(item);
|
|
_data.Remove(item);
|
|
|
|
if (index < _builtInEnd)
|
|
_builtInEnd--;
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Prepend an item to the collection.
|
|
/// </summary>
|
|
/// <param name="item"></param>
|
|
public void Prepend(T item)
|
|
{
|
|
lock (_syncObject)
|
|
{
|
|
RecordAdd(item);
|
|
|
|
item._builtIn = false;
|
|
_data.Insert(0, item);
|
|
_builtInEnd++;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Prepend items into the collection
|
|
/// </summary>
|
|
/// <param name="items"></param>
|
|
public void Prepend(IEnumerable<T> items)
|
|
{
|
|
if (items == null)
|
|
{
|
|
throw new ArgumentNullException("items");
|
|
}
|
|
|
|
lock (_syncObject)
|
|
{
|
|
int i = 0;
|
|
foreach (T t in items)
|
|
{
|
|
RecordAdd(t);
|
|
|
|
t._builtIn = false;
|
|
_data.Insert(i++, t);
|
|
_builtInEnd++;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Append one item to the collection
|
|
/// </summary>
|
|
/// <param name="item"></param>
|
|
public void Append(T item)
|
|
{
|
|
lock (_syncObject)
|
|
{
|
|
RecordAdd(item);
|
|
|
|
item._builtIn = false;
|
|
_data.Add(item);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Append items to the collection.
|
|
/// </summary>
|
|
/// <param name="items"></param>
|
|
public void Append(IEnumerable<T> items)
|
|
{
|
|
if (items == null)
|
|
{
|
|
throw new ArgumentNullException("items");
|
|
}
|
|
|
|
lock (_syncObject)
|
|
{
|
|
foreach (T t in items)
|
|
{
|
|
RecordAdd(t);
|
|
|
|
t._builtIn = false;
|
|
_data.Add(t);
|
|
}
|
|
}
|
|
}
|
|
|
|
internal void AddBuiltInItem(T item)
|
|
{
|
|
lock (_syncObject)
|
|
{
|
|
item._builtIn = true;
|
|
|
|
RecordAdd(item);
|
|
|
|
_data.Insert(_builtInEnd, item);
|
|
_builtInEnd++;
|
|
}
|
|
}
|
|
|
|
internal void AddBuiltInItem(IEnumerable<T> items)
|
|
{
|
|
lock (_syncObject)
|
|
{
|
|
foreach (T t in items)
|
|
{
|
|
t._builtIn = true;
|
|
|
|
RecordAdd(t);
|
|
|
|
_data.Insert(_builtInEnd, t);
|
|
_builtInEnd++;
|
|
}
|
|
}
|
|
}
|
|
|
|
internal void RemovePSSnapIn(string PSSnapinName)
|
|
{
|
|
lock (_syncObject)
|
|
{
|
|
for (int i = _data.Count - 1; i >= 0; i--)
|
|
{
|
|
if (_data[i].PSSnapIn != null)
|
|
{
|
|
if (_data[i].PSSnapIn.Name.Equals(PSSnapinName, StringComparison.Ordinal))
|
|
{
|
|
RecordRemove(_data[i]);
|
|
|
|
_data.RemoveAt(i);
|
|
|
|
if (i < _builtInEnd)
|
|
_builtInEnd--;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get enumerator for this collection.
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
/// <!--
|
|
/// Enumerator work is not thread safe by default. Any code trying
|
|
/// to do enumeration on this collection should lock it first.
|
|
///
|
|
/// Need to document this.
|
|
/// -->
|
|
IEnumerator System.Collections.IEnumerable.GetEnumerator()
|
|
{
|
|
return _data.GetEnumerator();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get enumerator for this collection.
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
/// <!--
|
|
/// Enumerator work is not thread safe by default. Any code trying
|
|
/// to do enumeration on this collection should lock it first.
|
|
///
|
|
/// Need to document this.
|
|
/// -->
|
|
IEnumerator<T> System.Collections.Generic.IEnumerable<T>.GetEnumerator()
|
|
{
|
|
return _data.GetEnumerator();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Update others about the collection change.
|
|
/// </summary>
|
|
public void Update()
|
|
{
|
|
Update(false);
|
|
}
|
|
|
|
internal void Update(bool force)
|
|
{
|
|
lock (_syncObject)
|
|
{
|
|
if (OnUpdate != null && (force || _updateList.Count > 0))
|
|
{
|
|
OnUpdate();
|
|
|
|
// Here we need to clear the Action for each item
|
|
// since _updateList is sharing data with _data.
|
|
foreach (T t in _updateList)
|
|
{
|
|
t._action = UpdateAction.None;
|
|
}
|
|
|
|
_updateList.Clear();
|
|
}
|
|
}
|
|
}
|
|
|
|
private void RecordRemove(T t)
|
|
{
|
|
// if this item was added recently, simply remove the add action.
|
|
if (t.Action == UpdateAction.Add)
|
|
{
|
|
t._action = UpdateAction.None;
|
|
_updateList.Remove(t);
|
|
}
|
|
else
|
|
{
|
|
t._action = UpdateAction.Remove;
|
|
_updateList.Add(t);
|
|
}
|
|
}
|
|
|
|
private void RecordAdd(T t)
|
|
{
|
|
// if this item was removed recently, simply remove the add action.
|
|
if (t.Action == UpdateAction.Remove)
|
|
{
|
|
t._action = UpdateAction.None;
|
|
_updateList.Remove(t);
|
|
}
|
|
else
|
|
{
|
|
t._action = UpdateAction.Add;
|
|
_updateList.Add(t);
|
|
}
|
|
}
|
|
|
|
//object to use for locking
|
|
private object _syncObject = new object();
|
|
|
|
/// <summary>
|
|
/// OnUpdate handler should lock the object itself.
|
|
/// </summary>
|
|
internal event RunspaceConfigurationEntryUpdateEventHandler OnUpdate;
|
|
}
|
|
}
|
|
|
|
#pragma warning restore 56517
|