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 * <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
051public 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}