• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 {
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    */
hashCode(boolean value)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    */
compare(boolean a, boolean b)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    */
contains(boolean[] array, boolean target)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    */
indexOf(boolean[] array, boolean target)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
indexOf( boolean[] array, boolean target, int start, int end)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    */
indexOf(boolean[] array, boolean[] target)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    */
lastIndexOf(boolean[] array, boolean target)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
lastIndexOf( boolean[] array, boolean target, int start, int end)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    */
concat(boolean[]... arrays)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    */
ensureCapacity( boolean[] array, int minLength, int padding)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
copyOf(boolean[] original, int length)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    */
join(String separator, boolean... array)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    */
lexicographicalComparator()272   public static Comparator<boolean[]> lexicographicalComparator() {
273     return LexicographicalComparator.INSTANCE;
274   }
275 
276   private enum LexicographicalComparator implements Comparator<boolean[]> {
277     INSTANCE;
278 
compare(boolean[] left, boolean[] right)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    */
toArray(Collection<Boolean> collection)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    */
asList(boolean... backingArray)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 
BooleanArrayAsList(boolean[] array)350     BooleanArrayAsList(boolean[] array) {
351       this(array, 0, array.length);
352     }
353 
BooleanArrayAsList(boolean[] array, int start, int end)354     BooleanArrayAsList(boolean[] array, int start, int end) {
355       this.array = array;
356       this.start = start;
357       this.end = end;
358     }
359 
size()360     @Override public int size() {
361       return end - start;
362     }
363 
isEmpty()364     @Override public boolean isEmpty() {
365       return false;
366     }
367 
get(int index)368     @Override public Boolean get(int index) {
369       checkElementIndex(index, size());
370       return array[start + index];
371     }
372 
contains(Object target)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 
indexOf(Object target)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 
lastIndexOf(Object target)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 
set(int index, Boolean element)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. */
subList(int fromIndex, int toIndex)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 
equals(Object object)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 
hashCode()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 
toString()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 
toBooleanArray()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