Skip to content

Commit c5e25e6

Browse files
committed
java 1.7 compatibility
1 parent 3683a05 commit c5e25e6

File tree

8 files changed

+677
-623
lines changed

8 files changed

+677
-623
lines changed

src/main/kotlin/unsigned/Ubyte.kt

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package unsigned
22

33
import unsigned.java_1_7.compareUnsigned
44
import unsigned.java_1_7.divideUnsigned
5+
import unsigned.java_1_7.parseUnsignedInt
56
import unsigned.java_1_7.remainderUnsigned
67
import java.math.BigInteger
78
import kotlin.experimental.and
@@ -24,7 +25,7 @@ data class Ubyte(var v: Byte = 0) : Number() {
2425
}
2526

2627
constructor(number: Number) : this(number.toByte())
27-
@JvmOverloads constructor(string: String, base: Int = 10) : this(Integer.parseUnsignedInt(string.filter { it != '_' && it != '\'' }, base).toByte())
28+
@JvmOverloads constructor(string: String, base: Int = 10) : this(string.filter { it != '_' && it != '\'' }.parseUnsignedInt(base).toByte())
2829

2930
override fun toByte() = v
3031
override fun toShort() = v.toUInt().toShort()
@@ -60,11 +61,11 @@ data class Ubyte(var v: Byte = 0) : Number() {
6061

6162
infix operator fun div(b: Ubyte) = Ubyte(toInt() / b.toInt())
6263
infix operator fun div(b: Byte) = Ubyte(toInt() / b.toUInt())
63-
infix operator fun div(b: Int) = Ubyte(toInt().divideUnsigned(b))
64+
infix operator fun div(b: Int) = Ubyte(toInt() divideUnsigned b)
6465

6566
infix operator fun rem(b: Ubyte) = Ubyte(toInt() % b.toInt())
6667
infix operator fun rem(b: Byte) = Ubyte(toInt() % b.toUInt())
67-
infix operator fun rem(b: Int) = Ubyte(toInt().remainderUnsigned(b))
68+
infix operator fun rem(b: Int) = Ubyte(toInt() remainderUnsigned b)
6869

6970
// TODO add counterparts with res
7071

@@ -90,7 +91,7 @@ data class Ubyte(var v: Byte = 0) : Number() {
9091

9192
fun inv() = Ubyte(v.inv())
9293

93-
operator fun compareTo(b: Ubyte) = toInt().compareUnsigned(b.toInt())
94-
operator fun compareTo(b: Byte) = toInt().compareUnsigned(b.toUInt())
95-
operator fun compareTo(b: Int) = toInt().compareUnsigned(b)
94+
operator fun compareTo(b: Ubyte) = toInt() compareUnsigned b.toInt()
95+
operator fun compareTo(b: Byte) = toInt() compareUnsigned b.toUInt()
96+
operator fun compareTo(b: Int) = toInt() compareUnsigned b
9697
}

src/main/kotlin/unsigned/Uint.kt

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
package unsigned
22

3+
import unsigned.java_1_7.compareUnsigned
4+
import unsigned.java_1_7.divideUnsigned
5+
import unsigned.java_1_7.parseUnsignedInt
6+
import unsigned.java_1_7.remainderUnsigned
37
import java.math.BigInteger
48

59
/**
@@ -21,7 +25,7 @@ data class Uint(var v: Int = 0) : Number() {
2125

2226

2327
constructor(number: Number) : this(number.toInt())
24-
@JvmOverloads constructor(string: String, base: Int = 10) : this(Integer.parseUnsignedInt(string.filter { it != '_' && it != '\'' }, base))
28+
@JvmOverloads constructor(string: String, base: Int = 10) : this(string.filter { it != '_' && it != '\'' }.parseUnsignedInt(base))
2529

2630
override fun toByte() = v.toByte()
2731
override fun toShort() = v.toShort()
@@ -47,11 +51,11 @@ data class Uint(var v: Int = 0) : Number() {
4751
infix operator fun times(b: Uint) = Uint(v * b.v)
4852
infix operator fun times(b: Int) = Uint(v * b)
4953

50-
infix operator fun div(b: Uint) = Uint(Integer.divideUnsigned(v, b.toInt()))
51-
infix operator fun div(b: Int) = Uint(Integer.divideUnsigned(v, b))
54+
infix operator fun div(b: Uint) = Uint(v divideUnsigned b.toInt())
55+
infix operator fun div(b: Int) = Uint(v divideUnsigned b)
5256

53-
infix operator fun rem(b: Uint) = Uint(Integer.remainderUnsigned(v, b.toInt()))
54-
infix operator fun rem(b: Int) = Uint(Integer.remainderUnsigned(v, b))
57+
infix operator fun rem(b: Uint) = Uint(v remainderUnsigned b.toInt())
58+
infix operator fun rem(b: Int) = Uint(v remainderUnsigned b)
5559

5660
infix fun and(b: Uint) = Uint(v and b.toInt())
5761
infix fun and(b: Int) = Uint(v and b)
@@ -70,8 +74,8 @@ data class Uint(var v: Int = 0) : Number() {
7074

7175
fun inv() = Uint(v.inv())
7276

73-
operator fun compareTo(b: Uint) = Integer.compareUnsigned(v, b.toInt())
74-
operator fun compareTo(b: Int) = Integer.compareUnsigned(v, b)
77+
operator fun compareTo(b: Uint) = v compareUnsigned b.toInt()
78+
operator fun compareTo(b: Int) = v compareUnsigned b
7579

7680
// TODO long?
7781
}

src/main/kotlin/unsigned/Ulong.kt

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package unsigned
22

3+
import unsigned.java_1_7.*
34
import java.math.BigInteger
45

56
/**
@@ -20,14 +21,14 @@ data class Ulong(var v: Long = 0) : Number(), Comparable<Ulong> {
2021
}
2122

2223
constructor(number: Number) : this(number.toLong())
23-
constructor(string: String, base: Int = 10) : this(java.lang.Long.parseUnsignedLong(string.filter { it != '_' && it != '\'' }, base))
24+
constructor(string: String, base: Int = 10) : this(string.filter { it != '_' && it != '\'' }.parseUnsignedLong(base))
2425

2526
override fun toByte() = v.toByte()
2627
override fun toShort() = v.toShort()
2728
override fun toInt() = v.toInt()
2829
override fun toLong() = v
2930

30-
fun toBigInt(): BigInteger = BigInteger(java.lang.Long.toUnsignedString(v))
31+
fun toBigInt(): BigInteger = BigInteger(v.toUnsignedString())
3132

3233
override fun toDouble() = toBigInt().toDouble()
3334
override fun toFloat() = toBigInt().toFloat()
@@ -46,11 +47,11 @@ data class Ulong(var v: Long = 0) : Number(), Comparable<Ulong> {
4647
infix operator fun times(b: Ulong) = Ulong(v * b.v)
4748
infix operator fun times(b: Long) = Ulong(v * b)
4849

49-
infix operator fun div(b: Ulong) = Ulong(java.lang.Long.divideUnsigned(v, b.toLong()))
50-
infix operator fun div(b: Long) = Ulong(java.lang.Long.divideUnsigned(v, b))
50+
infix operator fun div(b: Ulong) = Ulong(v divideUnsigned b.toLong())
51+
infix operator fun div(b: Long) = Ulong(v divideUnsigned b)
5152

52-
infix operator fun rem(b: Ulong) = Ulong(java.lang.Long.remainderUnsigned(v, b.toLong()))
53-
infix operator fun rem(b: Long) = Ulong(java.lang.Long.remainderUnsigned(v, b))
53+
infix operator fun rem(b: Ulong) = Ulong(v remainderUnsigned b.toLong())
54+
infix operator fun rem(b: Long) = Ulong(v remainderUnsigned b)
5455

5556
infix fun and(b: Ulong) = Ulong(v and b.toLong())
5657
infix fun and(b: Long) = Ulong(v and b)
@@ -67,8 +68,8 @@ data class Ulong(var v: Long = 0) : Number(), Comparable<Ulong> {
6768

6869
fun inv() = Ulong(v.inv())
6970

70-
override operator fun compareTo(other: Ulong) = java.lang.Long.compareUnsigned(v, other.toLong())
71-
operator fun compareTo(other: Long) = java.lang.Long.compareUnsigned(v, other)
71+
override operator fun compareTo(other: Ulong) = v compareUnsigned other.toLong()
72+
operator fun compareTo(other: Long) = v compareUnsigned other
7273

7374
// TODO others
7475

@@ -78,7 +79,7 @@ data class Ulong(var v: Long = 0) : Number(), Comparable<Ulong> {
7879

7980
override fun iterator(): Iterator<Ulong> = UlongIterator(this)
8081

81-
override fun contains(value: Ulong) = start <= value && value <= endInclusive
82+
override fun contains(value: Ulong): Boolean = value in start..endInclusive
8283
}
8384

8485
class UlongIterator(val ulongRange: UlongRange) : Iterator<Ulong> {

src/main/kotlin/unsigned/Ushort.kt

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
package unsigned
22

3+
import unsigned.java_1_7.compareUnsigned
4+
import unsigned.java_1_7.divideUnsigned
5+
import unsigned.java_1_7.parseUnsignedInt
6+
import unsigned.java_1_7.remainderUnsigned
37
import java.math.BigInteger
48
import kotlin.experimental.and
59
import kotlin.experimental.inv
@@ -25,7 +29,7 @@ data class Ushort(var v: Short = 0) : Number() {
2529

2630
constructor(number: Number) : this(number.toShort())
2731
@JvmOverloads constructor(string: String, base: Int = 10) :
28-
this(Integer.parseUnsignedInt(string.filter { it != '_' && it != '\'' }, base).toShort())
32+
this(string.filter { it != '_' && it != '\'' }.parseUnsignedInt(base).toShort())
2933

3034
override fun toByte() = v.toByte()
3135
override fun toShort() = v
@@ -56,11 +60,11 @@ data class Ushort(var v: Short = 0) : Number() {
5660

5761
infix operator fun div(b: Ushort) = Ushort(toInt() / b.toInt())
5862
infix operator fun div(b: Short) = Ushort(toInt() / b.toUInt())
59-
infix operator fun div(b: Int) = Ushort(Integer.divideUnsigned(toInt(), b))
63+
infix operator fun div(b: Int) = Ushort(toInt() divideUnsigned b)
6064

6165
infix operator fun rem(b: Ushort) = Ushort(toInt() % b.toInt())
6266
infix operator fun rem(b: Short) = Ushort(toInt() % b.toUInt())
63-
infix operator fun rem(b: Int) = Ushort(Integer.remainderUnsigned(toInt(), b))
67+
infix operator fun rem(b: Int) = Ushort(toInt() remainderUnsigned b)
6468

6569
infix fun and(b: Ushort) = Ushort(v and b.v)
6670
infix fun and(b: Short) = Ushort(v and b)
@@ -84,7 +88,7 @@ data class Ushort(var v: Short = 0) : Number() {
8488

8589
fun inv() = Ushort(v.inv())
8690

87-
operator fun compareTo(b: Ushort) = Integer.compareUnsigned(toInt(), b.toInt())
88-
operator fun compareTo(b: Short) = Integer.compareUnsigned(toInt(), b.toUInt())
89-
operator fun compareTo(b: Int) = Integer.compareUnsigned(toInt(), b)
91+
operator fun compareTo(b: Ushort) = toInt() compareUnsigned b.toInt()
92+
operator fun compareTo(b: Short) = toInt() compareUnsigned b.toUInt()
93+
operator fun compareTo(b: Int) = toInt() compareUnsigned b
9094
}

src/main/kotlin/unsigned/java_1_7/int.kt

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,32 +4,31 @@ import java.math.BigInteger
44

55

66
// In lieu of tricky code, for now just use long arithmetic.
7-
fun Int.divideUnsigned(divisor: Int) = (toUnsignedLong() / divisor.toUnsignedLong()).toInt()
7+
infix fun Int.divideUnsigned(divisor: Int) = (toUnsignedLong() / divisor.toUnsignedLong()).toInt()
88

99
fun Int.toUnsignedLong() = toLong() and 0xffffffffL
1010

1111
// In lieu of tricky code, for now just use long arithmetic.
12-
fun Int.remainderUnsigned(divisor: Int) = (toUnsignedLong() % divisor.toUnsignedLong()).toInt()
12+
infix fun Int.remainderUnsigned(divisor: Int) = (toUnsignedLong() % divisor.toUnsignedLong()).toInt()
1313

14-
fun Int.compareUnsigned(b: Int) = compare(this + Int.MIN_VALUE, b + Int.MIN_VALUE)
14+
infix fun Int.compareUnsigned(b: Int) = compare(this + Int.MIN_VALUE, b + Int.MIN_VALUE)
1515

16-
fun compare(x: Int, y: Int) = if (x < y) -1 else if (x == y) 0 else 1
16+
fun compare(a: Int, b: Int) = if (a < b) -1 else if (a == b) 0 else 1
1717

1818
@Throws(NumberFormatException::class)
1919
fun String.parseUnsignedInt(radix: Int): Int {
2020

21-
val len = length
22-
if (len > 0) {
21+
if (length > 0) {
2322
val firstChar = this[0]
2423
if (firstChar == '-')
2524
throw NumberFormatException(String.format("Illegal leading minus sign " + "on unsigned string %s.", this))
2625
else {
27-
if (len <= 5 || // Integer.MAX_VALUE in Character.MAX_RADIX is 6 digits
28-
radix == 10 && len <= 9) // Integer.MAX_VALUE in base 10 is 10 digits
26+
if (length <= 5 || // Integer.MAX_VALUE in Character.MAX_RADIX is 6 digits
27+
radix == 10 && length <= 9) // Integer.MAX_VALUE in base 10 is 10 digits
2928
return this.toInt(radix)
3029
else {
3130
val ell = this.toLong(radix)
32-
if (ell and BigInteger("0xffff_ffff_0000_0000").toLong() == 0L)
31+
if (ell and BigInteger("ffffffff00000000", 16).toLong() == 0L)
3332
return ell.toInt()
3433
else
3534
throw NumberFormatException(String.format("String value %s exceeds " + "range of unsigned int.", this))

src/main/kotlin/unsigned/java_1_7/long.kt

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,73 @@ private fun Long.toUnsignedBigInteger(): BigInteger {
205205
val lower = this.toInt()
206206

207207
// return (upper << 32) + lower
208-
return BigInteger.valueOf(Integer.toUnsignedLong(upper)).shiftLeft(32).add(BigInteger.valueOf(Integer.toUnsignedLong(lower)))
208+
return BigInteger.valueOf(upper.toUnsignedLong()).shiftLeft(32).add(BigInteger.valueOf(lower.toUnsignedLong()))
209209
}
210+
}
211+
212+
@Throws(NumberFormatException::class)
213+
fun String.parseUnsignedLong(radix: Int = 10): Long {
214+
215+
if (length > 0) {
216+
val firstChar = this[0]
217+
if (firstChar == '-')
218+
throw NumberFormatException(String.format("Illegal leading minus sign on unsigned string $this."))
219+
else {
220+
if (length <= 12 || // Long.MAX_VALUE in Character.MAX_RADIX is 13 digits
221+
radix == 10 && length <= 18) // Long.MAX_VALUE in base 10 is 19 digits
222+
return this.toLong(radix)
223+
224+
// No need for range checks on len due to testing above.
225+
val first = substring(0, length - 1).toLong(radix)
226+
val second = Character.digit(this[length - 1], radix)
227+
if (second < 0)
228+
throw NumberFormatException("Bad digit at end of $this")
229+
val result = first * radix + second
230+
if (result compareUnsigned first < 0) {
231+
/* The maximum unsigned value, (2^64)-1, takes at most one more digit to represent than the maximum
232+
signed value, (2^63)-1. Therefore, parsing (len - 1) digits will be appropriately in-range of the
233+
signed parsing. In other words, if parsing (len -1) digits overflows signed parsing, parsing len
234+
digits will certainly overflow unsigned parsing.
235+
236+
The compareUnsigned check above catches situations where an unsigned overflow occurs incorporating
237+
the contribution of the final digit. */
238+
throw NumberFormatException(String.format("String value $this exceeds range of unsigned long."))
239+
}
240+
return result
241+
}
242+
} else throw NumberFormatException("For input string: $this")
243+
}
244+
245+
infix fun Long.compareUnsigned(b: Long) = compare(this + Long.MIN_VALUE, b + Long.MIN_VALUE)
246+
247+
fun compare(a: Long, b: Long) = if (a < b) -1 else if (a == b) 0 else 1
248+
249+
infix fun Long.divideUnsigned(divisor: Long): Long {
250+
if (divisor < 0L) // signed comparison
251+
// Answer must be 0 or 1 depending on relative magnitude
252+
// of dividend and divisor.
253+
return if (compareUnsigned(divisor) < 0) 0L else 1L
254+
255+
if (this > 0)
256+
// Both inputs non-negative
257+
return this / divisor
258+
else
259+
/*
260+
* For simple code, leveraging BigInteger. Longer and faster
261+
* code written directly in terms of operations on longs is
262+
* possible; see "Hacker's Delight" for divide and remainder
263+
* algorithms.
264+
*/
265+
return toUnsignedBigInteger().divide(divisor.toUnsignedBigInteger()).toLong()
266+
}
267+
268+
infix fun Long.remainderUnsigned(divisor: Long): Long {
269+
if (this > 0 && divisor > 0) // signed comparisons
270+
return this % divisor
271+
else
272+
if (compareUnsigned(divisor) < 0)
273+
// Avoid explicit check for 0 divisor
274+
return this
275+
else
276+
return toUnsignedBigInteger().remainder(divisor.toUnsignedBigInteger()).toLong()
210277
}

0 commit comments

Comments
 (0)