String <-> CharArray conversion, ArrayBuilder by @elizarov (#98)
This commit is contained in:
@@ -314,6 +314,11 @@ task tostring1(type: RunKonanTest) {
|
||||
source = "runtime/basic/tostring1.kt"
|
||||
}
|
||||
|
||||
task tostring2(type: RunKonanTest) {
|
||||
goldValue = "H e l l o \nHello\n"
|
||||
source = "runtime/basic/tostring2.kt"
|
||||
}
|
||||
|
||||
task array0(type: RunKonanTest) {
|
||||
goldValue = "5\n6\n7\n8\n9\n10\n11\n12\n13\n"
|
||||
source = "runtime/basic/array0.kt"
|
||||
@@ -444,6 +449,11 @@ task moderately_large_array(type: RunKonanTest) {
|
||||
source = "runtime/collections/moderately_large_array.kt"
|
||||
}
|
||||
|
||||
task string_builder0(type: RunKonanTest) {
|
||||
goldValue = "OK\n"
|
||||
source = "runtime/text/string_builder0.kt"
|
||||
}
|
||||
|
||||
task catch1(type: RunKonanTest) {
|
||||
goldValue = "Before\nCaught Throwable\nDone\n"
|
||||
source = "runtime/exceptions/catch1.kt"
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
fun main(args : Array<String>) {
|
||||
val hello = "Hello"
|
||||
val array = toCharArray(hello)
|
||||
for (ch in array) {
|
||||
print(ch)
|
||||
print(" ")
|
||||
}
|
||||
println()
|
||||
println(fromCharArray(array, 0, array.size))
|
||||
}
|
||||
@@ -182,6 +182,12 @@ fun testToString() {
|
||||
assertTrue(a.toString() == makeList123().toString())
|
||||
}
|
||||
|
||||
fun testToString2() {
|
||||
val a = makeList123()
|
||||
assertEquals(a.toString(), "[1, 2, 3]")
|
||||
}
|
||||
|
||||
|
||||
fun testSubList() {
|
||||
val a0 = makeList01234()
|
||||
val a = a0.subList(1, 4)
|
||||
@@ -271,11 +277,12 @@ fun testIteratorAdd() {
|
||||
val next = it.next()
|
||||
if (i++ % 2 == 0)
|
||||
it.add("-" + next)
|
||||
it.next()
|
||||
}
|
||||
//assertEquals(listOf("1", "2", "-2", "3", "4", "-4", "5"), a)
|
||||
}
|
||||
|
||||
|
||||
|
||||
fun main(args : Array<String>) {
|
||||
testBasic()
|
||||
testIterator()
|
||||
@@ -286,6 +293,7 @@ fun main(args : Array<String>) {
|
||||
testEquals()
|
||||
testHashCode()
|
||||
testToString()
|
||||
testToString2()
|
||||
testSubList()
|
||||
testResize()
|
||||
testSubListContains()
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
fun assertTrue(cond: Boolean) {
|
||||
if (!cond)
|
||||
println("FAIL")
|
||||
}
|
||||
|
||||
fun assertFalse(cond: Boolean) {
|
||||
if (cond)
|
||||
println("FAIL")
|
||||
}
|
||||
|
||||
fun assertEquals(value1: String, value2: String) {
|
||||
if (value1 != value2)
|
||||
println("FAIL: '" + value1 + "' != '" + value2 + "'")
|
||||
}
|
||||
|
||||
fun assertEquals(value1: Int, value2: Int) {
|
||||
if (value1 != value2)
|
||||
println("FAIL" + value1.toString() + " != " + value2.toString())
|
||||
}
|
||||
|
||||
fun testBasic() {
|
||||
val sb = StringBuilder()
|
||||
assertEquals(0, sb.length)
|
||||
assertEquals("", sb.toString())
|
||||
sb.append(1)
|
||||
assertEquals(1, sb.length)
|
||||
assertEquals("1", sb.toString())
|
||||
sb.append(", ")
|
||||
assertEquals(3, sb.length)
|
||||
assertEquals("1, ", sb.toString())
|
||||
sb.append(true)
|
||||
assertEquals(7, sb.length)
|
||||
assertEquals("1, true", sb.toString())
|
||||
sb.append(12345678L)
|
||||
assertEquals(15, sb.length)
|
||||
assertEquals("1, true12345678", sb.toString())
|
||||
|
||||
sb.length = 0
|
||||
assertEquals(0, sb.length)
|
||||
assertEquals("", sb.toString())
|
||||
}
|
||||
|
||||
fun main(args : Array<String>) {
|
||||
testBasic()
|
||||
println("OK")
|
||||
}
|
||||
@@ -115,6 +115,17 @@ ArrayHeader* Kotlin_CharArray_clone(const ArrayHeader* array) {
|
||||
return result;
|
||||
}
|
||||
|
||||
ArrayHeader* Kotlin_CharArray_copyOf(const ArrayHeader* array, KInt newSize) {
|
||||
ArrayHeader* result = ArrayContainer(
|
||||
theCharArrayTypeInfo, newSize).GetPlace();
|
||||
KInt toCopy = array->count_ < newSize ? array->count_ : newSize;
|
||||
memcpy(
|
||||
PrimitiveArrayAddressOfElementAt<KChar>(result, 0),
|
||||
PrimitiveArrayAddressOfElementAt<KChar>(array, 0),
|
||||
toCopy * sizeof(KChar));
|
||||
return result;
|
||||
}
|
||||
|
||||
KInt Kotlin_CharArray_getArrayLength(const ArrayHeader* array) {
|
||||
return array->count_;
|
||||
}
|
||||
|
||||
@@ -79,18 +79,48 @@ KInt Kotlin_String_getStringLength(KString thiz) {
|
||||
return thiz->count_;
|
||||
}
|
||||
|
||||
KString Kotlin_String_fromUtf8Array(const ArrayHeader* array) {
|
||||
KString Kotlin_String_fromUtf8Array(
|
||||
const ArrayHeader* array, KInt start, KInt size) {
|
||||
RuntimeAssert(array->type_info() == theByteArrayTypeInfo, "Must use a byte array");
|
||||
if (start < 0 || start + size > array->count_) {
|
||||
ThrowArrayIndexOutOfBoundsException();
|
||||
}
|
||||
// TODO: support full UTF-8.
|
||||
ArrayHeader* result = ArrayContainer(
|
||||
theStringTypeInfo, array->count_).GetPlace();
|
||||
ArrayHeader* result = ArrayContainer(theStringTypeInfo, size).GetPlace();
|
||||
memcpy(
|
||||
ByteArrayAddressOfElementAt(result, 0),
|
||||
ByteArrayAddressOfElementAt(array, 0),
|
||||
ArrayDataSizeBytes(array));
|
||||
ByteArrayAddressOfElementAt(array, start),
|
||||
size);
|
||||
return result;
|
||||
}
|
||||
|
||||
KString Kotlin_String_fromCharArray(
|
||||
const ArrayHeader* array, KInt start, KInt size) {
|
||||
RuntimeAssert(array->type_info() == theCharArrayTypeInfo, "Must use a byte array");
|
||||
if (start < 0 || start + size > array->count_) {
|
||||
ThrowArrayIndexOutOfBoundsException();
|
||||
}
|
||||
// TODO: support full UTF-8.
|
||||
ArrayHeader* result = ArrayContainer(theStringTypeInfo, size).GetPlace();
|
||||
for (KInt index = 0; index < size; ++index) {
|
||||
*ByteArrayAddressOfElementAt(result, index) =
|
||||
*PrimitiveArrayAddressOfElementAt<KChar>(array, start + index);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
ArrayHeader* Kotlin_String_toCharArray(KString string) {
|
||||
// TODO: support full UTF-8.
|
||||
ArrayHeader* result = ArrayContainer(
|
||||
theCharArrayTypeInfo, string->count_).GetPlace();
|
||||
for (int index = 0; index < string->count_; ++index) {
|
||||
*PrimitiveArrayAddressOfElementAt<KChar>(result, index) =
|
||||
*ByteArrayAddressOfElementAt(string, index);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
KString Kotlin_String_plusImpl(KString thiz, KString other) {
|
||||
// TODO: support UTF-8
|
||||
RuntimeAssert(thiz != nullptr, "this cannot be null");
|
||||
@@ -113,7 +143,7 @@ KString Kotlin_String_plusImpl(KString thiz, KString other) {
|
||||
|
||||
KBoolean Kotlin_String_equals(KString thiz, KConstRef other) {
|
||||
if (other == nullptr || other->type_info() != theStringTypeInfo) return 0;
|
||||
const ArrayHeader* otherString = reinterpret_cast<const ArrayHeader*>(other);
|
||||
KString otherString = reinterpret_cast<KString>(other);
|
||||
return thiz->count_ == otherString->count_ &&
|
||||
memcmp(ByteArrayAddressOfElementAt(thiz, 0),
|
||||
ByteArrayAddressOfElementAt(otherString, 0),
|
||||
|
||||
@@ -80,7 +80,8 @@ KInt Kotlin_String_hashCode(KString thiz);
|
||||
KBoolean Kotlin_String_equals(KString thiz, KConstRef other);
|
||||
KInt Kotlin_String_compareTo(KString thiz, KString other);
|
||||
KChar Kotlin_String_get(KString thiz, KInt index);
|
||||
KString Kotlin_String_fromUtf8Array(const ArrayHeader* array);
|
||||
KString Kotlin_String_fromUtf8Array(const ArrayHeader* array, KInt start, KInt size);
|
||||
KString Kotlin_String_fromCharArray(const ArrayHeader* array, KInt start, KInt size);
|
||||
KString Kotlin_String_plusImpl(KString thiz, KString other);
|
||||
KInt Kotlin_String_getStringLength(KString thiz);
|
||||
KString Kotlin_String_subSequence(KString thiz, KInt startIndex, KInt endIndex);
|
||||
|
||||
@@ -66,6 +66,9 @@ public final class CharArray : Cloneable {
|
||||
@SymbolName("Kotlin_CharArray_clone")
|
||||
external public override fun clone(): Any
|
||||
|
||||
@SymbolName("Kotlin_CharArray_copyOf")
|
||||
external public fun copyOf(newSize: Int): CharArray
|
||||
|
||||
@SymbolName("Kotlin_CharArray_getArrayLength")
|
||||
external private fun getArrayLength(): Int
|
||||
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package kotlin
|
||||
|
||||
@SymbolName("Kotlin_String_fromUtf8Array")
|
||||
external fun fromUtf8Array(array: ByteArray) : String
|
||||
|
||||
// TODO: enable, once global variables implemented.
|
||||
// @SymbolName("theEmptyString")
|
||||
|
||||
@@ -167,15 +167,16 @@ class ArrayList<E> private constructor(
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
var result = "["
|
||||
val sb = StringBuilder(2 + length * 3)
|
||||
sb.append("[")
|
||||
var i = 0
|
||||
while (i < length) {
|
||||
if (i > 0) result += ", "
|
||||
result += array[offset + i].toString()
|
||||
if (i > 0) sb.append(", ")
|
||||
sb.append(array[offset + i])
|
||||
i++
|
||||
}
|
||||
result += "]"
|
||||
return result
|
||||
sb.append("]")
|
||||
return sb.toString()
|
||||
}
|
||||
|
||||
// ---------------------------- private ----------------------------
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
package kotlin.text
|
||||
|
||||
@SymbolName("Kotlin_String_fromUtf8Array")
|
||||
external fun fromUtf8Array(array: ByteArray, start: Int, size: Int) : String
|
||||
|
||||
// TODO: make it somewhat private?
|
||||
@SymbolName("Kotlin_String_fromCharArray")
|
||||
external fun fromCharArray(array: CharArray, start: Int, size: Int) : String
|
||||
|
||||
@SymbolName("Kotlin_String_toCharArray")
|
||||
external fun toCharArray(string: String) : CharArray
|
||||
|
||||
|
||||
class StringBuilder private constructor (
|
||||
private var array: CharArray
|
||||
) : CharSequence {
|
||||
constructor() : this(10)
|
||||
|
||||
constructor(capacity: Int) : this(CharArray(capacity))
|
||||
|
||||
constructor(string: String) : this(toCharArray(string)) {
|
||||
length = array.size
|
||||
}
|
||||
|
||||
override var length: Int = 0
|
||||
set(capacity) {
|
||||
ensureCapacity(capacity)
|
||||
field = capacity
|
||||
}
|
||||
|
||||
override fun get(index: Int): Char {
|
||||
checkIndex(index)
|
||||
return array[index]
|
||||
}
|
||||
|
||||
override fun subSequence(startIndex: Int, endIndex: Int): CharSequence = substring(startIndex, endIndex)
|
||||
|
||||
override fun toString(): String = fromCharArray(array, 0, length)
|
||||
|
||||
fun substring(startIndex: Int, endIndex: Int): String {
|
||||
checkInsertIndex(startIndex)
|
||||
checkInsertIndexFrom(endIndex, startIndex)
|
||||
return fromCharArray(array, startIndex, endIndex - startIndex)
|
||||
}
|
||||
|
||||
fun trimToSize() {
|
||||
if (length < array.size)
|
||||
array = array.copyOf(length)
|
||||
}
|
||||
|
||||
fun ensureCapacity(capacity: Int) {
|
||||
if (capacity > array.size) {
|
||||
var newSize = array.size * 3 / 2
|
||||
if (capacity > newSize)
|
||||
newSize = capacity
|
||||
array = array.copyOf(newSize)
|
||||
}
|
||||
}
|
||||
|
||||
fun append(it: Char) {
|
||||
ensureExtraCapacity(1)
|
||||
array[length++] = it
|
||||
}
|
||||
|
||||
fun append(it: CharArray) {
|
||||
ensureExtraCapacity(it.size)
|
||||
for (c in it)
|
||||
array[length++] = c
|
||||
}
|
||||
|
||||
fun append(it: String) {
|
||||
ensureExtraCapacity(it.length)
|
||||
for (c in toCharArray(it))
|
||||
array[length++] = c
|
||||
}
|
||||
|
||||
fun append(it: Boolean) = append(it.toString())
|
||||
fun append(it: Byte) = append(it.toString())
|
||||
fun append(it: Short) = append(it.toString())
|
||||
fun append(it: Int) = append(it.toString())
|
||||
fun append(it: Long) = append(it.toString())
|
||||
fun append(it: Float) = append(it.toString())
|
||||
fun append(it: Double) = append(it.toString())
|
||||
fun append(it: Any?) = append(it.toString())
|
||||
|
||||
// ---------------------------- private ----------------------------
|
||||
|
||||
private fun ensureExtraCapacity(n: Int) {
|
||||
ensureCapacity(length + n)
|
||||
}
|
||||
|
||||
private fun checkIndex(index: Int) {
|
||||
if (index < 0 || index >= length) throw IndexOutOfBoundsException()
|
||||
}
|
||||
|
||||
private fun checkInsertIndex(index: Int) {
|
||||
if (index < 0 || index > length) throw IndexOutOfBoundsException()
|
||||
}
|
||||
|
||||
private fun checkInsertIndexFrom(index: Int, fromIndex: Int) {
|
||||
if (index < fromIndex || index > length) throw IndexOutOfBoundsException()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user