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