Home | History | Annotate | Download | only in primitives
      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.Collection;
     25 import java.util.Collections;
     26 import java.util.Comparator;
     27 import java.util.List;
     28 import java.util.RandomAccess;
     29 
     30 import static com.google.common.base.Preconditions.checkArgument;
     31 import static com.google.common.base.Preconditions.checkElementIndex;
     32 import static com.google.common.base.Preconditions.checkNotNull;
     33 import static com.google.common.base.Preconditions.checkPositionIndexes;
     34 
     35 /**
     36  * Static utility methods pertaining to {@code float} primitives, that are not
     37  * already found in either {@link Float} or {@link Arrays}.
     38  *
     39  * @author Kevin Bourrillion
     40  * @since 2009.09.15 <b>tentative</b>
     41  */
     42 @GwtCompatible
     43 public final class Floats {
     44   private Floats() {}
     45 
     46   /**
     47    * Returns a hash code for {@code value}; equal to the result of invoking
     48    * {@code ((Float) value).hashCode()}.
     49    *
     50    * @param value a primitive {@code float} value
     51    * @return a hash code for the value
     52    */
     53   public static int hashCode(float value) {
     54     // TODO: is there a better way, that's still gwt-safe?
     55     return ((Float) value).hashCode();
     56   }
     57 
     58   /**
     59    * Compares the two specified {@code float} values using {@link
     60    * Float#compare(float, float)}. You may prefer to invoke that method
     61    * directly; this method exists only for consistency with the other utilities
     62    * in this package.
     63    *
     64    * @param a the first {@code float} to compare
     65    * @param b the second {@code float} to compare
     66    * @return the result of invoking {@link Float#compare(float, float)}
     67    */
     68   public static int compare(float a, float b) {
     69     return Float.compare(a, b);
     70   }
     71 
     72   /**
     73    * Returns {@code true} if {@code target} is present as an element anywhere in
     74    * {@code array}. Note that this always returns {@code false} when {@code
     75    * target} is {@code NaN}.
     76    *
     77    * @param array an array of {@code float} values, possibly empty
     78    * @param target a primitive {@code float} value
     79    * @return {@code true} if {@code array[i] == target} for some value of {@code
     80    *     i}
     81    */
     82   public static boolean contains(float[] array, float target) {
     83     for (float value : array) {
     84       if (value == target) {
     85         return true;
     86       }
     87     }
     88     return false;
     89   }
     90 
     91   /**
     92    * Returns the index of the first appearance of the value {@code target} in
     93    * {@code array}. Note that this always returns {@code -1} when {@code target}
     94    * is {@code NaN}.
     95    *
     96    * @param array an array of {@code float} values, possibly empty
     97    * @param target a primitive {@code float} value
     98    * @return the least index {@code i} for which {@code array[i] == target}, or
     99    *     {@code -1} if no such index exists.
    100    */
    101   public static int indexOf(float[] array, float target) {
    102     return indexOf(array, target, 0, array.length);
    103   }
    104 
    105   // TODO: consider making this public
    106   private static int indexOf(
    107       float[] array, float target, int start, int end) {
    108     for (int i = start; i < end; i++) {
    109       if (array[i] == target) {
    110         return i;
    111       }
    112     }
    113     return -1;
    114   }
    115 
    116   /**
    117    * Returns the start position of the first occurrence of the specified {@code
    118    * target} within {@code array}, or {@code -1} if there is no such occurrence.
    119    *
    120    * <p>More formally, returns the lowest index {@code i} such that {@code
    121    * java.util.Arrays.copyOfRange(array, i, i + target.length)} contains exactly
    122    * the same elements as {@code target}.
    123    *
    124    * <p>Note that this always returns {@code -1} when {@code target} contains
    125    * {@code NaN}.
    126    *
    127    * @param array the array to search for the sequence {@code target}
    128    * @param target the array to search for as a sub-sequence of {@code array}
    129    */
    130   public static int indexOf(float[] array, float[] target) {
    131     checkNotNull(array, "array");
    132     checkNotNull(target, "target");
    133     if (target.length == 0) {
    134       return 0;
    135     }
    136 
    137     outer:
    138     for (int i = 0; i < array.length - target.length + 1; i++) {
    139       for (int j = 0; j < target.length; j++) {
    140         if (array[i + j] != target[j]) {
    141           continue outer;
    142         }
    143       }
    144       return i;
    145     }
    146     return -1;
    147   }
    148 
    149   /**
    150    * Returns the index of the last appearance of the value {@code target} in
    151    * {@code array}. Note that this always returns {@code -1} when {@code target}
    152    * is {@code NaN}.
    153    *
    154    * @param array an array of {@code float} values, possibly empty
    155    * @param target a primitive {@code float} value
    156    * @return the greatest index {@code i} for which {@code array[i] == target},
    157    *     or {@code -1} if no such index exists.
    158    */
    159   public static int lastIndexOf(float[] array, float target) {
    160     return lastIndexOf(array, target, 0, array.length);
    161   }
    162 
    163   // TODO: consider making this public
    164   private static int lastIndexOf(
    165       float[] array, float target, int start, int end) {
    166     for (int i = end - 1; i >= start; i--) {
    167       if (array[i] == target) {
    168         return i;
    169       }
    170     }
    171     return -1;
    172   }
    173 
    174   /**
    175    * Returns the least value present in {@code array}, using the same rules of
    176    * comparison as {@link Math#min(float, float)}.
    177    *
    178    * @param array a <i>nonempty</i> array of {@code float} values
    179    * @return the value present in {@code array} that is less than or equal to
    180    *     every other value in the array
    181    * @throws IllegalArgumentException if {@code array} is empty
    182    */
    183   public static float min(float... array) {
    184     checkArgument(array.length > 0);
    185     float min = array[0];
    186     for (int i = 1; i < array.length; i++) {
    187       min = Math.min(min, array[i]);
    188     }
    189     return min;
    190   }
    191 
    192   /**
    193    * Returns the greatest value present in {@code array}, using the same rules
    194    * of comparison as {@link Math#min(float, float)}.
    195    *
    196    * @param array a <i>nonempty</i> array of {@code float} values
    197    * @return the value present in {@code array} that is greater than or equal to
    198    *     every other value in the array
    199    * @throws IllegalArgumentException if {@code array} is empty
    200    */
    201   public static float max(float... array) {
    202     checkArgument(array.length > 0);
    203     float max = array[0];
    204     for (int i = 1; i < array.length; i++) {
    205       max = Math.max(max, array[i]);
    206     }
    207     return max;
    208   }
    209 
    210   /**
    211    * Returns the values from each provided array combined into a single array.
    212    * For example, {@code concat(new float[] {a, b}, new float[] {}, new
    213    * float[] {c}} returns the array {@code {a, b, c}}.
    214    *
    215    * @param arrays zero or more {@code float} arrays
    216    * @return a single array containing all the values from the source arrays, in
    217    *     order
    218    */
    219   public static float[] concat(float[]... arrays) {
    220     int length = 0;
    221     for (float[] array : arrays) {
    222       length += array.length;
    223     }
    224     float[] result = new float[length];
    225     int pos = 0;
    226     for (float[] array : arrays) {
    227       System.arraycopy(array, 0, result, pos, array.length);
    228       pos += array.length;
    229     }
    230     return result;
    231   }
    232 
    233   /**
    234    * Returns an array containing the same values as {@code array}, but
    235    * guaranteed to be of a specified minimum length. If {@code array} already
    236    * has a length of at least {@code minLength}, it is returned directly.
    237    * Otherwise, a new array of size {@code minLength + padding} is returned,
    238    * containing the values of {@code array}, and zeroes in the remaining places.
    239    *
    240    * @param array the source array
    241    * @param minLength the minimum length the returned array must guarantee
    242    * @param padding an extra amount to "grow" the array by if growth is
    243    *     necessary
    244    * @throws IllegalArgumentException if {@code minLength} or {@code padding} is
    245    *     negative
    246    * @return an array containing the values of {@code array}, with guaranteed
    247    *     minimum length {@code minLength}
    248    */
    249   public static float[] ensureCapacity(
    250       float[] array, int minLength, int padding) {
    251     checkArgument(minLength >= 0, "Invalid minLength: %s", minLength);
    252     checkArgument(padding >= 0, "Invalid padding: %s", padding);
    253     return (array.length < minLength)
    254         ? copyOf(array, minLength + padding)
    255         : array;
    256   }
    257 
    258   // Arrays.copyOf() requires Java 6
    259   private static float[] copyOf(float[] original, int length) {
    260     float[] copy = new float[length];
    261     System.arraycopy(original, 0, copy, 0, Math.min(original.length, length));
    262     return copy;
    263   }
    264 
    265   /**
    266    * Returns a string containing the supplied {@code float} values, converted
    267    * to strings as specified by {@link Float#toString(float)}, and separated by
    268    * {@code separator}. For example, {@code join("-", 1.0f, 2.0f, 3.0f)}
    269    * returns the string {@code "1.0-2.0-3.0"}.
    270    *
    271    * @param separator the text that should appear between consecutive values in
    272    *     the resulting string (but not at the start or end)
    273    * @param array an array of {@code float} values, possibly empty
    274    */
    275   public static String join(String separator, float... array) {
    276     checkNotNull(separator);
    277     if (array.length == 0) {
    278       return "";
    279     }
    280 
    281     // For pre-sizing a builder, just get the right order of magnitude
    282     StringBuilder builder = new StringBuilder(array.length * 12);
    283     builder.append(array[0]);
    284     for (int i = 1; i < array.length; i++) {
    285       builder.append(separator).append(array[i]);
    286     }
    287     return builder.toString();
    288   }
    289 
    290   /**
    291    * Returns a comparator that compares two {@code float} arrays
    292    * lexicographically. That is, it compares, using {@link
    293    * #compare(float, float)}), the first pair of values that follow any
    294    * common prefix, or when one array is a prefix of the other, treats the
    295    * shorter array as the lesser. For example, {@code [] < [1.0f] < [1.0f, 2.0f]
    296    * < [2.0f]}.
    297    *
    298    * <p>The returned comparator is inconsistent with {@link
    299    * Object#equals(Object)} (since arrays support only identity equality), but
    300    * it is consistent with {@link Arrays#equals(float[], float[])}.
    301    *
    302    * @see <a href="http://en.wikipedia.org/wiki/Lexicographical_order">
    303    *     Lexicographical order</a> article at Wikipedia
    304    * @since 2010.01.04 <b>tentative</b>
    305    */
    306   public static Comparator<float[]> lexicographicalComparator() {
    307     return LexicographicalComparator.INSTANCE;
    308   }
    309 
    310   private enum LexicographicalComparator implements Comparator<float[]> {
    311     INSTANCE;
    312 
    313     public int compare(float[] left, float[] right) {
    314       int minLength = Math.min(left.length, right.length);
    315       for (int i = 0; i < minLength; i++) {
    316         int result = Floats.compare(left[i], right[i]);
    317         if (result != 0) {
    318           return result;
    319         }
    320       }
    321       return left.length - right.length;
    322     }
    323   }
    324 
    325   /**
    326    * Copies a collection of {@code Float} instances into a new array of
    327    * primitive {@code float} values.
    328    *
    329    * <p>Elements are copied from the argument collection as if by {@code
    330    * collection.toArray()}.  Calling this method is as thread-safe as calling
    331    * that method.
    332    *
    333    * @param collection a collection of {@code Float} objects
    334    * @return an array containing the same values as {@code collection}, in the
    335    *     same order, converted to primitives
    336    * @throws NullPointerException if {@code collection} or any of its elements
    337    *     is null
    338    */
    339   public static float[] toArray(Collection<Float> collection) {
    340     if (collection instanceof FloatArrayAsList) {
    341       return ((FloatArrayAsList) collection).toFloatArray();
    342     }
    343 
    344     Object[] boxedArray = collection.toArray();
    345     int len = boxedArray.length;
    346     float[] array = new float[len];
    347     for (int i = 0; i < len; i++) {
    348       array[i] = (Float) boxedArray[i];
    349     }
    350     return array;
    351   }
    352 
    353   /**
    354    * Returns a fixed-size list backed by the specified array, similar to {@link
    355    * Arrays#asList(Object[])}. The list supports {@link List#set(int, Object)},
    356    * but any attempt to set a value to {@code null} will result in a {@link
    357    * NullPointerException}.
    358    *
    359    * <p>The returned list maintains the values, but not the identities, of
    360    * {@code Float} objects written to or read from it.  For example, whether
    361    * {@code list.get(0) == list.get(0)} is true for the returned list is
    362    * unspecified.
    363    *
    364    * <p>The returned list may have unexpected behavior if it contains {@code
    365    * NaN}, or if {@code NaN} is used as a parameter to any of its methods.
    366    *
    367    * @param backingArray the array to back the list
    368    * @return a list view of the array
    369    */
    370   public static List<Float> asList(float... backingArray) {
    371     if (backingArray.length == 0) {
    372       return Collections.emptyList();
    373     }
    374     return new FloatArrayAsList(backingArray);
    375   }
    376 
    377   @GwtCompatible
    378   private static class FloatArrayAsList extends AbstractList<Float>
    379       implements RandomAccess, Serializable {
    380     final float[] array;
    381     final int start;
    382     final int end;
    383 
    384     FloatArrayAsList(float[] array) {
    385       this(array, 0, array.length);
    386     }
    387 
    388     FloatArrayAsList(float[] array, int start, int end) {
    389       this.array = array;
    390       this.start = start;
    391       this.end = end;
    392     }
    393 
    394     @Override public int size() {
    395       return end - start;
    396     }
    397 
    398     @Override public boolean isEmpty() {
    399       return false;
    400     }
    401 
    402     @Override public Float get(int index) {
    403       checkElementIndex(index, size());
    404       return array[start + index];
    405     }
    406 
    407     @Override public boolean contains(Object target) {
    408       // Overridden to prevent a ton of boxing
    409       return (target instanceof Float)
    410           && Floats.indexOf(array, (Float) target, start, end) != -1;
    411     }
    412 
    413     @Override public int indexOf(Object target) {
    414       // Overridden to prevent a ton of boxing
    415       if (target instanceof Float) {
    416         int i = Floats.indexOf(array, (Float) target, start, end);
    417         if (i >= 0) {
    418           return i - start;
    419         }
    420       }
    421       return -1;
    422     }
    423 
    424     @Override public int lastIndexOf(Object target) {
    425       // Overridden to prevent a ton of boxing
    426       if (target instanceof Float) {
    427         int i = Floats.lastIndexOf(array, (Float) target, start, end);
    428         if (i >= 0) {
    429           return i - start;
    430         }
    431       }
    432       return -1;
    433     }
    434 
    435     @Override public Float set(int index, Float element) {
    436       checkElementIndex(index, size());
    437       float oldValue = array[start + index];
    438       array[start + index] = element;
    439       return oldValue;
    440     }
    441 
    442     /** In GWT, List and AbstractList do not have the subList method. */
    443     /*@Override*/ public List<Float> subList(int fromIndex, int toIndex) {
    444       int size = size();
    445       checkPositionIndexes(fromIndex, toIndex, size);
    446       if (fromIndex == toIndex) {
    447         return Collections.emptyList();
    448       }
    449       return new FloatArrayAsList(array, start + fromIndex, start + toIndex);
    450     }
    451 
    452     @Override public boolean equals(Object object) {
    453       if (object == this) {
    454         return true;
    455       }
    456       if (object instanceof FloatArrayAsList) {
    457         FloatArrayAsList that = (FloatArrayAsList) object;
    458         int size = size();
    459         if (that.size() != size) {
    460           return false;
    461         }
    462         for (int i = 0; i < size; i++) {
    463           if (array[start + i] != that.array[that.start + i]) {
    464             return false;
    465           }
    466         }
    467         return true;
    468       }
    469       return super.equals(object);
    470     }
    471 
    472     @Override public int hashCode() {
    473       int result = 1;
    474       for (int i = start; i < end; i++) {
    475         result = 31 * result + Floats.hashCode(array[i]);
    476       }
    477       return result;
    478     }
    479 
    480     @Override public String toString() {
    481       StringBuilder builder = new StringBuilder(size() * 12);
    482       builder.append('[').append(array[start]);
    483       for (int i = start + 1; i < end; i++) {
    484         builder.append(", ").append(array[i]);
    485       }
    486       return builder.append(']').toString();
    487     }
    488 
    489     float[] toFloatArray() {
    490       // Arrays.copyOfRange() requires Java 6
    491       int size = size();
    492       float[] result = new float[size];
    493       System.arraycopy(array, start, result, 0, size);
    494       return result;
    495     }
    496 
    497     private static final long serialVersionUID = 0;
    498   }
    499 }
    500