001/* 002 * Copyright (C) 2008 The Guava Authors 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 005 * in compliance with the License. You may obtain a copy of the License at 006 * 007 * http://www.apache.org/licenses/LICENSE-2.0 008 * 009 * Unless required by applicable law or agreed to in writing, software distributed under the License 010 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 011 * or implied. See the License for the specific language governing permissions and limitations under 012 * the License. 013 */ 014 015package com.google.common.primitives; 016 017import static com.google.common.base.Preconditions.checkArgument; 018import static com.google.common.base.Preconditions.checkElementIndex; 019import static com.google.common.base.Preconditions.checkNotNull; 020import static com.google.common.base.Preconditions.checkPositionIndexes; 021 022import com.google.common.annotations.Beta; 023import com.google.common.annotations.GwtCompatible; 024import java.io.Serializable; 025import java.util.AbstractList; 026import java.util.Arrays; 027import java.util.Collection; 028import java.util.Collections; 029import java.util.Comparator; 030import java.util.List; 031import java.util.RandomAccess; 032import javax.annotation.Nullable; 033 034/** 035 * Static utility methods pertaining to {@code boolean} primitives, that are not already found in 036 * either {@link Boolean} or {@link Arrays}. 037 * 038 * <p>See the Guava User Guide article on 039 * <a href="https://github.com/google/guava/wiki/PrimitivesExplained">primitive utilities</a>. 040 * 041 * @author Kevin Bourrillion 042 * @since 1.0 043 */ 044@GwtCompatible 045public final class Booleans { 046 private Booleans() {} 047 048 /** 049 * Comparators for {@code Boolean} values. 050 */ 051 private enum BooleanComparator implements Comparator<Boolean> { 052 TRUE_FIRST(1, "Booleans.trueFirst()"), 053 FALSE_FIRST(-1, "Booleans.falseFirst()"); 054 055 private final int trueValue; 056 private final String toString; 057 058 BooleanComparator(int trueValue, String toString) { 059 this.trueValue = trueValue; 060 this.toString = toString; 061 } 062 063 @Override 064 public int compare(Boolean a, Boolean b) { 065 int aVal = a ? trueValue : 0; 066 int bVal = b ? trueValue : 0; 067 return bVal - aVal; 068 } 069 070 @Override 071 public String toString() { 072 return toString; 073 } 074 } 075 076 /** 077 * Returns a {@code Comparator<Boolean>} that sorts {@code true} before {@code false}. 078 * 079 * <p>This is particularly useful in Java 8+ in combination with {@code Comparators.comparing}, 080 * e.g. {@code Comparators.comparing(Foo::hasBar, trueFirst())}. 081 * 082 * @since 21.0 083 */ 084 @Beta 085 public static Comparator<Boolean> trueFirst() { 086 return BooleanComparator.TRUE_FIRST; 087 } 088 089 /** 090 * Returns a {@code Comparator<Boolean>} that sorts {@code false} before {@code true}. 091 * 092 * <p>This is particularly useful in Java 8+ in combination with {@code Comparators.comparing}, 093 * e.g. {@code Comparators.comparing(Foo::hasBar, falseFirst())}. 094 * 095 * @since 21.0 096 */ 097 @Beta 098 public static Comparator<Boolean> falseFirst() { 099 return BooleanComparator.FALSE_FIRST; 100 } 101 102 /** 103 * Returns a hash code for {@code value}; equal to the result of invoking 104 * {@code ((Boolean) value).hashCode()}. 105 * 106 * <p><b>Java 8 users:</b> use {@link Boolean#hashCode(boolean)} instead. 107 * 108 * @param value a primitive {@code boolean} value 109 * @return a hash code for the value 110 */ 111 public static int hashCode(boolean value) { 112 return value ? 1231 : 1237; 113 } 114 115 /** 116 * Compares the two specified {@code boolean} values in the standard way ({@code false} is 117 * considered less than {@code true}). The sign of the value returned is the same as that of 118 * {@code ((Boolean) a).compareTo(b)}. 119 * 120 * <p><b>Note for Java 7 and later:</b> this method should be treated as deprecated; use the 121 * equivalent {@link Boolean#compare} method instead. 122 * 123 * @param a the first {@code boolean} to compare 124 * @param b the second {@code boolean} to compare 125 * @return a positive number if only {@code a} is {@code true}, a negative number if only 126 * {@code b} is true, or zero if {@code a == b} 127 */ 128 public static int compare(boolean a, boolean b) { 129 return (a == b) ? 0 : (a ? 1 : -1); 130 } 131 132 /** 133 * Returns {@code true} if {@code target} is present as an element anywhere in {@code array}. 134 * 135 * <p><b>Note:</b> consider representing the array as a {@link java.util.BitSet} instead, 136 * replacing {@code Booleans.contains(array, true)} with {@code !bitSet.isEmpty()} and 137 * {@code Booleans.contains(array, false)} with {@code bitSet.nextClearBit(0) == sizeOfBitSet}. 138 * 139 * @param array an array of {@code boolean} values, possibly empty 140 * @param target a primitive {@code boolean} value 141 * @return {@code true} if {@code array[i] == target} for some value of {@code 142 * i} 143 */ 144 public static boolean contains(boolean[] array, boolean target) { 145 for (boolean value : array) { 146 if (value == target) { 147 return true; 148 } 149 } 150 return false; 151 } 152 153 /** 154 * Returns the index of the first appearance of the value {@code target} in {@code array}. 155 * 156 * <p><b>Note:</b> consider representing the array as a {@link java.util.BitSet} instead, and 157 * using {@link java.util.BitSet#nextSetBit(int)} or {@link java.util.BitSet#nextClearBit(int)}. 158 * 159 * @param array an array of {@code boolean} values, possibly empty 160 * @param target a primitive {@code boolean} value 161 * @return the least index {@code i} for which {@code array[i] == target}, or {@code -1} if no 162 * such index exists. 163 */ 164 public static int indexOf(boolean[] array, boolean target) { 165 return indexOf(array, target, 0, array.length); 166 } 167 168 // TODO(kevinb): consider making this public 169 private static int indexOf(boolean[] array, boolean target, int start, int end) { 170 for (int i = start; i < end; i++) { 171 if (array[i] == target) { 172 return i; 173 } 174 } 175 return -1; 176 } 177 178 /** 179 * Returns the start position of the first occurrence of the specified {@code 180 * target} within {@code array}, or {@code -1} if there is no such occurrence. 181 * 182 * <p>More formally, returns the lowest index {@code i} such that {@code 183 * Arrays.copyOfRange(array, i, i + target.length)} contains exactly the same elements as 184 * {@code target}. 185 * 186 * @param array the array to search for the sequence {@code target} 187 * @param target the array to search for as a sub-sequence of {@code array} 188 */ 189 public static int indexOf(boolean[] array, boolean[] target) { 190 checkNotNull(array, "array"); 191 checkNotNull(target, "target"); 192 if (target.length == 0) { 193 return 0; 194 } 195 196 outer: 197 for (int i = 0; i < array.length - target.length + 1; i++) { 198 for (int j = 0; j < target.length; j++) { 199 if (array[i + j] != target[j]) { 200 continue outer; 201 } 202 } 203 return i; 204 } 205 return -1; 206 } 207 208 /** 209 * Returns the index of the last appearance of the value {@code target} in {@code array}. 210 * 211 * @param array an array of {@code boolean} values, possibly empty 212 * @param target a primitive {@code boolean} value 213 * @return the greatest index {@code i} for which {@code array[i] == target}, or {@code -1} if no 214 * such index exists. 215 */ 216 public static int lastIndexOf(boolean[] array, boolean target) { 217 return lastIndexOf(array, target, 0, array.length); 218 } 219 220 // TODO(kevinb): consider making this public 221 private static int lastIndexOf(boolean[] array, boolean target, int start, int end) { 222 for (int i = end - 1; i >= start; i--) { 223 if (array[i] == target) { 224 return i; 225 } 226 } 227 return -1; 228 } 229 230 /** 231 * Returns the values from each provided array combined into a single array. For example, 232 * {@code concat(new boolean[] {a, b}, new boolean[] {}, new boolean[] {c}} returns the array 233 * {@code {a, b, c}}. 234 * 235 * @param arrays zero or more {@code boolean} arrays 236 * @return a single array containing all the values from the source arrays, in order 237 */ 238 public static boolean[] concat(boolean[]... arrays) { 239 int length = 0; 240 for (boolean[] array : arrays) { 241 length += array.length; 242 } 243 boolean[] result = new boolean[length]; 244 int pos = 0; 245 for (boolean[] array : arrays) { 246 System.arraycopy(array, 0, result, pos, array.length); 247 pos += array.length; 248 } 249 return result; 250 } 251 252 /** 253 * Returns an array containing the same values as {@code array}, but guaranteed to be of a 254 * specified minimum length. If {@code array} already has a length of at least {@code minLength}, 255 * it is returned directly. Otherwise, a new array of size {@code minLength + padding} is 256 * returned, containing the values of {@code array}, and zeroes in the remaining places. 257 * 258 * @param array the source array 259 * @param minLength the minimum length the returned array must guarantee 260 * @param padding an extra amount to "grow" the array by if growth is necessary 261 * @throws IllegalArgumentException if {@code minLength} or {@code padding} is negative 262 * @return an array containing the values of {@code array}, with guaranteed minimum length 263 * {@code minLength} 264 */ 265 public static boolean[] ensureCapacity(boolean[] array, int minLength, int padding) { 266 checkArgument(minLength >= 0, "Invalid minLength: %s", minLength); 267 checkArgument(padding >= 0, "Invalid padding: %s", padding); 268 return (array.length < minLength) ? Arrays.copyOf(array, minLength + padding) : array; 269 } 270 271 /** 272 * Returns a string containing the supplied {@code boolean} values separated by {@code separator}. 273 * For example, {@code join("-", false, true, false)} returns the string 274 * {@code "false-true-false"}. 275 * 276 * @param separator the text that should appear between consecutive values in the resulting string 277 * (but not at the start or end) 278 * @param array an array of {@code boolean} values, possibly empty 279 */ 280 public static String join(String separator, boolean... array) { 281 checkNotNull(separator); 282 if (array.length == 0) { 283 return ""; 284 } 285 286 // For pre-sizing a builder, just get the right order of magnitude 287 StringBuilder builder = new StringBuilder(array.length * 7); 288 builder.append(array[0]); 289 for (int i = 1; i < array.length; i++) { 290 builder.append(separator).append(array[i]); 291 } 292 return builder.toString(); 293 } 294 295 /** 296 * Returns a comparator that compares two {@code boolean} arrays <a 297 * href="http://en.wikipedia.org/wiki/Lexicographical_order">lexicographically</a>. That is, it 298 * compares, using {@link #compare(boolean, boolean)}), the first pair of values that follow any 299 * common prefix, or when one array is a prefix of the other, treats the shorter array as the 300 * lesser. For example, {@code [] < [false] < [false, true] < [true]}. 301 * 302 * <p>The returned comparator is inconsistent with {@link Object#equals(Object)} (since arrays 303 * support only identity equality), but it is consistent with 304 * {@link Arrays#equals(boolean[], boolean[])}. 305 * 306 * @since 2.0 307 */ 308 public static Comparator<boolean[]> lexicographicalComparator() { 309 return LexicographicalComparator.INSTANCE; 310 } 311 312 private enum LexicographicalComparator implements Comparator<boolean[]> { 313 INSTANCE; 314 315 @Override 316 public int compare(boolean[] left, boolean[] right) { 317 int minLength = Math.min(left.length, right.length); 318 for (int i = 0; i < minLength; i++) { 319 int result = Booleans.compare(left[i], right[i]); 320 if (result != 0) { 321 return result; 322 } 323 } 324 return left.length - right.length; 325 } 326 327 @Override 328 public String toString() { 329 return "Booleans.lexicographicalComparator()"; 330 } 331 } 332 333 /** 334 * Copies a collection of {@code Boolean} instances into a new array of primitive {@code boolean} 335 * values. 336 * 337 * <p>Elements are copied from the argument collection as if by {@code 338 * collection.toArray()}. Calling this method is as thread-safe as calling that method. 339 * 340 * <p><b>Note:</b> consider representing the collection as a {@link java.util.BitSet} instead. 341 * 342 * @param collection a collection of {@code Boolean} objects 343 * @return an array containing the same values as {@code collection}, in the same order, converted 344 * to primitives 345 * @throws NullPointerException if {@code collection} or any of its elements is null 346 */ 347 public static boolean[] toArray(Collection<Boolean> collection) { 348 if (collection instanceof BooleanArrayAsList) { 349 return ((BooleanArrayAsList) collection).toBooleanArray(); 350 } 351 352 Object[] boxedArray = collection.toArray(); 353 int len = boxedArray.length; 354 boolean[] array = new boolean[len]; 355 for (int i = 0; i < len; i++) { 356 // checkNotNull for GWT (do not optimize) 357 array[i] = (Boolean) checkNotNull(boxedArray[i]); 358 } 359 return array; 360 } 361 362 /** 363 * Returns a fixed-size list backed by the specified array, similar to 364 * {@link Arrays#asList(Object[])}. The list supports {@link List#set(int, Object)}, but any 365 * attempt to set a value to {@code null} will result in a {@link NullPointerException}. 366 * 367 * <p>The returned list maintains the values, but not the identities, of {@code Boolean} objects 368 * written to or read from it. For example, whether {@code list.get(0) == list.get(0)} is true for 369 * the returned list is unspecified. 370 * 371 * @param backingArray the array to back the list 372 * @return a list view of the array 373 */ 374 public static List<Boolean> asList(boolean... backingArray) { 375 if (backingArray.length == 0) { 376 return Collections.emptyList(); 377 } 378 return new BooleanArrayAsList(backingArray); 379 } 380 381 @GwtCompatible 382 private static class BooleanArrayAsList extends AbstractList<Boolean> 383 implements RandomAccess, Serializable { 384 final boolean[] array; 385 final int start; 386 final int end; 387 388 BooleanArrayAsList(boolean[] array) { 389 this(array, 0, array.length); 390 } 391 392 BooleanArrayAsList(boolean[] array, int start, int end) { 393 this.array = array; 394 this.start = start; 395 this.end = end; 396 } 397 398 @Override 399 public int size() { 400 return end - start; 401 } 402 403 @Override 404 public boolean isEmpty() { 405 return false; 406 } 407 408 @Override 409 public Boolean get(int index) { 410 checkElementIndex(index, size()); 411 return array[start + index]; 412 } 413 414 @Override 415 public boolean contains(Object target) { 416 // Overridden to prevent a ton of boxing 417 return (target instanceof Boolean) 418 && Booleans.indexOf(array, (Boolean) target, start, end) != -1; 419 } 420 421 @Override 422 public int indexOf(Object target) { 423 // Overridden to prevent a ton of boxing 424 if (target instanceof Boolean) { 425 int i = Booleans.indexOf(array, (Boolean) target, start, end); 426 if (i >= 0) { 427 return i - start; 428 } 429 } 430 return -1; 431 } 432 433 @Override 434 public int lastIndexOf(Object target) { 435 // Overridden to prevent a ton of boxing 436 if (target instanceof Boolean) { 437 int i = Booleans.lastIndexOf(array, (Boolean) target, start, end); 438 if (i >= 0) { 439 return i - start; 440 } 441 } 442 return -1; 443 } 444 445 @Override 446 public Boolean set(int index, Boolean element) { 447 checkElementIndex(index, size()); 448 boolean oldValue = array[start + index]; 449 // checkNotNull for GWT (do not optimize) 450 array[start + index] = checkNotNull(element); 451 return oldValue; 452 } 453 454 @Override 455 public List<Boolean> subList(int fromIndex, int toIndex) { 456 int size = size(); 457 checkPositionIndexes(fromIndex, toIndex, size); 458 if (fromIndex == toIndex) { 459 return Collections.emptyList(); 460 } 461 return new BooleanArrayAsList(array, start + fromIndex, start + toIndex); 462 } 463 464 @Override 465 public boolean equals(@Nullable Object object) { 466 if (object == this) { 467 return true; 468 } 469 if (object instanceof BooleanArrayAsList) { 470 BooleanArrayAsList that = (BooleanArrayAsList) object; 471 int size = size(); 472 if (that.size() != size) { 473 return false; 474 } 475 for (int i = 0; i < size; i++) { 476 if (array[start + i] != that.array[that.start + i]) { 477 return false; 478 } 479 } 480 return true; 481 } 482 return super.equals(object); 483 } 484 485 @Override 486 public int hashCode() { 487 int result = 1; 488 for (int i = start; i < end; i++) { 489 result = 31 * result + Booleans.hashCode(array[i]); 490 } 491 return result; 492 } 493 494 @Override 495 public String toString() { 496 StringBuilder builder = new StringBuilder(size() * 7); 497 builder.append(array[start] ? "[true" : "[false"); 498 for (int i = start + 1; i < end; i++) { 499 builder.append(array[i] ? ", true" : ", false"); 500 } 501 return builder.append(']').toString(); 502 } 503 504 boolean[] toBooleanArray() { 505 return Arrays.copyOfRange(array, start, end); 506 } 507 508 private static final long serialVersionUID = 0; 509 } 510 511 /** 512 * Returns the number of {@code values} that are {@code true}. 513 * 514 * @since 16.0 515 */ 516 @Beta 517 public static int countTrue(boolean... values) { 518 int count = 0; 519 for (boolean value : values) { 520 if (value) { 521 count++; 522 } 523 } 524 return count; 525 } 526}