AnyObjectId.java

  1. /*
  2.  * Copyright (C) 2006-2008, Shawn O. Pearce <spearce@spearce.org> and others
  3.  *
  4.  * This program and the accompanying materials are made available under the
  5.  * terms of the Eclipse Distribution License v. 1.0 which is available at
  6.  * https://www.eclipse.org/org/documents/edl-v10.php.
  7.  *
  8.  * SPDX-License-Identifier: BSD-3-Clause
  9.  */

  10. package org.eclipse.jgit.lib;

  11. import java.io.IOException;
  12. import java.io.OutputStream;
  13. import java.io.Writer;
  14. import java.nio.ByteBuffer;

  15. import org.eclipse.jgit.util.NB;
  16. import org.eclipse.jgit.util.References;

  17. /**
  18.  * A (possibly mutable) SHA-1 abstraction.
  19.  * <p>
  20.  * If this is an instance of {@link org.eclipse.jgit.lib.MutableObjectId} the
  21.  * concept of equality with this instance can alter at any time, if this
  22.  * instance is modified to represent a different object name.
  23.  */
  24. public abstract class AnyObjectId implements Comparable<AnyObjectId> {

  25.     /**
  26.      * Compare two object identifier byte sequences for equality.
  27.      *
  28.      * @param firstObjectId
  29.      *            the first identifier to compare. Must not be null.
  30.      * @param secondObjectId
  31.      *            the second identifier to compare. Must not be null.
  32.      * @return true if the two identifiers are the same.
  33.      * @deprecated use {@link #isEqual(AnyObjectId, AnyObjectId)} instead
  34.      */
  35.     @Deprecated
  36.     @SuppressWarnings("AmbiguousMethodReference")
  37.     public static boolean equals(final AnyObjectId firstObjectId,
  38.             final AnyObjectId secondObjectId) {
  39.         return isEqual(firstObjectId, secondObjectId);
  40.     }

  41.     /**
  42.      * Compare two object identifier byte sequences for equality.
  43.      *
  44.      * @param firstObjectId
  45.      *            the first identifier to compare. Must not be null.
  46.      * @param secondObjectId
  47.      *            the second identifier to compare. Must not be null.
  48.      * @return true if the two identifiers are the same.
  49.      * @since 5.4
  50.      */
  51.     public static boolean isEqual(final AnyObjectId firstObjectId,
  52.             final AnyObjectId secondObjectId) {
  53.         if (References.isSameObject(firstObjectId, secondObjectId)) {
  54.             return true;
  55.         }
  56.         // We test word 3 first since the git file-based ODB
  57.         // uses the first byte of w1, and we use w2 as the
  58.         // hash code, one of those probably came up with these
  59.         // two instances which we are comparing for equality.
  60.         // Therefore the first two words are very likely to be
  61.         // identical. We want to break away from collisions as
  62.         // quickly as possible.
  63.         return firstObjectId.w3 == secondObjectId.w3
  64.                 && firstObjectId.w4 == secondObjectId.w4
  65.                 && firstObjectId.w5 == secondObjectId.w5
  66.                 && firstObjectId.w1 == secondObjectId.w1
  67.                 && firstObjectId.w2 == secondObjectId.w2;
  68.     }

  69.     int w1;

  70.     int w2;

  71.     int w3;

  72.     int w4;

  73.     int w5;

  74.     /**
  75.      * Get the first 8 bits of the ObjectId.
  76.      *
  77.      * This is a faster version of {@code getByte(0)}.
  78.      *
  79.      * @return a discriminator usable for a fan-out style map. Returned values
  80.      *         are unsigned and thus are in the range [0,255] rather than the
  81.      *         signed byte range of [-128, 127].
  82.      */
  83.     public final int getFirstByte() {
  84.         return w1 >>> 24;
  85.     }

  86.     /**
  87.      * Get any byte from the ObjectId.
  88.      *
  89.      * Callers hard-coding {@code getByte(0)} should instead use the much faster
  90.      * special case variant {@link #getFirstByte()}.
  91.      *
  92.      * @param index
  93.      *            index of the byte to obtain from the raw form of the ObjectId.
  94.      *            Must be in range [0,
  95.      *            {@link org.eclipse.jgit.lib.Constants#OBJECT_ID_LENGTH}).
  96.      * @return the value of the requested byte at {@code index}. Returned values
  97.      *         are unsigned and thus are in the range [0,255] rather than the
  98.      *         signed byte range of [-128, 127].
  99.      * @throws java.lang.ArrayIndexOutOfBoundsException
  100.      *             {@code index} is less than 0, equal to
  101.      *             {@link org.eclipse.jgit.lib.Constants#OBJECT_ID_LENGTH}, or
  102.      *             greater than
  103.      *             {@link org.eclipse.jgit.lib.Constants#OBJECT_ID_LENGTH}.
  104.      */
  105.     public final int getByte(int index) {
  106.         int w;
  107.         switch (index >> 2) {
  108.         case 0:
  109.             w = w1;
  110.             break;
  111.         case 1:
  112.             w = w2;
  113.             break;
  114.         case 2:
  115.             w = w3;
  116.             break;
  117.         case 3:
  118.             w = w4;
  119.             break;
  120.         case 4:
  121.             w = w5;
  122.             break;
  123.         default:
  124.             throw new ArrayIndexOutOfBoundsException(index);
  125.         }

  126.         return (w >>> (8 * (3 - (index & 3)))) & 0xff;
  127.     }

  128.     /**
  129.      * {@inheritDoc}
  130.      * <p>
  131.      * Compare this ObjectId to another and obtain a sort ordering.
  132.      */
  133.     @Override
  134.     public final int compareTo(AnyObjectId other) {
  135.         if (this == other)
  136.             return 0;

  137.         int cmp;

  138.         cmp = NB.compareUInt32(w1, other.w1);
  139.         if (cmp != 0)
  140.             return cmp;

  141.         cmp = NB.compareUInt32(w2, other.w2);
  142.         if (cmp != 0)
  143.             return cmp;

  144.         cmp = NB.compareUInt32(w3, other.w3);
  145.         if (cmp != 0)
  146.             return cmp;

  147.         cmp = NB.compareUInt32(w4, other.w4);
  148.         if (cmp != 0)
  149.             return cmp;

  150.         return NB.compareUInt32(w5, other.w5);
  151.     }

  152.     /**
  153.      * Compare this ObjectId to a network-byte-order ObjectId.
  154.      *
  155.      * @param bs
  156.      *            array containing the other ObjectId in network byte order.
  157.      * @param p
  158.      *            position within {@code bs} to start the compare at. At least
  159.      *            20 bytes, starting at this position are required.
  160.      * @return a negative integer, zero, or a positive integer as this object is
  161.      *         less than, equal to, or greater than the specified object.
  162.      */
  163.     public final int compareTo(byte[] bs, int p) {
  164.         int cmp;

  165.         cmp = NB.compareUInt32(w1, NB.decodeInt32(bs, p));
  166.         if (cmp != 0)
  167.             return cmp;

  168.         cmp = NB.compareUInt32(w2, NB.decodeInt32(bs, p + 4));
  169.         if (cmp != 0)
  170.             return cmp;

  171.         cmp = NB.compareUInt32(w3, NB.decodeInt32(bs, p + 8));
  172.         if (cmp != 0)
  173.             return cmp;

  174.         cmp = NB.compareUInt32(w4, NB.decodeInt32(bs, p + 12));
  175.         if (cmp != 0)
  176.             return cmp;

  177.         return NB.compareUInt32(w5, NB.decodeInt32(bs, p + 16));
  178.     }

  179.     /**
  180.      * Compare this ObjectId to a network-byte-order ObjectId.
  181.      *
  182.      * @param bs
  183.      *            array containing the other ObjectId in network byte order.
  184.      * @param p
  185.      *            position within {@code bs} to start the compare at. At least 5
  186.      *            integers, starting at this position are required.
  187.      * @return a negative integer, zero, or a positive integer as this object is
  188.      *         less than, equal to, or greater than the specified object.
  189.      */
  190.     public final int compareTo(int[] bs, int p) {
  191.         int cmp;

  192.         cmp = NB.compareUInt32(w1, bs[p]);
  193.         if (cmp != 0)
  194.             return cmp;

  195.         cmp = NB.compareUInt32(w2, bs[p + 1]);
  196.         if (cmp != 0)
  197.             return cmp;

  198.         cmp = NB.compareUInt32(w3, bs[p + 2]);
  199.         if (cmp != 0)
  200.             return cmp;

  201.         cmp = NB.compareUInt32(w4, bs[p + 3]);
  202.         if (cmp != 0)
  203.             return cmp;

  204.         return NB.compareUInt32(w5, bs[p + 4]);
  205.     }

  206.     /**
  207.      * Tests if this ObjectId starts with the given abbreviation.
  208.      *
  209.      * @param abbr
  210.      *            the abbreviation.
  211.      * @return true if this ObjectId begins with the abbreviation; else false.
  212.      */
  213.     public boolean startsWith(AbbreviatedObjectId abbr) {
  214.         return abbr.prefixCompare(this) == 0;
  215.     }

  216.     /** {@inheritDoc} */
  217.     @Override
  218.     public final int hashCode() {
  219.         return w2;
  220.     }

  221.     /**
  222.      * Determine if this ObjectId has exactly the same value as another.
  223.      *
  224.      * @param other
  225.      *            the other id to compare to. May be null.
  226.      * @return true only if both ObjectIds have identical bits.
  227.      */
  228.     @SuppressWarnings({ "NonOverridingEquals", "AmbiguousMethodReference" })
  229.     public final boolean equals(AnyObjectId other) {
  230.         return other != null ? isEqual(this, other) : false;
  231.     }

  232.     /** {@inheritDoc} */
  233.     @Override
  234.     public final boolean equals(Object o) {
  235.         if (o instanceof AnyObjectId) {
  236.             return equals((AnyObjectId) o);
  237.         }
  238.         return false;
  239.     }

  240.     /**
  241.      * Copy this ObjectId to an output writer in raw binary.
  242.      *
  243.      * @param w
  244.      *            the buffer to copy to. Must be in big endian order.
  245.      */
  246.     public void copyRawTo(ByteBuffer w) {
  247.         w.putInt(w1);
  248.         w.putInt(w2);
  249.         w.putInt(w3);
  250.         w.putInt(w4);
  251.         w.putInt(w5);
  252.     }

  253.     /**
  254.      * Copy this ObjectId to a byte array.
  255.      *
  256.      * @param b
  257.      *            the buffer to copy to.
  258.      * @param o
  259.      *            the offset within b to write at.
  260.      */
  261.     public void copyRawTo(byte[] b, int o) {
  262.         NB.encodeInt32(b, o, w1);
  263.         NB.encodeInt32(b, o + 4, w2);
  264.         NB.encodeInt32(b, o + 8, w3);
  265.         NB.encodeInt32(b, o + 12, w4);
  266.         NB.encodeInt32(b, o + 16, w5);
  267.     }

  268.     /**
  269.      * Copy this ObjectId to an int array.
  270.      *
  271.      * @param b
  272.      *            the buffer to copy to.
  273.      * @param o
  274.      *            the offset within b to write at.
  275.      */
  276.     public void copyRawTo(int[] b, int o) {
  277.         b[o] = w1;
  278.         b[o + 1] = w2;
  279.         b[o + 2] = w3;
  280.         b[o + 3] = w4;
  281.         b[o + 4] = w5;
  282.     }

  283.     /**
  284.      * Copy this ObjectId to an output writer in raw binary.
  285.      *
  286.      * @param w
  287.      *            the stream to write to.
  288.      * @throws java.io.IOException
  289.      *             the stream writing failed.
  290.      */
  291.     public void copyRawTo(OutputStream w) throws IOException {
  292.         writeRawInt(w, w1);
  293.         writeRawInt(w, w2);
  294.         writeRawInt(w, w3);
  295.         writeRawInt(w, w4);
  296.         writeRawInt(w, w5);
  297.     }

  298.     private static void writeRawInt(OutputStream w, int v)
  299.             throws IOException {
  300.         w.write(v >>> 24);
  301.         w.write(v >>> 16);
  302.         w.write(v >>> 8);
  303.         w.write(v);
  304.     }

  305.     /**
  306.      * Copy this ObjectId to an output writer in hex format.
  307.      *
  308.      * @param w
  309.      *            the stream to copy to.
  310.      * @throws java.io.IOException
  311.      *             the stream writing failed.
  312.      */
  313.     public void copyTo(OutputStream w) throws IOException {
  314.         w.write(toHexByteArray());
  315.     }

  316.     /**
  317.      * Copy this ObjectId to a byte array in hex format.
  318.      *
  319.      * @param b
  320.      *            the buffer to copy to.
  321.      * @param o
  322.      *            the offset within b to write at.
  323.      */
  324.     public void copyTo(byte[] b, int o) {
  325.         formatHexByte(b, o + 0, w1);
  326.         formatHexByte(b, o + 8, w2);
  327.         formatHexByte(b, o + 16, w3);
  328.         formatHexByte(b, o + 24, w4);
  329.         formatHexByte(b, o + 32, w5);
  330.     }

  331.     /**
  332.      * Copy this ObjectId to a ByteBuffer in hex format.
  333.      *
  334.      * @param b
  335.      *            the buffer to copy to.
  336.      */
  337.     public void copyTo(ByteBuffer b) {
  338.         b.put(toHexByteArray());
  339.     }

  340.     private byte[] toHexByteArray() {
  341.         final byte[] dst = new byte[Constants.OBJECT_ID_STRING_LENGTH];
  342.         formatHexByte(dst, 0, w1);
  343.         formatHexByte(dst, 8, w2);
  344.         formatHexByte(dst, 16, w3);
  345.         formatHexByte(dst, 24, w4);
  346.         formatHexByte(dst, 32, w5);
  347.         return dst;
  348.     }

  349.     private static final byte[] hexbyte = { '0', '1', '2', '3', '4', '5', '6',
  350.             '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };

  351.     private static void formatHexByte(byte[] dst, int p, int w) {
  352.         int o = p + 7;
  353.         while (o >= p && w != 0) {
  354.             dst[o--] = hexbyte[w & 0xf];
  355.             w >>>= 4;
  356.         }
  357.         while (o >= p)
  358.             dst[o--] = '0';
  359.     }

  360.     /**
  361.      * Copy this ObjectId to an output writer in hex format.
  362.      *
  363.      * @param w
  364.      *            the stream to copy to.
  365.      * @throws java.io.IOException
  366.      *             the stream writing failed.
  367.      */
  368.     public void copyTo(Writer w) throws IOException {
  369.         w.write(toHexCharArray());
  370.     }

  371.     /**
  372.      * Copy this ObjectId to an output writer in hex format.
  373.      *
  374.      * @param tmp
  375.      *            temporary char array to buffer construct into before writing.
  376.      *            Must be at least large enough to hold 2 digits for each byte
  377.      *            of object id (40 characters or larger).
  378.      * @param w
  379.      *            the stream to copy to.
  380.      * @throws java.io.IOException
  381.      *             the stream writing failed.
  382.      */
  383.     public void copyTo(char[] tmp, Writer w) throws IOException {
  384.         toHexCharArray(tmp);
  385.         w.write(tmp, 0, Constants.OBJECT_ID_STRING_LENGTH);
  386.     }

  387.     /**
  388.      * Copy this ObjectId to a StringBuilder in hex format.
  389.      *
  390.      * @param tmp
  391.      *            temporary char array to buffer construct into before writing.
  392.      *            Must be at least large enough to hold 2 digits for each byte
  393.      *            of object id (40 characters or larger).
  394.      * @param w
  395.      *            the string to append onto.
  396.      */
  397.     public void copyTo(char[] tmp, StringBuilder w) {
  398.         toHexCharArray(tmp);
  399.         w.append(tmp, 0, Constants.OBJECT_ID_STRING_LENGTH);
  400.     }

  401.     private char[] toHexCharArray() {
  402.         final char[] dst = new char[Constants.OBJECT_ID_STRING_LENGTH];
  403.         toHexCharArray(dst);
  404.         return dst;
  405.     }

  406.     private void toHexCharArray(char[] dst) {
  407.         formatHexChar(dst, 0, w1);
  408.         formatHexChar(dst, 8, w2);
  409.         formatHexChar(dst, 16, w3);
  410.         formatHexChar(dst, 24, w4);
  411.         formatHexChar(dst, 32, w5);
  412.     }

  413.     private static final char[] hexchar = { '0', '1', '2', '3', '4', '5', '6',
  414.             '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };

  415.     static void formatHexChar(char[] dst, int p, int w) {
  416.         int o = p + 7;
  417.         while (o >= p && w != 0) {
  418.             dst[o--] = hexchar[w & 0xf];
  419.             w >>>= 4;
  420.         }
  421.         while (o >= p)
  422.             dst[o--] = '0';
  423.     }

  424.     /** {@inheritDoc} */
  425.     @SuppressWarnings("nls")
  426.     @Override
  427.     public String toString() {
  428.         return "AnyObjectId[" + name() + "]";
  429.     }

  430.     /**
  431.      * <p>name.</p>
  432.      *
  433.      * @return string form of the SHA-1, in lower case hexadecimal.
  434.      */
  435.     public final String name() {
  436.         return new String(toHexCharArray());
  437.     }

  438.     /**
  439.      * Get string form of the SHA-1, in lower case hexadecimal.
  440.      *
  441.      * @return string form of the SHA-1, in lower case hexadecimal.
  442.      */
  443.     public final String getName() {
  444.         return name();
  445.     }

  446.     /**
  447.      * Return an abbreviation (prefix) of this object SHA-1.
  448.      * <p>
  449.      * This implementation does not guarantee uniqueness. Callers should instead
  450.      * use
  451.      * {@link org.eclipse.jgit.lib.ObjectReader#abbreviate(AnyObjectId, int)} to
  452.      * obtain a unique abbreviation within the scope of a particular object
  453.      * database.
  454.      *
  455.      * @param len
  456.      *            length of the abbreviated string.
  457.      * @return SHA-1 abbreviation.
  458.      */
  459.     public AbbreviatedObjectId abbreviate(int len) {
  460.         final int a = AbbreviatedObjectId.mask(len, 1, w1);
  461.         final int b = AbbreviatedObjectId.mask(len, 2, w2);
  462.         final int c = AbbreviatedObjectId.mask(len, 3, w3);
  463.         final int d = AbbreviatedObjectId.mask(len, 4, w4);
  464.         final int e = AbbreviatedObjectId.mask(len, 5, w5);
  465.         return new AbbreviatedObjectId(len, a, b, c, d, e);
  466.     }

  467.     /**
  468.      * Obtain an immutable copy of this current object name value.
  469.      * <p>
  470.      * Only returns <code>this</code> if this instance is an unsubclassed
  471.      * instance of {@link org.eclipse.jgit.lib.ObjectId}; otherwise a new
  472.      * instance is returned holding the same value.
  473.      * <p>
  474.      * This method is useful to shed any additional memory that may be tied to
  475.      * the subclass, yet retain the unique identity of the object id for future
  476.      * lookups within maps and repositories.
  477.      *
  478.      * @return an immutable copy, using the smallest memory footprint possible.
  479.      */
  480.     public final ObjectId copy() {
  481.         if (getClass() == ObjectId.class)
  482.             return (ObjectId) this;
  483.         return new ObjectId(this);
  484.     }

  485.     /**
  486.      * Obtain an immutable copy of this current object name value.
  487.      * <p>
  488.      * See {@link #copy()} if <code>this</code> is a possibly subclassed (but
  489.      * immutable) identity and the application needs a lightweight identity
  490.      * <i>only</i> reference.
  491.      *
  492.      * @return an immutable copy. May be <code>this</code> if this is already
  493.      *         an immutable instance.
  494.      */
  495.     public abstract ObjectId toObjectId();
  496. }