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;
021import static java.lang.System.arraycopy;
022import static java.util.Collections.emptyList;
023
024import com.google.common.annotations.GwtCompatible;
025import com.google.common.annotations.GwtIncompatible;
026import com.google.common.annotations.J2ktIncompatible;
027import com.google.errorprone.annotations.InlineMe;
028import java.io.Serializable;
029import java.util.AbstractList;
030import java.util.Arrays;
031import java.util.Collection;
032import java.util.Comparator;
033import java.util.List;
034import java.util.RandomAccess;
035import org.jspecify.annotations.Nullable;
036
037/**
038 * Static utility methods pertaining to {@code boolean} primitives, that are not already found in
039 * either {@link Boolean} or {@link Arrays}.
040 *
041 * <p>See the Guava User Guide article on <a
042 * href="https://github.com/google/guava/wiki/PrimitivesExplained">primitive utilities</a>.
043 *
044 * @author Kevin Bourrillion
045 * @since 1.0
046 */
047@GwtCompatible
048public final class Booleans {
049  private Booleans() {}
050
051  /** Comparators for {@code Boolean} values. */
052  private enum BooleanComparator implements Comparator<Boolean> {
053    TRUE_FIRST(1, "Booleans.trueFirst()"),
054    FALSE_FIRST(-1, "Booleans.falseFirst()");
055
056    private final int trueValue;
057    private final String toString;
058
059    BooleanComparator(int trueValue, String toString) {
060      this.trueValue = trueValue;
061      this.toString = toString;
062    }
063
064    @Override
065    public int compare(Boolean a, Boolean b) {
066      int aVal = a ? trueValue : 0;
067      int bVal = b ? trueValue : 0;
068      return bVal - aVal;
069    }
070
071    @Override
072    public String toString() {
073      return toString;
074    }
075  }
076
077  /**
078   * Returns a {@code Comparator<Boolean>} that sorts {@code true} before {@code false}.
079   *
080   * <p>This is particularly useful in Java 8+ in combination with {@code Comparator.comparing},
081   * e.g. {@code Comparator.comparing(Foo::hasBar, trueFirst())}.
082   *
083   * @since 21.0
084   */
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 Comparator.comparing},
093   * e.g. {@code Comparator.comparing(Foo::hasBar, falseFirst())}.
094   *
095   * @since 21.0
096   */
097  public static Comparator<Boolean> falseFirst() {
098    return BooleanComparator.FALSE_FIRST;
099  }
100
101  /**
102   * Returns a hash code for {@code value}; obsolete alternative to {@link
103   * Boolean#hashCode(boolean)}.
104   *
105   * @param value a primitive {@code boolean} value
106   * @return a hash code for the value
107   */
108  @InlineMe(replacement = "Boolean.hashCode(value)")
109  public static int hashCode(boolean value) {
110    return Boolean.hashCode(value);
111  }
112
113  /**
114   * Compares the two specified {@code boolean} values in the standard way ({@code false} is
115   * considered less than {@code true}). The sign of the value returned is the same as that of
116   * {@code ((Boolean) a).compareTo(b)}.
117   *
118   * <p><b>Note:</b> this method is now unnecessary and should be treated as deprecated; use the
119   * equivalent {@link Boolean#compare} method instead.
120   *
121   * @param a the first {@code boolean} to compare
122   * @param b the second {@code boolean} to compare
123   * @return a positive number if only {@code a} is {@code true}, a negative number if only {@code
124   *     b} is true, or zero if {@code a == b}
125   */
126  @InlineMe(replacement = "Boolean.compare(a, b)")
127  public static int compare(boolean a, boolean b) {
128    return Boolean.compare(a, b);
129  }
130
131  /**
132   * Returns {@code true} if {@code target} is present as an element anywhere in {@code array}.
133   *
134   * <p><b>Note:</b> consider representing the array as a {@link java.util.BitSet} instead,
135   * replacing {@code Booleans.contains(array, true)} with {@code !bitSet.isEmpty()} and {@code
136   * Booleans.contains(array, false)} with {@code bitSet.nextClearBit(0) == sizeOfBitSet}.
137   *
138   * @param array an array of {@code boolean} values, possibly empty
139   * @param target a primitive {@code boolean} value
140   * @return {@code true} if {@code array[i] == target} for some value of {@code i}
141   */
142  public static boolean contains(boolean[] array, boolean target) {
143    for (boolean value : array) {
144      if (value == target) {
145        return true;
146      }
147    }
148    return false;
149  }
150
151  /**
152   * Returns the index of the first appearance of the value {@code target} in {@code array}.
153   *
154   * <p><b>Note:</b> consider representing the array as a {@link java.util.BitSet} instead, and
155   * using {@link java.util.BitSet#nextSetBit(int)} or {@link java.util.BitSet#nextClearBit(int)}.
156   *
157   * @param array an array of {@code boolean} values, possibly empty
158   * @param target a primitive {@code boolean} value
159   * @return the least index {@code i} for which {@code array[i] == target}, or {@code -1} if no
160   *     such index exists.
161   */
162  public static int indexOf(boolean[] array, boolean target) {
163    return indexOf(array, target, 0, array.length);
164  }
165
166  // TODO(kevinb): consider making this public
167  private static int indexOf(boolean[] array, boolean target, int start, int end) {
168    for (int i = start; i < end; i++) {
169      if (array[i] == target) {
170        return i;
171      }
172    }
173    return -1;
174  }
175
176  /**
177   * Returns the start position of the first occurrence of the specified {@code target} within
178   * {@code array}, or {@code -1} if there is no such occurrence.
179   *
180   * <p>More formally, returns the lowest index {@code i} such that {@code Arrays.copyOfRange(array,
181   * i, i + target.length)} contains exactly the same elements as {@code target}.
182   *
183   * @param array the array to search for the sequence {@code target}
184   * @param target the array to search for as a sub-sequence of {@code array}
185   */
186  public static int indexOf(boolean[] array, boolean[] target) {
187    checkNotNull(array, "array");
188    checkNotNull(target, "target");
189    if (target.length == 0) {
190      return 0;
191    }
192
193    outer:
194    for (int i = 0; i < array.length - target.length + 1; i++) {
195      for (int j = 0; j < target.length; j++) {
196        if (array[i + j] != target[j]) {
197          continue outer;
198        }
199      }
200      return i;
201    }
202    return -1;
203  }
204
205  /**
206   * Returns the index of the last appearance of the value {@code target} in {@code array}.
207   *
208   * @param array an array of {@code boolean} values, possibly empty
209   * @param target a primitive {@code boolean} value
210   * @return the greatest index {@code i} for which {@code array[i] == target}, or {@code -1} if no
211   *     such index exists.
212   */
213  public static int lastIndexOf(boolean[] array, boolean target) {
214    return lastIndexOf(array, target, 0, array.length);
215  }
216
217  // TODO(kevinb): consider making this public
218  private static int lastIndexOf(boolean[] array, boolean target, int start, int end) {
219    for (int i = end - 1; i >= start; i--) {
220      if (array[i] == target) {
221        return i;
222      }
223    }
224    return -1;
225  }
226
227  /**
228   * Returns the values from each provided array combined into a single array. For example, {@code
229   * concat(new boolean[] {a, b}, new boolean[] {}, new boolean[] {c}} returns the array {@code {a,
230   * b, c}}.
231   *
232   * @param arrays zero or more {@code boolean} arrays
233   * @return a single array containing all the values from the source arrays, in order
234   * @throws IllegalArgumentException if the total number of elements in {@code arrays} does not fit
235   *     in an {@code int}
236   */
237  public static boolean[] concat(boolean[]... arrays) {
238    long length = 0;
239    for (boolean[] array : arrays) {
240      length += array.length;
241    }
242    boolean[] result = new boolean[checkNoOverflow(length)];
243    int pos = 0;
244    for (boolean[] array : arrays) {
245      arraycopy(array, 0, result, pos, array.length);
246      pos += array.length;
247    }
248    return result;
249  }
250
251  private static int checkNoOverflow(long result) {
252    checkArgument(
253        result == (int) result,
254        "the total number of elements (%s) in the arrays must fit in an int",
255        result);
256    return (int) result;
257  }
258
259  /**
260   * Returns an array containing the same values as {@code array}, but guaranteed to be of a
261   * specified minimum length. If {@code array} already has a length of at least {@code minLength},
262   * it is returned directly. Otherwise, a new array of size {@code minLength + padding} is
263   * returned, containing the values of {@code array}, and zeroes in the remaining places.
264   *
265   * @param array the source array
266   * @param minLength the minimum length the returned array must guarantee
267   * @param padding an extra amount to "grow" the array by if growth is necessary
268   * @throws IllegalArgumentException if {@code minLength} or {@code padding} is negative
269   * @return an array containing the values of {@code array}, with guaranteed minimum length {@code
270   *     minLength}
271   */
272  public static boolean[] ensureCapacity(boolean[] array, int minLength, int padding) {
273    checkArgument(minLength >= 0, "Invalid minLength: %s", minLength);
274    checkArgument(padding >= 0, "Invalid padding: %s", padding);
275    return (array.length < minLength) ? Arrays.copyOf(array, minLength + padding) : array;
276  }
277
278  /**
279   * Returns a string containing the supplied {@code boolean} values separated by {@code separator}.
280   * For example, {@code join("-", false, true, false)} returns the string {@code
281   * "false-true-false"}.
282   *
283   * @param separator the text that should appear between consecutive values in the resulting string
284   *     (but not at the start or end)
285   * @param array an array of {@code boolean} values, possibly empty
286   */
287  public static String join(String separator, boolean... array) {
288    checkNotNull(separator);
289    if (array.length == 0) {
290      return "";
291    }
292
293    // For pre-sizing a builder, just get the right order of magnitude
294    StringBuilder builder = new StringBuilder(array.length * 7);
295    builder.append(array[0]);
296    for (int i = 1; i < array.length; i++) {
297      builder.append(separator).append(array[i]);
298    }
299    return builder.toString();
300  }
301
302  /**
303   * Returns a comparator that compares two {@code boolean} arrays <a
304   * href="http://en.wikipedia.org/wiki/Lexicographical_order">lexicographically</a>. That is, it
305   * compares, using {@link #compare(boolean, boolean)}), the first pair of values that follow any
306   * common prefix, or when one array is a prefix of the other, treats the shorter array as the
307   * lesser. For example, {@code [] < [false] < [false, true] < [true]}.
308   *
309   * <p>The returned comparator is inconsistent with {@link Object#equals(Object)} (since arrays
310   * support only identity equality), but it is consistent with {@link Arrays#equals(boolean[],
311   * boolean[])}.
312   *
313   * @since 2.0
314   */
315  public static Comparator<boolean[]> lexicographicalComparator() {
316    return LexicographicalComparator.INSTANCE;
317  }
318
319  private enum LexicographicalComparator implements Comparator<boolean[]> {
320    INSTANCE;
321
322    @Override
323    public int compare(boolean[] left, boolean[] right) {
324      // do not static import Math.min due to https://bugs.openjdk.org/browse/JDK-8357219
325      @SuppressWarnings("StaticImportPreferred")
326      int minLength = Math.min(left.length, right.length);
327      for (int i = 0; i < minLength; i++) {
328        int result = Boolean.compare(left[i], right[i]);
329        if (result != 0) {
330          return result;
331        }
332      }
333      return left.length - right.length;
334    }
335
336    @Override
337    public String toString() {
338      return "Booleans.lexicographicalComparator()";
339    }
340  }
341
342  /**
343   * Copies a collection of {@code Boolean} instances into a new array of primitive {@code boolean}
344   * values.
345   *
346   * <p>Elements are copied from the argument collection as if by {@code collection.toArray()}.
347   * Calling this method is as thread-safe as calling that method.
348   *
349   * <p><b>Note:</b> consider representing the collection as a {@link java.util.BitSet} instead.
350   *
351   * @param collection a collection of {@code Boolean} objects
352   * @return an array containing the same values as {@code collection}, in the same order, converted
353   *     to primitives
354   * @throws NullPointerException if {@code collection} or any of its elements is null
355   */
356  public static boolean[] toArray(Collection<Boolean> collection) {
357    if (collection instanceof BooleanArrayAsList) {
358      return ((BooleanArrayAsList) collection).toBooleanArray();
359    }
360
361    Object[] boxedArray = collection.toArray();
362    int len = boxedArray.length;
363    boolean[] array = new boolean[len];
364    for (int i = 0; i < len; i++) {
365      // checkNotNull for GWT (do not optimize)
366      array[i] = (Boolean) checkNotNull(boxedArray[i]);
367    }
368    return array;
369  }
370
371  /**
372   * Returns a fixed-size list backed by the specified array, similar to {@link
373   * Arrays#asList(Object[])}. The list supports {@link List#set(int, Object)}, but any attempt to
374   * set a value to {@code null} will result in a {@link NullPointerException}.
375   *
376   * <p>There are at most two distinct objects in this list, {@code (Boolean) true} and {@code
377   * (Boolean) false}. Java guarantees that those are always represented by the same objects.
378   *
379   * <p>The returned list is serializable.
380   *
381   * @param backingArray the array to back the list
382   * @return a list view of the array
383   */
384  public static List<Boolean> asList(boolean... backingArray) {
385    if (backingArray.length == 0) {
386      return emptyList();
387    }
388    return new BooleanArrayAsList(backingArray);
389  }
390
391  private static final class BooleanArrayAsList extends AbstractList<Boolean>
392      implements RandomAccess, Serializable {
393    final boolean[] array;
394    final int start;
395    final int end;
396
397    BooleanArrayAsList(boolean[] array) {
398      this(array, 0, array.length);
399    }
400
401    BooleanArrayAsList(boolean[] array, int start, int end) {
402      this.array = array;
403      this.start = start;
404      this.end = end;
405    }
406
407    @Override
408    public int size() {
409      return end - start;
410    }
411
412    @Override
413    public boolean isEmpty() {
414      return false;
415    }
416
417    @Override
418    public Boolean get(int index) {
419      checkElementIndex(index, size());
420      return array[start + index];
421    }
422
423    @Override
424    public boolean contains(@Nullable Object target) {
425      // Overridden to prevent a ton of boxing
426      return (target instanceof Boolean)
427          && Booleans.indexOf(array, (Boolean) target, start, end) != -1;
428    }
429
430    @Override
431    public int indexOf(@Nullable Object target) {
432      // Overridden to prevent a ton of boxing
433      if (target instanceof Boolean) {
434        int i = Booleans.indexOf(array, (Boolean) target, start, end);
435        if (i >= 0) {
436          return i - start;
437        }
438      }
439      return -1;
440    }
441
442    @Override
443    public int lastIndexOf(@Nullable Object target) {
444      // Overridden to prevent a ton of boxing
445      if (target instanceof Boolean) {
446        int i = Booleans.lastIndexOf(array, (Boolean) target, start, end);
447        if (i >= 0) {
448          return i - start;
449        }
450      }
451      return -1;
452    }
453
454    @Override
455    public Boolean set(int index, Boolean element) {
456      checkElementIndex(index, size());
457      boolean oldValue = array[start + index];
458      // checkNotNull for GWT (do not optimize)
459      array[start + index] = checkNotNull(element);
460      return oldValue;
461    }
462
463    @Override
464    public List<Boolean> subList(int fromIndex, int toIndex) {
465      int size = size();
466      checkPositionIndexes(fromIndex, toIndex, size);
467      if (fromIndex == toIndex) {
468        return emptyList();
469      }
470      return new BooleanArrayAsList(array, start + fromIndex, start + toIndex);
471    }
472
473    @Override
474    public boolean equals(@Nullable Object object) {
475      if (object == this) {
476        return true;
477      }
478      if (object instanceof BooleanArrayAsList) {
479        BooleanArrayAsList that = (BooleanArrayAsList) object;
480        int size = size();
481        if (that.size() != size) {
482          return false;
483        }
484        for (int i = 0; i < size; i++) {
485          if (array[start + i] != that.array[that.start + i]) {
486            return false;
487          }
488        }
489        return true;
490      }
491      return super.equals(object);
492    }
493
494    @Override
495    public int hashCode() {
496      int result = 1;
497      for (int i = start; i < end; i++) {
498        result = 31 * result + Boolean.hashCode(array[i]);
499      }
500      return result;
501    }
502
503    @Override
504    public String toString() {
505      StringBuilder builder = new StringBuilder(size() * 7);
506      builder.append(array[start] ? "[true" : "[false");
507      for (int i = start + 1; i < end; i++) {
508        builder.append(array[i] ? ", true" : ", false");
509      }
510      return builder.append(']').toString();
511    }
512
513    boolean[] toBooleanArray() {
514      return Arrays.copyOfRange(array, start, end);
515    }
516
517    @GwtIncompatible @J2ktIncompatible private static final long serialVersionUID = 0;
518  }
519
520  /**
521   * Returns the number of {@code values} that are {@code true}.
522   *
523   * @since 16.0
524   */
525  public static int countTrue(boolean... values) {
526    int count = 0;
527    for (boolean value : values) {
528      if (value) {
529        count++;
530      }
531    }
532    return count;
533  }
534
535  /**
536   * Reverses the elements of {@code array}. This is equivalent to {@code
537   * Collections.reverse(Booleans.asList(array))}, but is likely to be more efficient.
538   *
539   * @since 23.1
540   */
541  public static void reverse(boolean[] array) {
542    checkNotNull(array);
543    reverse(array, 0, array.length);
544  }
545
546  /**
547   * Reverses the elements of {@code array} between {@code fromIndex} inclusive and {@code toIndex}
548   * exclusive. This is equivalent to {@code
549   * Collections.reverse(Booleans.asList(array).subList(fromIndex, toIndex))}, but is likely to be
550   * more efficient.
551   *
552   * @throws IndexOutOfBoundsException if {@code fromIndex < 0}, {@code toIndex > array.length}, or
553   *     {@code toIndex > fromIndex}
554   * @since 23.1
555   */
556  public static void reverse(boolean[] array, int fromIndex, int toIndex) {
557    checkNotNull(array);
558    checkPositionIndexes(fromIndex, toIndex, array.length);
559    for (int i = fromIndex, j = toIndex - 1; i < j; i++, j--) {
560      boolean tmp = array[i];
561      array[i] = array[j];
562      array[j] = tmp;
563    }
564  }
565
566  /**
567   * Performs a right rotation of {@code array} of "distance" places, so that the first element is
568   * moved to index "distance", and the element at index {@code i} ends up at index {@code (distance
569   * + i) mod array.length}. This is equivalent to {@code Collections.rotate(Booleans.asList(array),
570   * distance)}, but is somewhat faster.
571   *
572   * <p>The provided "distance" may be negative, which will rotate left.
573   *
574   * @since 32.0.0
575   */
576  public static void rotate(boolean[] array, int distance) {
577    rotate(array, distance, 0, array.length);
578  }
579
580  /**
581   * Performs a right rotation of {@code array} between {@code fromIndex} inclusive and {@code
582   * toIndex} exclusive. This is equivalent to {@code
583   * Collections.rotate(Booleans.asList(array).subList(fromIndex, toIndex), distance)}, but is
584   * somewhat faster.
585   *
586   * <p>The provided "distance" may be negative, which will rotate left.
587   *
588   * @throws IndexOutOfBoundsException if {@code fromIndex < 0}, {@code toIndex > array.length}, or
589   *     {@code toIndex > fromIndex}
590   * @since 32.0.0
591   */
592  public static void rotate(boolean[] array, int distance, int fromIndex, int toIndex) {
593    // See Ints.rotate for more details about possible algorithms here.
594    checkNotNull(array);
595    checkPositionIndexes(fromIndex, toIndex, array.length);
596    if (array.length <= 1) {
597      return;
598    }
599
600    int length = toIndex - fromIndex;
601    // Obtain m = (-distance mod length), a non-negative value less than "length". This is how many
602    // places left to rotate.
603    int m = -distance % length;
604    m = (m < 0) ? m + length : m;
605    // The current index of what will become the first element of the rotated section.
606    int newFirstIndex = m + fromIndex;
607    if (newFirstIndex == fromIndex) {
608      return;
609    }
610
611    reverse(array, fromIndex, newFirstIndex);
612    reverse(array, newFirstIndex, toIndex);
613    reverse(array, fromIndex, toIndex);
614  }
615}