diff options
author | Aaron Bedra <aaron@aaronbedra.com> | 2010-11-26 13:36:57 -0500 |
---|---|---|
committer | Rich Hickey <richhickey@gmail.com> | 2010-11-26 13:50:26 -0500 |
commit | cbd789d1a5b472d92b91f2fe0e273f48c2583483 (patch) | |
tree | db3c2a66c9eeb028c8c53f8c39eb65c78a661f38 | |
parent | 8225407032ea643cbe3db7f35ef97b1230fc65b8 (diff) |
Added unchecked casts; fixes bug #441. Code and original patches supplied by @stuarthalloway
Signed-off-by: Rich Hickey <richhickey@gmail.com>
-rw-r--r-- | src/clj/clojure/core.clj | 54 | ||||
-rw-r--r-- | src/jvm/clojure/lang/RT.java | 208 | ||||
-rw-r--r-- | test/clojure/test_clojure/numbers.clj | 89 |
3 files changed, 343 insertions, 8 deletions
diff --git a/src/clj/clojure/core.clj b/src/clj/clojure/core.clj index 0c3d12ea..58cb0a82 100644 --- a/src/clj/clojure/core.clj +++ b/src/clj/clojure/core.clj @@ -3031,6 +3031,49 @@ :added "1.0"} [x] (clojure.lang.RT/booleanCast x)) +(defn unchecked-byte + "Coerce to byte. Subject to rounding or truncation." + {:inline (fn [x] `(. clojure.lang.RT (uncheckedByteCast ~x))) + :added "1.3"} + [^Number x] (clojure.lang.RT/uncheckedByteCast x)) + +(defn unchecked-short + "Coerce to short. Subject to rounding or truncation." + {:inline (fn [x] `(. clojure.lang.RT (uncheckedShortCast ~x))) + :added "1.3"} + [^Number x] (clojure.lang.RT/uncheckedShortCast x)) + +(defn unchecked-char + "Coerce to char. Subject to rounding or truncation." + {:inline (fn [x] `(. clojure.lang.RT (uncheckedCharCast ~x))) + :added "1.3"} + [x] (. clojure.lang.RT (uncheckedCharCast x))) + +(defn unchecked-int + "Coerce to int. Subject to rounding or truncation." + {:inline (fn [x] `(. clojure.lang.RT (uncheckedIntCast ~x))) + :added "1.3"} + [^Number x] (clojure.lang.RT/uncheckedIntCast x)) + +(defn unchecked-long + "Coerce to long. Subject to rounding or truncation." + {:inline (fn [x] `(. clojure.lang.RT (uncheckedLongCast ~x))) + :added "1.3"} + [^Number x] (clojure.lang.RT/uncheckedLongCast x)) + +(defn unchecked-float + "Coerce to float. Subject to rounding." + {:inline (fn [x] `(. clojure.lang.RT (uncheckedFloatCast ~x))) + :added "1.3"} + [^Number x] (clojure.lang.RT/uncheckedFloatCast x)) + +(defn unchecked-double + "Coerce to double. Subject to rounding." + {:inline (fn [x] `(. clojure.lang.RT (uncheckedDoubleCast ~x))) + :added "1.3"} + [^Number x] (clojure.lang.RT/uncheckedDoubleCast x)) + + (defn number? "Returns true if x is a Number" {:added "1.0" @@ -5832,14 +5875,11 @@ {:added "1.0"} ([f & opts] (let [opts (normalize-slurp-opts opts) - sb (StringBuilder.)] + sb (StringBuilder.) + sw (java.io.StringWriter.)] (with-open [#^java.io.Reader r (apply jio/reader f opts)] - (loop [c (.read r)] - (if (neg? c) - (str sb) - (do - (.append sb (char c)) - (recur (.read r))))))))) + (jio/copy r sw) + (str sw))))) (defn spit "Opposite of slurp. Opens f with writer, writes content, then diff --git a/src/jvm/clojure/lang/RT.java b/src/jvm/clojure/lang/RT.java index e144855b..086a3a6d 100644 --- a/src/jvm/clojure/lang/RT.java +++ b/src/jvm/clojure/lang/RT.java @@ -1055,6 +1055,214 @@ static public double doubleCast(double x){ return x; } +static public byte uncheckedByteCast(Object x){ + return ((Number) x).byteValue(); +} + +static public byte uncheckedByteCast(byte x){ + return x; +} + +static public byte uncheckedByteCast(short x){ + return (byte) x; +} + +static public byte uncheckedByteCast(int x){ + return (byte) x; +} + +static public byte uncheckedByteCast(long x){ + return (byte) x; +} + +static public byte uncheckedByteCast(float x){ + return (byte) x; +} + +static public byte uncheckedByteCast(double x){ + return (byte) x; +} + +static public short uncheckedShortCast(Object x){ + return ((Number) x).shortValue(); +} + +static public short uncheckedShortCast(byte x){ + return x; +} + +static public short uncheckedShortCast(short x){ + return x; +} + +static public short uncheckedShortCast(int x){ + return (short) x; +} + +static public short uncheckedShortCast(long x){ + return (short) x; +} + +static public short uncheckedShortCast(float x){ + return (short) x; +} + +static public short uncheckedShortCast(double x){ + return (short) x; +} + +static public char uncheckedCharCast(Object x){ + if(x instanceof Character) + return ((Character) x).charValue(); + return (char) ((Number) x).longValue(); +} + +static public char uncheckedCharCast(byte x){ + return (char) x; +} + +static public char uncheckedCharCast(short x){ + return (char) x; +} + +static public char uncheckedCharCast(char x){ + return x; +} + +static public char uncheckedCharCast(int x){ + return (char) x; +} + +static public char uncheckedCharCast(long x){ + return (char) x; +} + +static public char uncheckedCharCast(float x){ + return (char) x; +} + +static public char uncheckedCharCast(double x){ + return (char) x; +} + +static public int uncheckedIntCast(Object x){ + if(x instanceof Number) + return ((Number)x).intValue(); + return ((Character) x).charValue(); +} + +static public int uncheckedIntCast(byte x){ + return x; +} + +static public int uncheckedIntCast(short x){ + return x; +} + +static public int uncheckedIntCast(char x){ + return x; +} + +static public int uncheckedIntCast(int x){ + return x; +} + +static public int uncheckedIntCast(long x){ + return (int) x; +} + +static public int uncheckedIntCast(float x){ + return (int) x; +} + +static public int uncheckedIntCast(double x){ + return (int) x; +} + +static public long uncheckedLongCast(Object x){ + return ((Number) x).longValue(); +} + +static public long uncheckedLongCast(byte x){ + return x; +} + +static public long uncheckedLongCast(short x){ + return x; +} + +static public long uncheckedLongCast(int x){ + return x; +} + +static public long uncheckedLongCast(long x){ + return x; +} + +static public long uncheckedLongCast(float x){ + return (long) x; +} + +static public long uncheckedLongCast(double x){ + return (long) x; +} + +static public float uncheckedFloatCast(Object x){ + return ((Number) x).floatValue(); +} + +static public float uncheckedFloatCast(byte x){ + return x; +} + +static public float uncheckedFloatCast(short x){ + return x; +} + +static public float uncheckedFloatCast(int x){ + return x; +} + +static public float uncheckedFloatCast(long x){ + return x; +} + +static public float uncheckedFloatCast(float x){ + return x; +} + +static public float uncheckedFloatCast(double x){ + return (float) x; +} + +static public double uncheckedDoubleCast(Object x){ + return ((Number) x).doubleValue(); +} + +static public double uncheckedDoubleCast(byte x){ + return x; +} + +static public double uncheckedDoubleCast(short x){ + return x; +} + +static public double uncheckedDoubleCast(int x){ + return x; +} + +static public double uncheckedDoubleCast(long x){ + return x; +} + +static public double uncheckedDoubleCast(float x){ + return x; +} + +static public double uncheckedDoubleCast(double x){ + return x; +} + static public IPersistentMap map(Object... init){ if(init == null) return PersistentArrayMap.EMPTY; diff --git a/test/clojure/test_clojure/numbers.clj b/test/clojure/test_clojure/numbers.clj index 688c8c40..ced4dbde 100644 --- a/test/clojure/test_clojure/numbers.clj +++ b/test/clojure/test_clojure/numbers.clj @@ -12,7 +12,8 @@ ;; (ns clojure.test-clojure.numbers - (:use clojure.test)) + (:use clojure.test + clojure.template)) ; TODO: @@ -37,6 +38,91 @@ 13178456923875639284562345789M 13178456923875639284562345789N)) +(deftest unchecked-cast-num-obj + (do-template [prim-array cast] + (are [n] + (let [a (prim-array 1)] + (aset a 0 (cast n))) + (Byte. Byte/MAX_VALUE) + (Short. Short/MAX_VALUE) + (Integer. Integer/MAX_VALUE) + (Long. Long/MAX_VALUE) + (Float. Float/MAX_VALUE) + (Double. Double/MAX_VALUE)) + byte-array + unchecked-byte + short-array + unchecked-short + char-array + unchecked-char + int-array + unchecked-int + long-array + unchecked-long + float-array + unchecked-float + double-array + unchecked-double)) + +(deftest unchecked-cast-num-prim + (do-template [prim-array cast] + (are [n] + (let [a (prim-array 1)] + (aset a 0 (cast n))) + Byte/MAX_VALUE + Short/MAX_VALUE + Integer/MAX_VALUE + Long/MAX_VALUE + Float/MAX_VALUE + Double/MAX_VALUE) + byte-array + unchecked-byte + short-array + unchecked-short + char-array + unchecked-char + int-array + unchecked-int + long-array + unchecked-long + float-array + unchecked-float + double-array + unchecked-double)) + +(deftest unchecked-cast-char + ; in keeping with the checked cast functions, char and Character can only be cast to int + (is (unchecked-int (char 0xFFFF))) + (is (let [c (char 0xFFFF)] (unchecked-int c)))) ; force primitive char + +(def expected-casts + [ + [:input [-1 0 1 Byte/MAX_VALUE Short/MAX_VALUE Integer/MAX_VALUE Long/MAX_VALUE Float/MAX_VALUE Double/MAX_VALUE]] + [char [:error (char 0) (char 1) (char 127) (char 32767) :error :error :error :error]] + [unchecked-char [(char 65535) (char 0) (char 1) (char 127) (char 32767) (char 65535) (char 65535) (char 65535) (char 65535)]] + [byte [-1 0 1 Byte/MAX_VALUE :error :error :error :error :error]] + [unchecked-byte [-1 0 1 Byte/MAX_VALUE -1 -1 -1 -1 -1]] + [short [-1 0 1 Byte/MAX_VALUE Short/MAX_VALUE :error :error :error :error]] + [unchecked-short [-1 0 1 Byte/MAX_VALUE Short/MAX_VALUE -1 -1 -1 -1]] + [int [-1 0 1 Byte/MAX_VALUE Short/MAX_VALUE Integer/MAX_VALUE :error :error :error]] + [unchecked-int [-1 0 1 Byte/MAX_VALUE Short/MAX_VALUE Integer/MAX_VALUE -1 Integer/MAX_VALUE Integer/MAX_VALUE]] + [long [-1 0 1 Byte/MAX_VALUE Short/MAX_VALUE Integer/MAX_VALUE Long/MAX_VALUE Long/MAX_VALUE Long/MAX_VALUE]] + [unchecked-long [-1 0 1 Byte/MAX_VALUE Short/MAX_VALUE Integer/MAX_VALUE Long/MAX_VALUE Long/MAX_VALUE Long/MAX_VALUE]] + ;; 2.14748365E9 if when float/double conversion is avoided... + [float [-1.0 0.0 1.0 127.0 32767.0 2.147483648E9 9.223372036854776E18 Float/MAX_VALUE :error]] + [unchecked-float [-1.0 0.0 1.0 127.0 32767.0 2.147483648E9 9.223372036854776E18 Float/MAX_VALUE Float/POSITIVE_INFINITY]] + [double [-1.0 0.0 1.0 127.0 32767.0 2.147483647E9 9.223372036854776E18 Float/MAX_VALUE Double/MAX_VALUE]] + [unchecked-double [-1.0 0.0 1.0 127.0 32767.0 2.147483647E9 9.223372036854776E18 Float/MAX_VALUE Double/MAX_VALUE]]]) + +(deftest test-expected-casts + (let [[[_ inputs] & expectations] expected-casts] + (doseq [[f vals] expectations] + (let [wrapped (fn [x] + (try + (f x) + (catch IllegalArgumentException e :error)))] + (is (= vals (map wrapped inputs))))))) + ;; *** Functions *** (defonce DELTA 1e-12) @@ -394,3 +480,4 @@ Math/pow overflows to Infinity." (is (== (numerator 1/2) 1)) (is (= (bigint (/ 100000000000000000000 3)) 33333333333333333333)) (is (= (long 10000000000000000000/3) 3333333333333333333))) + |