Home | History | Annotate | Download | only in primitives
      1 /*
      2  * Copyright (C) 2008 Google Inc.
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  * http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.google.common.primitives;
     18 
     19 import com.google.common.annotations.GwtCompatible;
     20 import static com.google.common.base.Preconditions.checkArgument;
     21 import static com.google.common.base.Preconditions.checkElementIndex;
     22 import static com.google.common.base.Preconditions.checkNotNull;
     23 import static com.google.common.base.Preconditions.checkPositionIndexes;
     24 
     25 import java.io.Serializable;
     26 import java.util.AbstractList;
     27 import java.util.Arrays;
     28 import java.util.Collection;
     29 import java.util.Collections;
     30 import java.util.List;
     31 import java.util.RandomAccess;
     32 
     33 /**
     34  * Static utility methods pertaining to {@code byte} primitives, that are not
     35  * already found in either {@link Byte} or {@link Arrays}, <i>and interpret
     36  * bytes as neither signed nor unsigned</i>. The methods which specifically
     37  * treat bytes as signed or unsigned are found in {@link SignedBytes} and {@link
     38  * UnsignedBytes}.
     39  *
     40  * @author Kevin Bourrillion
     41  * @since 2009.09.15 <b>tentative</b>
     42  */
     43 @GwtCompatible
     44 public final class Bytes {
     45   private Bytes() {}
     46 
     47   /**
     48    * Returns a hash code for {@code value}; equal to the result of invoking
     49    * {@code ((Byte) value).hashCode()}.
     50    *
     51    * @param value a primitive {@code byte} value
     52    * @return a hash code for the value
     53    */
     54   public static int hashCode(byte value) {
     55     return value;
     56   }
     57 
     58   /**
     59    * Returns {@code true} if {@code target} is present as an element anywhere in
     60    * {@code array}.
     61    *
     62    * @param array an array of {@code byte} values, possibly empty
     63    * @param target a primitive {@code byte} value
     64    * @return {@code true} if {@code array[i] == target} for some value of {@code
     65    *     i}
     66    */
     67   public static boolean contains(byte[] array, byte target) {
     68     for (byte value : array) {
     69       if (value == target) {
     70         return true;
     71       }
     72     }
     73     return false;
     74   }
     75 
     76   /**
     77    * Returns the index of the first appearance of the value {@code target} in
     78    * {@code array}.
     79    *
     80    * @param array an array of {@code byte} values, possibly empty
     81    * @param target a primitive {@code byte} value
     82    * @return the least index {@code i} for which {@code array[i] == target}, or
     83    *     {@code -1} if no such index exists.
     84    */
     85   public static int indexOf(byte[] array, byte target) {
     86     return indexOf(array, target, 0, array.length);
     87   }
     88 
     89   // TODO: consider making this public
     90   private static int indexOf(
     91       byte[] array, byte target, int start, int end) {
     92     for (int i = start; i < end; i++) {
     93       if (array[i] == target) {
     94         return i;
     95       }
     96     }
     97     return -1;
     98   }
     99 
    100   /**
    101    * Returns the start position of the first occurrence of the specified {@code
    102    * target} within {@code array}, or {@code -1} if there is no such occurrence.
    103    *
    104    * <p>More formally, returns the lowest index {@code i} such that {@code
    105    * java.util.Arrays.copyOfRange(array, i, i + target.length)} contains exactly
    106    * the same elements as {@code target}.
    107    *
    108    * @param array the array to search for the sequence {@code target}
    109    * @param target the array to search for as a sub-sequence of {@code array}
    110    */
    111   public static int indexOf(byte[] array, byte[] target) {
    112     checkNotNull(array, "array");
    113     checkNotNull(target, "target");
    114     if (target.length == 0) {
    115       return 0;
    116     }
    117 
    118     outer:
    119     for (int i = 0; i < array.length - target.length + 1; i++) {
    120       for (int j = 0; j < target.length; j++) {
    121         if (array[i + j] != target[j]) {
    122           continue outer;
    123         }
    124       }
    125       return i;
    126     }
    127     return -1;
    128   }
    129 
    130   /**
    131    * Returns the index of the last appearance of the value {@code target} in
    132    * {@code array}.
    133    *
    134    * @param array an array of {@code byte} values, possibly empty
    135    * @param target a primitive {@code byte} value
    136    * @return the greatest index {@code i} for which {@code array[i] == target},
    137    *     or {@code -1} if no such index exists.
    138    */
    139   public static int lastIndexOf(byte[] array, byte target) {
    140     return lastIndexOf(array, target, 0, array.length);
    141   }
    142 
    143   // TODO: consider making this public
    144   private static int lastIndexOf(
    145       byte[] array, byte target, int start, int end) {
    146     for (int i = end - 1; i >= start; i--) {
    147       if (array[i] == target) {
    148         return i;
    149       }
    150     }
    151     return -1;
    152   }
    153 
    154   /**
    155    * Returns the values from each provided array combined into a single array.
    156    * For example, {@code concat(new byte[] {a, b}, new byte[] {}, new
    157    * byte[] {c}} returns the array {@code {a, b, c}}.
    158    *
    159    * @param arrays zero or more {@code byte} arrays
    160    * @return a single array containing all the values from the source arrays, in
    161    *     order
    162    */
    163   public static byte[] concat(byte[]... arrays) {
    164     int length = 0;
    165     for (byte[] array : arrays) {
    166       length += array.length;
    167     }
    168     byte[] result = new byte[length];
    169     int pos = 0;
    170     for (byte[] array : arrays) {
    171       System.arraycopy(array, 0, result, pos, array.length);
    172       pos += array.length;
    173     }
    174     return result;
    175   }
    176 
    177   /**
    178    * Returns an array containing the same values as {@code array}, but
    179    * guaranteed to be of a specified minimum length. If {@code array} already
    180    * has a length of at least {@code minLength}, it is returned directly.
    181    * Otherwise, a new array of size {@code minLength + padding} is returned,
    182    * containing the values of {@code array}, and zeroes in the remaining places.
    183    *
    184    * @param array the source array
    185    * @param minLength the minimum length the returned array must guarantee
    186    * @param padding an extra amount to "grow" the array by if growth is
    187    *     necessary
    188    * @throws IllegalArgumentException if {@code minLength} or {@code padding} is
    189    *     negative
    190    * @return an array containing the values of {@code array}, with guaranteed
    191    *     minimum length {@code minLength}
    192    */
    193   public static byte[] ensureCapacity(
    194       byte[] array, int minLength, int padding) {
    195     checkArgument(minLength >= 0, "Invalid minLength: %s", minLength);
    196     checkArgument(padding >= 0, "Invalid padding: %s", padding);
    197     return (array.length < minLength)
    198         ? copyOf(array, minLength + padding)
    199         : array;
    200   }
    201 
    202   // Arrays.copyOf() requires Java 6
    203   private static byte[] copyOf(byte[] original, int length) {
    204     byte[] copy = new byte[length];
    205     System.arraycopy(original, 0, copy, 0, Math.min(original.length, length));
    206     return copy;
    207   }
    208 
    209   /**
    210    * Copies a collection of {@code Byte} instances into a new array of
    211    * primitive {@code byte} values.
    212    *
    213    * <p>Elements are copied from the argument collection as if by {@code
    214    * collection.toArray()}.  Calling this method is as thread-safe as calling
    215    * that method.
    216    *
    217    * @param collection a collection of {@code Byte} objects
    218    * @return an array containing the same values as {@code collection}, in the
    219    *     same order, converted to primitives
    220    * @throws NullPointerException if {@code collection} or any of its elements
    221    *     is null
    222    */
    223   public static byte[] toArray(Collection<Byte> collection) {
    224     if (collection instanceof ByteArrayAsList) {
    225       return ((ByteArrayAsList) collection).toByteArray();
    226     }
    227 
    228     Object[] boxedArray = collection.toArray();
    229     int len = boxedArray.length;
    230     byte[] array = new byte[len];
    231     for (int i = 0; i < len; i++) {
    232       array[i] = (Byte) boxedArray[i];
    233     }
    234     return array;
    235   }
    236 
    237   /**
    238    * Returns a fixed-size list backed by the specified array, similar to {@link
    239    * Arrays#asList(Object[])}. The list supports {@link List#set(int, Object)},
    240    * but any attempt to set a value to {@code null} will result in a {@link
    241    * NullPointerException}.
    242    *
    243    * <p>The returned list maintains the values, but not the identities, of
    244    * {@code Byte} objects written to or read from it.  For example, whether
    245    * {@code list.get(0) == list.get(0)} is true for the returned list is
    246    * unspecified.
    247    *
    248    * @param backingArray the array to back the list
    249    * @return a list view of the array
    250    */
    251   public static List<Byte> asList(byte... backingArray) {
    252     if (backingArray.length == 0) {
    253       return Collections.emptyList();
    254     }
    255     return new ByteArrayAsList(backingArray);
    256   }
    257 
    258   @GwtCompatible
    259   private static class ByteArrayAsList extends AbstractList<Byte>
    260       implements RandomAccess, Serializable {
    261     final byte[] array;
    262     final int start;
    263     final int end;
    264 
    265     ByteArrayAsList(byte[] array) {
    266       this(array, 0, array.length);
    267     }
    268 
    269     ByteArrayAsList(byte[] array, int start, int end) {
    270       this.array = array;
    271       this.start = start;
    272       this.end = end;
    273     }
    274 
    275     @Override public int size() {
    276       return end - start;
    277     }
    278 
    279     @Override public boolean isEmpty() {
    280       return false;
    281     }
    282 
    283     @Override public Byte get(int index) {
    284       checkElementIndex(index, size());
    285       return array[start + index];
    286     }
    287 
    288     @Override public boolean contains(Object target) {
    289       // Overridden to prevent a ton of boxing
    290       return (target instanceof Byte)
    291           && Bytes.indexOf(array, (Byte) target, start, end) != -1;
    292     }
    293 
    294     @Override public int indexOf(Object target) {
    295       // Overridden to prevent a ton of boxing
    296       if (target instanceof Byte) {
    297         int i = Bytes.indexOf(array, (Byte) target, start, end);
    298         if (i >= 0) {
    299           return i - start;
    300         }
    301       }
    302       return -1;
    303     }
    304 
    305     @Override public int lastIndexOf(Object target) {
    306       // Overridden to prevent a ton of boxing
    307       if (target instanceof Byte) {
    308         int i = Bytes.lastIndexOf(array, (Byte) target, start, end);
    309         if (i >= 0) {
    310           return i - start;
    311         }
    312       }
    313       return -1;
    314     }
    315 
    316     @Override public Byte set(int index, Byte element) {
    317       checkElementIndex(index, size());
    318       byte oldValue = array[start + index];
    319       array[start + index] = element;
    320       return oldValue;
    321     }
    322 
    323     /** In GWT, List and AbstractList do not have the subList method. */
    324     /*@Override*/ public List<Byte> subList(int fromIndex, int toIndex) {
    325       int size = size();
    326       checkPositionIndexes(fromIndex, toIndex, size);
    327       if (fromIndex == toIndex) {
    328         return Collections.emptyList();
    329       }
    330       return new ByteArrayAsList(array, start + fromIndex, start + toIndex);
    331     }
    332 
    333     @Override public boolean equals(Object object) {
    334       if (object == this) {
    335         return true;
    336       }
    337       if (object instanceof ByteArrayAsList) {
    338         ByteArrayAsList that = (ByteArrayAsList) object;
    339         int size = size();
    340         if (that.size() != size) {
    341           return false;
    342         }
    343         for (int i = 0; i < size; i++) {
    344           if (array[start + i] != that.array[that.start + i]) {
    345             return false;
    346           }
    347         }
    348         return true;
    349       }
    350       return super.equals(object);
    351     }
    352 
    353     @Override public int hashCode() {
    354       int result = 1;
    355       for (int i = start; i < end; i++) {
    356         result = 31 * result + Bytes.hashCode(array[i]);
    357       }
    358       return result;
    359     }
    360 
    361     @Override public String toString() {
    362       StringBuilder builder = new StringBuilder(size() * 5);
    363       builder.append('[').append(array[start]);
    364       for (int i = start + 1; i < end; i++) {
    365         builder.append(", ").append(array[i]);
    366       }
    367       return builder.append(']').toString();
    368     }
    369 
    370     byte[] toByteArray() {
    371       // Arrays.copyOfRange() requires Java 6
    372       int size = size();
    373       byte[] result = new byte[size];
    374       System.arraycopy(array, start, result, 0, size);
    375       return result;
    376     }
    377 
    378     private static final long serialVersionUID = 0;
    379   }
    380 }
    381