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 }