    001    /*
    002     * Copyright (C) 2008 The Guava Authors
    003     *
    004     * Licensed under the Apache License, Version 2.0 (the "License");
    005     * you may not use this file except in compliance with the License.
    006     * You may obtain a copy of the License at
    007     *
    008     * http://www.apache.org/licenses/LICENSE-2.0
    009     *
    010     * Unless required by applicable law or agreed to in writing, software
    011     * distributed under the License is distributed on an "AS IS" BASIS,
    012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    013     * See the License for the specific language governing permissions and
    014     * limitations under the License.
    015     */
    016
    017    package com.google.common.primitives;
    018
    019    import static com.google.common.base.Preconditions.checkArgument;
    020    import static com.google.common.base.Preconditions.checkElementIndex;
    021    import static com.google.common.base.Preconditions.checkNotNull;
    022    import static com.google.common.base.Preconditions.checkPositionIndexes;
    023
    024    import com.google.common.annotations.GwtCompatible;
    025
    026    import java.io.Serializable;
    027    import java.util.AbstractList;
    028    import java.util.Arrays;
    029    import java.util.Collection;
    030    import java.util.Collections;
    031    import java.util.List;
    032    import java.util.RandomAccess;
    033
    034    /**
    035     * Static utility methods pertaining to {@code byte} primitives, that are not
    036     * already found in either {@link Byte} or {@link Arrays}, <i>and interpret
    037     * bytes as neither signed nor unsigned</i>. The methods which specifically
    038     * treat bytes as signed or unsigned are found in {@link SignedBytes} and {@link
    039     * UnsignedBytes}.
    040     *
    041     * <p>See the Guava User Guide article on <a href=
    042     * "http://code.google.com/p/guava-libraries/wiki/PrimitivesExplained">
    043     * primitive utilities</a>.
    044     *
    045     * @author Kevin Bourrillion
    046     * @since 1.0
    047     */
    048    // TODO(kevinb): how to prevent warning on UnsignedBytes when building GWT
    049    // javadoc?
    050    @GwtCompatible
    051    public final class Bytes {
    052      private Bytes() {}
    053
    054      /**
    055       * Returns a hash code for {@code value}; equal to the result of invoking
    056       * {@code ((Byte) value).hashCode()}.
    057       *
    058       * @param value a primitive {@code byte} value
    059       * @return a hash code for the value
    060       */
    061      public static int hashCode(byte value) {
    062        return value;
    063      }
    064
    065      /**
    066       * Returns {@code true} if {@code target} is present as an element anywhere in
    067       * {@code array}.
    068       *
    069       * @param array an array of {@code byte} values, possibly empty
    070       * @param target a primitive {@code byte} value
    071       * @return {@code true} if {@code array[i] == target} for some value of {@code
    072       *     i}
    073       */
    074      public static boolean contains(byte[] array, byte target) {
    075        for (byte value : array) {
    076          if (value == target) {
    077            return true;
    078          }
    079        }
    080        return false;
    081      }
    082
    083      /**
    084       * Returns the index of the first appearance of the value {@code target} in
    085       * {@code array}.
    086       *
    087       * @param array an array of {@code byte} values, possibly empty
    088       * @param target a primitive {@code byte} value
    089       * @return the least index {@code i} for which {@code array[i] == target}, or
    090       *     {@code -1} if no such index exists.
    091       */
    092      public static int indexOf(byte[] array, byte target) {
    093        return indexOf(array, target, 0, array.length);
    094      }
    095
    096      // TODO(kevinb): consider making this public
    097      private static int indexOf(
    098          byte[] array, byte target, int start, int end) {
    099        for (int i = start; i < end; i++) {
    100          if (array[i] == target) {
    101            return i;
    102          }
    103        }
    104        return -1;
    105      }
    106
    107      /**
    108       * Returns the start position of the first occurrence of the specified {@code
    109       * target} within {@code array}, or {@code -1} if there is no such occurrence.
    110       *
    111       * <p>More formally, returns the lowest index {@code i} such that {@code
    112       * java.util.Arrays.copyOfRange(array, i, i + target.length)} contains exactly
    113       * the same elements as {@code target}.
    114       *
    115       * @param array the array to search for the sequence {@code target}
    116       * @param target the array to search for as a sub-sequence of {@code array}
    117       */
    118      public static int indexOf(byte[] array, byte[] target) {
    119        checkNotNull(array, "array");
    120        checkNotNull(target, "target");
    121        if (target.length == 0) {
    122          return 0;
    123        }
    124
    125        outer:
    126        for (int i = 0; i < array.length - target.length + 1; i++) {
    127          for (int j = 0; j < target.length; j++) {
    128            if (array[i + j] != target[j]) {
    129              continue outer;
    130            }
    131          }
    132          return i;
    133        }
    134        return -1;
    135      }
    136
    137      /**
    138       * Returns the index of the last appearance of the value {@code target} in
    139       * {@code array}.
    140       *
    141       * @param array an array of {@code byte} values, possibly empty
    142       * @param target a primitive {@code byte} value
    143       * @return the greatest index {@code i} for which {@code array[i] == target},
    144       *     or {@code -1} if no such index exists.
    145       */
    146      public static int lastIndexOf(byte[] array, byte target) {
    147        return lastIndexOf(array, target, 0, array.length);
    148      }
    149
    150      // TODO(kevinb): consider making this public
    151      private static int lastIndexOf(
    152          byte[] array, byte target, int start, int end) {
    153        for (int i = end - 1; i >= start; i--) {
    154          if (array[i] == target) {
    155            return i;
    156          }
    157        }
    158        return -1;
    159      }
    160
    161      /**
    162       * Returns the values from each provided array combined into a single array.
    163       * For example, {@code concat(new byte[] {a, b}, new byte[] {}, new
    164       * byte[] {c}} returns the array {@code {a, b, c}}.
    165       *
    166       * @param arrays zero or more {@code byte} arrays
    167       * @return a single array containing all the values from the source arrays, in
    168       *     order
    169       */
    170      public static byte[] concat(byte[]... arrays) {
    171        int length = 0;
    172        for (byte[] array : arrays) {
    173          length += array.length;
    174        }
    175        byte[] result = new byte[length];
    176        int pos = 0;
    177        for (byte[] array : arrays) {
    178          System.arraycopy(array, 0, result, pos, array.length);
    179          pos += array.length;
    180        }
    181        return result;
    182      }
    183
    184      /**
    185       * Returns an array containing the same values as {@code array}, but
    186       * guaranteed to be of a specified minimum length. If {@code array} already
    187       * has a length of at least {@code minLength}, it is returned directly.
    188       * Otherwise, a new array of size {@code minLength + padding} is returned,
    189       * containing the values of {@code array}, and zeroes in the remaining places.
    190       *
    191       * @param array the source array
    192       * @param minLength the minimum length the returned array must guarantee
    193       * @param padding an extra amount to "grow" the array by if growth is
    194       *     necessary
    195       * @throws IllegalArgumentException if {@code minLength} or {@code padding} is
    196       *     negative
    197       * @return an array containing the values of {@code array}, with guaranteed
    198       *     minimum length {@code minLength}
    199       */
    200      public static byte[] ensureCapacity(
    201          byte[] array, int minLength, int padding) {
    202        checkArgument(minLength >= 0, "Invalid minLength: %s", minLength);
    203        checkArgument(padding >= 0, "Invalid padding: %s", padding);
    204        return (array.length < minLength)
    205            ? copyOf(array, minLength + padding)
    206            : array;
    207      }
    208
    209      // Arrays.copyOf() requires Java 6
    210      private static byte[] copyOf(byte[] original, int length) {
    211        byte[] copy = new byte[length];
    212        System.arraycopy(original, 0, copy, 0, Math.min(original.length, length));
    213        return copy;
    214      }
    215
    216      /**
    217       * Returns an array containing each value of {@code collection}, converted to
    218       * a {@code byte} value in the manner of {@link Number#byteValue}.
    219       *
    220       * <p>Elements are copied from the argument collection as if by {@code
    221       * collection.toArray()}.  Calling this method is as thread-safe as calling
    222       * that method.
    223       *
    224       * @param collection a collection of {@code Number} instances
    225       * @return an array containing the same values as {@code collection}, in the
    226       *     same order, converted to primitives
    227       * @throws NullPointerException if {@code collection} or any of its elements
    228       *     is null
    229       * @since 1.0 (parameter was {@code Collection<Byte>} before 12.0)
    230       */
    231      public static byte[] toArray(Collection<? extends Number> collection) {
    232        if (collection instanceof ByteArrayAsList) {
    233          return ((ByteArrayAsList) collection).toByteArray();
    234        }
    235
    236        Object[] boxedArray = collection.toArray();
    237        int len = boxedArray.length;
    238        byte[] array = new byte[len];
    239        for (int i = 0; i < len; i++) {
    240          // checkNotNull for GWT (do not optimize)
    241          array[i] = ((Number) checkNotNull(boxedArray[i])).byteValue();
    242        }
    243        return array;
    244      }
    245
    246      /**
    247       * Returns a fixed-size list backed by the specified array, similar to {@link
    248       * Arrays#asList(Object[])}. The list supports {@link List#set(int, Object)},
    249       * but any attempt to set a value to {@code null} will result in a {@link
    250       * NullPointerException}.
    251       *
    252       * <p>The returned list maintains the values, but not the identities, of
    253       * {@code Byte} objects written to or read from it.  For example, whether
    254       * {@code list.get(0) == list.get(0)} is true for the returned list is
    255       * unspecified.
    256       *
    257       * @param backingArray the array to back the list
    258       * @return a list view of the array
    259       */
    260      public static List<Byte> asList(byte... backingArray) {
    261        if (backingArray.length == 0) {
    262          return Collections.emptyList();
    263        }
    264        return new ByteArrayAsList(backingArray);
    265      }
    266
    267      @GwtCompatible
    268      private static class ByteArrayAsList extends AbstractList<Byte>
    269          implements RandomAccess, Serializable {
    270        final byte[] array;
    271        final int start;
    272        final int end;
    273
    274        ByteArrayAsList(byte[] array) {
    275          this(array, 0, array.length);
    276        }
    277
    278        ByteArrayAsList(byte[] array, int start, int end) {
    279          this.array = array;
    280          this.start = start;
    281          this.end = end;
    282        }
    283
    284        @Override public int size() {
    285          return end - start;
    286        }
    287
    288        @Override public boolean isEmpty() {
    289          return false;
    290        }
    291
    292        @Override public Byte get(int index) {
    293          checkElementIndex(index, size());
    294          return array[start + index];
    295        }
    296
    297        @Override public boolean contains(Object target) {
    298          // Overridden to prevent a ton of boxing
    299          return (target instanceof Byte)
    300              && Bytes.indexOf(array, (Byte) target, start, end) != -1;
    301        }
    302
    303        @Override public int indexOf(Object target) {
    304          // Overridden to prevent a ton of boxing
    305          if (target instanceof Byte) {
    306            int i = Bytes.indexOf(array, (Byte) target, start, end);
    307            if (i >= 0) {
    308              return i - start;
    309            }
    310          }
    311          return -1;
    312        }
    313
    314        @Override public int lastIndexOf(Object target) {
    315          // Overridden to prevent a ton of boxing
    316          if (target instanceof Byte) {
    317            int i = Bytes.lastIndexOf(array, (Byte) target, start, end);
    318            if (i >= 0) {
    319              return i - start;
    320            }
    321          }
    322          return -1;
    323        }
    324
    325        @Override public Byte set(int index, Byte element) {
    326          checkElementIndex(index, size());
    327          byte oldValue = array[start + index];
    328          // checkNotNull for GWT (do not optimize)
    329          array[start + index] = checkNotNull(element);
    330          return oldValue;
    331        }
    332
    333        @Override public List<Byte> subList(int fromIndex, int toIndex) {
    334          int size = size();
    335          checkPositionIndexes(fromIndex, toIndex, size);
    336          if (fromIndex == toIndex) {
    337            return Collections.emptyList();
    338          }
    339          return new ByteArrayAsList(array, start + fromIndex, start + toIndex);
    340        }
    341
    342        @Override public boolean equals(Object object) {
    343          if (object == this) {
    344            return true;
    345          }
    346          if (object instanceof ByteArrayAsList) {
    347            ByteArrayAsList that = (ByteArrayAsList) object;
    348            int size = size();
    349            if (that.size() != size) {
    350              return false;
    351            }
    352            for (int i = 0; i < size; i++) {
    353              if (array[start + i] != that.array[that.start + i]) {
    354                return false;
    355              }
    356            }
    357            return true;
    358          }
    359          return super.equals(object);
    360        }
    361
    362        @Override public int hashCode() {
    363          int result = 1;
    364          for (int i = start; i < end; i++) {
    365            result = 31 * result + Bytes.hashCode(array[i]);
    366          }
    367          return result;
    368        }
    369
    370        @Override public String toString() {
    371          StringBuilder builder = new StringBuilder(size() * 5);
    372          builder.append('[').append(array[start]);
    373          for (int i = start + 1; i < end; i++) {
    374            builder.append(", ").append(array[i]);
    375          }
    376          return builder.append(']').toString();
    377        }
    378
    379        byte[] toByteArray() {
    380          // Arrays.copyOfRange() is not available under GWT
    381          int size = size();
    382          byte[] result = new byte[size];
    383          System.arraycopy(array, start, result, 0, size);
    384          return result;
    385        }
    386
    387        private static final long serialVersionUID = 0;
    388      }
    389    }