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