A game about forced loneliness, made by TACStudios
1using System; 2using System.Collections; 3using System.Collections.Generic; 4 5namespace Unity.VisualScripting 6{ 7 public class ConnectionCollectionBase<TConnection, TSource, TDestination, TCollection> : IConnectionCollection<TConnection, TSource, TDestination> 8 where TConnection : IConnection<TSource, TDestination> 9 where TCollection : ICollection<TConnection> 10 { 11 public ConnectionCollectionBase(TCollection collection) 12 { 13 this.collection = collection; 14 bySource = new Dictionary<TSource, List<TConnection>>(); 15 byDestination = new Dictionary<TDestination, List<TConnection>>(); 16 } 17 18 // Using lists instead of HashSet to allow access by index 19 // instead of creating an enumeration and allocating memory 20 // specifically for the "With*NoAlloc" methods, used 21 // very often in flow graphs. 22 private readonly Dictionary<TDestination, List<TConnection>> byDestination; 23 private readonly Dictionary<TSource, List<TConnection>> bySource; 24 protected readonly TCollection collection; 25 26 public IEnumerable<TConnection> this[TSource source] => WithSource(source); 27 28 public IEnumerable<TConnection> this[TDestination destination] => WithDestination(destination); 29 30 public int Count => collection.Count; 31 32 public bool IsReadOnly => false; 33 34 public IEnumerator<TConnection> GetEnumerator() 35 { 36 return collection.GetEnumerator(); 37 } 38 39 IEnumerator IEnumerable.GetEnumerator() 40 { 41 return GetEnumerator(); 42 } 43 44 public IEnumerable<TConnection> WithSource(TSource source) 45 { 46 return WithSourceNoAlloc(source); 47 } 48 49 public List<TConnection> WithSourceNoAlloc(TSource source) 50 { 51 Ensure.That(nameof(source)).IsNotNull(source); 52 53 if (bySource.TryGetValue(source, out var withSource)) 54 { 55 return withSource; 56 } 57 else 58 { 59 return Empty<TConnection>.list; 60 } 61 } 62 63 public TConnection SingleOrDefaultWithSource(TSource source) 64 { 65 Ensure.That(nameof(source)).IsNotNull(source); 66 67 if (bySource.TryGetValue(source, out var withSource)) 68 { 69 if (withSource.Count == 1) 70 { 71 return withSource[0]; 72 } 73 else if (withSource.Count == 0) 74 { 75 return default(TConnection); 76 } 77 else 78 { 79 throw new InvalidOperationException(); 80 } 81 } 82 else 83 { 84 return default(TConnection); 85 } 86 } 87 88 public IEnumerable<TConnection> WithDestination(TDestination destination) 89 { 90 return WithDestinationNoAlloc(destination); 91 } 92 93 public List<TConnection> WithDestinationNoAlloc(TDestination destination) 94 { 95 Ensure.That(nameof(destination)).IsNotNull(destination); 96 97 if (byDestination.TryGetValue(destination, out var withDestination)) 98 { 99 return withDestination; 100 } 101 else 102 { 103 return Empty<TConnection>.list; 104 } 105 } 106 107 public TConnection SingleOrDefaultWithDestination(TDestination destination) 108 { 109 Ensure.That(nameof(destination)).IsNotNull(destination); 110 111 if (byDestination.TryGetValue(destination, out var withDestination)) 112 { 113 if (withDestination.Count == 1) 114 { 115 return withDestination[0]; 116 } 117 else if (withDestination.Count == 0) 118 { 119 return default(TConnection); 120 } 121 else 122 { 123 throw new InvalidOperationException(); 124 } 125 } 126 else 127 { 128 return default(TConnection); 129 } 130 } 131 132 public void Add(TConnection item) 133 { 134 if (item == null) 135 { 136 throw new ArgumentNullException(nameof(item)); 137 } 138 139 if (item.source == null) 140 { 141 throw new ArgumentNullException("item.source"); 142 } 143 144 if (item.destination == null) 145 { 146 throw new ArgumentNullException("item.destination"); 147 } 148 149 BeforeAdd(item); 150 collection.Add(item); 151 AddToDictionaries(item); 152 AfterAdd(item); 153 } 154 155 public void Clear() 156 { 157 collection.Clear(); 158 bySource.Clear(); 159 byDestination.Clear(); 160 } 161 162 public bool Contains(TConnection item) 163 { 164 if (item == null) 165 { 166 throw new ArgumentNullException(nameof(item)); 167 } 168 169 return collection.Contains(item); 170 } 171 172 public void CopyTo(TConnection[] array, int arrayIndex) 173 { 174 collection.CopyTo(array, arrayIndex); 175 } 176 177 public bool Remove(TConnection item) 178 { 179 if (item == null) 180 { 181 throw new ArgumentNullException(nameof(item)); 182 } 183 184 if (item.source == null) 185 { 186 throw new ArgumentNullException("item.source"); 187 } 188 189 if (item.destination == null) 190 { 191 throw new ArgumentNullException("item.destination"); 192 } 193 194 if (!collection.Contains(item)) 195 { 196 return false; 197 } 198 199 BeforeRemove(item); 200 collection.Remove(item); 201 RemoveFromDictionaries(item); 202 AfterRemove(item); 203 return true; 204 } 205 206 protected virtual void BeforeAdd(TConnection item) { } 207 protected virtual void AfterAdd(TConnection item) { } 208 protected virtual void BeforeRemove(TConnection item) { } 209 protected virtual void AfterRemove(TConnection item) { } 210 211 private void AddToDictionaries(TConnection item) 212 { 213 if (!bySource.ContainsKey(item.source)) 214 { 215 bySource.Add(item.source, new List<TConnection>()); 216 } 217 218 bySource[item.source].Add(item); 219 220 if (!byDestination.ContainsKey(item.destination)) 221 { 222 byDestination.Add(item.destination, new List<TConnection>()); 223 } 224 225 byDestination[item.destination].Add(item); 226 } 227 228 private void RemoveFromDictionaries(TConnection item) 229 { 230 bySource[item.source].Remove(item); 231 byDestination[item.destination].Remove(item); 232 } 233 } 234}