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