PageRenderTime 27ms CodeModel.GetById 8ms RepoModel.GetById 0ms app.codeStats 0ms

/EmlenMud/BrainTechLLC.ThreadSafeObjects/ThreadSafeObjects/ThreadSafeLookupNonRef.cs

#
C# | 344 lines | 277 code | 55 blank | 12 comment | 23 complexity | 86f5394060457442e38626af07a14f39 MD5 | raw file
  1. // Original author contact info: Owen Emlen (owene_1998@yahoo.com)
  2. // Note: other individuals may also have contributed to this code
  3. // Project hosted on CodePlex.com as of 1/10/2009 at http://www.codeplex.com/EmlenMud
  4. using System;
  5. using System.Xml.Serialization;
  6. using System.Runtime.Serialization;
  7. using System.Linq;
  8. using System.Collections.Generic;
  9. using System.Collections.Specialized;
  10. using System.Collections;
  11. using System.ComponentModel;
  12. #if USE_HYPER
  13. using Hyper.ComponentModel;
  14. #endif
  15. namespace BrainTechLLC.ThreadSafeObjects
  16. {
  17. /// <summary>
  18. /// Thread-safe lookup allows multiple threads to look up items by key, add items,
  19. /// and remove items in a thread-safe manner
  20. /// </summary>
  21. /// <typeparam name="TListType"></typeparam>
  22. /// <typeparam name="TIndex"></typeparam>
  23. #if NO_SILVERLIGHT
  24. [TypeDescriptionProvider(typeof(HyperTypeDescriptionProvider))]
  25. #endif
  26. [Serializable]
  27. [DataContract]
  28. public class ThreadSafeLookupNonRef<TIndex, TListType> : Lockable, INotifyCollectionChanged,
  29. IDictionary<TIndex, TListType>, IMultipleItems<TListType>, ISupportsCount
  30. {
  31. public override string ToString()
  32. {
  33. return Count.ToString();
  34. }
  35. // add track changes
  36. [NonSerialized, XmlIgnore]
  37. public bool Modified;
  38. [DataMember]
  39. public Dictionary<TIndex, TListType> Lookup = new Dictionary<TIndex, TListType>();
  40. #if NO_SILVERLIGHT
  41. [EditorBrowsable(EditorBrowsableState.Always)]
  42. #endif
  43. public TListType[] ArrayOfItems { get { return AllItems.ToArray(); } }
  44. #if NO_SILVERLIGHT
  45. [EditorBrowsable(EditorBrowsableState.Always)]
  46. #endif
  47. public int Count { get { return Lookup.Count; } }
  48. public bool ContainsKey(TIndex key) { return Lookup.ContainsKey(key); }
  49. public bool TryGetValue(TIndex key, out TListType items) { return Lookup.TryGetValue(key, out items); }
  50. public bool Remove(KeyValuePair<TIndex, TListType> kvp)
  51. {
  52. return Remove(kvp.Key, kvp.Value);
  53. }
  54. #if NO_SILVERLIGHT
  55. [EditorBrowsable(EditorBrowsableState.Never), Browsable(false)]
  56. #endif
  57. public List<TListType> AllItems
  58. {
  59. get
  60. {
  61. List<TListType> items = new List<TListType>(Lookup.Count);
  62. AquireLock();
  63. {
  64. foreach (KeyValuePair<TIndex, TListType> kvp in Lookup)
  65. items.Add(kvp.Value);
  66. }
  67. ReleaseLock();
  68. return items;
  69. }
  70. }
  71. public bool AddMultiple(IEnumerable<TIndex> keys, IList<TListType> values)
  72. {
  73. List<TListType> addedItems = null;
  74. bool added = false;
  75. int n = 0;
  76. if (CollectionChanged != null)
  77. addedItems = new List<TListType>();
  78. AquireLock();
  79. {
  80. foreach (TIndex key in keys)
  81. {
  82. if (!Lookup.ContainsKey(key))
  83. {
  84. Lookup.Add(key, values[n]);
  85. if (addedItems != null) addedItems.Add(values[n]);
  86. Modified = true;
  87. added = true;
  88. }
  89. n++;
  90. }
  91. }
  92. ReleaseLock();
  93. if (added)
  94. OnNotifyCollectionChanged(NotifyCollectionChangedAction.Add, addedItems);
  95. return added;
  96. }
  97. public bool Add(TIndex key, TListType item)
  98. {
  99. bool found = true;
  100. AquireLock();
  101. {
  102. if (!Lookup.ContainsKey(key))
  103. {
  104. Lookup.Add(key, item);
  105. Modified = true;
  106. found = false;
  107. }
  108. }
  109. ReleaseLock();
  110. if (!found)
  111. OnNotifyCollectionChanged(NotifyCollectionChangedAction.Add, item);
  112. return !found;
  113. }
  114. public void AddOrSet(TIndex key, TListType item)
  115. {
  116. if (Lookup.ContainsKey(key))
  117. {
  118. TListType old = default(TListType);
  119. Lookup.TryGetValue(key, out old);
  120. if (!old.Equals(item))
  121. {
  122. Lookup[key] = item;
  123. Modified = true;
  124. if (CollectionChanged != null)
  125. OnNotifyCollectionChanged(NotifyCollectionChangedAction.Replace, new List<TListType>() { old, item });
  126. }
  127. }
  128. else
  129. {
  130. Add(key, item);
  131. OnNotifyCollectionChanged(NotifyCollectionChangedAction.Add, item);
  132. }
  133. }
  134. public TListType this[TIndex key]
  135. {
  136. get
  137. {
  138. TListType item;
  139. // Not totally safe for lookups that frequently add/remove items.
  140. // For thread safety, surround the following line with AquireLock(); / ReleaseLock();
  141. if (!Lookup.TryGetValue(key, out item)) item = default(TListType);
  142. return item;
  143. }
  144. set
  145. {
  146. AddOrSet(key, value);
  147. }
  148. }
  149. public bool Remove(TIndex key, TListType item)
  150. {
  151. return Remove(key);
  152. }
  153. public bool Remove(TIndex key)
  154. {
  155. bool removed = false;
  156. if (!Lookup.ContainsKey(key))
  157. return false;
  158. TListType item = default(TListType);
  159. AquireLock();
  160. {
  161. if (Lookup.TryGetValue(key, out item))
  162. {
  163. Lookup.Remove(key);
  164. Modified = true;
  165. removed = true;
  166. }
  167. }
  168. ReleaseLock();
  169. if (removed)
  170. OnNotifyCollectionChanged(NotifyCollectionChangedAction.Remove, item);
  171. return removed;
  172. }
  173. public void Clear()
  174. {
  175. IList<TListType> items = null;
  176. if (CollectionChanged != null)
  177. items = new List<TListType>(AllItems);
  178. AquireLock();
  179. {
  180. Lookup.Clear();
  181. Modified = true;
  182. }
  183. ReleaseLock();
  184. OnNotifyCollectionChanged(NotifyCollectionChangedAction.Reset, items);
  185. }
  186. System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
  187. {
  188. return Lookup.GetEnumerator();
  189. }
  190. public IEnumerator<KeyValuePair<TIndex, TListType>> GetEnumerator()
  191. {
  192. return Lookup.GetEnumerator();
  193. }
  194. #if NO_SILVERLIGHT
  195. [EditorBrowsable(EditorBrowsableState.Never), Browsable(false)]
  196. #endif
  197. public bool IsReadOnly { get { return false; } }
  198. #if NO_SILVERLIGHT
  199. [EditorBrowsable(EditorBrowsableState.Never), Browsable(false)]
  200. #endif
  201. public List<TIndex> Keys
  202. {
  203. get
  204. {
  205. List<TIndex> items = new List<TIndex>(Lookup.Count);
  206. AquireLock(); { Lookup.ForEach(kvp => items.Add(kvp.Key)); } ReleaseLock();
  207. return items;
  208. }
  209. }
  210. public void OnNotifyCollectionChanged(NotifyCollectionChangedAction action, IList<TListType> changedItems)
  211. {
  212. if (CollectionChanged != null)
  213. {
  214. switch (action)
  215. {
  216. case NotifyCollectionChangedAction.Add:
  217. CollectionChanged(this, new NotifyCollectionChangedEventArgsEx<TListType>(action, changedItems));
  218. break;
  219. case NotifyCollectionChangedAction.Remove:
  220. CollectionChanged(this, new NotifyCollectionChangedEventArgsEx<TListType>(action, changedItems));
  221. break;
  222. case NotifyCollectionChangedAction.Replace:
  223. CollectionChanged(this, new NotifyCollectionChangedEventArgsEx<TListType>(action, changedItems[0], changedItems[1]));
  224. break;
  225. case NotifyCollectionChangedAction.Reset:
  226. CollectionChanged(this, new NotifyCollectionChangedEventArgsEx<TListType>(action));
  227. break;
  228. }
  229. }
  230. }
  231. public void OnNotifyCollectionChanged(NotifyCollectionChangedAction action, TListType changedItem)
  232. {
  233. if (CollectionChanged != null)
  234. OnNotifyCollectionChanged(action, new List<TListType>() { changedItem });
  235. }
  236. #region INotifyCollectionChanged Members
  237. #if NO_SILVERLIGHT
  238. [field: NonSerialized]
  239. public event NotifyCollectionChangedEventHandler CollectionChanged;
  240. #else
  241. [field: NonSerialized]
  242. public event EventHandler<NotifyCollectionChangedEventArgsEx<TListType>> CollectionChanged;
  243. #endif
  244. #endregion
  245. #region IDictionary<TIndex,TListType> Members
  246. void IDictionary<TIndex, TListType>.Add(TIndex key, TListType value)
  247. {
  248. this.Add(key, value);
  249. }
  250. #if NO_SILVERLIGHT
  251. [EditorBrowsable(EditorBrowsableState.Never), Browsable(false)]
  252. #endif
  253. ICollection<TIndex> IDictionary<TIndex, TListType>.Keys
  254. {
  255. get { return Lookup.Keys; }
  256. }
  257. #if NO_SILVERLIGHT
  258. [EditorBrowsable(EditorBrowsableState.Never), Browsable(false)]
  259. #endif
  260. public ICollection<TListType> Values
  261. {
  262. get { return Lookup.Values; }
  263. }
  264. #endregion
  265. #region ICollection<KeyValuePair<TIndex,TListType>> Members
  266. public void Add(KeyValuePair<TIndex, TListType> item)
  267. {
  268. Add(item.Key, item.Value);
  269. }
  270. public bool Contains(KeyValuePair<TIndex, TListType> item)
  271. {
  272. return Lookup.Contains(item);
  273. }
  274. #endregion
  275. #region ICollection<KeyValuePair<TIndex,TListType>> Members
  276. public void CopyTo(KeyValuePair<TIndex, TListType>[] array, int arrayIndex)
  277. {
  278. AquireLock();
  279. {
  280. foreach (KeyValuePair<TIndex, TListType> item in Lookup)
  281. {
  282. array[arrayIndex++] = item;
  283. }
  284. }
  285. ReleaseLock();
  286. }
  287. #endregion
  288. }
  289. }