001    /*
002     * Copyright (C) 2008 Google Inc.
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    
024    import com.google.common.annotations.GwtCompatible;
025    
026    import java.io.Serializable;
027    import java.util.AbstractList;
028    import java.util.Arrays;
029    import java.util.Collection;
030    import java.util.Collections;
031    import java.util.Comparator;
032    import java.util.List;
033    import java.util.RandomAccess;
034    
035    /**
036     * Static utility methods pertaining to {@code float} primitives, that are not
037     * already found in either {@link Float} or {@link Arrays}.
038     *
039     * @author Kevin Bourrillion
040     * @since 1
041     */
042    @GwtCompatible
043    public final class Floats {
044      private Floats() {}
045    
046      /**
047       * Returns a hash code for {@code value}; equal to the result of invoking
048       * {@code ((Float) value).hashCode()}.
049       *
050       * @param value a primitive {@code float} value
051       * @return a hash code for the value
052       */
053      public static int hashCode(float value) {
054        // TODO: is there a better way, that's still gwt-safe?
055        return ((Float) value).hashCode();
056      }
057    
058      /**
059       * Compares the two specified {@code float} values using {@link
060       * Float#compare(float, float)}. You may prefer to invoke that method
061       * directly; this method exists only for consistency with the other utilities
062       * in this package.
063       *
064       * @param a the first {@code float} to compare
065       * @param b the second {@code float} to compare
066       * @return the result of invoking {@link Float#compare(float, float)}
067       */
068      public static int compare(float a, float b) {
069        return Float.compare(a, b);
070      }
071    
072      /**
073       * Returns {@code true} if {@code target} is present as an element anywhere in
074       * {@code array}. Note that this always returns {@code false} when {@code
075       * target} is {@code NaN}.
076       *
077       * @param array an array of {@code float} values, possibly empty
078       * @param target a primitive {@code float} value
079       * @return {@code true} if {@code array[i] == target} for some value of {@code
080       *     i}
081       */
082      public static boolean contains(float[] array, float target) {
083        for (float value : array) {
084          if (value == target) {
085            return true;
086          }
087        }
088        return false;
089      }
090    
091      /**
092       * Returns the index of the first appearance of the value {@code target} in
093       * {@code array}. Note that this always returns {@code -1} when {@code target}
094       * is {@code NaN}.
095       *
096       * @param array an array of {@code float} values, possibly empty
097       * @param target a primitive {@code float} value
098       * @return the least index {@code i} for which {@code array[i] == target}, or
099       *     {@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 2
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    }