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