1 //
2 // Copyright (c) ZeroC, Inc. All rights reserved.
3 //
4 
5 namespace Ice
6 {
7     public class CollectionComparer
8     {
9         //
10         // Try to compare two collections efficiently, by doing a reference
11         // and count comparison. If equality or inequality can be determined
12         // this way, 'result' contains the outcome of the comparison and the
13         // return value is true. Otherwise, if equality or inequality cannot
14         // be determined this way, 'result' and return value are both false.
15         //
cheapComparison(System.Collections.ICollection c1, System.Collections.ICollection c2, out bool result)16         private static bool cheapComparison(System.Collections.ICollection c1,
17                                             System.Collections.ICollection c2,
18                                             out bool result)
19         {
20             if(ReferenceEquals(c1, c2))
21             {
22                 result = true;
23                 return true; // Equal references means the collections are equal.
24             }
25             if(c1 == null || c2 == null)
26             {
27                 result = false;
28                 return true; // The references are not equal and one of them is null, so c1 and c2 are not equal.
29             }
30             if(c1.Count != c2.Count)
31             {
32                 result = false;
33                 return true; // Different number of elements, so c1 and c2 are not equal.
34             }
35             if(c1.Count == 0)
36             {
37                 result = true;
38                 return true; // Same number of elements, both zero, so c1 and c2 are equal.
39             }
40 
41             result = false; // Couldn't get a result cheaply.
42             return false;   // c1 and c2 may still be equal, but we have to compare elements to find out.
43         }
44 
45         //
46         // Compare two dictionaries for value equality (as implemented by the Equals() method of its elements).
47         //
Equals(System.Collections.IDictionary d1, System.Collections.IDictionary d2)48         public static bool Equals(System.Collections.IDictionary d1, System.Collections.IDictionary d2)
49         {
50             try
51             {
52                 bool result;
53                 if(cheapComparison(d1, d2, out result))
54                 {
55                     return result;
56                 }
57 
58                 System.Collections.ICollection keys1 = d1.Keys;
59                 foreach(object k in keys1)
60                 {
61                     if(d2.Contains(k))
62                     {
63                         object v1 = d1[k];
64                         object v2 = d2[k];
65                         if(v1 == null)
66                         {
67                             if(v2 != null)
68                             {
69                                 return false;
70                             }
71                         }
72                         else
73                         {
74                             if(!v1.Equals(v2))
75                             {
76                                 return false;
77                             }
78                         }
79                     }
80                     else
81                     {
82                         return false;
83                     }
84                 }
85             }
86             catch(System.Exception)
87             {
88                 return false;
89             }
90 
91             return true;
92         }
93 
94         //
95         // Compare two collections for equality (as implemented by the Equals() method of its elements).
96         // Order is significant.
97         //
Equals(System.Collections.ICollection c1, System.Collections.ICollection c2)98         public static bool Equals(System.Collections.ICollection c1, System.Collections.ICollection c2)
99         {
100             try
101             {
102                 bool result;
103                 if(cheapComparison(c1, c2, out result))
104                 {
105                     return result;
106                 }
107 
108                 System.Collections.IEnumerator e = c2.GetEnumerator();
109                 foreach(object o in c1)
110                 {
111                     e.MoveNext();
112                     if(!Equals(o, e.Current))
113                     {
114                         return false;
115                     }
116                 }
117                 return true;
118             }
119             catch(System.Exception)
120             {
121                 return false;
122             }
123         }
124 
125         //
126         // Compare two collections for equality (as implemented by the Equals() method of its elements).
127         // Order is significant.
128         //
Equals(System.Collections.IEnumerable c1, System.Collections.IEnumerable c2)129         public static bool Equals(System.Collections.IEnumerable c1, System.Collections.IEnumerable c2)
130         {
131             try
132             {
133                 if(ReferenceEquals(c1, c2))
134                 {
135                     return true; // Equal references means the collections are equal.
136                 }
137                 if(c1 == null || c2 == null)
138                 {
139                     return false; // The references are not equal and one of them is null, so c1 and c2 are not equal.
140                 }
141 
142                 System.Collections.IEnumerator e1 = c1.GetEnumerator();
143                 System.Collections.IEnumerator e2 = c2.GetEnumerator();
144                 while(e1.MoveNext())
145                 {
146                     if(!e2.MoveNext())
147                     {
148                         return false; // c2 has fewer elements than c1.
149                     }
150                     if(e1.Current == null)
151                     {
152                         if(e2.Current != null)
153                         {
154                             return false;
155                         }
156                     }
157                     else
158                     {
159                         if(!e1.Current.Equals(e2.Current))
160                         {
161                             return false;
162                         }
163                     }
164                 }
165                 if(e2.MoveNext())
166                 {
167                     return false; // c2 has more elements than c1.
168                 }
169                 return true;
170             }
171             catch(System.Exception)
172             {
173                 return false;
174             }
175         }
176     }
177 }
178