From f9c6b6e6e47ea7ee803e0b31a4b39876c080dc99 Mon Sep 17 00:00:00 2001 From: Ilya Matveev Date: Wed, 19 Apr 2017 11:43:03 +0700 Subject: [PATCH] stdlib: Add StringBuilder.reverse method --- backend.native/tests/build.gradle | 5 ++ .../runtime/text/string_builder_reverse.kt | 90 +++++++++++++++++++ .../main/kotlin/kotlin/text/StringBuilder.kt | 35 ++++++++ 3 files changed, 130 insertions(+) create mode 100644 backend.native/tests/runtime/text/string_builder_reverse.kt diff --git a/backend.native/tests/build.gradle b/backend.native/tests/build.gradle index a1277755093..ae249a833f5 100644 --- a/backend.native/tests/build.gradle +++ b/backend.native/tests/build.gradle @@ -1080,6 +1080,11 @@ task string_builder0(type: RunKonanTest) { source = "runtime/text/string_builder0.kt" } +task string_builder_reverse(type: RunKonanTest) { + goldValue = "OK\n" + source = "runtime/text/string_builder_reverse.kt" +} + task string0(type: RunKonanTest) { goldValue = "true\ntrue\nПРИВЕТ\nпривет\nПока\ntrue\n" source = "runtime/text/string0.kt" diff --git a/backend.native/tests/runtime/text/string_builder_reverse.kt b/backend.native/tests/runtime/text/string_builder_reverse.kt new file mode 100644 index 00000000000..75ba238c66f --- /dev/null +++ b/backend.native/tests/runtime/text/string_builder_reverse.kt @@ -0,0 +1,90 @@ +fun assertEquals(builder: StringBuilder, content: String) { + if (builder.toString() != content) throw AssertionError("Test failed: $builder != $content") +} + +fun assertTrue(condition: Boolean) { + if (!condition) throw AssertionError("The condition is false") +} + +fun reverseTest(original: String, reversed: String, reversedBack: String) { + assertEquals(StringBuilder(original).reverse(), reversed) + assertEquals(StringBuilder(reversed).reverse(), reversedBack) +} + + +fun main(args: Array) { + var builder = StringBuilder("123456") + assertTrue(builder === builder.reverse()) + assertEquals(builder, "654321") + + builder.length = 1 + assertEquals(builder, "6") + + builder.length = 0 + assertEquals(builder, "") + + var str: String = "a" + reverseTest(str, str, str) + + str = "ab" + reverseTest(str, "ba", str) + + str = "abcdef" + reverseTest(str, "fedcba", str) + + str = "abcdefg" + reverseTest(str, "gfedcba", str) + + str = "\ud800\udc00" + reverseTest(str, str, str) + + str = "\udc00\ud800" + reverseTest(str, "\ud800\udc00", "\ud800\udc00") + + str = "a\ud800\udc00" + reverseTest(str, "\ud800\udc00a", str) + + str = "ab\ud800\udc00" + reverseTest(str, "\ud800\udc00ba", str) + + str = "abc\ud800\udc00" + reverseTest(str, "\ud800\udc00cba", str) + + str = "\ud800\udc00\udc01\ud801\ud802\udc02" + reverseTest(str, "\ud802\udc02\ud801\udc01\ud800\udc00", + "\ud800\udc00\ud801\udc01\ud802\udc02") + + str = "\ud800\udc00\ud801\udc01\ud802\udc02" + reverseTest(str, "\ud802\udc02\ud801\udc01\ud800\udc00", str) + + str = "\ud800\udc00\udc01\ud801a" + reverseTest(str, "a\ud801\udc01\ud800\udc00", + "\ud800\udc00\ud801\udc01a") + + str = "a\ud800\udc00\ud801\udc01" + reverseTest(str, "\ud801\udc01\ud800\udc00a", str) + + str = "\ud800\udc00\udc01\ud801ab" + reverseTest(str, "ba\ud801\udc01\ud800\udc00", + "\ud800\udc00\ud801\udc01ab") + + str = "ab\ud800\udc00\ud801\udc01" + reverseTest(str, "\ud801\udc01\ud800\udc00ba", str) + + str = "\ud800\udc00\ud801\udc01" + reverseTest(str, "\ud801\udc01\ud800\udc00", str) + + str = "a\ud800\udc00z\ud801\udc01" + reverseTest(str, "\ud801\udc01z\ud800\udc00a", str) + + str = "a\ud800\udc00bz\ud801\udc01" + reverseTest(str, "\ud801\udc01zb\ud800\udc00a", str) + + str = "abc\ud802\udc02\ud801\udc01\ud800\udc00" + reverseTest(str, "\ud800\udc00\ud801\udc01\ud802\udc02cba", str) + + str = "abcd\ud802\udc02\ud801\udc01\ud800\udc00" + reverseTest(str, "\ud800\udc00\ud801\udc01\ud802\udc02dcba", str) + + println("OK") +} \ No newline at end of file diff --git a/runtime/src/main/kotlin/kotlin/text/StringBuilder.kt b/runtime/src/main/kotlin/kotlin/text/StringBuilder.kt index 820982bf8f5..467cf68e9bd 100644 --- a/runtime/src/main/kotlin/kotlin/text/StringBuilder.kt +++ b/runtime/src/main/kotlin/kotlin/text/StringBuilder.kt @@ -40,6 +40,10 @@ class StringBuilder private constructor ( length = array.size } + constructor(sequence: CharSequence): this(sequence.length) { + append(sequence) + } + override var length: Int = 0 set(capacity) { ensureCapacity(capacity) @@ -75,6 +79,37 @@ class StringBuilder private constructor ( } } + fun reverse(): StringBuilder { + var front = 0 + var end = array.lastIndex + var hasSurrogates = false + while (front < end) { + if (array[front].isSurrogate() || array[end].isSurrogate()) { + hasSurrogates = true + } + val tmp = array[front] + array[front] = array[end] + array[end] = tmp + front++ + end-- + } + + // Reverse surrogate pairs back. + if (hasSurrogates) { + var i = 0 + while (i < length - 1) { + if (array[i].isLowSurrogate() && array[i + 1].isHighSurrogate()) { + val tmp = array[i] + array[i] = array[i + 1] + array[i + 1] = tmp + i++ + } + i++ + } + } + return this + } + // Of Appenable. override fun append(c: Char) : StringBuilder { ensureExtraCapacity(1)