Add some string operations, refactor runtime. (#249)

This commit is contained in:
Nikolay Igotti
2017-02-17 14:31:28 +03:00
committed by GitHub
parent 316ed73bd5
commit 45bb2fdb8b
19 changed files with 2644 additions and 113 deletions
+6 -1
View File
@@ -281,7 +281,7 @@ task hello4(type: RunKonanTest) {
}
task tostring0(type: RunKonanTest) {
goldValue = "127\n-1\n239\nA\n1122334455\n112233445566778899\n3.14159\n1E+27\n1E-300\ntrue\nfalse\n"
goldValue = "127\n-1\n239\nA\nЁ\nト\n1122334455\n112233445566778899\n3.14159\n1E+27\n1E-300\ntrue\nfalse\n"
source = "runtime/basic/tostring0.kt"
}
@@ -791,6 +791,11 @@ task string_builder0(type: RunKonanTest) {
source = "runtime/text/string_builder0.kt"
}
task string0(type: RunKonanTest) {
goldValue = "true\ntrue\nПРИВЕТ\nпривет\nПока\n"
source = "runtime/text/string0.kt"
}
task catch1(type: RunKonanTest) {
goldValue = "Before\nCaught Throwable\nDone\n"
source = "runtime/exceptions/catch1.kt"
@@ -3,8 +3,8 @@ fun main(args : Array<String>) {
println(255.toByte().toString())
println(239.toShort().toString())
println('A'.toString())
// println('Ё'.toString())
// println('ト'.toString())
println('Ё'.toString())
println('ト'.toString())
println(1122334455.toString())
println(112233445566778899.toString())
// Here we differ from Java, as have no dtoa() yet.
@@ -0,0 +1,9 @@
fun main(args: Array<String>) {
val str = "hello"
println(str.equals("HElLo", true))
val strI18n = "Привет"
println(strI18n.equals("прИВет", true))
println(strI18n.toUpperCase())
println(strI18n.toLowerCase())
println("пока".capitalize())
}
+10 -11
View File
@@ -2,6 +2,7 @@
#include "Memory.h"
#include "Natives.h"
#include "Runtime.h"
#include "String.h"
#include "Types.h"
@@ -22,18 +23,16 @@ OBJ_GETTER(setupArgs, int argc, char** argv) {
extern "C" void Konan_start(const ObjHeader* );
int main(int argc, char** argv) {
RuntimeState* state = InitRuntime();
InitMemory();
InitGlobalVariables();
if (state != nullptr) {
ObjHolder args;
setupArgs(argc, argv, args.slot());
Konan_start(args.obj());
}
{
ObjHolder args;
setupArgs(argc, argv, args.slot());
Konan_start(args.obj());
}
DeinitRuntime(state);
DeinitMemory();
// Yes, we have to follow Java convention and return zero.
return 0;
// Yes, we have to follow Java convention and return zero.
return 0;
}
+9 -3
View File
@@ -31,6 +31,8 @@ constexpr container_size_t kContainerAlignment = 1024;
// Single object alignment.
constexpr container_size_t kObjectAlignment = 8;
} // namespace
#if USE_GC
// Collection threshold default (collect after having so many elements in the
// release candidates set).
@@ -66,6 +68,9 @@ struct MemoryState {
#endif
};
namespace {
// TODO: remove this global.
MemoryState* memoryState = nullptr;
// TODO: use those allocators for STL containers as well.
@@ -450,7 +455,7 @@ inline void ReleaseRef(const ObjHeader* object) {
extern "C" {
void InitMemory() {
MemoryState* InitMemory() {
RuntimeAssert(offsetof(ArrayHeader, type_info_)
==
offsetof(ObjHeader, type_info_),
@@ -476,9 +481,10 @@ void InitMemory() {
memoryState->gcThreshold = kGcThreshold;
memoryState->gcSuspendCount = 0;
#endif
return memoryState;
}
void DeinitMemory() {
void DeinitMemory(MemoryState* memoryState) {
#if TRACE_MEMORY
// Free all global objects, to ensure no memory leaks happens.
for (auto location: *memoryState->globalObjects) {
@@ -505,7 +511,7 @@ void DeinitMemory() {
}
delete memoryState;
memoryState = nullptr;
::memoryState = nullptr;
}
OBJ_GETTER(AllocInstance, const TypeInfo* type_info) {
+4 -2
View File
@@ -304,8 +304,10 @@ extern "C" {
return result; \
}
void InitMemory();
void DeinitMemory();
struct MemoryState;
MemoryState* InitMemory();
void DeinitMemory(MemoryState*);
//
// Object allocation.
+58
View File
@@ -0,0 +1,58 @@
#include <locale.h>
#include "Runtime.h"
struct RuntimeState {
MemoryState* memoryState;
};
namespace {
InitNode* initHeadNode = nullptr;
InitNode* initTailNode = nullptr;
void InitGlobalVariables() {
InitNode *currNode = initHeadNode;
while (currNode != nullptr) {
currNode->init();
currNode = currNode->next;
}
}
} // namespace
#ifdef __cplusplus
extern "C" {
#endif
void AppendToInitializersTail(struct InitNode *next) {
// TODO: use RuntimeState.
if (initHeadNode == nullptr) {
initHeadNode = next;
} else {
initTailNode->next = next;
}
initTailNode = next;
}
// TODO: properly use RuntimeState.
RuntimeState* InitRuntime() {
// Set Unicode locale, otherwise towlower() and friends do not work properly.
if (setlocale(LC_CTYPE, "en_US.UTF-8") == nullptr) {
return nullptr;
}
RuntimeState* result = new RuntimeState();
result->memoryState = InitMemory();
// Keep global variables in state as well.
InitGlobalVariables();
return result;
}
void DeinitRuntime(RuntimeState* state) {
DeinitMemory(state->memoryState);
delete state;
}
#ifdef __cplusplus
}
#endif
+27
View File
@@ -0,0 +1,27 @@
#ifndef RUNTIME_RUNTIME_H
#define RUNTIME_RUNTIME_H
#include "Types.h"
struct RuntimeState;
#ifdef __cplusplus
extern "C" {
#endif
typedef void (*Initializer)();
struct InitNode {
Initializer init;
struct InitNode* next;
};
void AppendToInitializersTail(struct InitNode*);
RuntimeState* InitRuntime();
void DeinitRuntime(RuntimeState* state);
#ifdef __cplusplus
}
#endif
#endif // RUNTIME_RUNTIME_H
+228 -5
View File
@@ -4,6 +4,7 @@
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <wctype.h>
#include <iterator>
#include <string>
@@ -151,13 +152,236 @@ KBoolean Kotlin_String_equals(KString thiz, KConstRef other) {
if (thiz == otherString) return true;
return thiz->count_ == otherString->count_ &&
memcmp(CharArrayAddressOfElementAt(thiz, 0),
CharArrayAddressOfElementAt(otherString, 0),
thiz->count_ * sizeof(KChar)) == 0;
CharArrayAddressOfElementAt(otherString, 0),
thiz->count_ * sizeof(KChar)) == 0;
}
KBoolean Kotlin_String_equalsIgnoreCase(KString thiz, KConstRef other) {
RuntimeAssert(thiz->type_info() == theStringTypeInfo &&
other->type_info() == theStringTypeInfo, "Must be strings");
// Important, due to literal internalization.
KString otherString = other->array();
if (thiz == otherString) return true;
if (thiz->count_ != otherString->count_) return false;
auto count = thiz->count_;
const KChar* thizRaw = CharArrayAddressOfElementAt(thiz, 0);
const KChar* otherRaw = CharArrayAddressOfElementAt(otherString, 0);
for (KInt index = 0; index < count; ++index) {
if (towlower(*thizRaw++) != towlower(*otherRaw++)) return false;
}
return true;
}
OBJ_GETTER(Kotlin_String_replace, KString thiz, KChar oldChar, KChar newChar,
KBoolean ignoreCase) {
auto count = thiz->count_;
ArrayHeader* result = AllocArrayInstance(
theStringTypeInfo, count, OBJ_RESULT)->array();
const KChar* thizRaw = CharArrayAddressOfElementAt(thiz, 0);
KChar* resultRaw = CharArrayAddressOfElementAt(result, 0);
if (ignoreCase) {
KChar oldCharLower = towlower(oldChar);
for (KInt index = 0; index < count; ++index) {
KChar thizChar = *thizRaw++;
*resultRaw++ = towlower(thizChar) == oldCharLower ? newChar : thizChar;
}
} else {
for (KInt index = 0; index < count; ++index) {
KChar thizChar = *thizRaw++;
*resultRaw++ = thizChar == oldChar ? newChar : thizChar;
}
}
RETURN_OBJ(result->obj());
}
OBJ_GETTER(Kotlin_String_toUpperCase, KString thiz) {
auto count = thiz->count_;
ArrayHeader* result = AllocArrayInstance(
theStringTypeInfo, count, OBJ_RESULT)->array();
const KChar* thizRaw = CharArrayAddressOfElementAt(thiz, 0);
KChar* resultRaw = CharArrayAddressOfElementAt(result, 0);
for (KInt index = 0; index < count; ++index) {
*resultRaw++ = towupper(*thizRaw++);
}
RETURN_OBJ(result->obj());
}
OBJ_GETTER(Kotlin_String_toLowerCase, KString thiz) {
auto count = thiz->count_;
ArrayHeader* result = AllocArrayInstance(
theStringTypeInfo, count, OBJ_RESULT)->array();
const KChar* thizRaw = CharArrayAddressOfElementAt(thiz, 0);
KChar* resultRaw = CharArrayAddressOfElementAt(result, 0);
for (KInt index = 0; index < count; ++index) {
*resultRaw++ = towlower(*thizRaw++);
}
RETURN_OBJ(result->obj());
}
KBoolean Kotlin_String_regionMatches(KString thiz, KInt thizOffset,
KString other, KInt otherOffset,
KInt length, KBoolean ignoreCase) {
if (thizOffset < 0 || thizOffset + length > thiz->count_ ||
otherOffset < 0 || otherOffset + length > other->count_) {
return false;
}
const KChar* thizRaw = CharArrayAddressOfElementAt(thiz, thizOffset);
const KChar* otherRaw = CharArrayAddressOfElementAt(other, otherOffset);
if (ignoreCase) {
for (KInt index = 0; index < length; ++index) {
if (towlower(*thizRaw++) != towlower(*otherRaw++)) return false;
}
} else {
for (KInt index = 0; index < length; ++index) {
if (*thizRaw++ != *otherRaw++) return false;
}
}
return true;
}
KBoolean Kotlin_CharSequence_regionMatches(KString thiz, KInt thizOffset,
KString other, KInt otherOffset,
KInt length, KBoolean ignoreCase) {
RuntimeAssert(false, "Kotlin_CharSequence_regionMatches is not implemented");
return false;
}
KBoolean Kotlin_Char_isDefined(KChar ch) {
// TODO: fixme!
RuntimeAssert(false, "Kotlin_Char_isDefined() is not implemented");
return true;
}
KBoolean Kotlin_Char_isLetter(KChar ch) {
return iswalpha(ch);
}
KBoolean Kotlin_Char_isLetterOrDigit(KChar ch) {
return iswalnum(ch);
}
KBoolean Kotlin_Char_isDigit(KChar ch) {
return iswdigit(ch);
}
KBoolean Kotlin_Char_isIdentifierIgnorable(KChar ch) {
RuntimeAssert(false, "Kotlin_Char_isIdentifierIgnorable() is not implemented");
return false;
}
KBoolean Kotlin_Char_isISOControl(KChar ch) {
RuntimeAssert(false, "Kotlin_Char_isISOControl() is not implemented");
return false;
}
KBoolean Kotlin_Char_isHighSurrogate(KChar ch) {
return ((ch & 0xfc00) == 0xd800);
}
KBoolean Kotlin_Char_isLowSurrogate(KChar ch) {
return ((ch & 0xfc00) == 0xdc00);
}
KBoolean Kotlin_Char_isWhitespace(KChar ch) {
return iswspace(ch);
}
KBoolean Kotlin_Char_isLowerCase(KChar ch) {
return iswlower(ch);
}
KBoolean Kotlin_Char_isUpperCase(KChar ch) {
return iswupper(ch);
}
KChar Kotlin_Char_toLowerCase(KChar ch) {
return towlower(ch);
}
KChar Kotlin_Char_toUpperCase(KChar ch) {
return towupper(ch);
}
KInt Kotlin_String_indexOfChar(KString thiz, KChar ch, KInt fromIndex) {
if (fromIndex < 0 || fromIndex > thiz->count_) {
return false;
}
KInt count = thiz->count_;
const KChar* thizRaw = CharArrayAddressOfElementAt(thiz, fromIndex);
while (fromIndex < count) {
if (*thizRaw++ == ch) return fromIndex;
fromIndex++;
}
return -1;
}
KInt Kotlin_String_lastIndexOfChar(KString thiz, KChar ch, KInt fromIndex) {
if (fromIndex < 0 || fromIndex > thiz->count_ || thiz->count_ == 0) {
return false;
}
KInt count = thiz->count_;
KInt index = count - 1;
const KChar* thizRaw = CharArrayAddressOfElementAt(thiz, index);
while (index >= fromIndex) {
if (*thizRaw-- == ch) return index;
index--;
}
return -1;
}
// TODO: or code up Knuth-Moris-Pratt.
KInt Kotlin_String_indexOfString(KString thiz, KString other, KInt fromIndex) {
if (fromIndex < 0 || fromIndex > thiz->count_ ||
fromIndex + other->count_ > thiz->count_) {
return -1;
}
KInt count = thiz->count_;
const KChar* thizRaw = CharArrayAddressOfElementAt(thiz, fromIndex);
const KChar* otherRaw = CharArrayAddressOfElementAt(thiz, 0);
void* result = memmem(thizRaw, (thiz->count_ - fromIndex) * sizeof(KChar),
otherRaw, other->count_ * sizeof(KChar));
if (result == nullptr) return -1;
return (reinterpret_cast<intptr_t>(result) - reinterpret_cast<intptr_t>(
CharArrayAddressOfElementAt(thiz, 0))) / sizeof(KChar);
}
KInt Kotlin_String_lastIndexOfString(KString thiz, KString other, KInt fromIndex) {
if (fromIndex < 0 || fromIndex > thiz->count_ || thiz->count_ == 0 ||
fromIndex + other->count_ > thiz->count_) {
return false;
}
KInt count = thiz->count_;
KInt otherCount = other->count_;
KInt start = fromIndex;
if (otherCount <= count && start >= 0) {
if (otherCount > 0) {
if (fromIndex > count - otherCount)
start = count - otherCount;
KChar firstChar = *CharArrayAddressOfElementAt(other, 0);
while (true) {
KInt candidate = Kotlin_String_lastIndexOfChar(thiz, firstChar, start);
if (candidate == -1) return -1;
KInt offsetThiz = candidate;
KInt offsetOther = 0;
while (++offsetOther < otherCount &&
*CharArrayAddressOfElementAt(thiz, ++offsetThiz) ==
*CharArrayAddressOfElementAt(other, offsetOther)) {}
if (offsetOther == otherCount) {
return candidate;
}
start = candidate - 1;
}
}
return start < count ? start : count;
}
return -1;
}
KInt Kotlin_String_hashCode(KString thiz) {
// TODO: consider caching strings hashes.
// TODO: maybe use some simpler hashing algorithm?
// Note that we don't use Java's string hash.
return CityHash64(
CharArrayAddressOfElementAt(thiz, 0), thiz->count_ * sizeof(KChar));
}
@@ -174,8 +398,8 @@ OBJ_GETTER(Kotlin_String_subSequence, KString thiz, KInt startIndex, KInt endInd
ArrayHeader* result = AllocArrayInstance(
theStringTypeInfo, length, OBJ_RESULT)->array();
memcpy(CharArrayAddressOfElementAt(result, 0),
CharArrayAddressOfElementAt(thiz, startIndex),
length * sizeof(KChar));
CharArrayAddressOfElementAt(thiz, startIndex),
length * sizeof(KChar));
RETURN_OBJ(result->obj());
}
@@ -207,5 +431,4 @@ OBJ_GETTER0(Kotlin_io_Console_readLine) {
RETURN_RESULT_OF(CreateStringFromCString, data);
}
} // extern "C"
+6 -6
View File
@@ -13,8 +13,8 @@ extern "C" {
OBJ_GETTER(Kotlin_Any_toString, KConstRef thiz) {
char cstring[80];
snprintf(cstring, sizeof(cstring), "%s %p type %p",
IsArray(thiz) ? "array" : "object",
thiz, thiz->type_info_);
IsArray(thiz) ? "array" : "object",
thiz, thiz->type_info_);
RETURN_RESULT_OF(CreateStringFromCString, cstring);
}
@@ -25,10 +25,10 @@ OBJ_GETTER(Kotlin_Byte_toString, KByte value) {
}
OBJ_GETTER(Kotlin_Char_toString, KChar value) {
char cstring[5];
// TODO: support UTF-8.
snprintf(cstring, sizeof(cstring), "%c", value);
RETURN_RESULT_OF(CreateStringFromCString, cstring);
ArrayHeader* result = AllocArrayInstance(
theStringTypeInfo, 1, OBJ_RESULT)->array();
*CharArrayAddressOfElementAt(result, 0) = value;
RETURN_OBJ(result->obj());
}
OBJ_GETTER(Kotlin_Short_toString, KShort value) {
-19
View File
@@ -36,25 +36,6 @@ void CheckInstance(const ObjHeader* obj, const TypeInfo* type_info) {
ThrowClassCastException();
}
static struct InitNode* initHeadNode = nullptr;
static struct InitNode* initTailNode = nullptr;
void AppendToInitializersTail(struct InitNode *next) {
if (initHeadNode == nullptr) {
initHeadNode = next;
} else {
initTailNode->next = next;
}
initTailNode = next;
}
void InitGlobalVariables() {
struct InitNode *currNode = initHeadNode;
while(currNode != nullptr) {
currNode->init();
currNode = currNode->next;
}
}
#ifdef __cplusplus
}
#endif
-9
View File
@@ -41,15 +41,6 @@ KBoolean IsInstance(const ObjHeader* obj, const TypeInfo* type_info) RUNTIME_PUR
void CheckCast(const ObjHeader* obj, const TypeInfo* type_info);
KBoolean IsArray(KConstRef obj) RUNTIME_PURE;
typedef void (*Initializer)();
struct InitNode {
Initializer init;
struct InitNode* next;
};
void AppendToInitializersTail(struct InitNode*);
void InitGlobalVariables();
#ifdef __cplusplus
}
#endif
@@ -49,6 +49,11 @@ public annotation class FixmeSequences
*/
public annotation class FixmeVariance
/**
* Need to be fixed because of regular expressions.
*/
public annotation class FixmeRegex
/**
* Need to be fixed.
*/
@@ -0,0 +1,31 @@
package kotlin.text
/**
* Concatenates this Char and a String.
*/
@kotlin.internal.InlineOnly
public inline operator fun Char.plus(other: String) : String = this.toString() + other
/**
* Returns `true` if this character is equal to the [other] character, optionally ignoring character case.
*
* @param ignoreCase `true` to ignore character case when comparing characters. By default `false`.
*
* Two characters are considered the same ignoring case if at least one of the following is `true`:
* - The two characters are the same (as compared by the == operator)
* - Applying the method [toUpperCase] to each character produces the same result
* - Applying the method [toLowerCase] to each character produces the same result
*/
public fun Char.equals(other: Char, ignoreCase: Boolean = false): Boolean {
if (this === other) return true
if (!ignoreCase) return false
if (this.toUpperCase() === other.toUpperCase()) return true
if (this.toLowerCase() === other.toLowerCase()) return true
return false
}
/**
* Returns `true` if this character is a Unicode surrogate code unit.
*/
public fun Char.isSurrogate(): Boolean = this in Char.MIN_SURROGATE..Char.MAX_SURROGATE
@@ -0,0 +1,138 @@
package kotlin.text
/**
* Returns the index within this string of the first occurrence of the specified character, starting from the specified offset.
*/
@SymbolName("Kotlin_String_indexOfChar")
external internal fun String.nativeIndexOf(ch: Char, fromIndex: Int): Int
/**
* Returns the index within this string of the first occurrence of the specified substring, starting from the specified offset.
*/
@SymbolName("Kotlin_String_indexOfString")
external internal fun String.nativeIndexOf(str: String, fromIndex: Int): Int
/**
* Returns the index within this string of the last occurrence of the specified character.
*/
@SymbolName("Kotlin_String_lastIndexOfChar")
external internal fun String.nativeLastIndexOf(ch: Char, fromIndex: Int): Int
/**
* Returns the index within this string of the last occurrence of the specified character, starting from the specified offset.
*/
@SymbolName("Kotlin_String_lastIndexOfString")
external internal fun String.nativeLastIndexOf(str: String, fromIndex: Int): Int
/**
* Returns `true` if this string is equal to [other], optionally ignoring character case.
*
* @param ignoreCase `true` to ignore character case when comparing strings. By default `false`.
*/
public fun String?.equals(other: String?, ignoreCase: Boolean = false): Boolean {
if (this === null)
return other === null
if (other === null)
return false
return if (!ignoreCase)
this.equals(other)
else
stringEqualsIgnoreCase(this, other)
}
@SymbolName("Kotlin_String_equalsIgnoreCase")
external internal fun stringEqualsIgnoreCase(thiz: String, other: String): Boolean
/**
* Returns a new string with all occurrences of [oldChar] replaced with [newChar].
*/
@SymbolName("Kotlin_String_replace")
external public fun String.replace(
oldChar: Char, newChar: Char, ignoreCase: Boolean = false): String
/**
* Returns a new string obtained by replacing all occurrences of the [oldValue] substring in this string
* with the specified [newValue] string.
*/
public fun String.replace(oldValue: String, newValue: String, ignoreCase: Boolean = false): String =
splitToSequence(oldValue, ignoreCase = ignoreCase).joinToString(separator = newValue)
/**
* Returns a new string with the first occurrence of [oldChar] replaced with [newChar].
*/
public fun String.replaceFirst(oldChar: Char, newChar: Char, ignoreCase: Boolean = false): String {
val index = indexOf(oldChar, ignoreCase = ignoreCase)
return if (index < 0) this else this.replaceRange(index, index + 1, newChar.toString())
}
/**
* Returns a new string obtained by replacing the first occurrence of the [oldValue] substring in this string
* with the specified [newValue] string.
*/
public fun String.replaceFirst(oldValue: String, newValue: String, ignoreCase: Boolean = false): String {
val index = indexOf(oldValue, ignoreCase = ignoreCase)
return if (index < 0) this else this.replaceRange(index, index + oldValue.length, newValue)
}
/**
* Returns a copy of this string converted to upper case using the rules of the default locale.
*/
@SymbolName("Kotlin_String_toUpperCase")
external public fun String.toUpperCase(): String
/**
* Returns a copy of this string converted to lower case using the rules of the default locale.
*/
@SymbolName("Kotlin_String_toLowerCase")
external public inline fun String.toLowerCase(): String
/**
* Returns a copy of this string having its first letter uppercased, or the original string,
* if it's empty or already starts with an upper case letter.
*
* @sample samples.text.Strings.captialize
*/
public fun String.capitalize(): String {
return if (isNotEmpty() && this[0].isLowerCase()) substring(0, 1).toUpperCase() + substring(1) else this
}
/**
* Returns a copy of this string having its first letter lowercased, or the original string,
* if it's empty or already starts with a lower case letter.
*
* @sample samples.text.Strings.decaptialize
*/
public fun String.decapitalize(): String {
return if (isNotEmpty() && this[0].isUpperCase()) substring(0, 1).toLowerCase() + substring(1) else this
}
/**
* Returns `true` if this string is empty or consists solely of whitespace characters.
*/
public fun CharSequence.isBlank(): Boolean = length == 0 || indices.all { this[it].isWhitespace() }
/**
* Returns `true` if the specified range in this char sequence is equal to the specified range in another char sequence.
* @param thisOffset the start offset in this char sequence of the substring to compare.
* @param other the string against a substring of which the comparison is performed.
* @param otherOffset the start offset in the other char sequence of the substring to compare.
* @param length the length of the substring to compare.
*/
@SymbolName("Kotlin_CharSequence_regionMatches")
external public fun CharSequence.regionMatches(
thisOffset: Int, other: CharSequence, otherOffset: Int, length: Int,
ignoreCase: Boolean = false): Boolean
/**
* Returns `true` if the specified range in this string is equal to the specified range in another string.
* @param thisOffset the start offset in this string of the substring to compare.
* @param other the string against a substring of which the comparison is performed.
* @param otherOffset the start offset in the other string of the substring to compare.
* @param length the length of the substring to compare.
*/
@SymbolName("Kotlin_String_regionMatches")
external public fun String.regionMatches(
thisOffset: Int, other: String, otherOffset: Int, length: Int,
ignoreCase: Boolean = false): Boolean
+716 -55
View File
@@ -371,6 +371,134 @@ public operator fun <@kotlin.internal.OnlyInputTypes T> Array<out T>.contains(el
return indexOf(element) >= 0
}
/**
* Returns `true` if [element] is found in the array.
*/
public operator fun ByteArray.contains(element: Byte): Boolean {
return indexOf(element) >= 0
}
/**
* Returns `true` if [element] is found in the array.
*/
public operator fun ShortArray.contains(element: Short): Boolean {
return indexOf(element) >= 0
}
/**
* Returns `true` if [element] is found in the array.
*/
public operator fun IntArray.contains(element: Int): Boolean {
return indexOf(element) >= 0
}
/**
* Returns `true` if [element] is found in the array.
*/
public operator fun LongArray.contains(element: Long): Boolean {
return indexOf(element) >= 0
}
/**
* Returns `true` if [element] is found in the array.
*/
public operator fun FloatArray.contains(element: Float): Boolean {
return indexOf(element) >= 0
}
/**
* Returns `true` if [element] is found in the array.
*/
public operator fun DoubleArray.contains(element: Double): Boolean {
return indexOf(element) >= 0
}
/**
* Returns `true` if [element] is found in the array.
*/
public operator fun BooleanArray.contains(element: Boolean): Boolean {
return indexOf(element) >= 0
}
/**
* Returns `true` if [element] is found in the array.
*/
public operator fun CharArray.contains(element: Char): Boolean {
return indexOf(element) >= 0
}
/**
* Returns an element at the given [index] or throws an [IndexOutOfBoundsException] if the [index] is out of bounds of this array.
*/
@kotlin.internal.InlineOnly
public inline fun <T> Array<out T>.elementAt(index: Int): T {
return get(index)
}
/**
* Returns an element at the given [index] or throws an [IndexOutOfBoundsException] if the [index] is out of bounds of this array.
*/
@kotlin.internal.InlineOnly
public inline fun ByteArray.elementAt(index: Int): Byte {
return get(index)
}
/**
* Returns an element at the given [index] or throws an [IndexOutOfBoundsException] if the [index] is out of bounds of this array.
*/
@kotlin.internal.InlineOnly
public inline fun ShortArray.elementAt(index: Int): Short {
return get(index)
}
/**
* Returns an element at the given [index] or throws an [IndexOutOfBoundsException] if the [index] is out of bounds of this array.
*/
@kotlin.internal.InlineOnly
public inline fun IntArray.elementAt(index: Int): Int {
return get(index)
}
/**
* Returns an element at the given [index] or throws an [IndexOutOfBoundsException] if the [index] is out of bounds of this array.
*/
@kotlin.internal.InlineOnly
public inline fun LongArray.elementAt(index: Int): Long {
return get(index)
}
/**
* Returns an element at the given [index] or throws an [IndexOutOfBoundsException] if the [index] is out of bounds of this array.
*/
@kotlin.internal.InlineOnly
public inline fun FloatArray.elementAt(index: Int): Float {
return get(index)
}
/**
* Returns an element at the given [index] or throws an [IndexOutOfBoundsException] if the [index] is out of bounds of this array.
*/
@kotlin.internal.InlineOnly
public inline fun DoubleArray.elementAt(index: Int): Double {
return get(index)
}
/**
* Returns an element at the given [index] or throws an [IndexOutOfBoundsException] if the [index] is out of bounds of this array.
*/
@kotlin.internal.InlineOnly
public inline fun BooleanArray.elementAt(index: Int): Boolean {
return get(index)
}
/**
* Returns an element at the given [index] or throws an [IndexOutOfBoundsException] if the [index] is out of bounds of this array.
*/
@kotlin.internal.InlineOnly
public inline fun CharArray.elementAt(index: Int): Char {
return get(index)
}
/**
* Returns first index of [element], or -1 if the array does not contain element.
*/
@@ -391,6 +519,102 @@ public fun <@kotlin.internal.OnlyInputTypes T> Array<out T>.indexOf(element: T):
return -1
}
/**
* Returns first index of [element], or -1 if the array does not contain element.
*/
public fun ByteArray.indexOf(element: Byte): Int {
for (index in indices) {
if (element == this[index]) {
return index
}
}
return -1
}
/**
* Returns first index of [element], or -1 if the array does not contain element.
*/
public fun ShortArray.indexOf(element: Short): Int {
for (index in indices) {
if (element == this[index]) {
return index
}
}
return -1
}
/**
* Returns first index of [element], or -1 if the array does not contain element.
*/
public fun IntArray.indexOf(element: Int): Int {
for (index in indices) {
if (element == this[index]) {
return index
}
}
return -1
}
/**
* Returns first index of [element], or -1 if the array does not contain element.
*/
public fun LongArray.indexOf(element: Long): Int {
for (index in indices) {
if (element == this[index]) {
return index
}
}
return -1
}
/**
* Returns first index of [element], or -1 if the array does not contain element.
*/
public fun FloatArray.indexOf(element: Float): Int {
for (index in indices) {
if (element == this[index]) {
return index
}
}
return -1
}
/**
* Returns first index of [element], or -1 if the array does not contain element.
*/
public fun DoubleArray.indexOf(element: Double): Int {
for (index in indices) {
if (element == this[index]) {
return index
}
}
return -1
}
/**
* Returns first index of [element], or -1 if the array does not contain element.
*/
public fun BooleanArray.indexOf(element: Boolean): Int {
for (index in indices) {
if (element == this[index]) {
return index
}
}
return -1
}
/**
* Returns first index of [element], or -1 if the array does not contain element.
*/
public fun CharArray.indexOf(element: Char): Int {
for (index in indices) {
if (element == this[index]) {
return index
}
}
return -1
}
/**
* Returns index of the first element matching the given [predicate], or -1 if the array does not contain such element.
*/
@@ -403,6 +627,102 @@ public inline fun <T> Array<out T>.indexOfFirst(predicate: (T) -> Boolean): Int
return -1
}
/**
* Returns index of the first element matching the given [predicate], or -1 if the array does not contain such element.
*/
public inline fun ByteArray.indexOfFirst(predicate: (Byte) -> Boolean): Int {
for (index in indices) {
if (predicate(this[index])) {
return index
}
}
return -1
}
/**
* Returns index of the first element matching the given [predicate], or -1 if the array does not contain such element.
*/
public inline fun ShortArray.indexOfFirst(predicate: (Short) -> Boolean): Int {
for (index in indices) {
if (predicate(this[index])) {
return index
}
}
return -1
}
/**
* Returns index of the first element matching the given [predicate], or -1 if the array does not contain such element.
*/
public inline fun IntArray.indexOfFirst(predicate: (Int) -> Boolean): Int {
for (index in indices) {
if (predicate(this[index])) {
return index
}
}
return -1
}
/**
* Returns index of the first element matching the given [predicate], or -1 if the array does not contain such element.
*/
public inline fun LongArray.indexOfFirst(predicate: (Long) -> Boolean): Int {
for (index in indices) {
if (predicate(this[index])) {
return index
}
}
return -1
}
/**
* Returns index of the first element matching the given [predicate], or -1 if the array does not contain such element.
*/
public inline fun FloatArray.indexOfFirst(predicate: (Float) -> Boolean): Int {
for (index in indices) {
if (predicate(this[index])) {
return index
}
}
return -1
}
/**
* Returns index of the first element matching the given [predicate], or -1 if the array does not contain such element.
*/
public inline fun DoubleArray.indexOfFirst(predicate: (Double) -> Boolean): Int {
for (index in indices) {
if (predicate(this[index])) {
return index
}
}
return -1
}
/**
* Returns index of the first element matching the given [predicate], or -1 if the array does not contain such element.
*/
public inline fun BooleanArray.indexOfFirst(predicate: (Boolean) -> Boolean): Int {
for (index in indices) {
if (predicate(this[index])) {
return index
}
}
return -1
}
/**
* Returns index of the first element matching the given [predicate], or -1 if the array does not contain such element.
*/
public inline fun CharArray.indexOfFirst(predicate: (Char) -> Boolean): Int {
for (index in indices) {
if (predicate(this[index])) {
return index
}
}
return -1
}
/**
* Returns index of the last element matching the given [predicate], or -1 if the array does not contain such element.
*/
@@ -415,6 +735,102 @@ public inline fun <T> Array<out T>.indexOfLast(predicate: (T) -> Boolean): Int {
return -1
}
/**
* Returns index of the last element matching the given [predicate], or -1 if the array does not contain such element.
*/
public inline fun ByteArray.indexOfLast(predicate: (Byte) -> Boolean): Int {
for (index in indices.reversed()) {
if (predicate(this[index])) {
return index
}
}
return -1
}
/**
* Returns index of the last element matching the given [predicate], or -1 if the array does not contain such element.
*/
public inline fun ShortArray.indexOfLast(predicate: (Short) -> Boolean): Int {
for (index in indices.reversed()) {
if (predicate(this[index])) {
return index
}
}
return -1
}
/**
* Returns index of the last element matching the given [predicate], or -1 if the array does not contain such element.
*/
public inline fun IntArray.indexOfLast(predicate: (Int) -> Boolean): Int {
for (index in indices.reversed()) {
if (predicate(this[index])) {
return index
}
}
return -1
}
/**
* Returns index of the last element matching the given [predicate], or -1 if the array does not contain such element.
*/
public inline fun LongArray.indexOfLast(predicate: (Long) -> Boolean): Int {
for (index in indices.reversed()) {
if (predicate(this[index])) {
return index
}
}
return -1
}
/**
* Returns index of the last element matching the given [predicate], or -1 if the array does not contain such element.
*/
public inline fun FloatArray.indexOfLast(predicate: (Float) -> Boolean): Int {
for (index in indices.reversed()) {
if (predicate(this[index])) {
return index
}
}
return -1
}
/**
* Returns index of the last element matching the given [predicate], or -1 if the array does not contain such element.
*/
public inline fun DoubleArray.indexOfLast(predicate: (Double) -> Boolean): Int {
for (index in indices.reversed()) {
if (predicate(this[index])) {
return index
}
}
return -1
}
/**
* Returns index of the last element matching the given [predicate], or -1 if the array does not contain such element.
*/
public inline fun BooleanArray.indexOfLast(predicate: (Boolean) -> Boolean): Int {
for (index in indices.reversed()) {
if (predicate(this[index])) {
return index
}
}
return -1
}
/**
* Returns index of the last element matching the given [predicate], or -1 if the array does not contain such element.
*/
public inline fun CharArray.indexOfLast(predicate: (Char) -> Boolean): Int {
for (index in indices.reversed()) {
if (predicate(this[index])) {
return index
}
}
return -1
}
/**
* Returns a list containing all elements not matching the given [predicate].
*/
@@ -492,6 +908,253 @@ public inline fun <T> Array<out T>.lastOrNull(predicate: (T) -> Boolean): T? {
return null
}
/**
* Returns the single element, or throws an exception if the array is empty or has more than one element.
*/
public fun <T> Array<out T>.single(): T {
return when (size) {
0 -> throw NoSuchElementException("Array is empty.")
1 -> this[0]
else -> throw IllegalArgumentException("Array has more than one element.")
}
}
/**
* Returns the single element, or throws an exception if the array is empty or has more than one element.
*/
public fun ByteArray.single(): Byte {
return when (size) {
0 -> throw NoSuchElementException("Array is empty.")
1 -> this[0]
else -> throw IllegalArgumentException("Array has more than one element.")
}
}
/**
* Returns the single element, or throws an exception if the array is empty or has more than one element.
*/
public fun ShortArray.single(): Short {
return when (size) {
0 -> throw NoSuchElementException("Array is empty.")
1 -> this[0]
else -> throw IllegalArgumentException("Array has more than one element.")
}
}
/**
* Returns the single element, or throws an exception if the array is empty or has more than one element.
*/
public fun IntArray.single(): Int {
return when (size) {
0 -> throw NoSuchElementException("Array is empty.")
1 -> this[0]
else -> throw IllegalArgumentException("Array has more than one element.")
}
}
/**
* Returns the single element, or throws an exception if the array is empty or has more than one element.
*/
public fun LongArray.single(): Long {
return when (size) {
0 -> throw NoSuchElementException("Array is empty.")
1 -> this[0]
else -> throw IllegalArgumentException("Array has more than one element.")
}
}
/**
* Returns the single element, or throws an exception if the array is empty or has more than one element.
*/
public fun DoubleArray.single(): Double {
return when (size) {
0 -> throw NoSuchElementException("Array is empty.")
1 -> this[0]
else -> throw IllegalArgumentException("Array has more than one element.")
}
}
/**
* Returns the single element, or throws an exception if the array is empty or has more than one element.
*/
public fun BooleanArray.single(): Boolean {
return when (size) {
0 -> throw NoSuchElementException("Array is empty.")
1 -> this[0]
else -> throw IllegalArgumentException("Array has more than one element.")
}
}
/**
* Returns the single element, or throws an exception if the array is empty or has more than one element.
*/
public fun CharArray.single(): Char {
return when (size) {
0 -> throw NoSuchElementException("Array is empty.")
1 -> this[0]
else -> throw IllegalArgumentException("Array has more than one element.")
}
}
/**
* Returns the single element matching the given [predicate], or throws exception if there is no or more than one matching element.
*/
public inline fun <T> Array<out T>.single(predicate: (T) -> Boolean): T {
var single: T? = null
var found = false
for (element in this) {
if (predicate(element)) {
if (found) throw IllegalArgumentException("Array contains more than one matching element.")
single = element
found = true
}
}
if (!found) throw NoSuchElementException("Array contains no element matching the predicate.")
return single as T
}
/**
* Returns the single element matching the given [predicate], or throws exception if there is no or more than one matching element.
*/
public inline fun ByteArray.single(predicate: (Byte) -> Boolean): Byte {
var single: Byte? = null
var found = false
for (element in this) {
if (predicate(element)) {
if (found) throw IllegalArgumentException("Array contains more than one matching element.")
single = element
found = true
}
}
if (!found) throw NoSuchElementException("Array contains no element matching the predicate.")
return single as Byte
}
/**
* Returns the single element matching the given [predicate], or throws exception if there is no or more than one matching element.
*/
public inline fun ShortArray.single(predicate: (Short) -> Boolean): Short {
var single: Short? = null
var found = false
for (element in this) {
if (predicate(element)) {
if (found) throw IllegalArgumentException("Array contains more than one matching element.")
single = element
found = true
}
}
if (!found) throw NoSuchElementException("Array contains no element matching the predicate.")
return single as Short
}
/**
* Returns the single element matching the given [predicate], or throws exception if there is no or more than one matching element.
*/
public inline fun IntArray.single(predicate: (Int) -> Boolean): Int {
var single: Int? = null
var found = false
for (element in this) {
if (predicate(element)) {
if (found) throw IllegalArgumentException("Array contains more than one matching element.")
single = element
found = true
}
}
if (!found) throw NoSuchElementException("Array contains no element matching the predicate.")
return single as Int
}
/**
* Returns the single element matching the given [predicate], or throws exception if there is no or more than one matching element.
*/
public inline fun LongArray.single(predicate: (Long) -> Boolean): Long {
var single: Long? = null
var found = false
for (element in this) {
if (predicate(element)) {
if (found) throw IllegalArgumentException("Array contains more than one matching element.")
single = element
found = true
}
}
if (!found) throw NoSuchElementException("Array contains no element matching the predicate.")
return single as Long
}
/**
* Returns the single element matching the given [predicate], or throws exception if there is no or more than one matching element.
*/
public inline fun FloatArray.single(predicate: (Float) -> Boolean): Float {
var single: Float? = null
var found = false
for (element in this) {
if (predicate(element)) {
if (found) throw IllegalArgumentException("Array contains more than one matching element.")
single = element
found = true
}
}
if (!found) throw NoSuchElementException("Array contains no element matching the predicate.")
return single as Float
}
/**
* Returns the single element matching the given [predicate], or throws exception if there is no or more than one matching element.
*/
public inline fun DoubleArray.single(predicate: (Double) -> Boolean): Double {
var single: Double? = null
var found = false
for (element in this) {
if (predicate(element)) {
if (found) throw IllegalArgumentException("Array contains more than one matching element.")
single = element
found = true
}
}
if (!found) throw NoSuchElementException("Array contains no element matching the predicate.")
return single as Double
}
/**
* Returns the single element matching the given [predicate], or throws exception if there is no or more than one matching element.
*/
public inline fun BooleanArray.single(predicate: (Boolean) -> Boolean): Boolean {
var single: Boolean? = null
var found = false
for (element in this) {
if (predicate(element)) {
if (found) throw IllegalArgumentException("Array contains more than one matching element.")
single = element
found = true
}
}
if (!found) throw NoSuchElementException("Array contains no element matching the predicate.")
return single as Boolean
}
/**
* Returns the single element matching the given [predicate], or throws exception if there is no or more than one matching element.
*/
public inline fun CharArray.single(predicate: (Char) -> Boolean): Char {
var single: Char? = null
var found = false
for (element in this) {
if (predicate(element)) {
if (found) throw IllegalArgumentException("Array contains more than one matching element.")
single = element
found = true
}
}
if (!found) throw NoSuchElementException("Array contains no element matching the predicate.")
return single as Char
}
/**
* Returns single element, or `null` if the array is empty or has more than one element.
*/
public fun <T> Array<out T>.singleOrNull(): T? {
return if (size == 1) this[0] else null
}
/**
* Applies the given [transform] function to each element of the original array
@@ -578,7 +1241,6 @@ public fun Array<out Double>.sum(): Double {
}
// From _Arrays.kt.
/**
* Returns the range of valid indices for the array.
*/
@@ -633,6 +1295,59 @@ public val BooleanArray.indices: IntRange
public val CharArray.indices: IntRange
get() = IntRange(0, lastIndex)
/**
* Returns the last valid index for the array.
*/
public val <T> Array<out T>.lastIndex: Int
get() = size - 1
/**
* Returns the last valid index for the array.
*/
public val ByteArray.lastIndex: Int
get() = size - 1
/**
* Returns the last valid index for the array.
*/
public val ShortArray.lastIndex: Int
get() = size - 1
/**
* Returns the last valid index for the array.
*/
public val IntArray.lastIndex: Int
get() = size - 1
/**
* Returns the last valid index for the array.
*/
public val LongArray.lastIndex: Int
get() = size - 1
/**
* Returns the last valid index for the array.
*/
public val FloatArray.lastIndex: Int
get() = size - 1
/**
* Returns the last valid index for the array.
*/
public val DoubleArray.lastIndex: Int
get() = size - 1
/**
* Returns the last valid index for the array.
*/
public val BooleanArray.lastIndex: Int
get() = size - 1
/**
* Returns the last valid index for the array.
*/
public val CharArray.lastIndex: Int
get() = size - 1
/**
* Returns `true` if the array is empty.
@@ -777,12 +1492,6 @@ public inline fun CharArray.isNotEmpty(): Boolean {
return !isEmpty()
}
/**
* Returns the last valid index for the array.
*/
public val <T> Array<out T>.lastIndex: Int
get() = size - 1
/**
* Returns last index of [element], or -1 if the array does not contain element.
*/
@@ -803,54 +1512,6 @@ public fun <@kotlin.internal.OnlyInputTypes T> Array<out T>.lastIndexOf(element:
return -1
}
/**
* Returns the last valid index for the array.
*/
public val ByteArray.lastIndex: Int
get() = size - 1
/**
* Returns the last valid index for the array.
*/
public val ShortArray.lastIndex: Int
get() = size - 1
/**
* Returns the last valid index for the array.
*/
public val IntArray.lastIndex: Int
get() = size - 1
/**
* Returns the last valid index for the array.
*/
public val LongArray.lastIndex: Int
get() = size - 1
/**
* Returns the last valid index for the array.
*/
public val FloatArray.lastIndex: Int
get() = size - 1
/**
* Returns the last valid index for the array.
*/
public val DoubleArray.lastIndex: Int
get() = size - 1
/**
* Returns the last valid index for the array.
*/
public val BooleanArray.lastIndex: Int
get() = size - 1
/**
* Returns the last valid index for the array.
*/
public val CharArray.lastIndex: Int
get() = size - 1
/**
* Appends all elements to the given [destination] collection.
*/
@@ -298,3 +298,37 @@ private object ReverseOrderComparator: Comparator<Comparable<Any>> {
@Suppress("VIRTUAL_MEMBER_HIDDEN")
fun reversed(): Comparator<Comparable<Any>> = NaturalOrderComparator
}
// From _Comparisions.kt.
/**
* Returns the greater of two values.
* If values are equal, returns the first one.
*/
public fun <T: Comparable<T>> maxOf(a: T, b: T): T {
return if (a >= b) a else b
}
/**
* Returns the greater of two values.
*/
@kotlin.internal.InlineOnly
public inline fun maxOf(a: Int, b: Int): Int {
return if (a >= b) a else b
}
/**
* Returns the smaller of two values.
* If values are equal, returns the first one.
*/
@SinceKotlin("1.1")
public fun <T: Comparable<T>> minOf(a: T, b: T): T {
return if (a <= b) a else b
}
/**
* Returns the smaller of two values.
*/
@kotlin.internal.InlineOnly
public inline fun minOf(a: Int, b: Int): Int {
return if (a <= b) a else b
}
@@ -0,0 +1,81 @@
package kotlin.text
/**
* Returns `true` if this character (Unicode code point) is defined in Unicode.
*/
@SymbolName("Kotlin_Char_isDefined")
external public fun Char.isDefined(): Boolean
/**
* Returns `true` if this character is a letter.
*/
@SymbolName("Kotlin_Char_isLetter")
external public fun Char.isLetter(): Boolean
/**
* Returns `true` if this character is a letter or digit.
*/
@SymbolName("Kotlin_Char_isLetterOrDigit")
external public fun Char.isLetterOrDigit(): Boolean
/**
* Returns `true` if this character (Unicode code point) is a digit.
*/
@SymbolName("Kotlin_Char_isDigit")
external public fun Char.isDigit(): Boolean
/**
* Returns `true` if this character (Unicode code point) should be regarded as an ignorable
* character in a Java identifier or a Unicode identifier.
*/
@SymbolName("Kotlin_Char_isIdentifierIgnorable")
external public fun Char.isIdentifierIgnorable(): Boolean
/**
* Returns `true` if this character is an ISO control character.
*/
@SymbolName("Kotlin_Char_isISOControl")
external public inline fun Char.isISOControl(): Boolean
/**
* Determines whether a character is whitespace according to the Unicode standard.
* Returns `true` if the character is whitespace.
*/
@SymbolName("Kotlin_Char_isWhitespace")
external public fun Char.isWhitespace(): Boolean
/**
* Returns `true` if this character is upper case.
*/
@SymbolName("Kotlin_Char_isUpperCase")
external public fun Char.isUpperCase(): Boolean
/**
* Returns `true` if this character is lower case.
*/
@SymbolName("Kotlin_Char_isLowerCase")
external public fun Char.isLowerCase(): Boolean
/**
* Converts this character to uppercase.
*/
@SymbolName("Kotlin_Char_toUpperCase")
external public fun Char.toUpperCase(): Char
/**
* Converts this character to lowercase.
*/
@SymbolName("Kotlin_Char_toLowerCase")
external public fun Char.toLowerCase(): Char
/**
* Returns `true` if this character is a Unicode high-surrogate code unit (also known as leading-surrogate code unit).
*/
@SymbolName("Kotlin_Char_isHighSurrogate")
external public fun Char.isHighSurrogate(): Boolean
/**
* Returns `true` if this character is a Unicode low-surrogate code unit (also known as trailing-surrogate code unit).
*/
@SymbolName("Kotlin_Char_isLowSurrogate")
external public fun Char.isLowSurrogate(): Boolean
File diff suppressed because it is too large Load Diff