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
17package com.google.common.primitives;
18
19import com.google.common.annotations.GwtCompatible;
20
21import java.io.Serializable;
22import java.util.AbstractList;
23import java.util.Arrays;
24import java.util.BitSet;
25import java.util.Collection;
26import java.util.Collections;
27import java.util.Comparator;
28import java.util.List;
29import java.util.RandomAccess;
30
31import static com.google.common.base.Preconditions.checkArgument;
32import static com.google.common.base.Preconditions.checkElementIndex;
33import static com.google.common.base.Preconditions.checkNotNull;
34import 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
44public 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