Home | History | Annotate | Download | only in primitives
      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.Beta;
     25 import com.google.common.annotations.GwtCompatible;
     26 
     27 import java.io.Serializable;
     28 import java.util.AbstractList;
     29 import java.util.Arrays;
     30 import java.util.BitSet;
     31 import java.util.Collection;
     32 import java.util.Collections;
     33 import java.util.Comparator;
     34 import java.util.List;
     35 import java.util.RandomAccess;
     36 
     37 /**
     38  * Static utility methods pertaining to {@code boolean} primitives, that are not
     39  * already found in either {@link Boolean} or {@link Arrays}.
     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 @GwtCompatible
     49 public final class Booleans {
     50   private Booleans() {}
     51 
     52   /**
     53    * Returns a hash code for {@code value}; equal to the result of invoking
     54    * {@code ((Boolean) value).hashCode()}.
     55    *
     56    * @param value a primitive {@code boolean} value
     57    * @return a hash code for the value
     58    */
     59   public static int hashCode(boolean value) {
     60     return value ? 1231 : 1237;
     61   }
     62 
     63   /**
     64    * Compares the two specified {@code boolean} values in the standard way
     65    * ({@code false} is considered less than {@code true}). The sign of the
     66    * value returned is the same as that of {@code ((Boolean) a).compareTo(b)}.
     67    *
     68    * <p><b>Note for Java 7 and later:</b> this method should be treated as
     69    * deprecated; use the equivalent {@link Boolean#compare} method instead.
     70    *
     71    * @param a the first {@code boolean} to compare
     72    * @param b the second {@code boolean} to compare
     73    * @return a positive number if only {@code a} is {@code true}, a negative
     74    *     number if only {@code b} is true, or zero if {@code a == b}
     75    */
     76   public static int compare(boolean a, boolean b) {
     77     return (a == b) ? 0 : (a ? 1 : -1);
     78   }
     79 
     80   /**
     81    * Returns {@code true} if {@code target} is present as an element anywhere in
     82    * {@code array}.
     83    *
     84    * <p><b>Note:</b> consider representing the array as a {@link
     85    * BitSet} instead, replacing {@code Booleans.contains(array, true)}
     86    * with {@code !bitSet.isEmpty()} and {@code Booleans.contains(array, false)}
     87    * with {@code bitSet.nextClearBit(0) == sizeOfBitSet}.
     88    *
     89    * @param array an array of {@code boolean} values, possibly empty
     90    * @param target a primitive {@code boolean} value
     91    * @return {@code true} if {@code array[i] == target} for some value of {@code
     92    *     i}
     93    */
     94   public static boolean contains(boolean[] array, boolean target) {
     95     for (boolean value : array) {
     96       if (value == target) {
     97         return true;
     98       }
     99     }
    100     return false;
    101   }
    102 
    103   /**
    104    * Returns the index of the first appearance of the value {@code target} in
    105    * {@code array}.
    106    *
    107    * <p><b>Note:</b> consider representing the array as a {@link BitSet}
    108    * instead, and using {@link BitSet#nextSetBit(int)} or {@link
    109    * BitSet#nextClearBit(int)}.
    110    *
    111    * @param array an array of {@code boolean} values, possibly empty
    112    * @param target a primitive {@code boolean} value
    113    * @return the least index {@code i} for which {@code array[i] == target}, or
    114    *     {@code -1} if no such index exists.
    115    */
    116   public static int indexOf(boolean[] array, boolean target) {
    117     return indexOf(array, target, 0, array.length);
    118   }
    119 
    120   // TODO(kevinb): consider making this public
    121   private static int indexOf(
    122       boolean[] array, boolean target, int start, int end) {
    123     for (int i = start; i < end; i++) {
    124       if (array[i] == target) {
    125         return i;
    126       }
    127     }
    128     return -1;
    129   }
    130 
    131   /**
    132    * Returns the start position of the first occurrence of the specified {@code
    133    * target} within {@code array}, or {@code -1} if there is no such occurrence.
    134    *
    135    * <p>More formally, returns the lowest index {@code i} such that {@code
    136    * java.util.Arrays.copyOfRange(array, i, i + target.length)} contains exactly
    137    * the same elements as {@code target}.
    138    *
    139    * @param array the array to search for the sequence {@code target}
    140    * @param target the array to search for as a sub-sequence of {@code array}
    141    */
    142   public static int indexOf(boolean[] array, boolean[] target) {
    143     checkNotNull(array, "array");
    144     checkNotNull(target, "target");
    145     if (target.length == 0) {
    146       return 0;
    147     }
    148 
    149     outer:
    150     for (int i = 0; i < array.length - target.length + 1; i++) {
    151       for (int j = 0; j < target.length; j++) {
    152         if (array[i + j] != target[j]) {
    153           continue outer;
    154         }
    155       }
    156       return i;
    157     }
    158     return -1;
    159   }
    160 
    161   /**
    162    * Returns the index of the last appearance of the value {@code target} in
    163    * {@code array}.
    164    *
    165    * @param array an array of {@code boolean} values, possibly empty
    166    * @param target a primitive {@code boolean} value
    167    * @return the greatest index {@code i} for which {@code array[i] == target},
    168    *     or {@code -1} if no such index exists.
    169    */
    170   public static int lastIndexOf(boolean[] array, boolean target) {
    171     return lastIndexOf(array, target, 0, array.length);
    172   }
    173 
    174   // TODO(kevinb): consider making this public
    175   private static int lastIndexOf(
    176       boolean[] array, boolean target, int start, int end) {
    177     for (int i = end - 1; i >= start; i--) {
    178       if (array[i] == target) {
    179         return i;
    180       }
    181     }
    182     return -1;
    183   }
    184 
    185   /**
    186    * Returns the values from each provided array combined into a single array.
    187    * For example, {@code concat(new boolean[] {a, b}, new boolean[] {}, new
    188    * boolean[] {c}} returns the array {@code {a, b, c}}.
    189    *
    190    * @param arrays zero or more {@code boolean} arrays
    191    * @return a single array containing all the values from the source arrays, in
    192    *     order
    193    */
    194   public static boolean[] concat(boolean[]... arrays) {
    195     int length = 0;
    196     for (boolean[] array : arrays) {
    197       length += array.length;
    198     }
    199     boolean[] result = new boolean[length];
    200     int pos = 0;
    201     for (boolean[] array : arrays) {
    202       System.arraycopy(array, 0, result, pos, array.length);
    203       pos += array.length;
    204     }
    205     return result;
    206   }
    207 
    208   /**
    209    * Returns an array containing the same values as {@code array}, but
    210    * guaranteed to be of a specified minimum length. If {@code array} already
    211    * has a length of at least {@code minLength}, it is returned directly.
    212    * Otherwise, a new array of size {@code minLength + padding} is returned,
    213    * containing the values of {@code array}, and zeroes in the remaining places.
    214    *
    215    * @param array the source array
    216    * @param minLength the minimum length the returned array must guarantee
    217    * @param padding an extra amount to "grow" the array by if growth is
    218    *     necessary
    219    * @throws IllegalArgumentException if {@code minLength} or {@code padding} is
    220    *     negative
    221    * @return an array containing the values of {@code array}, with guaranteed
    222    *     minimum length {@code minLength}
    223    */
    224   public static boolean[] ensureCapacity(
    225       boolean[] array, int minLength, int padding) {
    226     checkArgument(minLength >= 0, "Invalid minLength: %s", minLength);
    227     checkArgument(padding >= 0, "Invalid padding: %s", padding);
    228     return (array.length < minLength)
    229         ? copyOf(array, minLength + padding)
    230         : array;
    231   }
    232 
    233   // Arrays.copyOf() requires Java 6
    234   private static boolean[] copyOf(boolean[] original, int length) {
    235     boolean[] copy = new boolean[length];
    236     System.arraycopy(original, 0, copy, 0, Math.min(original.length, length));
    237     return copy;
    238   }
    239 
    240   /**
    241    * Returns a string containing the supplied {@code boolean} values separated
    242    * by {@code separator}. For example, {@code join("-", false, true, false)}
    243    * returns the string {@code "false-true-false"}.
    244    *
    245    * @param separator the text that should appear between consecutive values in
    246    *     the resulting string (but not at the start or end)
    247    * @param array an array of {@code boolean} values, possibly empty
    248    */
    249   public static String join(String separator, boolean... array) {
    250     checkNotNull(separator);
    251     if (array.length == 0) {
    252       return "";
    253     }
    254 
    255     // For pre-sizing a builder, just get the right order of magnitude
    256     StringBuilder builder = new StringBuilder(array.length * 7);
    257     builder.append(array[0]);
    258     for (int i = 1; i < array.length; i++) {
    259       builder.append(separator).append(array[i]);
    260     }
    261     return builder.toString();
    262   }
    263 
    264   /**
    265    * Returns a comparator that compares two {@code boolean} arrays
    266    * lexicographically. That is, it compares, using {@link
    267    * #compare(boolean, boolean)}), the first pair of values that follow any
    268    * common prefix, or when one array is a prefix of the other, treats the
    269    * shorter array as the lesser. For example,
    270    * {@code [] < [false] < [false, true] < [true]}.
    271    *
    272    * <p>The returned comparator is inconsistent with {@link
    273    * Object#equals(Object)} (since arrays support only identity equality), but
    274    * it is consistent with {@link Arrays#equals(boolean[], boolean[])}.
    275    *
    276    * @see <a href="http://en.wikipedia.org/wiki/Lexicographical_order">
    277    *     Lexicographical order article at Wikipedia</a>
    278    * @since 2.0
    279    */
    280   public static Comparator<boolean[]> lexicographicalComparator() {
    281     return LexicographicalComparator.INSTANCE;
    282   }
    283 
    284   private enum LexicographicalComparator implements Comparator<boolean[]> {
    285     INSTANCE;
    286 
    287     @Override
    288     public int compare(boolean[] left, boolean[] right) {
    289       int minLength = Math.min(left.length, right.length);
    290       for (int i = 0; i < minLength; i++) {
    291         int result = Booleans.compare(left[i], right[i]);
    292         if (result != 0) {
    293           return result;
    294         }
    295       }
    296       return left.length - right.length;
    297     }
    298   }
    299 
    300   /**
    301    * Copies a collection of {@code Boolean} instances into a new array of
    302    * primitive {@code boolean} values.
    303    *
    304    * <p>Elements are copied from the argument collection as if by {@code
    305    * collection.toArray()}.  Calling this method is as thread-safe as calling
    306    * that method.
    307    *
    308    * <p><b>Note:</b> consider representing the collection as a {@link
    309    * BitSet} instead.
    310    *
    311    * @param collection a collection of {@code Boolean} objects
    312    * @return an array containing the same values as {@code collection}, in the
    313    *     same order, converted to primitives
    314    * @throws NullPointerException if {@code collection} or any of its elements
    315    *     is null
    316    */
    317   public static boolean[] toArray(Collection<Boolean> collection) {
    318     if (collection instanceof BooleanArrayAsList) {
    319       return ((BooleanArrayAsList) collection).toBooleanArray();
    320     }
    321 
    322     Object[] boxedArray = collection.toArray();
    323     int len = boxedArray.length;
    324     boolean[] array = new boolean[len];
    325     for (int i = 0; i < len; i++) {
    326       // checkNotNull for GWT (do not optimize)
    327       array[i] = (Boolean) checkNotNull(boxedArray[i]);
    328     }
    329     return array;
    330   }
    331 
    332   /**
    333    * Returns a fixed-size list backed by the specified array, similar to {@link
    334    * Arrays#asList(Object[])}. The list supports {@link List#set(int, Object)},
    335    * but any attempt to set a value to {@code null} will result in a {@link
    336    * NullPointerException}.
    337    *
    338    * <p>The returned list maintains the values, but not the identities, of
    339    * {@code Boolean} objects written to or read from it.  For example, whether
    340    * {@code list.get(0) == list.get(0)} is true for the returned list is
    341    * unspecified.
    342    *
    343    * @param backingArray the array to back the list
    344    * @return a list view of the array
    345    */
    346   public static List<Boolean> asList(boolean... backingArray) {
    347     if (backingArray.length == 0) {
    348       return Collections.emptyList();
    349     }
    350     return new BooleanArrayAsList(backingArray);
    351   }
    352 
    353   @GwtCompatible
    354   private static class BooleanArrayAsList extends AbstractList<Boolean>
    355       implements RandomAccess, Serializable {
    356     final boolean[] array;
    357     final int start;
    358     final int end;
    359 
    360     BooleanArrayAsList(boolean[] array) {
    361       this(array, 0, array.length);
    362     }
    363 
    364     BooleanArrayAsList(boolean[] array, int start, int end) {
    365       this.array = array;
    366       this.start = start;
    367       this.end = end;
    368     }
    369 
    370     @Override public int size() {
    371       return end - start;
    372     }
    373 
    374     @Override public boolean isEmpty() {
    375       return false;
    376     }
    377 
    378     @Override public Boolean get(int index) {
    379       checkElementIndex(index, size());
    380       return array[start + index];
    381     }
    382 
    383     @Override public boolean contains(Object target) {
    384       // Overridden to prevent a ton of boxing
    385       return (target instanceof Boolean)
    386           && Booleans.indexOf(array, (Boolean) target, start, end) != -1;
    387     }
    388 
    389     @Override public int indexOf(Object target) {
    390       // Overridden to prevent a ton of boxing
    391       if (target instanceof Boolean) {
    392         int i = Booleans.indexOf(array, (Boolean) target, start, end);
    393         if (i >= 0) {
    394           return i - start;
    395         }
    396       }
    397       return -1;
    398     }
    399 
    400     @Override public int lastIndexOf(Object target) {
    401       // Overridden to prevent a ton of boxing
    402       if (target instanceof Boolean) {
    403         int i = Booleans.lastIndexOf(array, (Boolean) target, start, end);
    404         if (i >= 0) {
    405           return i - start;
    406         }
    407       }
    408       return -1;
    409     }
    410 
    411     @Override public Boolean set(int index, Boolean element) {
    412       checkElementIndex(index, size());
    413       boolean oldValue = array[start + index];
    414       // checkNotNull for GWT (do not optimize)
    415       array[start + index] = checkNotNull(element);
    416       return oldValue;
    417     }
    418 
    419     @Override public List<Boolean> subList(int fromIndex, int toIndex) {
    420       int size = size();
    421       checkPositionIndexes(fromIndex, toIndex, size);
    422       if (fromIndex == toIndex) {
    423         return Collections.emptyList();
    424       }
    425       return new BooleanArrayAsList(array, start + fromIndex, start + toIndex);
    426     }
    427 
    428     @Override public boolean equals(Object object) {
    429       if (object == this) {
    430         return true;
    431       }
    432       if (object instanceof BooleanArrayAsList) {
    433         BooleanArrayAsList that = (BooleanArrayAsList) object;
    434         int size = size();
    435         if (that.size() != size) {
    436           return false;
    437         }
    438         for (int i = 0; i < size; i++) {
    439           if (array[start + i] != that.array[that.start + i]) {
    440             return false;
    441           }
    442         }
    443         return true;
    444       }
    445       return super.equals(object);
    446     }
    447 
    448     @Override public int hashCode() {
    449       int result = 1;
    450       for (int i = start; i < end; i++) {
    451         result = 31 * result + Booleans.hashCode(array[i]);
    452       }
    453       return result;
    454     }
    455 
    456     @Override public String toString() {
    457       StringBuilder builder = new StringBuilder(size() * 7);
    458       builder.append(array[start] ? "[true" : "[false");
    459       for (int i = start + 1; i < end; i++) {
    460         builder.append(array[i] ? ", true" : ", false");
    461       }
    462       return builder.append(']').toString();
    463     }
    464 
    465     boolean[] toBooleanArray() {
    466       // Arrays.copyOfRange() is not available under GWT
    467       int size = size();
    468       boolean[] result = new boolean[size];
    469       System.arraycopy(array, start, result, 0, size);
    470       return result;
    471     }
    472 
    473     private static final long serialVersionUID = 0;
    474   }
    475 
    476   /**
    477    * Returns the number of {@code values} that are {@code true}.
    478    *
    479    * @since 16.0
    480    */
    481   @Beta
    482   public static int countTrue(boolean... values) {
    483     int count = 0;
    484     for (boolean value : values) {
    485       if (value) {
    486         count++;
    487       }
    488     }
    489     return count;
    490   }
    491 }
    492