PageRenderTime 49ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/src/Base/Set`1.cs

https://bitbucket.org/tuldok89/openpdn
C# | 358 lines | 225 code | 58 blank | 75 comment | 7 complexity | 19f612a649283333c3eb652ea4d38328 MD5 | raw file
  1. /////////////////////////////////////////////////////////////////////////////////
  2. // Paint.NET //
  3. // Copyright (C) dotPDN LLC, Rick Brewster, Tom Jackson, and contributors. //
  4. // Portions Copyright (C) Microsoft Corporation. All Rights Reserved. //
  5. // See src/Resources/Files/License.txt for full licensing and attribution //
  6. // details. //
  7. // . //
  8. /////////////////////////////////////////////////////////////////////////////////
  9. using System;
  10. using System.Collections;
  11. using System.Collections.Generic;
  12. using System.Linq;
  13. namespace PaintDotNet.Base
  14. {
  15. /// <summary>
  16. /// Represents an enumerable collection of items. Each item can only be present
  17. /// in the collection once. An item's identity is determined by a combination
  18. /// of the return values from its GetHashCode and Equals methods.
  19. /// This class is analagous to C++'s std::set template class.
  20. /// </summary>
  21. [Serializable]
  22. public class Set<T>
  23. : ICloneable,
  24. ICollection<T>
  25. {
  26. private Dictionary<T, object> _dictionary;
  27. public static Set<T> Intersect(Set<T> set1, Set<T> set2)
  28. {
  29. var intersection = new Set<T>();
  30. foreach (T item in set1.Where(set2.Contains))
  31. {
  32. intersection.Add(item);
  33. }
  34. return intersection;
  35. }
  36. public static Set<T> Union(Set<T> set1, Set<T> set2)
  37. {
  38. var union = new Set<T>(set1);
  39. foreach (T item in set2.Where(item => !union.Contains(item)))
  40. {
  41. union.Add(item);
  42. }
  43. return union;
  44. }
  45. public static Set<T> Without(Set<T> withUs, Set<T> withoutUs)
  46. {
  47. var result = new Set<T>();
  48. foreach (T item in withUs.Where(item => !withoutUs.Contains(item)))
  49. {
  50. result.Add(item);
  51. }
  52. return result;
  53. }
  54. public static bool AreEqual(Set<T> set1, Set<T> set2)
  55. {
  56. if (set1.Count != set2.Count)
  57. {
  58. // Can't be equal if sizes are different
  59. return false;
  60. }
  61. return set1.Count == 0 || set1.All(set2.Contains);
  62. // At this point we know that either everything in set1 is in set2, or
  63. // that there is something in set1 which is not in set2.
  64. }
  65. public bool IsEqualTo(Set<T> set2)
  66. {
  67. return AreEqual(this, set2);
  68. }
  69. public bool IsSubsetOf(Set<T> set2)
  70. {
  71. return this.All(set2.Contains);
  72. }
  73. public Set<T> Without(Set<T> withoutUs)
  74. {
  75. return Without(this, withoutUs);
  76. }
  77. /// <summary>
  78. /// Adds an element to the set.
  79. /// </summary>
  80. /// <param name="item">The object reference to be included in the set.</param>
  81. /// <exception cref="ArgumentNullException">item is a null reference</exception>
  82. /// <exception cref="ArgumentException">item is already in the Set</exception>
  83. public void Add(T item)
  84. {
  85. try
  86. {
  87. _dictionary.Add(item, null);
  88. }
  89. catch (ArgumentNullException e1)
  90. {
  91. throw e1;
  92. }
  93. catch (ArgumentException e2)
  94. {
  95. throw e2;
  96. }
  97. }
  98. public void AddRange(IEnumerable<T> items)
  99. {
  100. foreach (T item in items)
  101. {
  102. Add(item);
  103. }
  104. }
  105. public void AddRange(params T[] items)
  106. {
  107. AddRange((IEnumerable<T>)items);
  108. }
  109. /// <summary>
  110. /// Removes an element from the set.
  111. /// </summary>
  112. /// <param name="item">The object reference to be excluded from the set.</param>
  113. /// <exception cref="ArgumentNullException">item is a null reference</exception>
  114. public bool Remove(T item)
  115. {
  116. try
  117. {
  118. _dictionary.Remove(item);
  119. return true;
  120. }
  121. catch (ArgumentNullException)
  122. {
  123. return false;
  124. }
  125. }
  126. /// <summary>
  127. /// Determines whether the Set includes a specific element.
  128. /// </summary>
  129. /// <param name="item">The object reference to check for.</param>
  130. /// <returns>true if the Set includes item, false if it doesn't.</returns>
  131. /// <exception cref="ArgumentNullException">item is a null reference.</exception>
  132. public bool Contains(T item)
  133. {
  134. try
  135. {
  136. return _dictionary.ContainsKey(item);
  137. }
  138. catch (ArgumentNullException e1)
  139. {
  140. throw e1;
  141. }
  142. }
  143. /// <summary>
  144. /// Constructs an empty Set.
  145. /// </summary>
  146. public Set()
  147. {
  148. _dictionary = new Dictionary<T, object>();
  149. }
  150. /// <summary>
  151. /// Constructs a Set with data copied from the given list.
  152. /// </summary>
  153. /// <param name="cloneMe"></param>
  154. public Set(IEnumerable<T> cloneMe)
  155. {
  156. _dictionary = new Dictionary<T, object>();
  157. foreach (T theObject in cloneMe)
  158. {
  159. Add(theObject);
  160. }
  161. }
  162. public Set(params T[] items)
  163. : this((IEnumerable<T>)items)
  164. {
  165. }
  166. /// <summary>
  167. /// Constructs a copy of a Set.
  168. /// </summary>
  169. /// <param name="copyMe">The Set to copy from.</param>
  170. private Set(Set<T> copyMe)
  171. {
  172. _dictionary = new Dictionary<T, object>(copyMe._dictionary);
  173. }
  174. #region IEnumerable<T> Members
  175. /// <summary>
  176. /// Returns an IEnumerator that can be used to enumerate through the items in the Set.
  177. /// </summary>
  178. /// <returns>An IEnumerator for the Set.</returns>
  179. IEnumerator IEnumerable.GetEnumerator()
  180. {
  181. return _dictionary.Keys.GetEnumerator();
  182. }
  183. public IEnumerator<T> GetEnumerator()
  184. {
  185. return _dictionary.Keys.GetEnumerator();
  186. }
  187. #endregion
  188. public Set<T> Clone()
  189. {
  190. return new Set<T>(this);
  191. }
  192. #region ICloneable Members
  193. /// <summary>
  194. /// Returns a copy of the Set. The elements in the Set are copied by-reference only.
  195. /// </summary>
  196. /// <returns></returns>
  197. object ICloneable.Clone()
  198. {
  199. return Clone();
  200. }
  201. #endregion
  202. #region ICollection<T> Members
  203. /// <summary>
  204. /// Gets a value indicating whether or not the Set is synchronized (thread-safe).
  205. /// </summary>
  206. public bool IsSynchronized
  207. {
  208. get
  209. {
  210. return false;
  211. }
  212. }
  213. /// <summary>
  214. /// Gets a value indicating how many elements are contained within the Set.
  215. /// </summary>
  216. public int Count
  217. {
  218. get
  219. {
  220. return _dictionary.Count;
  221. }
  222. }
  223. /// <summary>
  224. /// Copies the Set elements to a one-dimensional Array instance at a specified index.
  225. /// </summary>
  226. /// <param name="array">The one-dimensional Array that is the destination of the objects copied from the Set. The Array must have zero-based indexing.</param>
  227. /// <param name="index">The zero-based index in array at which copying begins.</param>
  228. /// <exception cref="ArgumentNullException">array is a null reference.</exception>
  229. /// <exception cref="ArgumentOutOfRangeException">index is less than zero.</exception>
  230. /// <exception cref="ArgumentException">The array is not one-dimensional, or the array could not contain the objects copied to it.</exception>
  231. /// <exception cref="IndexOutOfRangeException">The Array does not have enough space, starting from the given offset, to contain all the Set's objects.</exception>
  232. public void CopyTo(T[] array, int index)
  233. {
  234. int i = index;
  235. if (array == null)
  236. {
  237. throw new ArgumentNullException("array");
  238. }
  239. if (index < 0)
  240. {
  241. throw new ArgumentOutOfRangeException("index");
  242. }
  243. foreach (T o in this)
  244. {
  245. try
  246. {
  247. array.SetValue(o, i);
  248. }
  249. catch (ArgumentException e1)
  250. {
  251. throw e1;
  252. }
  253. catch (IndexOutOfRangeException e2)
  254. {
  255. throw e2;
  256. }
  257. ++i;
  258. }
  259. }
  260. /// <summary>
  261. /// Gets an object that can be used to synchronize access to the Set.
  262. /// </summary>
  263. public object SyncRoot
  264. {
  265. get
  266. {
  267. return this;
  268. }
  269. }
  270. #endregion
  271. /// <summary>
  272. /// Copies the elements of the Set to a new generic array.
  273. /// </summary>
  274. /// <returns>An array of object references.</returns>
  275. public T[] ToArray()
  276. {
  277. var array = new T[Count];
  278. int index = 0;
  279. foreach (T o in this)
  280. {
  281. array[index] = o;
  282. ++index;
  283. }
  284. return array;
  285. }
  286. #region ICollection<T> Members
  287. public void Clear()
  288. {
  289. _dictionary = new Dictionary<T, object>();
  290. }
  291. public bool IsReadOnly
  292. {
  293. get
  294. {
  295. return false;
  296. }
  297. }
  298. #endregion
  299. }
  300. }