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