stdlib: Implement toString with radix in accordance with Kotlin JVM
Old Int.toString(radix: Int) and Long.toString(radix: Long) implementations didn't add sign for negative values. E.g. -1.toString(16) == "0xff..ff" while JVM returns "-1" in such case. This patch fixes this behaviour and allow us to use any radix between 2 and 36 as JVM does.
This commit is contained in:
@@ -1098,6 +1098,11 @@ task parse0(type: RunKonanTest) {
|
||||
source = "runtime/text/parse0.kt"
|
||||
}
|
||||
|
||||
task to_string0(type: RunKonanTest) {
|
||||
goldValue = "OK\n"
|
||||
source = "runtime/text/to_string0.kt"
|
||||
}
|
||||
|
||||
task catch1(type: RunKonanTest) {
|
||||
goldValue = "Before\nCaught Throwable\nDone\n"
|
||||
source = "runtime/exceptions/catch1.kt"
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
// Based on Apache Harmony tests.
|
||||
|
||||
fun assertEquals(actual: String, expected: String, msg: String) {
|
||||
if (actual != expected) throw AssertionError("$msg. Actual: $actual. Expected: $expected")
|
||||
}
|
||||
|
||||
fun testIntToStringWithRadix() {
|
||||
assertEquals(2147483647.toString(8), "17777777777", "Octal string")
|
||||
assertEquals(2147483647.toString(16), "7fffffff", "Hex string")
|
||||
assertEquals(2147483647.toString(2), "1111111111111111111111111111111", "Binary string")
|
||||
assertEquals(2147483647.toString(10), "2147483647", "Decimal string")
|
||||
|
||||
assertEquals((-2147483647).toString(8), "-17777777777", "Octal string")
|
||||
assertEquals((-2147483647).toString(16), "-7fffffff", "Hex string")
|
||||
assertEquals((-2147483647).toString(2), "-1111111111111111111111111111111", "Binary string")
|
||||
assertEquals((-2147483647).toString(10), "-2147483647", "Decimal string")
|
||||
|
||||
assertEquals((-2147483648).toString(8), "-20000000000", "Octal string")
|
||||
assertEquals((-2147483648).toString(16), "-80000000", "Hex string")
|
||||
assertEquals((-2147483648).toString(2), "-10000000000000000000000000000000", "Binary string")
|
||||
assertEquals((-2147483648).toString(10), "-2147483648", "Decimal string")
|
||||
}
|
||||
|
||||
fun testLongToStringWithRadix() {
|
||||
assertEquals(100000000L.toString(10), "100000000", "Decimal string")
|
||||
assertEquals(68719476735L.toString(16), "fffffffff", "Hex string")
|
||||
assertEquals(8589934591L.toString(8), "77777777777", "Octal string")
|
||||
assertEquals(8796093022207L.toString(2), "1111111111111111111111111111111111111111111", "Binary string")
|
||||
|
||||
assertEquals((-0x7fffffffffffffffL - 1).toString(10), "-9223372036854775808", "Min decimal string")
|
||||
assertEquals(0x7fffffffffffffffL.toString(10), "9223372036854775807", "Max decimal string")
|
||||
assertEquals((-0x7fffffffffffffffL - 1).toString(16), "-8000000000000000", "Min hex string")
|
||||
assertEquals(0x7fffffffffffffffL.toString(16), "7fffffffffffffff", "Max hex string")
|
||||
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
testIntToStringWithRadix()
|
||||
testLongToStringWithRadix()
|
||||
println("OK")
|
||||
}
|
||||
@@ -24,6 +24,17 @@
|
||||
#include "KString.h"
|
||||
#include "Types.h"
|
||||
|
||||
constexpr int MIN_RADIX = 2;
|
||||
constexpr int MAX_RADIX = 36;
|
||||
|
||||
char int_to_digit(uint32_t value) {
|
||||
if (value < 10) {
|
||||
return '0' + value;
|
||||
} else {
|
||||
return 'a' + (value - 10);
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
OBJ_GETTER(Kotlin_Any_toString, KConstRef thiz) {
|
||||
@@ -60,21 +71,34 @@ OBJ_GETTER(Kotlin_Int_toString, KInt value) {
|
||||
}
|
||||
|
||||
OBJ_GETTER(Kotlin_Int_toStringRadix, KInt value, KInt radix) {
|
||||
if (value == 0) {
|
||||
RETURN_RESULT_OF(CreateStringFromCString, "0");
|
||||
}
|
||||
if (radix < MIN_RADIX || radix > MAX_RADIX) {
|
||||
radix = 10;
|
||||
}
|
||||
// TODO: maye not fit for smaller radices.
|
||||
char cstring[32];
|
||||
switch (radix) {
|
||||
case 8:
|
||||
snprintf(cstring, sizeof(cstring), "%o", value);
|
||||
break;
|
||||
case 10:
|
||||
snprintf(cstring, sizeof(cstring), "%d", value);
|
||||
break;
|
||||
case 16:
|
||||
snprintf(cstring, sizeof(cstring), "%x", value);
|
||||
break;
|
||||
default:
|
||||
RuntimeAssert(false, "Unsupported radix");
|
||||
bool negative = (value < 0);
|
||||
// Calculate in negative values because MIN_VALUE * -1 == MIN_VALUE
|
||||
if (!negative) {
|
||||
value = -value;
|
||||
}
|
||||
|
||||
int32_t length = 0;
|
||||
while (value < 0) {
|
||||
cstring[length++] = int_to_digit(-(value % radix));
|
||||
value /= radix;
|
||||
}
|
||||
if (negative) {
|
||||
cstring[length++] = '-';
|
||||
}
|
||||
for (int i = 0, j = length - 1; i < j; i++, j--) {
|
||||
char tmp = cstring[i];
|
||||
cstring[i] = cstring[j];
|
||||
cstring[j] = tmp;
|
||||
}
|
||||
cstring[length] = '\0';
|
||||
RETURN_RESULT_OF(CreateStringFromCString, cstring);
|
||||
}
|
||||
|
||||
@@ -85,21 +109,34 @@ OBJ_GETTER(Kotlin_Long_toString, KLong value) {
|
||||
}
|
||||
|
||||
OBJ_GETTER(Kotlin_Long_toStringRadix, KLong value, KInt radix) {
|
||||
// TODO: may not fit for smaller radices.
|
||||
char cstring[64];
|
||||
switch (radix) {
|
||||
case 8:
|
||||
snprintf(cstring, sizeof(cstring), "%llo", value);
|
||||
break;
|
||||
case 10:
|
||||
snprintf(cstring, sizeof(cstring), "%lld", value);
|
||||
break;
|
||||
case 16:
|
||||
snprintf(cstring, sizeof(cstring), "%llx", value);
|
||||
break;
|
||||
default:
|
||||
RuntimeAssert(false, "Unsupported radix");
|
||||
if (value == 0) {
|
||||
RETURN_RESULT_OF(CreateStringFromCString, "0");
|
||||
}
|
||||
if (radix < MIN_RADIX || radix > MAX_RADIX) {
|
||||
radix = 10;
|
||||
}
|
||||
// TODO: maye not fit for smaller radices.
|
||||
char cstring[64];
|
||||
bool negative = (value < 0);
|
||||
// Calculate in negative values because MIN_VALUE * -1 == MIN_VALUE
|
||||
if (!negative) {
|
||||
value = -value;
|
||||
}
|
||||
|
||||
int32_t length = 0;
|
||||
while (value < 0) {
|
||||
cstring[length++] = int_to_digit(-(value % radix));
|
||||
value /= radix;
|
||||
}
|
||||
if (negative) {
|
||||
cstring[length++] = '-';
|
||||
}
|
||||
for (int i = 0, j = length - 1; i < j; i++, j--) {
|
||||
char tmp = cstring[i];
|
||||
cstring[i] = cstring[j];
|
||||
cstring[j] = tmp;
|
||||
}
|
||||
cstring[length] = '\0';
|
||||
RETURN_RESULT_OF(CreateStringFromCString, cstring);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user