• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008 The Guava Authors
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 static com.google.common.base.Preconditions.checkArgument;
20 import static com.google.common.base.Preconditions.checkElementIndex;
21 import static com.google.common.base.Preconditions.checkNotNull;
22 import static com.google.common.base.Preconditions.checkPositionIndexes;
23 
24 import com.google.common.annotations.GwtCompatible;
25 
26 import java.io.Serializable;
27 import java.util.AbstractList;
28 import java.util.Arrays;
29 import java.util.Collection;
30 import java.util.Collections;
31 import java.util.List;
32 import java.util.RandomAccess;
33 
34 /**
35  * Static utility methods pertaining to {@code byte} primitives, that are not
36  * already found in either {@link Byte} or {@link Arrays}, <i>and interpret
37  * bytes as neither signed nor unsigned</i>. The methods which specifically
38  * treat bytes as signed or unsigned are found in {@link SignedBytes} and {@link
39  * UnsignedBytes}.
40  *
41  * <p>See the Guava User Guide article on <a href=
42  * "http://code.google.com/p/guava-libraries/wiki/PrimitivesExplained">
43  * primitive utilities</a>.
44  *
45  * @author Kevin Bourrillion
46  * @since 1.0
47  */
48 // TODO(kevinb): how to prevent warning on UnsignedBytes when building GWT
49 // javadoc?
50 @GwtCompatible
51 public final class Bytes {
Bytes()52   private Bytes() {}
53 
54   /**
55    * Returns a hash code for {@code value}; equal to the result of invoking
56    * {@code ((Byte) value).hashCode()}.
57    *
58    * @param value a primitive {@code byte} value
59    * @return a hash code for the value
60    */
hashCode(byte value)61   public static int hashCode(byte value) {
62     return value;
63   }
64 
65   /**
66    * Returns {@code true} if {@code target} is present as an element anywhere in
67    * {@code array}.
68    *
69    * @param array an array of {@code byte} values, possibly empty
70    * @param target a primitive {@code byte} value
71    * @return {@code true} if {@code array[i] == target} for some value of {@code
72    *     i}
73    */
contains(byte[] array, byte target)74   public static boolean contains(byte[] array, byte target) {
75     for (byte value : array) {
76       if (value == target) {
77         return true;
78       }
79     }
80     return false;
81   }
82 
83   /**
84    * Returns the index of the first appearance of the value {@code target} in
85    * {@code array}.
86    *
87    * @param array an array of {@code byte} values, possibly empty
88    * @param target a primitive {@code byte} value
89    * @return the least index {@code i} for which {@code array[i] == target}, or
90    *     {@code -1} if no such index exists.
91    */
indexOf(byte[] array, byte target)92   public static int indexOf(byte[] array, byte target) {
93     return indexOf(array, target, 0, array.length);
94   }
95 
96   // TODO(kevinb): consider making this public
indexOf( byte[] array, byte target, int start, int end)97   private static int indexOf(
98       byte[] array, byte target, int start, int end) {
99     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    */
indexOf(byte[] array, byte[] target)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    */
lastIndexOf(byte[] array, byte target)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
lastIndexOf( byte[] array, byte target, int start, int end)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    */
concat(byte[]... arrays)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    */
ensureCapacity( byte[] array, int minLength, int padding)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
copyOf(byte[] original, int length)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    */
toArray(Collection<? extends Number> collection)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    */
asList(byte... backingArray)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 
ByteArrayAsList(byte[] array)274     ByteArrayAsList(byte[] array) {
275       this(array, 0, array.length);
276     }
277 
ByteArrayAsList(byte[] array, int start, int end)278     ByteArrayAsList(byte[] array, int start, int end) {
279       this.array = array;
280       this.start = start;
281       this.end = end;
282     }
283 
size()284     @Override public int size() {
285       return end - start;
286     }
287 
isEmpty()288     @Override public boolean isEmpty() {
289       return false;
290     }
291 
get(int index)292     @Override public Byte get(int index) {
293       checkElementIndex(index, size());
294       return array[start + index];
295     }
296 
contains(Object target)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 
indexOf(Object target)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 
lastIndexOf(Object target)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 
set(int index, Byte element)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 
subList(int fromIndex, int toIndex)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 
equals(Object object)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 
hashCode()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 
toString()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 
toByteArray()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 }
390