1 // Licensed to the Apache Software Foundation(ASF) under one
2 // or more contributor license agreements.See the NOTICE file
3 // distributed with this work for additional information
4 // regarding copyright ownership.The ASF licenses this file
5 // to you under the Apache License, Version 2.0 (the
6 // "License"); you may not use this file except in compliance
7 // with the License. You may obtain a copy of the License at
8 //
9 //     http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing,
12 // software distributed under the License is distributed on an
13 // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 // KIND, either express or implied. See the License for the
15 // specific language governing permissions and limitations
16 // under the License.
17 
18 using System.Collections;
19 using System.Collections.Generic;
20 
21 namespace Thrift.Collections
22 {
23     // ReSharper disable once InconsistentNaming
24     public static class TCollections
25     {
26         /// <summary>
27         ///     This will return true if the two collections are value-wise the same.
28         ///     If the collection contains a collection, the collections will be compared using this method.
29         /// </summary>
Equals(IEnumerable first, IEnumerable second)30         public static bool Equals(IEnumerable first, IEnumerable second)
31         {
32             if (first == null && second == null)
33             {
34                 return true;
35             }
36 
37             if (first == null || second == null)
38             {
39                 return false;
40             }
41 
42             // for dictionaries, we need to compare keys and values separately
43             // because KeyValuePair<K,V>.Equals() will not do what we want
44             var fdict = first as IDictionary;
45             var sdict = second as IDictionary;
46             if ((fdict != null) || (sdict != null))
47             {
48                 if ((fdict == null) || (sdict == null))
49                     return false;
50                 return TCollections.Equals(fdict.Keys, sdict.Keys)
51                     && TCollections.Equals(fdict.Values, sdict.Values);
52             }
53 
54             var fiter = first.GetEnumerator();
55             var siter = second.GetEnumerator();
56 
57             var fnext = fiter.MoveNext();
58             var snext = siter.MoveNext();
59 
60             while (fnext && snext)
61             {
62                 var fenum = fiter.Current as IEnumerable;
63                 var senum = siter.Current as IEnumerable;
64 
65                 if (fenum != null && senum != null)
66                 {
67                     if (!Equals(fenum, senum))
68                     {
69                         return false;
70                     }
71                 }
72                 else if (fenum == null ^ senum == null)
73                 {
74                     return false;
75                 }
76                 else if (!Equals(fiter.Current, siter.Current))
77                 {
78                     return false;
79                 }
80 
81                 fnext = fiter.MoveNext();
82                 snext = siter.MoveNext();
83             }
84 
85             return fnext == snext;
86         }
87 
88         /// <summary>
89         ///     This returns a hashcode based on the value of the enumerable.
90         /// </summary>
GetHashCode(IEnumerable enumerable)91         public static int GetHashCode(IEnumerable enumerable)
92         {
93             if (enumerable == null)
94             {
95                 return 0;
96             }
97 
98             var hashcode = 0;
99 
100             foreach (var obj in enumerable)
101             {
102                 var enum2 = obj as IEnumerable;
103                 var objHash = enum2 == null ? obj.GetHashCode() : GetHashCode(enum2);
104 
105                 unchecked
106                 {
107                     hashcode = (hashcode * 397) ^ (objHash);
108                 }
109             }
110 
111             return hashcode;
112         }
113 
114 
115     }
116 }
117