Home | History | Annotate | Download | only in primitives
      1 /*
      2  * Copyright (C) 2011 The Guava Authors
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
      5  * in compliance with the License. You may obtain a copy of the License at
      6  *
      7  * http://www.apache.org/licenses/LICENSE-2.0
      8  *
      9  * Unless required by applicable law or agreed to in writing, software distributed under the
     10  * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
     11  * express or implied. See the License for the specific language governing permissions and
     12  * limitations under the License.
     13  */
     14 
     15 package com.google.common.primitives;
     16 
     17 import static com.google.common.base.Preconditions.checkArgument;
     18 import static com.google.common.base.Preconditions.checkNotNull;
     19 
     20 import java.util.Arrays;
     21 import java.util.Comparator;
     22 
     23 import com.google.common.annotations.Beta;
     24 import com.google.common.annotations.GwtCompatible;
     25 
     26 /**
     27  * Static utility methods pertaining to {@code int} primitives that interpret values as
     28  * <i>unsigned</i> (that is, any negative value {@code x} is treated as the positive value
     29  * {@code 2^32 + x}). The methods for which signedness is not an issue are in {@link Ints}, as well
     30  * as signed versions of methods for which signedness is an issue.
     31  *
     32  * <p>In addition, this class provides several static methods for converting an {@code int} to a
     33  * {@code String} and a {@code String} to an {@code int} that treat the {@code int} as an unsigned
     34  * number.
     35  *
     36  * <p>Users of these utilities must be <i>extremely careful</i> not to mix up signed and unsigned
     37  * {@code int} values. When possible, it is recommended that the {@link UnsignedInteger} wrapper
     38  * class be used, at a small efficiency penalty, to enforce the distinction in the type system.
     39  *
     40  * @author Louis Wasserman
     41  * @since 11.0
     42  */
     43 @Beta
     44 @GwtCompatible
     45 public final class UnsignedInts {
     46   static final long INT_MASK = 0xffffffffL;
     47 
     48   private UnsignedInts() {}
     49 
     50   static int flip(int value) {
     51     return value ^ Integer.MIN_VALUE;
     52   }
     53 
     54   /**
     55    * Compares the two specified {@code int} values, treating them as unsigned values between
     56    * {@code 0} and {@code 2^32 - 1} inclusive.
     57    *
     58    * @param a the first unsigned {@code int} to compare
     59    * @param b the second unsigned {@code int} to compare
     60    * @return a negative value if {@code a} is less than {@code b}; a positive value if {@code a} is
     61    *         greater than {@code b}; or zero if they are equal
     62    */
     63   public static int compare(int a, int b) {
     64     return Ints.compare(flip(a), flip(b));
     65   }
     66 
     67   /**
     68    * Returns the value of the given {@code int} as a {@code long}, when treated as unsigned.
     69    */
     70   public static long toLong(int value) {
     71     return value & INT_MASK;
     72   }
     73 
     74   /**
     75    * Returns the least value present in {@code array}, treating values as unsigned.
     76    *
     77    * @param array a <i>nonempty</i> array of unsigned {@code int} values
     78    * @return the value present in {@code array} that is less than or equal to every other value in
     79    *         the array according to {@link #compare}
     80    * @throws IllegalArgumentException if {@code array} is empty
     81    */
     82   public static int min(int... array) {
     83     checkArgument(array.length > 0);
     84     int min = flip(array[0]);
     85     for (int i = 1; i < array.length; i++) {
     86       int next = flip(array[i]);
     87       if (next < min) {
     88         min = next;
     89       }
     90     }
     91     return flip(min);
     92   }
     93 
     94   /**
     95    * Returns the greatest value present in {@code array}, treating values as unsigned.
     96    *
     97    * @param array a <i>nonempty</i> array of unsigned {@code int} values
     98    * @return the value present in {@code array} that is greater than or equal to every other value
     99    *         in the array according to {@link #compare}
    100    * @throws IllegalArgumentException if {@code array} is empty
    101    */
    102   public static int max(int... array) {
    103     checkArgument(array.length > 0);
    104     int max = flip(array[0]);
    105     for (int i = 1; i < array.length; i++) {
    106       int next = flip(array[i]);
    107       if (next > max) {
    108         max = next;
    109       }
    110     }
    111     return flip(max);
    112   }
    113 
    114   /**
    115    * Returns a string containing the supplied unsigned {@code int} values separated by
    116    * {@code separator}. For example, {@code join("-", 1, 2, 3)} returns the string {@code "1-2-3"}.
    117    *
    118    * @param separator the text that should appear between consecutive values in the resulting
    119    *        string (but not at the start or end)
    120    * @param array an array of unsigned {@code int} values, possibly empty
    121    */
    122   public static String join(String separator, int... array) {
    123     checkNotNull(separator);
    124     if (array.length == 0) {
    125       return "";
    126     }
    127 
    128     // For pre-sizing a builder, just get the right order of magnitude
    129     StringBuilder builder = new StringBuilder(array.length * 5);
    130     builder.append(array[0]);
    131     for (int i = 1; i < array.length; i++) {
    132       builder.append(separator).append(toString(array[i]));
    133     }
    134     return builder.toString();
    135   }
    136 
    137   /**
    138    * Returns a comparator that compares two arrays of unsigned {@code int} values lexicographically.
    139    * That is, it compares, using {@link #compare(int, int)}), the first pair of values that follow
    140    * any common prefix, or when one array is a prefix of the other, treats the shorter array as the
    141    * lesser. For example, {@code [] < [1] < [1, 2] < [2] < [1 << 31]}.
    142    *
    143    * <p>The returned comparator is inconsistent with {@link Object#equals(Object)} (since arrays
    144    * support only identity equality), but it is consistent with {@link Arrays#equals(int[], int[])}.
    145    *
    146    * @see <a href="http://en.wikipedia.org/wiki/Lexicographical_order"> Lexicographical order
    147    *      article at Wikipedia</a>
    148    */
    149   public static Comparator<int[]> lexicographicalComparator() {
    150     return LexicographicalComparator.INSTANCE;
    151   }
    152 
    153   enum LexicographicalComparator implements Comparator<int[]> {
    154     INSTANCE;
    155 
    156     @Override
    157     public int compare(int[] left, int[] right) {
    158       int minLength = Math.min(left.length, right.length);
    159       for (int i = 0; i < minLength; i++) {
    160         if (left[i] != right[i]) {
    161           return UnsignedInts.compare(left[i], right[i]);
    162         }
    163       }
    164       return left.length - right.length;
    165     }
    166   }
    167 
    168   /**
    169    * Returns dividend / divisor, where the dividend and divisor are treated as unsigned 32-bit
    170    * quantities.
    171    *
    172    * @param dividend the dividend (numerator)
    173    * @param divisor the divisor (denominator)
    174    * @throws ArithmeticException if divisor is 0
    175    */
    176   public static int divide(int dividend, int divisor) {
    177     return (int) (toLong(dividend) / toLong(divisor));
    178   }
    179 
    180   /**
    181    * Returns dividend % divisor, where the dividend and divisor are treated as unsigned 32-bit
    182    * quantities.
    183    *
    184    * @param dividend the dividend (numerator)
    185    * @param divisor the divisor (denominator)
    186    * @throws ArithmeticException if divisor is 0
    187    */
    188   public static int remainder(int dividend, int divisor) {
    189     return (int) (toLong(dividend) % toLong(divisor));
    190   }
    191 
    192   /**
    193    * Returns the unsigned {@code int} value represented by the given decimal string.
    194    *
    195    * @throws NumberFormatException if the string does not contain a valid unsigned integer, or if
    196    *         the value represented is too large to fit in an unsigned {@code int}.
    197    * @throws NullPointerException if {@code s} is null
    198    */
    199   public static int parseUnsignedInt(String s) {
    200     return parseUnsignedInt(s, 10);
    201   }
    202 
    203   /**
    204    * Returns the unsigned {@code int} value represented by a string with the given radix.
    205    *
    206    * @param string the string containing the unsigned integer representation to be parsed.
    207    * @param radix the radix to use while parsing {@code s}; must be between
    208    *        {@link Character#MIN_RADIX} and {@link Character#MAX_RADIX}.
    209    * @throws NumberFormatException if the string does not contain a valid unsigned {@code int}, or
    210    *         if supplied radix is invalid.
    211    */
    212   public static int parseUnsignedInt(String string, int radix) {
    213     checkNotNull(string);
    214     long result = Long.parseLong(string, radix);
    215     if ((result & INT_MASK) != result) {
    216       throw new NumberFormatException("Input " + string + " in base " + radix
    217           + " is not in the range of an unsigned integer");
    218     }
    219     return (int) result;
    220   }
    221 
    222   /**
    223    * Returns a string representation of x, where x is treated as unsigned.
    224    */
    225   public static String toString(int x) {
    226     return toString(x, 10);
    227   }
    228 
    229   /**
    230    * Returns a string representation of {@code x} for the given radix, where {@code x} is treated
    231    * as unsigned.
    232    *
    233    * @param x the value to convert to a string.
    234    * @param radix the radix to use while working with {@code x}
    235    * @throws IllegalArgumentException if {@code radix} is not between {@link Character#MIN_RADIX}
    236    *         and {@link Character#MAX_RADIX}.
    237    */
    238   public static String toString(int x, int radix) {
    239     long asLong = x & INT_MASK;
    240     return Long.toString(asLong, radix);
    241   }
    242 }
    243