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