Add some string operations, refactor runtime. (#249)
This commit is contained in:
@@ -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())
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -304,8 +304,10 @@ extern "C" {
|
||||
return result; \
|
||||
}
|
||||
|
||||
void InitMemory();
|
||||
void DeinitMemory();
|
||||
struct MemoryState;
|
||||
|
||||
MemoryState* InitMemory();
|
||||
void DeinitMemory(MemoryState*);
|
||||
|
||||
//
|
||||
// Object allocation.
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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"
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
Reference in New Issue
Block a user