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.GwtCompatible;
025
026import java.io.Serializable;
027import java.util.AbstractList;
028import java.util.Arrays;
029import java.util.BitSet;
030import java.util.Collection;
031import java.util.Collections;
032import java.util.Comparator;
033import java.util.List;
034import java.util.RandomAccess;
035
036/**
037 * Static utility methods pertaining to {@code boolean} primitives, that are not
038 * already found in either {@link Boolean} or {@link Arrays}.
039 *
040 * @author Kevin Bourrillion
041 * @since 1
042 */
043@GwtCompatible
044public final class Booleans {
045  private Booleans() {}
046
047  /**
048   * Returns a hash code for {@code value}; equal to the result of invoking
049   * {@code ((Boolean) value).hashCode()}.
050   *
051   * @param value a primitive {@code boolean} value
052   * @return a hash code for the value
053   */
054  public static int hashCode(boolean value) {
055    return value ? 1231 : 1237;
056  }
057
058  /**
059   * Compares the two specified {@code boolean} values in the standard way
060   * ({@code false} is considered less than {@code true}). The sign of the
061   * value returned is the same as that of {@code ((Boolean) a).compareTo(b)}.
062   *
063   * @param a the first {@code boolean} to compare
064   * @param b the second {@code boolean} to compare
065   * @return a positive number if only {@code a} is {@code true},  a negative
066   *     number if only {@code b} is true, or zero if {@code a == b}
067   */
068  public static int compare(boolean a, boolean b) {
069    return (a == b) ? 0 : (a ? 1 : -1);
070  }
071
072  /**
073   * Returns {@code true} if {@code target} is present as an element anywhere in
074   * {@code array}.
075   *
076   * <p><b>Note:</b> consider representing the array as a {@link
077   * BitSet} instead, replacing {@code Booleans.contains(array, true)}
078   * with {@code !bitSet.isEmpty()} and {@code Booleans.contains(array, false)}
079   * with {@code bitSet.nextClearBit(0) == sizeOfBitSet}.
080   *
081   * @param array an array of {@code boolean} values, possibly empty
082   * @param target a primitive {@code boolean} value
083   * @return {@code true} if {@code array[i] == target} for some value of {@code
084   *     i}
085   */
086  public static boolean contains(boolean[] array, boolean target) {
087    for (boolean value : array) {
088      if (value == target) {
089        return true;
090      }
091    }
092    return false;
093  }
094
095  /**
096   * Returns the index of the first appearance of the value {@code target} in
097   * {@code array}.
098   *
099   * <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(kevinb): 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(kevinb): 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 article at Wikipedia</a>
270   * @since 2
271   */
272  public static Comparator<boolean[]> lexicographicalComparator() {
273    return LexicographicalComparator.INSTANCE;
274  }
275
276  private enum LexicographicalComparator implements Comparator<boolean[]> {
277    INSTANCE;
278
279    @Override
280    public int compare(boolean[] left, boolean[] right) {
281      int minLength = Math.min(left.length, right.length);
282      for (int i = 0; i < minLength; i++) {
283        int result = Booleans.compare(left[i], right[i]);
284        if (result != 0) {
285          return result;
286        }
287      }
288      return left.length - right.length;
289    }
290  }
291
292  /**
293   * Copies a collection of {@code Boolean} instances into a new array of
294   * primitive {@code boolean} values.
295   *
296   * <p>Elements are copied from the argument collection as if by {@code
297   * collection.toArray()}.  Calling this method is as thread-safe as calling
298   * that method.
299   *
300   * <p><b>Note:</b> consider representing the collection as a {@link
301   * BitSet} instead.
302   *
303   * @param collection a collection of {@code Boolean} objects
304   * @return an array containing the same values as {@code collection}, in the
305   *     same order, converted to primitives
306   * @throws NullPointerException if {@code collection} or any of its elements
307   *     is null
308   */
309  public static boolean[] toArray(Collection<Boolean> collection) {
310    if (collection instanceof BooleanArrayAsList) {
311      return ((BooleanArrayAsList) collection).toBooleanArray();
312    }
313
314    Object[] boxedArray = collection.toArray();
315    int len = boxedArray.length;
316    boolean[] array = new boolean[len];
317    for (int i = 0; i < len; i++) {
318      array[i] = (Boolean) boxedArray[i];
319    }
320    return array;
321  }
322
323  /**
324   * Returns a fixed-size list backed by the specified array, similar to {@link
325   * Arrays#asList(Object[])}. The list supports {@link List#set(int, Object)},
326   * but any attempt to set a value to {@code null} will result in a {@link
327   * NullPointerException}.
328   *
329   * <p>The returned list maintains the values, but not the identities, of
330   * {@code Boolean} objects written to or read from it.  For example, whether
331   * {@code list.get(0) == list.get(0)} is true for the returned list is
332   * unspecified.
333   *
334   * @param backingArray the array to back the list
335   * @return a list view of the array
336   */
337  public static List<Boolean> asList(boolean... backingArray) {
338    if (backingArray.length == 0) {
339      return Collections.emptyList();
340    }
341    return new BooleanArrayAsList(backingArray);
342  }
343
344  @GwtCompatible
345  private static class BooleanArrayAsList extends AbstractList<Boolean>
346      implements RandomAccess, Serializable {
347    final boolean[] array;
348    final int start;
349    final int end;
350
351    BooleanArrayAsList(boolean[] array) {
352      this(array, 0, array.length);
353    }
354
355    BooleanArrayAsList(boolean[] array, int start, int end) {
356      this.array = array;
357      this.start = start;
358      this.end = end;
359    }
360
361    @Override public int size() {
362      return end - start;
363    }
364
365    @Override public boolean isEmpty() {
366      return false;
367    }
368
369    @Override public Boolean get(int index) {
370      checkElementIndex(index, size());
371      return array[start + index];
372    }
373
374    @Override public boolean contains(Object target) {
375      // Overridden to prevent a ton of boxing
376      return (target instanceof Boolean)
377          && Booleans.indexOf(array, (Boolean) target, start, end) != -1;
378    }
379
380    @Override public int indexOf(Object target) {
381      // Overridden to prevent a ton of boxing
382      if (target instanceof Boolean) {
383        int i = Booleans.indexOf(array, (Boolean) target, start, end);
384        if (i >= 0) {
385          return i - start;
386        }
387      }
388      return -1;
389    }
390
391    @Override public int lastIndexOf(Object target) {
392      // Overridden to prevent a ton of boxing
393      if (target instanceof Boolean) {
394        int i = Booleans.lastIndexOf(array, (Boolean) target, start, end);
395        if (i >= 0) {
396          return i - start;
397        }
398      }
399      return -1;
400    }
401
402    @Override public Boolean set(int index, Boolean element) {
403      checkElementIndex(index, size());
404      boolean oldValue = array[start + index];
405      array[start + index] = element;
406      return oldValue;
407    }
408
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}