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    
017    package com.google.common.primitives;
018    
019    import static com.google.common.base.Preconditions.checkArgument;
020    import static com.google.common.base.Preconditions.checkElementIndex;
021    import static com.google.common.base.Preconditions.checkNotNull;
022    import static com.google.common.base.Preconditions.checkPositionIndexes;
023    
024    import com.google.common.annotations.GwtCompatible;
025    
026    import java.io.Serializable;
027    import java.util.AbstractList;
028    import java.util.Arrays;
029    import java.util.Collection;
030    import java.util.Collections;
031    import java.util.List;
032    import 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
051    public 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        
285        @Override
286        public int size() {
287          return end - start;
288        }
289    
290        
291        @Override
292        public boolean isEmpty() {
293          return false;
294        }
295    
296        
297        @Override
298        public Byte get(int index) {
299          checkElementIndex(index, size());
300          return array[start + index];
301        }
302    
303        
304        @Override
305        public boolean contains(Object target) {
306          // Overridden to prevent a ton of boxing
307          return (target instanceof Byte)
308              && Bytes.indexOf(array, (Byte) target, start, end) != -1;
309        }
310    
311        
312        @Override
313        public int indexOf(Object target) {
314          // Overridden to prevent a ton of boxing
315          if (target instanceof Byte) {
316            int i = Bytes.indexOf(array, (Byte) target, start, end);
317            if (i >= 0) {
318              return i - start;
319            }
320          }
321          return -1;
322        }
323    
324        
325        @Override
326        public int lastIndexOf(Object target) {
327          // Overridden to prevent a ton of boxing
328          if (target instanceof Byte) {
329            int i = Bytes.lastIndexOf(array, (Byte) target, start, end);
330            if (i >= 0) {
331              return i - start;
332            }
333          }
334          return -1;
335        }
336    
337        
338        @Override
339        public Byte set(int index, Byte element) {
340          checkElementIndex(index, size());
341          byte oldValue = array[start + index];
342          // checkNotNull for GWT (do not optimize)
343          array[start + index] = checkNotNull(element);
344          return oldValue;
345        }
346    
347        
348        @Override
349        public List<Byte> subList(int fromIndex, int toIndex) {
350          int size = size();
351          checkPositionIndexes(fromIndex, toIndex, size);
352          if (fromIndex == toIndex) {
353            return Collections.emptyList();
354          }
355          return new ByteArrayAsList(array, start + fromIndex, start + toIndex);
356        }
357    
358        
359        @Override
360        public boolean equals(Object object) {
361          if (object == this) {
362            return true;
363          }
364          if (object instanceof ByteArrayAsList) {
365            ByteArrayAsList that = (ByteArrayAsList) object;
366            int size = size();
367            if (that.size() != size) {
368              return false;
369            }
370            for (int i = 0; i < size; i++) {
371              if (array[start + i] != that.array[that.start + i]) {
372                return false;
373              }
374            }
375            return true;
376          }
377          return super.equals(object);
378        }
379    
380        
381        @Override
382        public int hashCode() {
383          int result = 1;
384          for (int i = start; i < end; i++) {
385            result = 31 * result + Bytes.hashCode(array[i]);
386          }
387          return result;
388        }
389    
390        
391        @Override
392        public String toString() {
393          StringBuilder builder = new StringBuilder(size() * 5);
394          builder.append('[').append(array[start]);
395          for (int i = start + 1; i < end; i++) {
396            builder.append(", ").append(array[i]);
397          }
398          return builder.append(']').toString();
399        }
400    
401        byte[] toByteArray() {
402          // Arrays.copyOfRange() is not available under GWT
403          int size = size();
404          byte[] result = new byte[size];
405          System.arraycopy(array, start, result, 0, size);
406          return result;
407        }
408    
409        private static final long serialVersionUID = 0;
410      }
411    }