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 }