1 /*******************************************************************************
2  * Copyright (c) 2009, 2017 Cloudsmith Inc. and others.
3  *
4  * This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License 2.0
6  * which accompanies this distribution, and is available at
7  * https://www.eclipse.org/legal/epl-2.0/
8  *
9  * SPDX-License-Identifier: EPL-2.0
10  *
11  * Contributors:
12  *     Cloudsmith Inc. - initial API and implementation
13  *******************************************************************************/
14 package org.eclipse.equinox.internal.p2.metadata;
15 
16 import java.io.Serializable;
17 
18 /**
19  * The VersionVector represents an array of Comparable objects. The array can be
20  * nested since a VersionVector is Comparable in itself.
21  *
22  * @Immutable
23  */
24 public class VersionVector implements Comparable<VersionVector>, Serializable {
25 
26 	interface MinMaxComparable extends Comparable<Object>, Serializable {
27 		//
28 	}
29 
30 	private static final class MaxStringValue implements MinMaxComparable {
31 		private static final long serialVersionUID = -4936252230441132767L;
32 
MaxStringValue()33 		MaxStringValue() {
34 			// Empty constructor
35 		}
36 
37 		@Override
compareTo(Object o)38 		public int compareTo(Object o) {
39 			return o == this ? 0 : (o == MAX_VALUE || o instanceof Integer || o instanceof EnumDefinition.EnumSegment || o instanceof VersionVector ? -1 : 1);
40 		}
41 
42 		// For singleton deserialization
readResolve()43 		private Object readResolve() {
44 			return MAXS_VALUE;
45 		}
46 
47 		@Override
toString()48 		public String toString() {
49 			return "m"; //$NON-NLS-1$
50 		}
51 	}
52 
53 	private static final class MaxValue implements MinMaxComparable {
54 		private static final long serialVersionUID = -5889641741635253589L;
55 
MaxValue()56 		MaxValue() {
57 			// Empty constructor
58 		}
59 
60 		@Override
compareTo(Object o)61 		public int compareTo(Object o) {
62 			return o == this ? 0 : 1;
63 		}
64 
65 		// For singleton deserialization
readResolve()66 		private Object readResolve() {
67 			return MAX_VALUE;
68 		}
69 
70 		@Override
toString()71 		public String toString() {
72 			return "M"; //$NON-NLS-1$
73 		}
74 	}
75 
76 	private static class MinValue implements MinMaxComparable {
77 		private static final long serialVersionUID = -1066323980049812226L;
78 
MinValue()79 		MinValue() {
80 			// Empty constructor
81 		}
82 
83 		@Override
compareTo(Object o)84 		public int compareTo(Object o) {
85 			return o == this ? 0 : -1;
86 		}
87 
readResolve()88 		private Object readResolve() {
89 			return MIN_VALUE;
90 		}
91 
92 		@Override
toString()93 		public String toString() {
94 			return "-M"; //$NON-NLS-1$
95 		}
96 	}
97 
98 	/**
99 	 * A value that is greater then any other value
100 	 */
101 	public static final Comparable<Object> MAX_VALUE = new MaxValue();
102 
103 	/**
104 	 * A value that is greater then any string but less then {@link #MAX_VALUE} and
105 	 * any Integer or VersionVector.
106 	 */
107 	public static final Comparable<Object> MAXS_VALUE = new MaxStringValue();
108 
109 	/**
110 	 * A value that is less then any other value
111 	 */
112 	public static final Comparable<Object> MIN_VALUE = new MinValue();
113 
114 	/**
115 	 * A value that is greater then {@link #MIN_VALUE} and less then any string,
116 	 * Integer, or VersionVector (a.k.a. empty_string)
117 	 */
118 	public static final String MINS_VALUE = ""; //$NON-NLS-1$
119 
120 	private static final long serialVersionUID = -8385373304298723744L;
121 
compare(Comparable<?>[] vectorA, Comparable<?> padA, Comparable<?>[] vectorB, Comparable<?> padB)122 	static int compare(Comparable<?>[] vectorA, Comparable<?> padA, Comparable<?>[] vectorB, Comparable<?> padB) {
123 		int top = vectorA.length;
124 		if (top > vectorB.length)
125 			top = vectorB.length;
126 
127 		for (int idx = 0; idx < top; ++idx) {
128 			int cmp = compareSegments(vectorA[idx], vectorB[idx]);
129 			if (cmp != 0)
130 				return cmp;
131 		}
132 
133 		// All elements compared equal up to this point. Check
134 		// pad values
135 		if (top < vectorA.length)
136 			return (padB == null) ? 1 : compareReminder(top, vectorA, padA, padB);
137 
138 		if (top < vectorB.length)
139 			return (padA == null) ? -1 : -compareReminder(top, vectorB, padB, padA);
140 
141 		// Lengths are equal. Compare pad values
142 		return padA == null ? (padB == null ? 0 : -1) : (padB == null ? 1 : compareSegments(padA, padB));
143 	}
144 
equals(Comparable<?>[] vectorA, Comparable<?> padValueA, Comparable<?>[] vectorB, Comparable<?> padValueB)145 	static boolean equals(Comparable<?>[] vectorA, Comparable<?> padValueA, Comparable<?>[] vectorB, Comparable<?> padValueB) {
146 		// We compare pad first since it is impossible for versions with
147 		// different pad to be equal (versions are padded to infinity)
148 		if (padValueA == null) {
149 			if (padValueB != null)
150 				return false;
151 		} else {
152 			if (padValueB == null || !padValueA.equals(padValueB))
153 				return false;
154 		}
155 
156 		int idx = vectorA.length;
157 
158 		// If the length of the vector differs, the versions cannot be equal
159 		// since segments equal to pad are stripped by the parser
160 		if (idx != vectorB.length)
161 			return false;
162 
163 		while (--idx >= 0)
164 			if (!vectorA[idx].equals(vectorB[idx]))
165 				return false;
166 
167 		return true;
168 	}
169 
hashCode(Comparable<?>[] vector, Comparable<?> padValue)170 	static int hashCode(Comparable<?>[] vector, Comparable<?> padValue) {
171 		int hashCode = padValue == null ? 31 : padValue.hashCode();
172 		int idx = vector.length;
173 		while (--idx >= 0) {
174 			Object elem = vector[idx];
175 			if (elem != null)
176 				hashCode += elem.hashCode();
177 			hashCode = hashCode * 31;
178 		}
179 		return hashCode;
180 	}
181 
toString(StringBuffer sb, Comparable<?>[] vector, Comparable<?> padValue, boolean rangeSafe)182 	static void toString(StringBuffer sb, Comparable<?>[] vector, Comparable<?> padValue, boolean rangeSafe) {
183 		int top = vector.length;
184 		if (top == 0)
185 			// Write one pad value as explicit. It will be considered
186 			// redundant and removed by the parser but the raw format
187 			// does not allow zero elements
188 			VersionFormat.rawToString(sb, rangeSafe, padValue == null ? MIN_VALUE : padValue);
189 		else {
190 			for (int idx = 0; idx < top; ++idx) {
191 				if (idx > 0)
192 					sb.append('.');
193 				VersionFormat.rawToString(sb, rangeSafe, vector[idx]);
194 			}
195 		}
196 		if (padValue != null) {
197 			sb.append('p');
198 			VersionFormat.rawToString(sb, rangeSafe, padValue);
199 		}
200 	}
201 
compareReminder(int idx, Comparable<?>[] vector, Comparable<?> padValue, Comparable<?> othersPad)202 	private static int compareReminder(int idx, Comparable<?>[] vector, Comparable<?> padValue, Comparable<?> othersPad) {
203 		int cmp;
204 		for (cmp = 0; idx < vector.length && cmp == 0; ++idx)
205 			cmp = compareSegments(vector[idx], othersPad);
206 		if (cmp == 0)
207 			cmp = (padValue == null) ? -1 : compareSegments(padValue, othersPad);
208 		return cmp;
209 	}
210 
compareSegments(Comparable<?> a, Comparable<?> b)211 	static int compareSegments(Comparable<?> a, Comparable<?> b) {
212 		if (a == b)
213 			return 0;
214 
215 		if (a instanceof Integer && b instanceof Integer) {
216 			int ai = ((Integer) a).intValue();
217 			int bi = ((Integer) b).intValue();
218 			return ai > bi ? 1 : (ai < bi ? -1 : 0);
219 		}
220 
221 		if (a instanceof String && b instanceof String)
222 			return ((String) a).compareTo((String) b);
223 
224 		if (a == MAX_VALUE || a == MIN_VALUE || a == MAXS_VALUE)
225 			return ((MinMaxComparable) a).compareTo(b);
226 
227 		if (b == MAX_VALUE || b == MIN_VALUE || b == MAXS_VALUE)
228 			return -((MinMaxComparable) b).compareTo(a);
229 
230 		if (a instanceof Integer)
231 			return 1;
232 		if (b instanceof Integer)
233 			return -1;
234 
235 		if (a instanceof VersionVector)
236 			return (b instanceof VersionVector) ? ((VersionVector) a).compareTo((VersionVector) b) : 1;
237 		if (b instanceof VersionVector)
238 			return -1;
239 
240 		if (a instanceof EnumDefinition.EnumSegment)
241 			return (b instanceof EnumDefinition.EnumSegment) ? ((EnumDefinition.EnumSegment) a).compareTo((EnumDefinition.EnumSegment) b) : 1;
242 		if (b instanceof EnumDefinition.EnumSegment)
243 			return -1;
244 
245 		throw new IllegalArgumentException();
246 	}
247 
248 	private final Comparable<?> padValue;
249 
250 	private final Comparable<?>[] vector;
251 
VersionVector(Comparable<?>[] vector, Comparable<?> pad)252 	public VersionVector(Comparable<?>[] vector, Comparable<?> pad) {
253 		this.vector = vector;
254 		this.padValue = (pad == MIN_VALUE) ? null : pad;
255 	}
256 
257 	@Override
compareTo(VersionVector ov)258 	public int compareTo(VersionVector ov) {
259 		if (ov == this)
260 			return 0;
261 
262 		return compare(vector, padValue, ov.vector, ov.padValue);
263 	}
264 
265 	@Override
equals(Object o)266 	public boolean equals(Object o) {
267 		if (o == this)
268 			return true;
269 
270 		if (!(o instanceof VersionVector))
271 			return false;
272 
273 		VersionVector ov = (VersionVector) o;
274 		return equals(vector, padValue, ov.vector, ov.padValue);
275 	}
276 
277 	/**
278 	 * Returns the pad value used when comparing this versions to
279 	 * versions that has a raw vector with a larger number of elements
280 	 * @return The pad value or <code>null</code> if not set.
281 	 */
getPad()282 	public Comparable<?> getPad() {
283 		return padValue;
284 	}
285 
286 	/**
287 	 * An element from the raw vector
288 	 * @param index The zero based index of the desired element
289 	 * @return An element from the raw vector
290 	 */
getSegment(int index)291 	public Comparable<?> getSegment(int index) {
292 		return vector[index];
293 	}
294 
295 	/**
296 	 * Returns the number of elements in the raw vector
297 	 * @return The element count
298 	 */
getSegmentCount()299 	public int getSegmentCount() {
300 		return vector.length;
301 	}
302 
303 	/**
304 	 * This method is package protected since it violates the immutable
305 	 * contract.
306 	 * @return The raw vector. Must be treated as read-only
307 	 */
getVector()308 	Comparable<?>[] getVector() {
309 		return vector;
310 	}
311 
312 	@Override
hashCode()313 	public int hashCode() {
314 		return hashCode(vector, padValue);
315 	}
316 
317 	@Override
toString()318 	public String toString() {
319 		StringBuffer sb = new StringBuffer();
320 		toString(sb);
321 		return sb.toString();
322 	}
323 
324 	/**
325 	 * Append the string representation of this instance to the
326 	 * <code>sb</code> buffer.
327 	 * @param sb The buffer to append to
328 	 */
toString(StringBuffer sb)329 	public void toString(StringBuffer sb) {
330 		toString(sb, vector, padValue, false);
331 	}
332 
333 	/**
334 	 * Append the string representation of this instance to the
335 	 * <code>sb</code> buffer.
336 	 * @param sb The buffer to append to
337 	 * @param rangeSafe If <code>true</code>, the range delimiters will be escaped
338 	 * with backslash.
339 	 */
toString(StringBuffer sb, boolean rangeSafe)340 	void toString(StringBuffer sb, boolean rangeSafe) {
341 		toString(sb, vector, padValue, rangeSafe);
342 	}
343 
readResolve()344 	private Object readResolve() {
345 		VersionVector vv = this;
346 		// Preserve the emptyString singleton
347 		int idx = vector.length;
348 		while (--idx >= 0)
349 			if (MINS_VALUE.equals(vector[idx]))
350 				vector[idx] = MINS_VALUE;
351 		if (MINS_VALUE.equals(padValue))
352 			vv = new VersionVector(vector, MINS_VALUE);
353 		return vv;
354 	}
355 }
356