1 /* 2 * Copyright (C) 2006-2008, Shawn O. Pearce <spearce@spearce.org> 3 * and other copyright owners as documented in the project's IP log. 4 * 5 * This program and the accompanying materials are made available 6 * under the terms of the Eclipse Distribution License v1.0 which 7 * accompanies this distribution, is reproduced below, and is 8 * available at http://www.eclipse.org/org/documents/edl-v10.php 9 * 10 * All rights reserved. 11 * 12 * Redistribution and use in source and binary forms, with or 13 * without modification, are permitted provided that the following 14 * conditions are met: 15 * 16 * - Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 19 * - Redistributions in binary form must reproduce the above 20 * copyright notice, this list of conditions and the following 21 * disclaimer in the documentation and/or other materials provided 22 * with the distribution. 23 * 24 * - Neither the name of the Eclipse Foundation, Inc. nor the 25 * names of its contributors may be used to endorse or promote 26 * products derived from this software without specific prior 27 * written permission. 28 * 29 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 30 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 31 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 32 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 33 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 34 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 35 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 36 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 37 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 38 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 40 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 41 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 42 */ 43 44 package org.eclipse.jgit.lib; 45 46 import java.io.IOException; 47 import java.io.OutputStream; 48 import java.io.Writer; 49 import java.nio.ByteBuffer; 50 51 import org.eclipse.jgit.util.NB; 52 import org.eclipse.jgit.util.References; 53 54 /** 55 * A (possibly mutable) SHA-1 abstraction. 56 * <p> 57 * If this is an instance of {@link org.eclipse.jgit.lib.MutableObjectId} the 58 * concept of equality with this instance can alter at any time, if this 59 * instance is modified to represent a different object name. 60 */ 61 public abstract class AnyObjectId implements Comparable<AnyObjectId> { 62 63 /** 64 * Compare two object identifier byte sequences for equality. 65 * 66 * @param firstObjectId 67 * the first identifier to compare. Must not be null. 68 * @param secondObjectId 69 * the second identifier to compare. Must not be null. 70 * @return true if the two identifiers are the same. 71 * @deprecated use {@link #isEqual(AnyObjectId, AnyObjectId)} instead 72 */ 73 @Deprecated 74 @SuppressWarnings("AmbiguousMethodReference") 75 public static boolean equals(final AnyObjectId firstObjectId, 76 final AnyObjectId secondObjectId) { 77 return isEqual(firstObjectId, secondObjectId); 78 } 79 80 /** 81 * Compare two object identifier byte sequences for equality. 82 * 83 * @param firstObjectId 84 * the first identifier to compare. Must not be null. 85 * @param secondObjectId 86 * the second identifier to compare. Must not be null. 87 * @return true if the two identifiers are the same. 88 * @since 5.4 89 */ 90 public static boolean isEqual(final AnyObjectId firstObjectId, 91 final AnyObjectId secondObjectId) { 92 if (References.isSameObject(firstObjectId, secondObjectId)) { 93 return true; 94 } 95 // We test word 3 first since the git file-based ODB 96 // uses the first byte of w1, and we use w2 as the 97 // hash code, one of those probably came up with these 98 // two instances which we are comparing for equality. 99 // Therefore the first two words are very likely to be 100 // identical. We want to break away from collisions as 101 // quickly as possible. 102 return firstObjectId.w3 == secondObjectId.w3 103 && firstObjectId.w4 == secondObjectId.w4 104 && firstObjectId.w5 == secondObjectId.w5 105 && firstObjectId.w1 == secondObjectId.w1 106 && firstObjectId.w2 == secondObjectId.w2; 107 } 108 109 int w1; 110 111 int w2; 112 113 int w3; 114 115 int w4; 116 117 int w5; 118 119 /** 120 * Get the first 8 bits of the ObjectId. 121 * 122 * This is a faster version of {@code getByte(0)}. 123 * 124 * @return a discriminator usable for a fan-out style map. Returned values 125 * are unsigned and thus are in the range [0,255] rather than the 126 * signed byte range of [-128, 127]. 127 */ 128 public final int getFirstByte() { 129 return w1 >>> 24; 130 } 131 132 /** 133 * Get any byte from the ObjectId. 134 * 135 * Callers hard-coding {@code getByte(0)} should instead use the much faster 136 * special case variant {@link #getFirstByte()}. 137 * 138 * @param index 139 * index of the byte to obtain from the raw form of the ObjectId. 140 * Must be in range [0, 141 * {@link org.eclipse.jgit.lib.Constants#OBJECT_ID_LENGTH}). 142 * @return the value of the requested byte at {@code index}. Returned values 143 * are unsigned and thus are in the range [0,255] rather than the 144 * signed byte range of [-128, 127]. 145 * @throws java.lang.ArrayIndexOutOfBoundsException 146 * {@code index} is less than 0, equal to 147 * {@link org.eclipse.jgit.lib.Constants#OBJECT_ID_LENGTH}, or 148 * greater than 149 * {@link org.eclipse.jgit.lib.Constants#OBJECT_ID_LENGTH}. 150 */ 151 public final int getByte(int index) { 152 int w; 153 switch (index >> 2) { 154 case 0: 155 w = w1; 156 break; 157 case 1: 158 w = w2; 159 break; 160 case 2: 161 w = w3; 162 break; 163 case 3: 164 w = w4; 165 break; 166 case 4: 167 w = w5; 168 break; 169 default: 170 throw new ArrayIndexOutOfBoundsException(index); 171 } 172 173 return (w >>> (8 * (3 - (index & 3)))) & 0xff; 174 } 175 176 /** 177 * {@inheritDoc} 178 * <p> 179 * Compare this ObjectId to another and obtain a sort ordering. 180 */ 181 @Override 182 public final int compareTo(AnyObjectId other) { 183 if (this == other) 184 return 0; 185 186 int cmp; 187 188 cmp = NB.compareUInt32(w1, other.w1); 189 if (cmp != 0) 190 return cmp; 191 192 cmp = NB.compareUInt32(w2, other.w2); 193 if (cmp != 0) 194 return cmp; 195 196 cmp = NB.compareUInt32(w3, other.w3); 197 if (cmp != 0) 198 return cmp; 199 200 cmp = NB.compareUInt32(w4, other.w4); 201 if (cmp != 0) 202 return cmp; 203 204 return NB.compareUInt32(w5, other.w5); 205 } 206 207 /** 208 * Compare this ObjectId to a network-byte-order ObjectId. 209 * 210 * @param bs 211 * array containing the other ObjectId in network byte order. 212 * @param p 213 * position within {@code bs} to start the compare at. At least 214 * 20 bytes, starting at this position are required. 215 * @return a negative integer, zero, or a positive integer as this object is 216 * less than, equal to, or greater than the specified object. 217 */ 218 public final int compareTo(byte[] bs, int p) { 219 int cmp; 220 221 cmp = NB.compareUInt32(w1, NB.decodeInt32(bs, p)); 222 if (cmp != 0) 223 return cmp; 224 225 cmp = NB.compareUInt32(w2, NB.decodeInt32(bs, p + 4)); 226 if (cmp != 0) 227 return cmp; 228 229 cmp = NB.compareUInt32(w3, NB.decodeInt32(bs, p + 8)); 230 if (cmp != 0) 231 return cmp; 232 233 cmp = NB.compareUInt32(w4, NB.decodeInt32(bs, p + 12)); 234 if (cmp != 0) 235 return cmp; 236 237 return NB.compareUInt32(w5, NB.decodeInt32(bs, p + 16)); 238 } 239 240 /** 241 * Compare this ObjectId to a network-byte-order ObjectId. 242 * 243 * @param bs 244 * array containing the other ObjectId in network byte order. 245 * @param p 246 * position within {@code bs} to start the compare at. At least 5 247 * integers, starting at this position are required. 248 * @return a negative integer, zero, or a positive integer as this object is 249 * less than, equal to, or greater than the specified object. 250 */ 251 public final int compareTo(int[] bs, int p) { 252 int cmp; 253 254 cmp = NB.compareUInt32(w1, bs[p]); 255 if (cmp != 0) 256 return cmp; 257 258 cmp = NB.compareUInt32(w2, bs[p + 1]); 259 if (cmp != 0) 260 return cmp; 261 262 cmp = NB.compareUInt32(w3, bs[p + 2]); 263 if (cmp != 0) 264 return cmp; 265 266 cmp = NB.compareUInt32(w4, bs[p + 3]); 267 if (cmp != 0) 268 return cmp; 269 270 return NB.compareUInt32(w5, bs[p + 4]); 271 } 272 273 /** 274 * Tests if this ObjectId starts with the given abbreviation. 275 * 276 * @param abbr 277 * the abbreviation. 278 * @return true if this ObjectId begins with the abbreviation; else false. 279 */ 280 public boolean startsWith(AbbreviatedObjectId abbr) { 281 return abbr.prefixCompare(this) == 0; 282 } 283 284 /** {@inheritDoc} */ 285 @Override 286 public final int hashCode() { 287 return w2; 288 } 289 290 /** 291 * Determine if this ObjectId has exactly the same value as another. 292 * 293 * @param other 294 * the other id to compare to. May be null. 295 * @return true only if both ObjectIds have identical bits. 296 */ 297 @SuppressWarnings({ "NonOverridingEquals", "AmbiguousMethodReference" }) 298 public final boolean equals(AnyObjectId other) { 299 return other != null ? isEqual(this, other) : false; 300 } 301 302 /** {@inheritDoc} */ 303 @Override 304 public final boolean equals(Object o) { 305 if (o instanceof AnyObjectId) 306 return equals((AnyObjectId) o); 307 else 308 return false; 309 } 310 311 /** 312 * Copy this ObjectId to an output writer in raw binary. 313 * 314 * @param w 315 * the buffer to copy to. Must be in big endian order. 316 */ 317 public void copyRawTo(ByteBuffer w) { 318 w.putInt(w1); 319 w.putInt(w2); 320 w.putInt(w3); 321 w.putInt(w4); 322 w.putInt(w5); 323 } 324 325 /** 326 * Copy this ObjectId to a byte array. 327 * 328 * @param b 329 * the buffer to copy to. 330 * @param o 331 * the offset within b to write at. 332 */ 333 public void copyRawTo(byte[] b, int o) { 334 NB.encodeInt32(b, o, w1); 335 NB.encodeInt32(b, o + 4, w2); 336 NB.encodeInt32(b, o + 8, w3); 337 NB.encodeInt32(b, o + 12, w4); 338 NB.encodeInt32(b, o + 16, w5); 339 } 340 341 /** 342 * Copy this ObjectId to an int array. 343 * 344 * @param b 345 * the buffer to copy to. 346 * @param o 347 * the offset within b to write at. 348 */ 349 public void copyRawTo(int[] b, int o) { 350 b[o] = w1; 351 b[o + 1] = w2; 352 b[o + 2] = w3; 353 b[o + 3] = w4; 354 b[o + 4] = w5; 355 } 356 357 /** 358 * Copy this ObjectId to an output writer in raw binary. 359 * 360 * @param w 361 * the stream to write to. 362 * @throws java.io.IOException 363 * the stream writing failed. 364 */ 365 public void copyRawTo(OutputStream w) throws IOException { 366 writeRawInt(w, w1); 367 writeRawInt(w, w2); 368 writeRawInt(w, w3); 369 writeRawInt(w, w4); 370 writeRawInt(w, w5); 371 } 372 373 private static void writeRawInt(OutputStream w, int v) 374 throws IOException { 375 w.write(v >>> 24); 376 w.write(v >>> 16); 377 w.write(v >>> 8); 378 w.write(v); 379 } 380 381 /** 382 * Copy this ObjectId to an output writer in hex format. 383 * 384 * @param w 385 * the stream to copy to. 386 * @throws java.io.IOException 387 * the stream writing failed. 388 */ 389 public void copyTo(OutputStream w) throws IOException { 390 w.write(toHexByteArray()); 391 } 392 393 /** 394 * Copy this ObjectId to a byte array in hex format. 395 * 396 * @param b 397 * the buffer to copy to. 398 * @param o 399 * the offset within b to write at. 400 */ 401 public void copyTo(byte[] b, int o) { 402 formatHexByte(b, o + 0, w1); 403 formatHexByte(b, o + 8, w2); 404 formatHexByte(b, o + 16, w3); 405 formatHexByte(b, o + 24, w4); 406 formatHexByte(b, o + 32, w5); 407 } 408 409 /** 410 * Copy this ObjectId to a ByteBuffer in hex format. 411 * 412 * @param b 413 * the buffer to copy to. 414 */ 415 public void copyTo(ByteBuffer b) { 416 b.put(toHexByteArray()); 417 } 418 419 private byte[] toHexByteArray() { 420 final byte[] dst = new byte[Constants.OBJECT_ID_STRING_LENGTH]; 421 formatHexByte(dst, 0, w1); 422 formatHexByte(dst, 8, w2); 423 formatHexByte(dst, 16, w3); 424 formatHexByte(dst, 24, w4); 425 formatHexByte(dst, 32, w5); 426 return dst; 427 } 428 429 private static final byte[] hexbyte = { '0', '1', '2', '3', '4', '5', '6', 430 '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; 431 432 private static void formatHexByte(byte[] dst, int p, int w) { 433 int o = p + 7; 434 while (o >= p && w != 0) { 435 dst[o--] = hexbyte[w & 0xf]; 436 w >>>= 4; 437 } 438 while (o >= p) 439 dst[o--] = '0'; 440 } 441 442 /** 443 * Copy this ObjectId to an output writer in hex format. 444 * 445 * @param w 446 * the stream to copy to. 447 * @throws java.io.IOException 448 * the stream writing failed. 449 */ 450 public void copyTo(Writer w) throws IOException { 451 w.write(toHexCharArray()); 452 } 453 454 /** 455 * Copy this ObjectId to an output writer in hex format. 456 * 457 * @param tmp 458 * temporary char array to buffer construct into before writing. 459 * Must be at least large enough to hold 2 digits for each byte 460 * of object id (40 characters or larger). 461 * @param w 462 * the stream to copy to. 463 * @throws java.io.IOException 464 * the stream writing failed. 465 */ 466 public void copyTo(char[] tmp, Writer w) throws IOException { 467 toHexCharArray(tmp); 468 w.write(tmp, 0, Constants.OBJECT_ID_STRING_LENGTH); 469 } 470 471 /** 472 * Copy this ObjectId to a StringBuilder in hex format. 473 * 474 * @param tmp 475 * temporary char array to buffer construct into before writing. 476 * Must be at least large enough to hold 2 digits for each byte 477 * of object id (40 characters or larger). 478 * @param w 479 * the string to append onto. 480 */ 481 public void copyTo(char[] tmp, StringBuilder w) { 482 toHexCharArray(tmp); 483 w.append(tmp, 0, Constants.OBJECT_ID_STRING_LENGTH); 484 } 485 486 private char[] toHexCharArray() { 487 final char[] dst = new char[Constants.OBJECT_ID_STRING_LENGTH]; 488 toHexCharArray(dst); 489 return dst; 490 } 491 492 private void toHexCharArray(char[] dst) { 493 formatHexChar(dst, 0, w1); 494 formatHexChar(dst, 8, w2); 495 formatHexChar(dst, 16, w3); 496 formatHexChar(dst, 24, w4); 497 formatHexChar(dst, 32, w5); 498 } 499 500 private static final char[] hexchar = { '0', '1', '2', '3', '4', '5', '6', 501 '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; 502 503 static void formatHexChar(char[] dst, int p, int w) { 504 int o = p + 7; 505 while (o >= p && w != 0) { 506 dst[o--] = hexchar[w & 0xf]; 507 w >>>= 4; 508 } 509 while (o >= p) 510 dst[o--] = '0'; 511 } 512 513 /** {@inheritDoc} */ 514 @SuppressWarnings("nls") 515 @Override 516 public String toString() { 517 return "AnyObjectId[" + name() + "]"; 518 } 519 520 /** 521 * <p>name.</p> 522 * 523 * @return string form of the SHA-1, in lower case hexadecimal. 524 */ 525 public final String name() { 526 return new String(toHexCharArray()); 527 } 528 529 /** 530 * Get string form of the SHA-1, in lower case hexadecimal. 531 * 532 * @return string form of the SHA-1, in lower case hexadecimal. 533 */ 534 public final String getName() { 535 return name(); 536 } 537 538 /** 539 * Return an abbreviation (prefix) of this object SHA-1. 540 * <p> 541 * This implementation does not guarantee uniqueness. Callers should instead 542 * use 543 * {@link org.eclipse.jgit.lib.ObjectReader#abbreviate(AnyObjectId, int)} to 544 * obtain a unique abbreviation within the scope of a particular object 545 * database. 546 * 547 * @param len 548 * length of the abbreviated string. 549 * @return SHA-1 abbreviation. 550 */ 551 public AbbreviatedObjectId abbreviate(int len) { 552 final int a = AbbreviatedObjectId.mask(len, 1, w1); 553 final int b = AbbreviatedObjectId.mask(len, 2, w2); 554 final int c = AbbreviatedObjectId.mask(len, 3, w3); 555 final int d = AbbreviatedObjectId.mask(len, 4, w4); 556 final int e = AbbreviatedObjectId.mask(len, 5, w5); 557 return new AbbreviatedObjectId(len, a, b, c, d, e); 558 } 559 560 /** 561 * Obtain an immutable copy of this current object name value. 562 * <p> 563 * Only returns <code>this</code> if this instance is an unsubclassed 564 * instance of {@link org.eclipse.jgit.lib.ObjectId}; otherwise a new 565 * instance is returned holding the same value. 566 * <p> 567 * This method is useful to shed any additional memory that may be tied to 568 * the subclass, yet retain the unique identity of the object id for future 569 * lookups within maps and repositories. 570 * 571 * @return an immutable copy, using the smallest memory footprint possible. 572 */ 573 public final ObjectId copy() { 574 if (getClass() == ObjectId.class) 575 return (ObjectId) this; 576 return new ObjectId(this); 577 } 578 579 /** 580 * Obtain an immutable copy of this current object name value. 581 * <p> 582 * See {@link #copy()} if <code>this</code> is a possibly subclassed (but 583 * immutable) identity and the application needs a lightweight identity 584 * <i>only</i> reference. 585 * 586 * @return an immutable copy. May be <code>this</code> if this is already 587 * an immutable instance. 588 */ 589 public abstract ObjectId toObjectId(); 590 }