    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
    017    package com.google.common.primitives;
    018
    019    import static com.google.common.base.Preconditions.checkArgument;
    020    import static com.google.common.base.Preconditions.checkElementIndex;
    021    import static com.google.common.base.Preconditions.checkNotNull;
    022    import static com.google.common.base.Preconditions.checkPositionIndexes;
    023    import static java.lang.Float.NEGATIVE_INFINITY;
    024    import static java.lang.Float.POSITIVE_INFINITY;
    025
    026    import com.google.common.annotations.GwtCompatible;
    027
    028    import java.io.Serializable;
    029    import java.util.AbstractList;
    030    import java.util.Arrays;
    031    import java.util.Collection;
    032    import java.util.Collections;
    033    import java.util.Comparator;
    034    import java.util.List;
    035    import java.util.RandomAccess;
    036
    037    /**
    038     * Static utility methods pertaining to {@code float} primitives, that are not
    039     * already found in either {@link Float} or {@link Arrays}.
    040     *
    041     * <p>See the Guava User Guide article on <a href=
    042     * "http://code.google.com/p/guava-libraries/wiki/PrimitivesExplained">
    043     * primitive utilities</a>.
    044     *
    045     * @author Kevin Bourrillion
    046     * @since 1.0
    047     */
    048    @GwtCompatible
    049    public final class Floats {
    050      private Floats() {}
    051
    052      /**
    053       * The number of bytes required to represent a primitive {@code float}
    054       * value.
    055       *
    056       * @since 10.0
    057       */
    058      public static final int BYTES = Float.SIZE / Byte.SIZE;
    059
    060      /**
    061       * Returns a hash code for {@code value}; equal to the result of invoking
    062       * {@code ((Float) value).hashCode()}.
    063       *
    064       * @param value a primitive {@code float} value
    065       * @return a hash code for the value
    066       */
    067      public static int hashCode(float value) {
    068        // TODO(kevinb): is there a better way, that's still gwt-safe?
    069        return ((Float) value).hashCode();
    070      }
    071
    072      /**
    073       * Compares the two specified {@code float} values using {@link
    074       * Float#compare(float, float)}. You may prefer to invoke that method
    075       * directly; this method exists only for consistency with the other utilities
    076       * in this package.
    077       *
    078       * @param a the first {@code float} to compare
    079       * @param b the second {@code float} to compare
    080       * @return the result of invoking {@link Float#compare(float, float)}
    081       */
    082      public static int compare(float a, float b) {
    083        return Float.compare(a, b);
    084      }
    085
    086      /**
    087       * Returns {@code true} if {@code value} represents a real number. This is
    088       * equivalent to, but not necessarily implemented as,
    089       * {@code !(Float.isInfinite(value) || Float.isNaN(value))}.
    090       *
    091       * @since 10.0
    092       */
    093      public static boolean isFinite(float value) {
    094        return NEGATIVE_INFINITY < value & value < POSITIVE_INFINITY;
    095      }
    096
    097      /**
    098       * Returns {@code true} if {@code target} is present as an element anywhere in
    099       * {@code array}. Note that this always returns {@code false} when {@code
    100       * target} is {@code NaN}.
    101       *
    102       * @param array an array of {@code float} values, possibly empty
    103       * @param target a primitive {@code float} value
    104       * @return {@code true} if {@code array[i] == target} for some value of {@code
    105       *     i}
    106       */
    107      public static boolean contains(float[] array, float target) {
    108        for (float value : array) {
    109          if (value == target) {
    110            return true;
    111          }
    112        }
    113        return false;
    114      }
    115
    116      /**
    117       * Returns the index of the first appearance of the value {@code target} in
    118       * {@code array}. Note that this always returns {@code -1} when {@code target}
    119       * is {@code NaN}.
    120       *
    121       * @param array an array of {@code float} values, possibly empty
    122       * @param target a primitive {@code float} value
    123       * @return the least index {@code i} for which {@code array[i] == target}, or
    124       *     {@code -1} if no such index exists.
    125       */
    126      public static int indexOf(float[] array, float target) {
    127        return indexOf(array, target, 0, array.length);
    128      }
    129
    130      // TODO(kevinb): consider making this public
    131      private static int indexOf(
    132          float[] array, float target, int start, int end) {
    133        for (int i = start; i < end; i++) {
    134          if (array[i] == target) {
    135            return i;
    136          }
    137        }
    138        return -1;
    139      }
    140
    141      /**
    142       * Returns the start position of the first occurrence of the specified {@code
    143       * target} within {@code array}, or {@code -1} if there is no such occurrence.
    144       *
    145       * <p>More formally, returns the lowest index {@code i} such that {@code
    146       * java.util.Arrays.copyOfRange(array, i, i + target.length)} contains exactly
    147       * the same elements as {@code target}.
    148       *
    149       * <p>Note that this always returns {@code -1} when {@code target} contains
    150       * {@code NaN}.
    151       *
    152       * @param array the array to search for the sequence {@code target}
    153       * @param target the array to search for as a sub-sequence of {@code array}
    154       */
    155      public static int indexOf(float[] array, float[] target) {
    156        checkNotNull(array, "array");
    157        checkNotNull(target, "target");
    158        if (target.length == 0) {
    159          return 0;
    160        }
    161
    162        outer:
    163        for (int i = 0; i < array.length - target.length + 1; i++) {
    164          for (int j = 0; j < target.length; j++) {
    165            if (array[i + j] != target[j]) {
    166              continue outer;
    167            }
    168          }
    169          return i;
    170        }
    171        return -1;
    172      }
    173
    174      /**
    175       * Returns the index of the last appearance of the value {@code target} in
    176       * {@code array}. Note that this always returns {@code -1} when {@code target}
    177       * is {@code NaN}.
    178       *
    179       * @param array an array of {@code float} values, possibly empty
    180       * @param target a primitive {@code float} value
    181       * @return the greatest index {@code i} for which {@code array[i] == target},
    182       *     or {@code -1} if no such index exists.
    183       */
    184      public static int lastIndexOf(float[] array, float target) {
    185        return lastIndexOf(array, target, 0, array.length);
    186      }
    187
    188      // TODO(kevinb): consider making this public
    189      private static int lastIndexOf(
    190          float[] array, float target, int start, int end) {
    191        for (int i = end - 1; i >= start; i--) {
    192          if (array[i] == target) {
    193            return i;
    194          }
    195        }
    196        return -1;
    197      }
    198
    199      /**
    200       * Returns the least value present in {@code array}, using the same rules of
    201       * comparison as {@link Math#min(float, float)}.
    202       *
    203       * @param array a <i>nonempty</i> array of {@code float} values
    204       * @return the value present in {@code array} that is less than or equal to
    205       *     every other value in the array
    206       * @throws IllegalArgumentException if {@code array} is empty
    207       */
    208      public static float min(float... array) {
    209        checkArgument(array.length > 0);
    210        float min = array[0];
    211        for (int i = 1; i < array.length; i++) {
    212          min = Math.min(min, array[i]);
    213        }
    214        return min;
    215      }
    216
    217      /**
    218       * Returns the greatest value present in {@code array}, using the same rules
    219       * of comparison as {@link Math#min(float, float)}.
    220       *
    221       * @param array a <i>nonempty</i> array of {@code float} values
    222       * @return the value present in {@code array} that is greater than or equal to
    223       *     every other value in the array
    224       * @throws IllegalArgumentException if {@code array} is empty
    225       */
    226      public static float max(float... array) {
    227        checkArgument(array.length > 0);
    228        float max = array[0];
    229        for (int i = 1; i < array.length; i++) {
    230          max = Math.max(max, array[i]);
    231        }
    232        return max;
    233      }
    234
    235      /**
    236       * Returns the values from each provided array combined into a single array.
    237       * For example, {@code concat(new float[] {a, b}, new float[] {}, new
    238       * float[] {c}} returns the array {@code {a, b, c}}.
    239       *
    240       * @param arrays zero or more {@code float} arrays
    241       * @return a single array containing all the values from the source arrays, in
    242       *     order
    243       */
    244      public static float[] concat(float[]... arrays) {
    245        int length = 0;
    246        for (float[] array : arrays) {
    247          length += array.length;
    248        }
    249        float[] result = new float[length];
    250        int pos = 0;
    251        for (float[] array : arrays) {
    252          System.arraycopy(array, 0, result, pos, array.length);
    253          pos += array.length;
    254        }
    255        return result;
    256      }
    257
    258      /**
    259       * Returns an array containing the same values as {@code array}, but
    260       * guaranteed to be of a specified minimum length. If {@code array} already
    261       * has a length of at least {@code minLength}, it is returned directly.
    262       * Otherwise, a new array of size {@code minLength + padding} is returned,
    263       * 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
    268       *     necessary
    269       * @throws IllegalArgumentException if {@code minLength} or {@code padding} is
    270       *     negative
    271       * @return an array containing the values of {@code array}, with guaranteed
    272       *     minimum length {@code minLength}
    273       */
    274      public static float[] ensureCapacity(
    275          float[] array, int minLength, int padding) {
    276        checkArgument(minLength >= 0, "Invalid minLength: %s", minLength);
    277        checkArgument(padding >= 0, "Invalid padding: %s", padding);
    278        return (array.length < minLength)
    279            ? copyOf(array, minLength + padding)
    280            : array;
    281      }
    282
    283      // Arrays.copyOf() requires Java 6
    284      private static float[] copyOf(float[] original, int length) {
    285        float[] copy = new float[length];
    286        System.arraycopy(original, 0, copy, 0, Math.min(original.length, length));
    287        return copy;
    288      }
    289
    290      /**
    291       * Returns a string containing the supplied {@code float} values, converted
    292       * to strings as specified by {@link Float#toString(float)}, and separated by
    293       * {@code separator}. For example, {@code join("-", 1.0f, 2.0f, 3.0f)}
    294       * returns the string {@code "1.0-2.0-3.0"}.
    295       *
    296       * <p>Note that {@link Float#toString(float)} formats {@code float}
    297       * differently in GWT.  In the previous example, it returns the string {@code
    298       * "1-2-3"}.
    299       *
    300       * @param separator the text that should appear between consecutive values in
    301       *     the resulting string (but not at the start or end)
    302       * @param array an array of {@code float} values, possibly empty
    303       */
    304      public static String join(String separator, float... array) {
    305        checkNotNull(separator);
    306        if (array.length == 0) {
    307          return "";
    308        }
    309
    310        // For pre-sizing a builder, just get the right order of magnitude
    311        StringBuilder builder = new StringBuilder(array.length * 12);
    312        builder.append(array[0]);
    313        for (int i = 1; i < array.length; i++) {
    314          builder.append(separator).append(array[i]);
    315        }
    316        return builder.toString();
    317      }
    318
    319      /**
    320       * Returns a comparator that compares two {@code float} arrays
    321       * lexicographically. That is, it compares, using {@link
    322       * #compare(float, float)}), the first pair of values that follow any
    323       * common prefix, or when one array is a prefix of the other, treats the
    324       * shorter array as the lesser. For example, {@code [] < [1.0f] < [1.0f, 2.0f]
    325       * < [2.0f]}.
    326       *
    327       * <p>The returned comparator is inconsistent with {@link
    328       * Object#equals(Object)} (since arrays support only identity equality), but
    329       * it is consistent with {@link Arrays#equals(float[], float[])}.
    330       *
    331       * @see <a href="http://en.wikipedia.org/wiki/Lexicographical_order">
    332       *     Lexicographical order article at Wikipedia</a>
    333       * @since 2.0
    334       */
    335      public static Comparator<float[]> lexicographicalComparator() {
    336        return LexicographicalComparator.INSTANCE;
    337      }
    338
    339      private enum LexicographicalComparator implements Comparator<float[]> {
    340        INSTANCE;
    341
    342        @Override
    343        public int compare(float[] left, float[] right) {
    344          int minLength = Math.min(left.length, right.length);
    345          for (int i = 0; i < minLength; i++) {
    346            int result = Floats.compare(left[i], right[i]);
    347            if (result != 0) {
    348              return result;
    349            }
    350          }
    351          return left.length - right.length;
    352        }
    353      }
    354
    355      /**
    356       * Returns an array containing each value of {@code collection}, converted to
    357       * a {@code float} value in the manner of {@link Number#floatValue}.
    358       *
    359       * <p>Elements are copied from the argument collection as if by {@code
    360       * collection.toArray()}.  Calling this method is as thread-safe as calling
    361       * that method.
    362       *
    363       * @param collection a collection of {@code Number} instances
    364       * @return an array containing the same values as {@code collection}, in the
    365       *     same order, converted to primitives
    366       * @throws NullPointerException if {@code collection} or any of its elements
    367       *     is null
    368       * @since 1.0 (parameter was {@code Collection<Float>} before 12.0)
    369       */
    370      public static float[] toArray(Collection<? extends Number> collection) {
    371        if (collection instanceof FloatArrayAsList) {
    372          return ((FloatArrayAsList) collection).toFloatArray();
    373        }
    374
    375        Object[] boxedArray = collection.toArray();
    376        int len = boxedArray.length;
    377        float[] array = new float[len];
    378        for (int i = 0; i < len; i++) {
    379          // checkNotNull for GWT (do not optimize)
    380          array[i] = ((Number) checkNotNull(boxedArray[i])).floatValue();
    381        }
    382        return array;
    383      }
    384
    385      /**
    386       * Returns a fixed-size list backed by the specified array, similar to {@link
    387       * Arrays#asList(Object[])}. The list supports {@link List#set(int, Object)},
    388       * but any attempt to set a value to {@code null} will result in a {@link
    389       * NullPointerException}.
    390       *
    391       * <p>The returned list maintains the values, but not the identities, of
    392       * {@code Float} objects written to or read from it.  For example, whether
    393       * {@code list.get(0) == list.get(0)} is true for the returned list is
    394       * unspecified.
    395       *
    396       * <p>The returned list may have unexpected behavior if it contains {@code
    397       * NaN}, or if {@code NaN} is used as a parameter to any of its methods.
    398       *
    399       * @param backingArray the array to back the list
    400       * @return a list view of the array
    401       */
    402      public static List<Float> asList(float... backingArray) {
    403        if (backingArray.length == 0) {
    404          return Collections.emptyList();
    405        }
    406        return new FloatArrayAsList(backingArray);
    407      }
    408
    409      @GwtCompatible
    410      private static class FloatArrayAsList extends AbstractList<Float>
    411          implements RandomAccess, Serializable {
    412        final float[] array;
    413        final int start;
    414        final int end;
    415
    416        FloatArrayAsList(float[] array) {
    417          this(array, 0, array.length);
    418        }
    419
    420        FloatArrayAsList(float[] array, int start, int end) {
    421          this.array = array;
    422          this.start = start;
    423          this.end = end;
    424        }
    425
    426        @Override public int size() {
    427          return end - start;
    428        }
    429
    430        @Override public boolean isEmpty() {
    431          return false;
    432        }
    433
    434        @Override public Float get(int index) {
    435          checkElementIndex(index, size());
    436          return array[start + index];
    437        }
    438
    439        @Override public boolean contains(Object target) {
    440          // Overridden to prevent a ton of boxing
    441          return (target instanceof Float)
    442              && Floats.indexOf(array, (Float) target, start, end) != -1;
    443        }
    444
    445        @Override public int indexOf(Object target) {
    446          // Overridden to prevent a ton of boxing
    447          if (target instanceof Float) {
    448            int i = Floats.indexOf(array, (Float) target, start, end);
    449            if (i >= 0) {
    450              return i - start;
    451            }
    452          }
    453          return -1;
    454        }
    455
    456        @Override public int lastIndexOf(Object target) {
    457          // Overridden to prevent a ton of boxing
    458          if (target instanceof Float) {
    459            int i = Floats.lastIndexOf(array, (Float) target, start, end);
    460            if (i >= 0) {
    461              return i - start;
    462            }
    463          }
    464          return -1;
    465        }
    466
    467        @Override public Float set(int index, Float element) {
    468          checkElementIndex(index, size());
    469          float oldValue = array[start + index];
    470          // checkNotNull for GWT (do not optimize)
    471          array[start + index] = checkNotNull(element);
    472          return oldValue;
    473        }
    474
    475        @Override public List<Float> subList(int fromIndex, int toIndex) {
    476          int size = size();
    477          checkPositionIndexes(fromIndex, toIndex, size);
    478          if (fromIndex == toIndex) {
    479            return Collections.emptyList();
    480          }
    481          return new FloatArrayAsList(array, start + fromIndex, start + toIndex);
    482        }
    483
    484        @Override public boolean equals(Object object) {
    485          if (object == this) {
    486            return true;
    487          }
    488          if (object instanceof FloatArrayAsList) {
    489            FloatArrayAsList that = (FloatArrayAsList) object;
    490            int size = size();
    491            if (that.size() != size) {
    492              return false;
    493            }
    494            for (int i = 0; i < size; i++) {
    495              if (array[start + i] != that.array[that.start + i]) {
    496                return false;
    497              }
    498            }
    499            return true;
    500          }
    501          return super.equals(object);
    502        }
    503
    504        @Override public int hashCode() {
    505          int result = 1;
    506          for (int i = start; i < end; i++) {
    507            result = 31 * result + Floats.hashCode(array[i]);
    508          }
    509          return result;
    510        }
    511
    512        @Override public String toString() {
    513          StringBuilder builder = new StringBuilder(size() * 12);
    514          builder.append('[').append(array[start]);
    515          for (int i = start + 1; i < end; i++) {
    516            builder.append(", ").append(array[i]);
    517          }
    518          return builder.append(']').toString();
    519        }
    520
    521        float[] toFloatArray() {
    522          // Arrays.copyOfRange() is not available under GWT
    523          int size = size();
    524          float[] result = new float[size];
    525          System.arraycopy(array, start, result, 0, size);
    526          return result;
    527        }
    528
    529        private static final long serialVersionUID = 0;
    530      }
    531    }