Client LuaCsForBarotrauma
CursedDictionary.cs
1 #if DEBUG && MODBREAKER
2 #nullable enable
3 using System;
4 using System.Collections;
5 using System.Collections.Generic;
6 using System.Linq;
8 
9 namespace Barotrauma
10 {
17  public class CursedDictionary<TKey, TValue> : IDictionary<TKey, TValue>, IReadOnlyDictionary<TKey, TValue> where TKey: notnull
18  {
19  private ICollection<TKey> keys;
20  private ICollection<TValue> values;
21  private readonly List<KeyValuePair<TKey, TValue>> keyValuePairs = new List<KeyValuePair<TKey, TValue>>();
22  private readonly Dictionary<TKey, int> keyToKvpIndex = new Dictionary<TKey, int>();
23  private readonly object mutex = new object();
24 
25  private readonly Random rng;
26 
27  public CursedDictionary()
28  {
29  rng = new Random((int)(DateTime.Now.ToBinary() % int.MaxValue));
30  keys = Array.Empty<TKey>();
31  values = Array.Empty<TValue>();
32  }
33 
34  private void Refresh()
35  {
36  keys = keyValuePairs.Select(kvp => kvp.Key).ToArray();
37  values = keyValuePairs.Select(kvp => kvp.Value).ToArray();
38  keyToKvpIndex.Clear();
39  for (int i=0; i<keyValuePairs.Count; i++)
40  {
41  keyToKvpIndex[keyValuePairs[i].Key] = i;
42  }
43  }
44 
45  public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
46  {
47  KeyValuePair<TKey, TValue>[] clone;
48  lock (mutex)
49  {
50  keyValuePairs.Shuffle(rng);
51  Refresh();
52  clone = keyValuePairs.ToArray();
53  }
54 
55  foreach (var kvp in clone)
56  {
57  yield return kvp;
58  }
59  }
60 
61  IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
62 
63  public void Add(KeyValuePair<TKey, TValue> item)
64  {
65  lock (mutex)
66  {
67  if (keyToKvpIndex.ContainsKey(item.Key))
68  {
69  throw new InvalidOperationException($"Duplicate key: {item.Key}");
70  }
71 
72  keyValuePairs.Add(item);
73  keyValuePairs.Shuffle(rng);
74  Refresh();
75  }
76  }
77 
78  public void Clear()
79  {
80  lock (mutex)
81  {
82  keyValuePairs.Clear();
83  Refresh();
84  }
85  }
86 
87  public bool Contains(KeyValuePair<TKey, TValue> item)
88  {
89  lock (mutex)
90  {
91  return keyValuePairs.Contains(item);
92  }
93  }
94 
95  public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
96  {
97  lock (mutex)
98  {
99  keyValuePairs.Shuffle(rng);
100  keyValuePairs.CopyTo(array, arrayIndex);
101  Refresh();
102  }
103  }
104 
105  public bool Remove(KeyValuePair<TKey, TValue> item)
106  {
107  lock (mutex)
108  {
109  bool success = keyValuePairs.Remove(item);
110  keyValuePairs.Shuffle(rng);
111  Refresh();
112  return success;
113  }
114  }
115 
116  public int Count
117  {
118  get
119  {
120  lock (mutex)
121  {
122  return keyValuePairs.Count;
123  }
124  }
125  }
126 
127  public bool IsReadOnly => false;
128 
129  public void Add(TKey key, TValue value) => Add(new KeyValuePair<TKey, TValue>(key, value));
130 
131  public bool ContainsKey(TKey key)
132  {
133  lock (mutex)
134  {
135  return keyToKvpIndex.ContainsKey(key);
136  }
137  }
138 
139  public bool TryGetValue(TKey key, out TValue value)
140  {
141  lock (mutex)
142  {
143  value = default!;
144  bool success = keyToKvpIndex.TryGetValue(key, out int index);
145  if (success)
146  {
147  value = keyValuePairs[index].Value;
148  }
149 
150  keyValuePairs.Shuffle(rng);
151  Refresh();
152  return success;
153  }
154  }
155 
156  public bool Remove(TKey key) => TryRemove(key, out _);
157 
158  public bool TryRemove(TKey key, out TValue value)
159  {
160  lock (mutex)
161  {
162  value = default!;
163  bool success = false;
164  if (keyToKvpIndex.TryGetValue(key, out int index))
165  {
166  value = keyValuePairs[index].Value;
167  keyValuePairs.RemoveAt(index);
168  success = true;
169  }
170 
171  keyValuePairs.Shuffle(rng);
172  Refresh();
173  return success;
174  }
175  }
176 
177  public TValue this[TKey key]
178  {
179  get
180  {
181  lock (mutex)
182  {
183  return keyValuePairs[keyToKvpIndex[key]].Value;
184  }
185  }
186  set
187  {
188  lock (mutex)
189  {
190  if (!keyToKvpIndex.ContainsKey(key))
191  {
192  Add(key, value);
193  }
194  else
195  {
196  keyValuePairs[keyToKvpIndex[key]] = new KeyValuePair<TKey, TValue>(key, value);
197  }
198 
199  keyValuePairs.Shuffle(rng);
200  Refresh();
201  }
202  }
203  }
204 
205 
206  public ICollection<TKey> Keys
207  {
208  get
209  {
210  lock (mutex)
211  {
212  return keys.ToArray();
213  }
214  }
215  }
216  public ICollection<TValue> Values
217  {
218  get
219  {
220  lock (mutex)
221  {
222  return values.ToArray();
223  }
224  }
225  }
226 
227  IEnumerable<TKey> IReadOnlyDictionary<TKey, TValue>.Keys => Keys;
228  IEnumerable<TValue> IReadOnlyDictionary<TKey, TValue>.Values => Values;
229  }
230 }
231 #endif