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