Mirror of Svelto.ECS because we're a fan of it
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

292 lines
6.8KB

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Threading;
  4. namespace Svelto.DataStructures
  5. {
  6. /// <summary>
  7. /// original code: http://devplanet.com/blogs/brianr/archive/2008/09/29/thread-safe-dictionary-update.aspx
  8. /// simplified (not an IDictionary) and apdated (uses FasterList)
  9. /// </summary>
  10. /// <typeparam name = "TKey"></typeparam>
  11. /// <typeparam name = "TValue"></typeparam>
  12. [Serializable]
  13. public class ThreadSafeDictionary<TKey, TValue>
  14. {
  15. public ThreadSafeDictionary(int v)
  16. {
  17. dict = new Dictionary<TKey, TValue>(v);
  18. }
  19. public ThreadSafeDictionary()
  20. {
  21. dict = new Dictionary<TKey, TValue>();
  22. }
  23. // setup the lock;
  24. public virtual int Count
  25. {
  26. get
  27. {
  28. LockQ.EnterReadLock();
  29. try
  30. {
  31. return dict.Count;
  32. }
  33. finally
  34. {
  35. LockQ.ExitReadLock();
  36. }
  37. }
  38. }
  39. public virtual bool IsReadOnly
  40. {
  41. get
  42. {
  43. LockQ.EnterReadLock();
  44. try
  45. {
  46. return dict.IsReadOnly;
  47. }
  48. finally
  49. {
  50. LockQ.ExitReadLock();
  51. }
  52. }
  53. }
  54. public virtual FasterList<TKey> Keys
  55. {
  56. get
  57. {
  58. LockQ.EnterReadLock();
  59. try
  60. {
  61. return new FasterList<TKey>(dict.Keys);
  62. }
  63. finally
  64. {
  65. LockQ.ExitReadLock();
  66. }
  67. }
  68. }
  69. public virtual FasterList<TValue> Values
  70. {
  71. get
  72. {
  73. LockQ.EnterReadLock();
  74. try
  75. {
  76. return new FasterList<TValue>(dict.Values);
  77. }
  78. finally
  79. {
  80. LockQ.ExitReadLock();
  81. }
  82. }
  83. }
  84. public virtual TValue this[TKey key]
  85. {
  86. get
  87. {
  88. LockQ.EnterReadLock();
  89. try
  90. {
  91. return dict[key];
  92. }
  93. finally
  94. {
  95. LockQ.ExitReadLock();
  96. }
  97. }
  98. set
  99. {
  100. LockQ.EnterWriteLock();
  101. try
  102. {
  103. dict[key] = value;
  104. }
  105. finally
  106. {
  107. LockQ.ExitWriteLock();
  108. }
  109. }
  110. }
  111. public virtual void Add(KeyValuePair<TKey, TValue> item)
  112. {
  113. LockQ.EnterWriteLock();
  114. try
  115. {
  116. dict.Add(item);
  117. }
  118. finally
  119. {
  120. LockQ.ExitWriteLock();
  121. }
  122. }
  123. public virtual void Clear()
  124. {
  125. LockQ.EnterWriteLock();
  126. try
  127. {
  128. dict.Clear();
  129. }
  130. finally
  131. {
  132. LockQ.ExitWriteLock();
  133. }
  134. }
  135. public virtual bool Contains(KeyValuePair<TKey, TValue> item)
  136. {
  137. LockQ.EnterReadLock();
  138. try
  139. {
  140. return dict.Contains(item);
  141. }
  142. finally
  143. {
  144. LockQ.ExitReadLock();
  145. }
  146. }
  147. public virtual void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
  148. {
  149. LockQ.EnterReadLock();
  150. try
  151. {
  152. dict.CopyTo(array, arrayIndex);
  153. }
  154. finally
  155. {
  156. LockQ.ExitReadLock();
  157. }
  158. }
  159. public virtual bool Remove(KeyValuePair<TKey, TValue> item)
  160. {
  161. LockQ.EnterWriteLock();
  162. try
  163. {
  164. return dict.Remove(item);
  165. }
  166. finally
  167. {
  168. LockQ.ExitWriteLock();
  169. }
  170. }
  171. public virtual void Add(TKey key, TValue value)
  172. {
  173. LockQ.EnterWriteLock();
  174. try
  175. {
  176. dict.Add(key, value);
  177. }
  178. finally
  179. {
  180. LockQ.ExitWriteLock();
  181. }
  182. }
  183. public virtual bool ContainsKey(TKey key)
  184. {
  185. LockQ.EnterReadLock();
  186. try
  187. {
  188. return dict.ContainsKey(key);
  189. }
  190. finally
  191. {
  192. LockQ.ExitReadLock();
  193. }
  194. }
  195. public virtual bool Remove(TKey key)
  196. {
  197. LockQ.EnterWriteLock();
  198. try
  199. {
  200. return dict.Remove(key);
  201. }
  202. finally
  203. {
  204. LockQ.ExitWriteLock();
  205. }
  206. }
  207. public virtual bool TryGetValue(TKey key, out TValue value)
  208. {
  209. LockQ.EnterReadLock();
  210. try
  211. {
  212. return dict.TryGetValue(key, out value);
  213. }
  214. finally
  215. {
  216. LockQ.ExitReadLock();
  217. }
  218. }
  219. /// <summary>
  220. /// Merge does a blind remove, and then add. Basically a blind Upsert.
  221. /// </summary>
  222. /// <param name = "key">Key to lookup</param>
  223. /// <param name = "newValue">New Value</param>
  224. public void MergeSafe(TKey key, TValue newValue)
  225. {
  226. LockQ.EnterWriteLock();
  227. try
  228. {
  229. // take a writelock immediately since we will always be writing
  230. if (dict.ContainsKey(key))
  231. dict.Remove(key);
  232. dict.Add(key, newValue);
  233. }
  234. finally
  235. {
  236. LockQ.ExitWriteLock();
  237. }
  238. }
  239. /// <summary>
  240. /// This is a blind remove. Prevents the need to check for existence first.
  241. /// </summary>
  242. /// <param name = "key">Key to remove</param>
  243. public void RemoveSafe(TKey key)
  244. {
  245. LockQ.EnterReadLock();
  246. try
  247. {
  248. if (dict.ContainsKey(key))
  249. LockQ.EnterWriteLock();
  250. try
  251. {
  252. dict.Remove(key);
  253. }
  254. finally
  255. {
  256. LockQ.ExitWriteLock();
  257. }
  258. }
  259. finally
  260. {
  261. LockQ.ExitReadLock();
  262. }
  263. }
  264. // This is the internal dictionary that we are wrapping
  265. readonly IDictionary<TKey, TValue> dict;
  266. readonly ReaderWriterLockSlim LockQ = new ReaderWriterLockSlim();
  267. }
  268. }