testss
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
public class ConnectionCollection<TConnection, TSource, TDestination> : ConnectionCollectionBase<TConnection, TSource, TDestination, List<TConnection>>
|
||||
where TConnection : IConnection<TSource, TDestination>
|
||||
{
|
||||
public ConnectionCollection() : base(new List<TConnection>()) { }
|
||||
}
|
||||
}
|
@@ -0,0 +1,234 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
public class ConnectionCollectionBase<TConnection, TSource, TDestination, TCollection> : IConnectionCollection<TConnection, TSource, TDestination>
|
||||
where TConnection : IConnection<TSource, TDestination>
|
||||
where TCollection : ICollection<TConnection>
|
||||
{
|
||||
public ConnectionCollectionBase(TCollection collection)
|
||||
{
|
||||
this.collection = collection;
|
||||
bySource = new Dictionary<TSource, List<TConnection>>();
|
||||
byDestination = new Dictionary<TDestination, List<TConnection>>();
|
||||
}
|
||||
|
||||
// Using lists instead of HashSet to allow access by index
|
||||
// instead of creating an enumeration and allocating memory
|
||||
// specifically for the "With*NoAlloc" methods, used
|
||||
// very often in flow graphs.
|
||||
private readonly Dictionary<TDestination, List<TConnection>> byDestination;
|
||||
private readonly Dictionary<TSource, List<TConnection>> bySource;
|
||||
protected readonly TCollection collection;
|
||||
|
||||
public IEnumerable<TConnection> this[TSource source] => WithSource(source);
|
||||
|
||||
public IEnumerable<TConnection> this[TDestination destination] => WithDestination(destination);
|
||||
|
||||
public int Count => collection.Count;
|
||||
|
||||
public bool IsReadOnly => false;
|
||||
|
||||
public IEnumerator<TConnection> GetEnumerator()
|
||||
{
|
||||
return collection.GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
public IEnumerable<TConnection> WithSource(TSource source)
|
||||
{
|
||||
return WithSourceNoAlloc(source);
|
||||
}
|
||||
|
||||
public List<TConnection> WithSourceNoAlloc(TSource source)
|
||||
{
|
||||
Ensure.That(nameof(source)).IsNotNull(source);
|
||||
|
||||
if (bySource.TryGetValue(source, out var withSource))
|
||||
{
|
||||
return withSource;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Empty<TConnection>.list;
|
||||
}
|
||||
}
|
||||
|
||||
public TConnection SingleOrDefaultWithSource(TSource source)
|
||||
{
|
||||
Ensure.That(nameof(source)).IsNotNull(source);
|
||||
|
||||
if (bySource.TryGetValue(source, out var withSource))
|
||||
{
|
||||
if (withSource.Count == 1)
|
||||
{
|
||||
return withSource[0];
|
||||
}
|
||||
else if (withSource.Count == 0)
|
||||
{
|
||||
return default(TConnection);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return default(TConnection);
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<TConnection> WithDestination(TDestination destination)
|
||||
{
|
||||
return WithDestinationNoAlloc(destination);
|
||||
}
|
||||
|
||||
public List<TConnection> WithDestinationNoAlloc(TDestination destination)
|
||||
{
|
||||
Ensure.That(nameof(destination)).IsNotNull(destination);
|
||||
|
||||
if (byDestination.TryGetValue(destination, out var withDestination))
|
||||
{
|
||||
return withDestination;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Empty<TConnection>.list;
|
||||
}
|
||||
}
|
||||
|
||||
public TConnection SingleOrDefaultWithDestination(TDestination destination)
|
||||
{
|
||||
Ensure.That(nameof(destination)).IsNotNull(destination);
|
||||
|
||||
if (byDestination.TryGetValue(destination, out var withDestination))
|
||||
{
|
||||
if (withDestination.Count == 1)
|
||||
{
|
||||
return withDestination[0];
|
||||
}
|
||||
else if (withDestination.Count == 0)
|
||||
{
|
||||
return default(TConnection);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return default(TConnection);
|
||||
}
|
||||
}
|
||||
|
||||
public void Add(TConnection item)
|
||||
{
|
||||
if (item == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(item));
|
||||
}
|
||||
|
||||
if (item.source == null)
|
||||
{
|
||||
throw new ArgumentNullException("item.source");
|
||||
}
|
||||
|
||||
if (item.destination == null)
|
||||
{
|
||||
throw new ArgumentNullException("item.destination");
|
||||
}
|
||||
|
||||
BeforeAdd(item);
|
||||
collection.Add(item);
|
||||
AddToDictionaries(item);
|
||||
AfterAdd(item);
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
collection.Clear();
|
||||
bySource.Clear();
|
||||
byDestination.Clear();
|
||||
}
|
||||
|
||||
public bool Contains(TConnection item)
|
||||
{
|
||||
if (item == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(item));
|
||||
}
|
||||
|
||||
return collection.Contains(item);
|
||||
}
|
||||
|
||||
public void CopyTo(TConnection[] array, int arrayIndex)
|
||||
{
|
||||
collection.CopyTo(array, arrayIndex);
|
||||
}
|
||||
|
||||
public bool Remove(TConnection item)
|
||||
{
|
||||
if (item == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(item));
|
||||
}
|
||||
|
||||
if (item.source == null)
|
||||
{
|
||||
throw new ArgumentNullException("item.source");
|
||||
}
|
||||
|
||||
if (item.destination == null)
|
||||
{
|
||||
throw new ArgumentNullException("item.destination");
|
||||
}
|
||||
|
||||
if (!collection.Contains(item))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
BeforeRemove(item);
|
||||
collection.Remove(item);
|
||||
RemoveFromDictionaries(item);
|
||||
AfterRemove(item);
|
||||
return true;
|
||||
}
|
||||
|
||||
protected virtual void BeforeAdd(TConnection item) { }
|
||||
protected virtual void AfterAdd(TConnection item) { }
|
||||
protected virtual void BeforeRemove(TConnection item) { }
|
||||
protected virtual void AfterRemove(TConnection item) { }
|
||||
|
||||
private void AddToDictionaries(TConnection item)
|
||||
{
|
||||
if (!bySource.ContainsKey(item.source))
|
||||
{
|
||||
bySource.Add(item.source, new List<TConnection>());
|
||||
}
|
||||
|
||||
bySource[item.source].Add(item);
|
||||
|
||||
if (!byDestination.ContainsKey(item.destination))
|
||||
{
|
||||
byDestination.Add(item.destination, new List<TConnection>());
|
||||
}
|
||||
|
||||
byDestination[item.destination].Add(item);
|
||||
}
|
||||
|
||||
private void RemoveFromDictionaries(TConnection item)
|
||||
{
|
||||
bySource[item.source].Remove(item);
|
||||
byDestination[item.destination].Remove(item);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,83 @@
|
||||
using System;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
public class GraphConnectionCollection<TConnection, TSource, TDestination> :
|
||||
ConnectionCollectionBase<TConnection, TSource, TDestination, GraphElementCollection<TConnection>>,
|
||||
IGraphElementCollection<TConnection>
|
||||
where TConnection : IConnection<TSource, TDestination>, IGraphElement
|
||||
{
|
||||
public GraphConnectionCollection(IGraph graph) : base(new GraphElementCollection<TConnection>(graph))
|
||||
{
|
||||
// The issue of reusing GEC as the internal collection a CCB is that
|
||||
// the add / remove events will NOT be in sync with the CCB's dictionaries
|
||||
// if we just watched the collection's insertion.
|
||||
// Therefore, we must provide a way to let the CCB proxy its own events
|
||||
// and to disable our the GEC's events by default.
|
||||
collection.ProxyCollectionChange = true;
|
||||
}
|
||||
|
||||
TConnection IKeyedCollection<Guid, TConnection>.this[Guid key] => collection[key];
|
||||
|
||||
TConnection IKeyedCollection<Guid, TConnection>.this[int index] => collection[index];
|
||||
|
||||
public bool TryGetValue(Guid key, out TConnection value)
|
||||
{
|
||||
return collection.TryGetValue(key, out value);
|
||||
}
|
||||
|
||||
public bool Contains(Guid key)
|
||||
{
|
||||
return collection.Contains(key);
|
||||
}
|
||||
|
||||
public bool Remove(Guid key)
|
||||
{
|
||||
if (Contains(key))
|
||||
{
|
||||
// Call base remove to remove from dictionaries as well
|
||||
return Remove(collection[key]);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public event Action<TConnection> ItemAdded
|
||||
{
|
||||
add { collection.ItemAdded += value; }
|
||||
remove { collection.ItemAdded -= value; }
|
||||
}
|
||||
|
||||
public event Action<TConnection> ItemRemoved
|
||||
{
|
||||
add { collection.ItemRemoved += value; }
|
||||
remove { collection.ItemRemoved -= value; }
|
||||
}
|
||||
|
||||
public event Action CollectionChanged
|
||||
{
|
||||
add { collection.CollectionChanged += value; }
|
||||
remove { collection.CollectionChanged -= value; }
|
||||
}
|
||||
|
||||
protected override void BeforeAdd(TConnection item)
|
||||
{
|
||||
collection.BeforeAdd(item);
|
||||
}
|
||||
|
||||
protected override void AfterAdd(TConnection item)
|
||||
{
|
||||
collection.AfterAdd(item);
|
||||
}
|
||||
|
||||
protected override void BeforeRemove(TConnection item)
|
||||
{
|
||||
collection.BeforeRemove(item);
|
||||
}
|
||||
|
||||
protected override void AfterRemove(TConnection item)
|
||||
{
|
||||
collection.AfterRemove(item);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,8 @@
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
public interface IConnection<out TSource, out TDestination>
|
||||
{
|
||||
TSource source { get; }
|
||||
TDestination destination { get; }
|
||||
}
|
||||
}
|
@@ -0,0 +1,13 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
public interface IConnectionCollection<TConnection, TSource, TDestination> : ICollection<TConnection>
|
||||
where TConnection : IConnection<TSource, TDestination>
|
||||
{
|
||||
IEnumerable<TConnection> this[TSource source] { get; }
|
||||
IEnumerable<TConnection> this[TDestination destination] { get; }
|
||||
IEnumerable<TConnection> WithSource(TSource source);
|
||||
IEnumerable<TConnection> WithDestination(TDestination destination);
|
||||
}
|
||||
}
|
@@ -0,0 +1,10 @@
|
||||
using System;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
public class InvalidConnectionException : Exception
|
||||
{
|
||||
public InvalidConnectionException() : base("") { }
|
||||
public InvalidConnectionException(string message) : base(message) { }
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user