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