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"
|
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) {
|
task array0(type: RunKonanTest) {
|
||||||
goldValue = "5\n6\n7\n8\n9\n10\n11\n12\n13\n"
|
goldValue = "5\n6\n7\n8\n9\n10\n11\n12\n13\n"
|
||||||
source = "runtime/basic/array0.kt"
|
source = "runtime/basic/array0.kt"
|
||||||
@@ -444,6 +449,11 @@ task moderately_large_array(type: RunKonanTest) {
|
|||||||
source = "runtime/collections/moderately_large_array.kt"
|
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) {
|
task catch1(type: RunKonanTest) {
|
||||||
goldValue = "Before\nCaught Throwable\nDone\n"
|
goldValue = "Before\nCaught Throwable\nDone\n"
|
||||||
source = "runtime/exceptions/catch1.kt"
|
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())
|
assertTrue(a.toString() == makeList123().toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun testToString2() {
|
||||||
|
val a = makeList123()
|
||||||
|
assertEquals(a.toString(), "[1, 2, 3]")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
fun testSubList() {
|
fun testSubList() {
|
||||||
val a0 = makeList01234()
|
val a0 = makeList01234()
|
||||||
val a = a0.subList(1, 4)
|
val a = a0.subList(1, 4)
|
||||||
@@ -271,11 +277,12 @@ fun testIteratorAdd() {
|
|||||||
val next = it.next()
|
val next = it.next()
|
||||||
if (i++ % 2 == 0)
|
if (i++ % 2 == 0)
|
||||||
it.add("-" + next)
|
it.add("-" + next)
|
||||||
it.next()
|
|
||||||
}
|
}
|
||||||
//assertEquals(listOf("1", "2", "-2", "3", "4", "-4", "5"), a)
|
//assertEquals(listOf("1", "2", "-2", "3", "4", "-4", "5"), a)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
fun main(args : Array<String>) {
|
fun main(args : Array<String>) {
|
||||||
testBasic()
|
testBasic()
|
||||||
testIterator()
|
testIterator()
|
||||||
@@ -286,6 +293,7 @@ fun main(args : Array<String>) {
|
|||||||
testEquals()
|
testEquals()
|
||||||
testHashCode()
|
testHashCode()
|
||||||
testToString()
|
testToString()
|
||||||
|
testToString2()
|
||||||
testSubList()
|
testSubList()
|
||||||
testResize()
|
testResize()
|
||||||
testSubListContains()
|
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;
|
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) {
|
KInt Kotlin_CharArray_getArrayLength(const ArrayHeader* array) {
|
||||||
return array->count_;
|
return array->count_;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -79,18 +79,48 @@ KInt Kotlin_String_getStringLength(KString thiz) {
|
|||||||
return thiz->count_;
|
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");
|
RuntimeAssert(array->type_info() == theByteArrayTypeInfo, "Must use a byte array");
|
||||||
|
if (start < 0 || start + size > array->count_) {
|
||||||
|
ThrowArrayIndexOutOfBoundsException();
|
||||||
|
}
|
||||||
// TODO: support full UTF-8.
|
// TODO: support full UTF-8.
|
||||||
ArrayHeader* result = ArrayContainer(
|
ArrayHeader* result = ArrayContainer(theStringTypeInfo, size).GetPlace();
|
||||||
theStringTypeInfo, array->count_).GetPlace();
|
|
||||||
memcpy(
|
memcpy(
|
||||||
ByteArrayAddressOfElementAt(result, 0),
|
ByteArrayAddressOfElementAt(result, 0),
|
||||||
ByteArrayAddressOfElementAt(array, 0),
|
ByteArrayAddressOfElementAt(array, start),
|
||||||
ArrayDataSizeBytes(array));
|
size);
|
||||||
return result;
|
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) {
|
KString Kotlin_String_plusImpl(KString thiz, KString other) {
|
||||||
// TODO: support UTF-8
|
// TODO: support UTF-8
|
||||||
RuntimeAssert(thiz != nullptr, "this cannot be null");
|
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) {
|
KBoolean Kotlin_String_equals(KString thiz, KConstRef other) {
|
||||||
if (other == nullptr || other->type_info() != theStringTypeInfo) return 0;
|
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_ &&
|
return thiz->count_ == otherString->count_ &&
|
||||||
memcmp(ByteArrayAddressOfElementAt(thiz, 0),
|
memcmp(ByteArrayAddressOfElementAt(thiz, 0),
|
||||||
ByteArrayAddressOfElementAt(otherString, 0),
|
ByteArrayAddressOfElementAt(otherString, 0),
|
||||||
|
|||||||
@@ -80,7 +80,8 @@ KInt Kotlin_String_hashCode(KString thiz);
|
|||||||
KBoolean Kotlin_String_equals(KString thiz, KConstRef other);
|
KBoolean Kotlin_String_equals(KString thiz, KConstRef other);
|
||||||
KInt Kotlin_String_compareTo(KString thiz, KString other);
|
KInt Kotlin_String_compareTo(KString thiz, KString other);
|
||||||
KChar Kotlin_String_get(KString thiz, KInt index);
|
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);
|
KString Kotlin_String_plusImpl(KString thiz, KString other);
|
||||||
KInt Kotlin_String_getStringLength(KString thiz);
|
KInt Kotlin_String_getStringLength(KString thiz);
|
||||||
KString Kotlin_String_subSequence(KString thiz, KInt startIndex, KInt endIndex);
|
KString Kotlin_String_subSequence(KString thiz, KInt startIndex, KInt endIndex);
|
||||||
|
|||||||
@@ -66,6 +66,9 @@ public final class CharArray : Cloneable {
|
|||||||
@SymbolName("Kotlin_CharArray_clone")
|
@SymbolName("Kotlin_CharArray_clone")
|
||||||
external public override fun clone(): Any
|
external public override fun clone(): Any
|
||||||
|
|
||||||
|
@SymbolName("Kotlin_CharArray_copyOf")
|
||||||
|
external public fun copyOf(newSize: Int): CharArray
|
||||||
|
|
||||||
@SymbolName("Kotlin_CharArray_getArrayLength")
|
@SymbolName("Kotlin_CharArray_getArrayLength")
|
||||||
external private fun getArrayLength(): Int
|
external private fun getArrayLength(): Int
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
package kotlin
|
package kotlin
|
||||||
|
|
||||||
@SymbolName("Kotlin_String_fromUtf8Array")
|
|
||||||
external fun fromUtf8Array(array: ByteArray) : String
|
|
||||||
|
|
||||||
// TODO: enable, once global variables implemented.
|
// TODO: enable, once global variables implemented.
|
||||||
// @SymbolName("theEmptyString")
|
// @SymbolName("theEmptyString")
|
||||||
|
|||||||
@@ -167,15 +167,16 @@ class ArrayList<E> private constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
var result = "["
|
val sb = StringBuilder(2 + length * 3)
|
||||||
|
sb.append("[")
|
||||||
var i = 0
|
var i = 0
|
||||||
while (i < length) {
|
while (i < length) {
|
||||||
if (i > 0) result += ", "
|
if (i > 0) sb.append(", ")
|
||||||
result += array[offset + i].toString()
|
sb.append(array[offset + i])
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
result += "]"
|
sb.append("]")
|
||||||
return result
|
return sb.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------- private ----------------------------
|
// ---------------------------- 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