Commit | Line | Data |
---|---|---|
ac1d454a PT |
1 | /******************************************************************************* |
2 | * Copyright (c) 2015 Ericsson | |
3 | * | |
4 | * All rights reserved. This program and the accompanying materials are | |
5 | * made available under the terms of the Eclipse Public License v1.0 which | |
6 | * accompanies this distribution, and is available at | |
7 | * http://www.eclipse.org/legal/epl-v10.html | |
8 | * | |
9 | * Contributors: | |
10 | * Patrick Tasse - Initial API and implementation | |
11 | *******************************************************************************/ | |
12 | ||
13 | package org.eclipse.tracecompass.common.core; | |
14 | ||
15 | import java.lang.reflect.Array; | |
16 | import java.util.Collection; | |
17 | import java.util.Iterator; | |
18 | import java.util.Set; | |
19 | import java.util.SortedSet; | |
20 | ||
21 | import org.eclipse.jdt.annotation.Nullable; | |
22 | ||
23 | /** | |
24 | * Utility methods for arbitrary objects. | |
25 | * | |
26 | * @author Patrick Tasse | |
4c4e2816 | 27 | * @since 2.0 |
ac1d454a PT |
28 | */ |
29 | public final class ObjectUtils { | |
30 | ||
31 | private ObjectUtils() {} | |
32 | ||
33 | /** | |
34 | * Checks deep equality of two objects that may be arrays or collections. | |
35 | * The objects (and each of their respective elements, if applicable) must | |
36 | * be of the same class to be considered equal. Deep equality is recursively | |
37 | * called on each element of an array or collection, if applicable. | |
38 | * | |
39 | * @param o1 | |
40 | * the first object to compare | |
41 | * @param o2 | |
42 | * the second object to compare | |
43 | * @return true if the objects are deeply equal, false otherwise | |
44 | */ | |
45 | public static boolean deepEquals(final @Nullable Object o1, @Nullable final Object o2) { | |
46 | if (o1 == o2) { | |
47 | return true; | |
48 | } | |
49 | if (o1 == null || o2 == null) { | |
50 | return false; | |
51 | } | |
52 | Class<?> class1 = o1.getClass(); | |
53 | Class<?> class2 = o2.getClass(); | |
54 | if (!class1.equals(class2)) { | |
55 | return false; | |
56 | } | |
57 | if (class1.isArray()) { | |
58 | int length = Array.getLength(o1); | |
59 | if (Array.getLength(o2) != length) { | |
60 | return false; | |
61 | } | |
62 | for (int i = 0; i < length; i++) { | |
63 | if (!deepEquals(Array.get(o1, i), Array.get(o2, i))) { | |
64 | return false; | |
65 | } | |
66 | } | |
67 | return true; | |
68 | } else if (o1 instanceof Collection) { | |
69 | Collection<?> c1 = (Collection<?>) o1; | |
70 | Collection<?> c2 = (Collection<?>) o2; | |
71 | int size = c1.size(); | |
72 | if (c2.size() != size) { | |
73 | return false; | |
74 | } | |
75 | if (o1 instanceof Set && !(o1 instanceof SortedSet<?>)) { | |
76 | /* Iteration order is undefined */ | |
77 | for (Object e1 : c1) { | |
78 | boolean contains = false; | |
79 | for (Object e2 : c2) { | |
80 | if (deepEquals(e1, e2)) { | |
81 | contains = true; | |
82 | break; | |
83 | } | |
84 | } | |
85 | if (!contains) { | |
86 | return false; | |
87 | } | |
88 | } | |
89 | return true; | |
90 | } | |
91 | Iterator<?> i1 = c1.iterator(); | |
92 | Iterator<?> i2 = c2.iterator(); | |
93 | while (i1.hasNext()) { | |
94 | if (!deepEquals(i1.next(), i2.next())) { | |
95 | return false; | |
96 | } | |
97 | } | |
98 | return true; | |
99 | } | |
100 | return o1.equals(o2); | |
101 | } | |
102 | ||
103 | /** | |
104 | * Returns a hash code value for an object which may be an array or a | |
105 | * collection. The deep hash code is recursively computed for each element | |
106 | * of an array or collection, if applicable. | |
107 | * | |
108 | * @param o | |
109 | * the object | |
110 | * @return a hash code value for this object. | |
111 | */ | |
112 | public static int deepHashCode(final @Nullable Object o) { | |
113 | if (o == null) { | |
114 | return 0; | |
115 | } | |
116 | if (o.getClass().isArray()) { | |
117 | final int prime = 31; | |
118 | int result = 1; | |
119 | for (int i = 0; i < Array.getLength(o); i++) { | |
120 | result = prime * result + deepHashCode(Array.get(o, i)); | |
121 | } | |
122 | return result; | |
123 | } | |
124 | if (o instanceof Collection) { | |
125 | Collection<?> c = (Collection<?>) o; | |
126 | if (o instanceof Set && !(o instanceof SortedSet<?>)) { | |
127 | /* Iteration order is undefined */ | |
128 | int result = 0; | |
129 | for (Object e : c) { | |
130 | result += deepHashCode(e); | |
131 | } | |
132 | return result; | |
133 | } | |
134 | final int prime = 31; | |
135 | int result = 1; | |
136 | for (Object e : c) { | |
137 | result = prime * result + deepHashCode(e); | |
138 | } | |
139 | return result; | |
140 | } | |
141 | return o.hashCode(); | |
142 | } | |
143 | } |