Lucene.Net  3.0.3
Lucene.Net is a port of the Lucene search engine library, written in C# and targeted at .NET runtime users.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Properties Pages
EquatableList.cs
Go to the documentation of this file.
1 /*
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements. See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership. The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License. You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied. See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20 */
21 
22 using System;
23 using System.Collections;
24 using System.Collections.Generic;
25 
26 namespace Lucene.Net.Support
27 {
28  /// <summary>Represents a strongly typed list of objects that can be accessed by index.
29  /// Provides methods to search, sort, and manipulate lists. Also provides functionality
30  /// to compare lists against each other through an implementations of
31  /// <see cref="IEquatable{T}"/>.</summary>
32  /// <typeparam name="T">The type of elements in the list.</typeparam>
33  [Serializable]
34  public class EquatableList<T> : System.Collections.Generic.List<T>,
35  IEquatable<System.Collections.Generic.IEnumerable<T>>,
36  ICloneable
37  {
38  /// <summary>Initializes a new instance of the
39  /// <see cref="EquatableList{T}"/> class that is empty and has the
40  /// default initial capacity.</summary>
41  public EquatableList() : base() { }
42 
43  /// <summary>Initializes a new instance of the <see cref="EquatableList{T}"/>
44  /// class that contains elements copied from the specified collection and has
45  /// sufficient capacity to accommodate the number of elements copied.</summary>
46  /// <param name="collection">The collection whose elements are copied to the new list.</param>
47  public EquatableList(System.Collections.Generic.IEnumerable<T> collection) : base(collection) { }
48 
49  /// <summary>Initializes a new instance of the <see cref="EquatableList{T}"/>
50  /// class that is empty and has the specified initial capacity.</summary>
51  /// <param name="capacity">The number of elements that the new list can initially store.</param>
52  public EquatableList(int capacity) : base(capacity) { }
53 
54  /// <summary>Adds a range of objects represented by the <see cref="ICollection"/>
55  /// implementation.</summary>
56  /// <param name="c">The <see cref="ICollection"/>
57  /// implementation to add to this list.</param>
58  public void AddRange(ICollection c)
59  {
60  // If the collection is null, throw an exception.
61  if (c == null) throw new ArgumentNullException("c");
62 
63  // Pre-compute capacity.
64  Capacity = Math.Max(c.Count + Count, Capacity);
65 
66  // Cycle through the items and add.
67  foreach (T item in c)
68  {
69  // Add the item.
70  Add(item);
71  }
72  }
73 
74  /// <summary>Compares the counts of two <see cref="System.Collections.Generic.IEnumerable{T}"/>
75  /// implementations.</summary>
76  /// <remarks>This uses a trick in LINQ, sniffing types for implementations
77  /// of interfaces that might supply shortcuts when trying to make comparisons.
78  /// In this case, that is the <see cref="System.Collections.Generic.ICollection{T}"/> and
79  /// <see cref="ICollection"/> interfaces, either of which can provide a count
80  /// which can be used in determining the equality of sequences (if they don't have
81  /// the same count, then they can't be equal).</remarks>
82  /// <param name="x">The <see cref="System.Collections.Generic.IEnumerable{T}"/> from the left hand side of the
83  /// comparison to check the count of.</param>
84  /// <param name="y">The <see cref="System.Collections.Generic.IEnumerable{T}"/> from the right hand side of the
85  /// comparison to check the count of.</param>
86  /// <returns>Null if the result is indeterminate. This occurs when either <paramref name="x"/>
87  /// or <paramref name="y"/> doesn't implement <see cref="ICollection"/> or <see cref="System.Collections.Generic.ICollection{T}"/>.
88  /// Otherwise, it will get the count from each and return true if they are equal, false otherwise.</returns>
89  private static bool? EnumerableCountsEqual(System.Collections.Generic.IEnumerable<T> x, System.Collections.Generic.IEnumerable<T> y)
90  {
91  // Get the ICollection<T> and ICollection interfaces.
92  System.Collections.Generic.ICollection<T> xOfTCollection = x as System.Collections.Generic.ICollection<T>;
93  System.Collections.Generic.ICollection<T> yOfTCollection = y as System.Collections.Generic.ICollection<T>;
94  ICollection xCollection = x as ICollection;
95  ICollection yCollection = y as ICollection;
96 
97  // The count in x and y.
98  int? xCount = xOfTCollection != null ? xOfTCollection.Count : xCollection != null ? xCollection.Count : (int?)null;
99  int? yCount = yOfTCollection != null ? yOfTCollection.Count : yCollection != null ? yCollection.Count : (int?)null;
100 
101  // If either are null, return null, the result is indeterminate.
102  if (xCount == null || yCount == null)
103  {
104  // Return null, indeterminate.
105  return null;
106  }
107 
108  // Both counts are non-null, compare.
109  return xCount == yCount;
110  }
111 
112  /// <summary>Compares the contents of a <see cref="System.Collections.Generic.IEnumerable{T}"/>
113  /// implementation to another one to determine equality.</summary>
114  /// <remarks>Thinking of the <see cref="System.Collections.Generic.IEnumerable{T}"/> implementation as
115  /// a string with any number of characters, the algorithm checks
116  /// each item in each list. If any item of the list is not equal (or
117  /// one list contains all the elements of another list), then that list
118  /// element is compared to the other list element to see which
119  /// list is greater.</remarks>
120  /// <param name="x">The <see cref="System.Collections.Generic.IEnumerable{T}"/> implementation
121  /// that is considered the left hand side.</param>
122  /// <param name="y">The <see cref="System.Collections.Generic.IEnumerable{T}"/> implementation
123  /// that is considered the right hand side.</param>
124  /// <returns>True if the items are equal, false otherwise.</returns>
125  private static bool Equals(System.Collections.Generic.IEnumerable<T> x,
126  System.Collections.Generic.IEnumerable<T> y)
127  {
128  // If x and y are null, then return true, they are the same.
129  if (x == null && y == null)
130  {
131  // They are the same, return 0.
132  return true;
133  }
134 
135  // If one is null, then return a value based on whether or not
136  // one is null or not.
137  if (x == null || y == null)
138  {
139  // Return false, one is null, the other is not.
140  return false;
141  }
142 
143  // Check to see if the counts on the IEnumerable implementations are equal.
144  // This is a shortcut, if they are not equal, then the lists are not equal.
145  // If the result is indeterminate, then get out.
146  bool? enumerableCountsEqual = EnumerableCountsEqual(x, y);
147 
148  // If the enumerable counts have been able to be calculated (indicated by
149  // a non-null value) and it is false, then no need to iterate through the items.
150  if (enumerableCountsEqual != null && !enumerableCountsEqual.Value)
151  {
152  // The sequences are not equal.
153  return false;
154  }
155 
156  // The counts of the items in the enumerations are equal, or indeterminate
157  // so a full iteration needs to be made to compare each item.
158  // Get the default comparer for T first.
159  System.Collections.Generic.EqualityComparer<T> defaultComparer =
160  EqualityComparer<T>.Default;
161 
162  // Get the enumerator for y.
163  System.Collections.Generic.IEnumerator<T> otherEnumerator = y.GetEnumerator();
164 
165  // Call Dispose on IDisposable if there is an implementation on the
166  // IEnumerator<T> returned by a call to y.GetEnumerator().
167  using (otherEnumerator as IDisposable)
168  {
169  // Cycle through the items in this list.
170  foreach (T item in x)
171  {
172  // If there isn't an item to get, then this has more
173  // items than that, they are not equal.
174  if (!otherEnumerator.MoveNext())
175  {
176  // Return false.
177  return false;
178  }
179 
180  // Perform a comparison. Must check this on the left hand side
181  // and that on the right hand side.
182  bool comparison = defaultComparer.Equals(item, otherEnumerator.Current);
183 
184  // If the value is false, return false.
185  if (!comparison)
186  {
187  // Return the value.
188  return comparison;
189  }
190  }
191 
192  // If there are no more items, then return true, the sequences
193  // are equal.
194  if (!otherEnumerator.MoveNext())
195  {
196  // The sequences are equal.
197  return true;
198  }
199 
200  // The other sequence has more items than this one, return
201  // false, these are not equal.
202  return false;
203  }
204  }
205 
206  #region IEquatable<IEnumerable<T>> Members
207  /// <summary>Compares this sequence to another <see cref="System.Collections.Generic.IEnumerable{T}"/>
208  /// implementation, returning true if they are equal, false otherwise.</summary>
209  /// <param name="other">The other <see cref="System.Collections.Generic.IEnumerable{T}"/> implementation
210  /// to compare against.</param>
211  /// <returns>True if the sequence in <paramref name="other"/>
212  /// is the same as this one.</returns>
213  public bool Equals(System.Collections.Generic.IEnumerable<T> other)
214  {
215  // Compare to the other sequence. If 0, then equal.
216  return Equals(this, other);
217  }
218  #endregion
219 
220  /// <summary>Compares this object for equality against other.</summary>
221  /// <param name="obj">The other object to compare this object against.</param>
222  /// <returns>True if this object and <paramref name="obj"/> are equal, false
223  /// otherwise.</returns>
224  public override bool Equals(object obj)
225  {
226  // Call the strongly typed version.
227  return Equals(obj as System.Collections.Generic.IEnumerable<T>);
228  }
229 
230  /// <summary>Gets the hash code for the list.</summary>
231  /// <returns>The hash code value.</returns>
232  public override int GetHashCode()
233  {
234  // Call the static method, passing this.
235  return GetHashCode(this);
236  }
237 
238 #if __MonoCS__
239  public static int GetHashCode<T>(System.Collections.Generic.IEnumerable<T> source)
240 #else
241  /// <summary>Gets the hash code for the list.</summary>
242  /// <param name="source">The <see cref="System.Collections.Generic.IEnumerable{T}"/>
243  /// implementation which will have all the contents hashed.</param>
244  /// <returns>The hash code value.</returns>
245  public static int GetHashCode(System.Collections.Generic.IEnumerable<T> source)
246 #endif
247  {
248  // If source is null, then return 0.
249  if (source == null) return 0;
250 
251  // Seed the hash code with the hash code of the type.
252  // This is done so that you don't have a lot of collisions of empty
253  // ComparableList instances when placed in dictionaries
254  // and things that rely on hashcodes.
255  int hashCode = typeof(T).GetHashCode();
256 
257  // Iterate through the items in this implementation.
258  foreach (T item in source)
259  {
260  // Adjust the hash code.
261  hashCode = 31 * hashCode + (item == null ? 0 : item.GetHashCode());
262  }
263 
264  // Return the hash code.
265  return hashCode;
266  }
267 
268  // TODO: When diverging from Java version of Lucene, can uncomment these to adhere to best practices when overriding the Equals method and implementing IEquatable<T>.
269  ///// <summary>Overload of the == operator, it compares a
270  ///// <see cref="ComparableList{T}"/> to an <see cref="IEnumerable{T}"/>
271  ///// implementation.</summary>
272  ///// <param name="x">The <see cref="ComparableList{T}"/> to compare
273  ///// against <paramref name="y"/>.</param>
274  ///// <param name="y">The <see cref="IEnumerable{T}"/> to compare
275  ///// against <paramref name="x"/>.</param>
276  ///// <returns>True if the instances are equal, false otherwise.</returns>
277  //public static bool operator ==(EquatableList<T> x, System.Collections.Generic.IEnumerable<T> y)
278  //{
279  // // Call Equals.
280  // return Equals(x, y);
281  //}
282 
283  ///// <summary>Overload of the == operator, it compares a
284  ///// <see cref="ComparableList{T}"/> to an <see cref="IEnumerable{T}"/>
285  ///// implementation.</summary>
286  ///// <param name="y">The <see cref="ComparableList{T}"/> to compare
287  ///// against <paramref name="x"/>.</param>
288  ///// <param name="x">The <see cref="IEnumerable{T}"/> to compare
289  ///// against <paramref name="y"/>.</param>
290  ///// <returns>True if the instances are equal, false otherwise.</returns>
291  //public static bool operator ==(System.Collections.Generic.IEnumerable<T> x, EquatableList<T> y)
292  //{
293  // // Call equals.
294  // return Equals(x, y);
295  //}
296 
297  ///// <summary>Overload of the != operator, it compares a
298  ///// <see cref="ComparableList{T}"/> to an <see cref="IEnumerable{T}"/>
299  ///// implementation.</summary>
300  ///// <param name="x">The <see cref="ComparableList{T}"/> to compare
301  ///// against <paramref name="y"/>.</param>
302  ///// <param name="y">The <see cref="IEnumerable{T}"/> to compare
303  ///// against <paramref name="x"/>.</param>
304  ///// <returns>True if the instances are not equal, false otherwise.</returns>
305  //public static bool operator !=(EquatableList<T> x, System.Collections.Generic.IEnumerable<T> y)
306  //{
307  // // Return the negative of the equals operation.
308  // return !(x == y);
309  //}
310 
311  ///// <summary>Overload of the != operator, it compares a
312  ///// <see cref="ComparableList{T}"/> to an <see cref="IEnumerable{T}"/>
313  ///// implementation.</summary>
314  ///// <param name="y">The <see cref="ComparableList{T}"/> to compare
315  ///// against <paramref name="x"/>.</param>
316  ///// <param name="x">The <see cref="IEnumerable{T}"/> to compare
317  ///// against <paramref name="y"/>.</param>
318  ///// <returns>True if the instances are not equal, false otherwise.</returns>
319  //public static bool operator !=(System.Collections.Generic.IEnumerable<T> x, EquatableList<T> y)
320  //{
321  // // Return the negative of the equals operation.
322  // return !(x == y);
323  //}
324 
325  #region ICloneable Members
326 
327  /// <summary>Clones the <see cref="EquatableList{T}"/>.</summary>
328  /// <remarks>This is a shallow clone.</remarks>
329  /// <returns>A new shallow clone of this
330  /// <see cref="EquatableList{T}"/>.</returns>
331  public object Clone()
332  {
333  // Just create a new one, passing this to the constructor.
334  return new EquatableList<T>(this);
335  }
336 
337  #endregion
338  }
339 }