From 5d13b1681fb04e52b4be11738e12812e8e4ec042 Mon Sep 17 00:00:00 2001 From: Ilya Gorbunov Date: Fri, 16 Mar 2018 22:11:56 +0300 Subject: [PATCH] Refactor: extract JVM API into separate files Increase visibility to internal for: - copyToArrayOfAny - UNINITIALIZED_VALUE - InitializedLazyImpl Change file classes to multifile: - LazyKt - GroupingKt - IntrinsicsKt (coroutines) --- .../src/kotlin/collections/Collections.kt | 36 --- .../src/kotlin/collections/CollectionsJVM.kt | 49 +++ .../stdlib/src/kotlin/collections/Grouping.kt | 45 +-- .../src/kotlin/collections/GroupingJVM.kt | 55 ++++ .../src/kotlin/collections/Iterators.kt | 10 - .../src/kotlin/collections/IteratorsJVM.kt | 20 ++ .../stdlib/src/kotlin/collections/Maps.kt | 21 -- .../stdlib/src/kotlin/collections/MapsJVM.kt | 22 ++ .../kotlin/collections/MutableCollections.kt | 76 ----- .../collections/MutableCollectionsJVM.kt | 87 +++++ .../src/kotlin/collections/Sequences.kt | 18 -- .../src/kotlin/collections/SequencesJVM.kt | 30 ++ .../stdlib/src/kotlin/collections/Sets.kt | 21 -- .../stdlib/src/kotlin/collections/SetsJVM.kt | 31 ++ .../experimental/intrinsics/Intrinsics.kt | 73 +---- .../experimental/intrinsics/IntrinsicsJvm.kt | 76 +++++ libraries/stdlib/src/kotlin/ranges/Ranges.kt | 40 --- .../stdlib/src/kotlin/ranges/RangesJVM.kt | 52 +++ .../stdlib/src/kotlin/text/StringBuilder.kt | 6 - .../src/kotlin/text/StringBuilderJVM.kt | 8 + .../kotlin/text/StringNumberConversions.kt | 286 +---------------- .../kotlin/text/StringNumberConversionsJVM.kt | 300 ++++++++++++++++++ .../src/kotlin/text/regex/RegexExtensions.kt | 9 - .../kotlin/text/regex/RegexExtensionsJVM.kt | 19 ++ libraries/stdlib/src/kotlin/util/Lazy.kt | 127 +------- libraries/stdlib/src/kotlin/util/LazyJVM.kt | 135 ++++++++ 26 files changed, 893 insertions(+), 759 deletions(-) create mode 100644 libraries/stdlib/src/kotlin/collections/CollectionsJVM.kt create mode 100644 libraries/stdlib/src/kotlin/collections/GroupingJVM.kt create mode 100644 libraries/stdlib/src/kotlin/collections/IteratorsJVM.kt create mode 100644 libraries/stdlib/src/kotlin/collections/MutableCollectionsJVM.kt create mode 100644 libraries/stdlib/src/kotlin/collections/SequencesJVM.kt create mode 100644 libraries/stdlib/src/kotlin/collections/SetsJVM.kt create mode 100644 libraries/stdlib/src/kotlin/ranges/RangesJVM.kt create mode 100644 libraries/stdlib/src/kotlin/text/StringNumberConversionsJVM.kt create mode 100644 libraries/stdlib/src/kotlin/text/regex/RegexExtensionsJVM.kt create mode 100644 libraries/stdlib/src/kotlin/util/LazyJVM.kt diff --git a/libraries/stdlib/src/kotlin/collections/Collections.kt b/libraries/stdlib/src/kotlin/collections/Collections.kt index 454c9ef2f48..5e123a58184 100644 --- a/libraries/stdlib/src/kotlin/collections/Collections.kt +++ b/libraries/stdlib/src/kotlin/collections/Collections.kt @@ -92,14 +92,6 @@ public fun listOf(vararg elements: T): List = if (elements.size > 0) elem @kotlin.internal.InlineOnly public inline fun listOf(): List = emptyList() -/** - * Returns an immutable list containing only the specified object [element]. - * The returned list is serializable. - * @sample samples.collections.Collections.Lists.singletonReadOnlyList - */ -@JvmVersion -public fun listOf(element: T): List = java.util.Collections.singletonList(element) - /** * Returns an empty new [MutableList]. * @sample samples.collections.Collections.Lists.emptyMutableList @@ -200,15 +192,6 @@ public inline fun Collection?.orEmpty(): Collection = this ?: emptyLis @kotlin.internal.InlineOnly public inline fun List?.orEmpty(): List = this ?: emptyList() -/** - * Returns a list containing the elements returned by this enumeration - * in the order they are returned by the enumeration. - * @sample samples.collections.Collections.Lists.listFromEnumeration - */ -@JvmVersion -@kotlin.internal.InlineOnly -public inline fun java.util.Enumeration.toList(): List = java.util.Collections.list(this) - /** * Checks if all elements in the specified collection are contained in this collection. * @@ -225,25 +208,6 @@ internal fun List.optimizeReadOnlyList() = when (size) { else -> this } -@JvmVersion -@kotlin.internal.InlineOnly -internal inline fun copyToArrayImpl(collection: Collection<*>): Array = - kotlin.jvm.internal.collectionToArray(collection) - -@JvmVersion -@kotlin.internal.InlineOnly -internal inline fun copyToArrayImpl(collection: Collection<*>, array: Array): Array = - kotlin.jvm.internal.collectionToArray(collection, array as Array) as Array - -// copies typed varargs array to array of objects -@JvmVersion -private fun Array.copyToArrayOfAny(isVarargs: Boolean): Array = - if (isVarargs && this.javaClass == Array::class.java) - // if the array came from varargs and already is array of Any, copying isn't required - @Suppress("UNCHECKED_CAST") (this as Array) - else - java.util.Arrays.copyOf(this, this.size, Array::class.java) - /** * Searches this list or its range for the provided [element] using the binary search algorithm. * The list is expected to be sorted into ascending order according to the Comparable natural ordering of its elements, diff --git a/libraries/stdlib/src/kotlin/collections/CollectionsJVM.kt b/libraries/stdlib/src/kotlin/collections/CollectionsJVM.kt new file mode 100644 index 00000000000..781f3c18325 --- /dev/null +++ b/libraries/stdlib/src/kotlin/collections/CollectionsJVM.kt @@ -0,0 +1,49 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +@file:kotlin.jvm.JvmMultifileClass +@file:kotlin.jvm.JvmName("CollectionsKt") + +package kotlin.collections + +import kotlin.* + +/** + * Returns an immutable list containing only the specified object [element]. + * The returned list is serializable. + * @sample samples.collections.Collections.Lists.singletonReadOnlyList + */ +@JvmVersion +public fun listOf(element: T): List = java.util.Collections.singletonList(element) + + +/** + * Returns a list containing the elements returned by this enumeration + * in the order they are returned by the enumeration. + * @sample samples.collections.Collections.Lists.listFromEnumeration + */ +@JvmVersion +@kotlin.internal.InlineOnly +public inline fun java.util.Enumeration.toList(): List = java.util.Collections.list(this) + + +@JvmVersion +@kotlin.internal.InlineOnly +internal inline fun copyToArrayImpl(collection: Collection<*>): Array = + kotlin.jvm.internal.collectionToArray(collection) + +@JvmVersion +@kotlin.internal.InlineOnly +internal inline fun copyToArrayImpl(collection: Collection<*>, array: Array): Array = + kotlin.jvm.internal.collectionToArray(collection, array as Array) as Array + +// copies typed varargs array to array of objects +@JvmVersion +internal fun Array.copyToArrayOfAny(isVarargs: Boolean): Array = + if (isVarargs && this.javaClass == Array::class.java) + // if the array came from varargs and already is array of Any, copying isn't required + @Suppress("UNCHECKED_CAST") (this as Array) + else + java.util.Arrays.copyOf(this, this.size, Array::class.java) diff --git a/libraries/stdlib/src/kotlin/collections/Grouping.kt b/libraries/stdlib/src/kotlin/collections/Grouping.kt index 484bdec6b6f..0763e5bae24 100644 --- a/libraries/stdlib/src/kotlin/collections/Grouping.kt +++ b/libraries/stdlib/src/kotlin/collections/Grouping.kt @@ -1,3 +1,6 @@ +@file:kotlin.jvm.JvmName("GroupingKt") +@file:kotlin.jvm.JvmMultifileClass + package kotlin.collections /** @@ -226,22 +229,6 @@ public inline fun > Grouping.reduceTo } -/** - * Groups elements from the [Grouping] source by key and counts elements in each group. - * - * @return a [Map] associating the key of each group with the count of elements in the group. - * - * @sample samples.collections.Collections.Transformations.groupingByEachCount - */ -@SinceKotlin("1.1") -@JvmVersion -public fun Grouping.eachCount(): Map = - // fold(0) { acc, e -> acc + 1 } optimized for boxing - foldTo( destination = mutableMapOf(), - initialValueSelector = { _, _ -> kotlin.jvm.internal.Ref.IntRef() }, - operation = { _, acc, _ -> acc.apply { element += 1 } }) - .mapValuesInPlace { it.value.element } - /** * Groups elements from the [Grouping] source by key and counts elements in each group to the given [destination] map. * @@ -256,21 +243,7 @@ public fun Grouping.eachCount(): Map = public fun > Grouping.eachCountTo(destination: M): M = foldTo(destination, 0) { acc, _ -> acc + 1 } -/** -/** - * Groups elements from the [Grouping] source by key and sums values provided by the [valueSelector] function for elements in each group. - * - * @return a [Map] associating the key of each group with the sum of elements in the group. - */ -@SinceKotlin("1.1") -@JvmVersion -public inline fun Grouping.eachSumOf(valueSelector: (T) -> Int): Map = - // fold(0) { acc, e -> acc + valueSelector(e)} optimized for boxing - foldTo( destination = mutableMapOf(), - initialValueSelector = { _, _ -> kotlin.jvm.internal.Ref.IntRef() }, - operation = { _, acc, e -> acc.apply { element += valueSelector(e) } }) - .mapValuesInPlace { it.value.element } - +/* /** * Groups elements from the [Grouping] source by key and sums values provided by the [valueSelector] function for elements in each group * to the given [destination] map. @@ -286,16 +259,6 @@ public inline fun > Grouping.eachSumOfTo(d foldTo(destination, 0) { acc, e -> acc + valueSelector(e)} */ -@JvmVersion -@PublishedApi -@kotlin.internal.InlineOnly -@Suppress("UNCHECKED_CAST") // tricks with erased generics go here, do not repeat at reified platforms -internal inline fun MutableMap.mapValuesInPlace(f: (Map.Entry) -> R): MutableMap { - entries.forEach { - (it as MutableMap.MutableEntry).setValue(f(it)) - } - return (this as MutableMap) -} /* // TODO: sum by long and by double overloads diff --git a/libraries/stdlib/src/kotlin/collections/GroupingJVM.kt b/libraries/stdlib/src/kotlin/collections/GroupingJVM.kt new file mode 100644 index 00000000000..cbef4f6f713 --- /dev/null +++ b/libraries/stdlib/src/kotlin/collections/GroupingJVM.kt @@ -0,0 +1,55 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +@file:kotlin.jvm.JvmName("GroupingKt") +@file:kotlin.jvm.JvmMultifileClass + +package kotlin.collections + + +/** + * Groups elements from the [Grouping] source by key and counts elements in each group. + * + * @return a [Map] associating the key of each group with the count of elements in the group. + * + * @sample samples.collections.Collections.Transformations.groupingByEachCount + */ +@SinceKotlin("1.1") +@JvmVersion +public fun Grouping.eachCount(): Map = +// fold(0) { acc, e -> acc + 1 } optimized for boxing + foldTo(destination = mutableMapOf(), + initialValueSelector = { _, _ -> kotlin.jvm.internal.Ref.IntRef() }, + operation = { _, acc, _ -> acc.apply { element += 1 } }) + .mapValuesInPlace { it.value.element } + +/* +/** + * Groups elements from the [Grouping] source by key and sums values provided by the [valueSelector] function for elements in each group. + * + * @return a [Map] associating the key of each group with the sum of elements in the group. + */ +@SinceKotlin("1.X") +@JvmVersion +public inline fun Grouping.eachSumOf(valueSelector: (T) -> Int): Map = + // fold(0) { acc, e -> acc + valueSelector(e)} optimized for boxing + foldTo( destination = mutableMapOf(), + initialValueSelector = { _, _ -> kotlin.jvm.internal.Ref.IntRef() }, + operation = { _, acc, e -> acc.apply { element += valueSelector(e) } }) + .mapValuesInPlace { it.value.element } +*/ + + + +@JvmVersion +@PublishedApi +@kotlin.internal.InlineOnly +@Suppress("UNCHECKED_CAST") // tricks with erased generics go here, do not repeat on reified platforms +internal inline fun MutableMap.mapValuesInPlace(f: (Map.Entry) -> R): MutableMap { + entries.forEach { + (it as MutableMap.MutableEntry).setValue(f(it)) + } + return (this as MutableMap) +} \ No newline at end of file diff --git a/libraries/stdlib/src/kotlin/collections/Iterators.kt b/libraries/stdlib/src/kotlin/collections/Iterators.kt index 51ed1c524be..257fa47a449 100644 --- a/libraries/stdlib/src/kotlin/collections/Iterators.kt +++ b/libraries/stdlib/src/kotlin/collections/Iterators.kt @@ -3,16 +3,6 @@ package kotlin.collections -/** - * Creates an [Iterator] for an [java.util.Enumeration], allowing to use it in `for` loops. - * @sample samples.collections.Iterators.iteratorForEnumeration - */ -@kotlin.jvm.JvmVersion -public operator fun java.util.Enumeration.iterator(): Iterator = object : Iterator { - override fun hasNext(): Boolean = hasMoreElements() - - public override fun next(): T = nextElement() -} /** * Returns the given iterator itself. This allows to use an instance of iterator in a `for` loop. diff --git a/libraries/stdlib/src/kotlin/collections/IteratorsJVM.kt b/libraries/stdlib/src/kotlin/collections/IteratorsJVM.kt new file mode 100644 index 00000000000..dc56a0e32b4 --- /dev/null +++ b/libraries/stdlib/src/kotlin/collections/IteratorsJVM.kt @@ -0,0 +1,20 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +@file:kotlin.jvm.JvmMultifileClass +@file:kotlin.jvm.JvmName("CollectionsKt") + +package kotlin.collections + +/** + * Creates an [Iterator] for an [java.util.Enumeration], allowing to use it in `for` loops. + * @sample samples.collections.Iterators.iteratorForEnumeration + */ +@kotlin.jvm.JvmVersion +public operator fun java.util.Enumeration.iterator(): Iterator = object : Iterator { + override fun hasNext(): Boolean = hasMoreElements() + + public override fun next(): T = nextElement() +} diff --git a/libraries/stdlib/src/kotlin/collections/Maps.kt b/libraries/stdlib/src/kotlin/collections/Maps.kt index f1213339bc1..553dc360690 100644 --- a/libraries/stdlib/src/kotlin/collections/Maps.kt +++ b/libraries/stdlib/src/kotlin/collections/Maps.kt @@ -54,17 +54,6 @@ public fun mapOf(vararg pairs: Pair): Map = if (pairs.size > @kotlin.internal.InlineOnly public inline fun mapOf(): Map = emptyMap() -/** - * Returns an immutable map, mapping only the specified key to the - * specified value. - * - * The returned map is serializable. - * - * @sample samples.collections.Maps.Instantiation.mapFromPairs - */ -@JvmVersion -public fun mapOf(pair: Pair): Map = java.util.Collections.singletonMap(pair.first, pair.second) - /** * Returns an empty new [MutableMap]. * @@ -705,13 +694,3 @@ internal fun Map.optimizeReadOnlyMap() = when (size) { 1 -> toSingletonMapOrSelf() else -> this } - -// creates a singleton copy of map, if there is specialization available in target platform, otherwise returns itself -@kotlin.jvm.JvmVersion -@kotlin.internal.InlineOnly -internal inline fun Map.toSingletonMapOrSelf(): Map = toSingletonMap() - -// creates a singleton copy of map -@kotlin.jvm.JvmVersion -internal fun Map.toSingletonMap(): Map - = with (entries.iterator().next()) { java.util.Collections.singletonMap(key, value) } diff --git a/libraries/stdlib/src/kotlin/collections/MapsJVM.kt b/libraries/stdlib/src/kotlin/collections/MapsJVM.kt index 3d7e1c44118..7744fc66360 100644 --- a/libraries/stdlib/src/kotlin/collections/MapsJVM.kt +++ b/libraries/stdlib/src/kotlin/collections/MapsJVM.kt @@ -12,6 +12,17 @@ import java.util.TreeMap import java.util.concurrent.ConcurrentMap +/** + * Returns an immutable map, mapping only the specified key to the + * specified value. + * + * The returned map is serializable. + * + * @sample samples.collections.Maps.Instantiation.mapFromPairs + */ +@JvmVersion +public fun mapOf(pair: Pair): Map = java.util.Collections.singletonMap(pair.first, pair.second) + /** * Concurrent getOrPut, that is safe for concurrent maps. @@ -65,3 +76,14 @@ public fun , V> sortedMapOf(vararg pairs: Pair): SortedM public inline fun Map.toProperties(): Properties = Properties().apply { putAll(this@toProperties) } + +// creates a singleton copy of map, if there is specialization available in target platform, otherwise returns itself +@kotlin.jvm.JvmVersion +@kotlin.internal.InlineOnly +internal inline fun Map.toSingletonMapOrSelf(): Map = toSingletonMap() + +// creates a singleton copy of map +@kotlin.jvm.JvmVersion +internal fun Map.toSingletonMap(): Map + = with (entries.iterator().next()) { java.util.Collections.singletonMap(key, value) } + diff --git a/libraries/stdlib/src/kotlin/collections/MutableCollections.kt b/libraries/stdlib/src/kotlin/collections/MutableCollections.kt index e0a7f9f1986..a5d9d3b0c8e 100644 --- a/libraries/stdlib/src/kotlin/collections/MutableCollections.kt +++ b/libraries/stdlib/src/kotlin/collections/MutableCollections.kt @@ -45,18 +45,6 @@ public inline fun <@kotlin.internal.OnlyInputTypes T> MutableCollection.r @kotlin.internal.InlineOnly public inline fun MutableList.remove(index: Int): T = removeAt(index) -@Deprecated("Use sortWith(comparator) instead.", ReplaceWith("this.sortWith(comparator)"), level = DeprecationLevel.ERROR) -@JvmVersion -@kotlin.internal.InlineOnly -@Suppress("UNUSED_PARAMETER") -public inline fun MutableList.sort(comparator: Comparator): Unit = throw NotImplementedError() - -@Deprecated("Use sortWith(Comparator(comparison)) instead.", ReplaceWith("this.sortWith(Comparator(comparison))"), level = DeprecationLevel.ERROR) -@JvmVersion -@kotlin.internal.InlineOnly -@Suppress("UNUSED_PARAMETER") -public inline fun MutableList.sort(comparison: (T, T) -> Int): Unit = throw NotImplementedError() - /** * Adds the specified [element] to this mutable collection. */ @@ -267,67 +255,3 @@ private fun MutableCollection<*>.retainNothing(): Boolean { clear() return result } - -/** - * Sorts elements in the list in-place according to their natural sort order. - */ -@kotlin.jvm.JvmVersion -public fun > MutableList.sort(): Unit { - if (size > 1) java.util.Collections.sort(this) -} - -/** - * Sorts elements in the list in-place according to the order specified with [comparator]. - */ -@kotlin.jvm.JvmVersion -public fun MutableList.sortWith(comparator: Comparator): Unit { - if (size > 1) java.util.Collections.sort(this, comparator) -} - -/** - * Fills the list with the provided [value]. - * - * Each element in the list gets replaced with the [value]. - */ -@kotlin.jvm.JvmVersion -@kotlin.internal.InlineOnly -@SinceKotlin("1.2") -public inline fun MutableList.fill(value: T) { - java.util.Collections.fill(this, value) -} - - -/** - * Randomly shuffles elements in this mutable list. - */ -@kotlin.jvm.JvmVersion -@kotlin.internal.InlineOnly -@SinceKotlin("1.2") -public inline fun MutableList.shuffle() { - java.util.Collections.shuffle(this) -} - -/** - * Randomly shuffles elements in this mutable list using the specified [random] instance as the source of randomness. - */ -@kotlin.jvm.JvmVersion -@kotlin.internal.InlineOnly -@SinceKotlin("1.2") -public inline fun MutableList.shuffle(random: java.util.Random) { - java.util.Collections.shuffle(this, random) -} - -/** - * Returns a new list with the elements of this list randomly shuffled. - */ -@kotlin.jvm.JvmVersion -@SinceKotlin("1.2") -public fun Iterable.shuffled(): List = toMutableList().apply { shuffle() } - -/** - * Returns a new list with the elements of this list randomly shuffled - * using the specified [random] instance as the source of randomness. - */ -@kotlin.jvm.JvmVersion -@SinceKotlin("1.2") -public fun Iterable.shuffled(random: java.util.Random): List = toMutableList().apply { shuffle(random) } diff --git a/libraries/stdlib/src/kotlin/collections/MutableCollectionsJVM.kt b/libraries/stdlib/src/kotlin/collections/MutableCollectionsJVM.kt new file mode 100644 index 00000000000..2f5ae2cc2c1 --- /dev/null +++ b/libraries/stdlib/src/kotlin/collections/MutableCollectionsJVM.kt @@ -0,0 +1,87 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +@file:kotlin.jvm.JvmMultifileClass +@file:kotlin.jvm.JvmName("CollectionsKt") + +package kotlin.collections + + +@Deprecated("Use sortWith(comparator) instead.", ReplaceWith("this.sortWith(comparator)"), level = DeprecationLevel.ERROR) +@JvmVersion +@kotlin.internal.InlineOnly +@Suppress("UNUSED_PARAMETER") +public inline fun MutableList.sort(comparator: Comparator): Unit = throw NotImplementedError() + +@Deprecated("Use sortWith(Comparator(comparison)) instead.", ReplaceWith("this.sortWith(Comparator(comparison))"), level = DeprecationLevel.ERROR) +@JvmVersion +@kotlin.internal.InlineOnly +@Suppress("UNUSED_PARAMETER") +public inline fun MutableList.sort(comparison: (T, T) -> Int): Unit = throw NotImplementedError() + + +/** + * Sorts elements in the list in-place according to their natural sort order. + */ +@kotlin.jvm.JvmVersion +public fun > MutableList.sort(): Unit { + if (size > 1) java.util.Collections.sort(this) +} + +/** + * Sorts elements in the list in-place according to the order specified with [comparator]. + */ +@kotlin.jvm.JvmVersion +public fun MutableList.sortWith(comparator: Comparator): Unit { + if (size > 1) java.util.Collections.sort(this, comparator) +} + +/** + * Fills the list with the provided [value]. + * + * Each element in the list gets replaced with the [value]. + */ +@kotlin.jvm.JvmVersion +@kotlin.internal.InlineOnly +@SinceKotlin("1.2") +public inline fun MutableList.fill(value: T) { + java.util.Collections.fill(this, value) +} + + +/** + * Randomly shuffles elements in this mutable list. + */ +@kotlin.jvm.JvmVersion +@kotlin.internal.InlineOnly +@SinceKotlin("1.2") +public inline fun MutableList.shuffle() { + java.util.Collections.shuffle(this) +} + +/** + * Randomly shuffles elements in this mutable list using the specified [random] instance as the source of randomness. + */ +@kotlin.jvm.JvmVersion +@kotlin.internal.InlineOnly +@SinceKotlin("1.2") +public inline fun MutableList.shuffle(random: java.util.Random) { + java.util.Collections.shuffle(this, random) +} + +/** + * Returns a new list with the elements of this list randomly shuffled. + */ +@kotlin.jvm.JvmVersion +@SinceKotlin("1.2") +public fun Iterable.shuffled(): List = toMutableList().apply { shuffle() } + +/** + * Returns a new list with the elements of this list randomly shuffled + * using the specified [random] instance as the source of randomness. + */ +@kotlin.jvm.JvmVersion +@SinceKotlin("1.2") +public fun Iterable.shuffled(random: java.util.Random): List = toMutableList().apply { shuffle(random) } diff --git a/libraries/stdlib/src/kotlin/collections/Sequences.kt b/libraries/stdlib/src/kotlin/collections/Sequences.kt index 81e77377a1c..73fdb46b785 100644 --- a/libraries/stdlib/src/kotlin/collections/Sequences.kt +++ b/libraries/stdlib/src/kotlin/collections/Sequences.kt @@ -22,14 +22,6 @@ public inline fun Sequence(crossinline iterator: () -> Iterator): Sequenc */ public fun Iterator.asSequence(): Sequence = Sequence { this }.constrainOnce() -/** - * Creates a sequence that returns all values from this enumeration. The sequence is constrained to be iterated only once. - * @sample samples.collections.Sequences.Building.sequenceFromEnumeration - */ -@kotlin.jvm.JvmVersion -@kotlin.internal.InlineOnly -public inline fun java.util.Enumeration.asSequence(): Sequence = this.iterator().asSequence() - /** * Creates a sequence that returns the specified values. * @@ -553,16 +545,6 @@ public fun Sequence.constrainOnce(): Sequence { return if (this is ConstrainedOnceSequence) this else ConstrainedOnceSequence(this) } -@kotlin.jvm.JvmVersion -private class ConstrainedOnceSequence(sequence: Sequence) : Sequence { - private val sequenceRef = java.util.concurrent.atomic.AtomicReference(sequence) - - override fun iterator(): Iterator { - val sequence = sequenceRef.getAndSet(null) ?: throw IllegalStateException("This sequence can be consumed only once.") - return sequence.iterator() - } -} - /** diff --git a/libraries/stdlib/src/kotlin/collections/SequencesJVM.kt b/libraries/stdlib/src/kotlin/collections/SequencesJVM.kt new file mode 100644 index 00000000000..969b38a26c7 --- /dev/null +++ b/libraries/stdlib/src/kotlin/collections/SequencesJVM.kt @@ -0,0 +1,30 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +@file:kotlin.jvm.JvmMultifileClass +@file:kotlin.jvm.JvmName("SequencesKt") + +package kotlin.sequences + +import kotlin.* + +/** + * Creates a sequence that returns all values from this enumeration. The sequence is constrained to be iterated only once. + * @sample samples.collections.Sequences.Building.sequenceFromEnumeration + */ +@kotlin.jvm.JvmVersion +@kotlin.internal.InlineOnly +public inline fun java.util.Enumeration.asSequence(): Sequence = this.iterator().asSequence() + + +@kotlin.jvm.JvmVersion +internal class ConstrainedOnceSequence(sequence: Sequence) : Sequence { + private val sequenceRef = java.util.concurrent.atomic.AtomicReference(sequence) + + override fun iterator(): Iterator { + val sequence = sequenceRef.getAndSet(null) ?: throw IllegalStateException("This sequence can be consumed only once.") + return sequence.iterator() + } +} diff --git a/libraries/stdlib/src/kotlin/collections/Sets.kt b/libraries/stdlib/src/kotlin/collections/Sets.kt index 1825d213b3c..dd4530dd064 100644 --- a/libraries/stdlib/src/kotlin/collections/Sets.kt +++ b/libraries/stdlib/src/kotlin/collections/Sets.kt @@ -79,27 +79,6 @@ public fun linkedSetOf(vararg elements: T): LinkedHashSet = elements.toCo @kotlin.internal.InlineOnly public inline fun Set?.orEmpty(): Set = this ?: emptySet() -/** - * Returns an immutable set containing only the specified object [element]. - * The returned set is serializable. - */ -@JvmVersion -public fun setOf(element: T): Set = java.util.Collections.singleton(element) - - -/** - * Returns a new [java.util.SortedSet] with the given elements. - */ -@JvmVersion -public fun sortedSetOf(vararg elements: T): java.util.TreeSet = elements.toCollection(java.util.TreeSet()) - -/** - * Returns a new [java.util.SortedSet] with the given [comparator] and elements. - */ -@JvmVersion -public fun sortedSetOf(comparator: Comparator, vararg elements: T): java.util.TreeSet = elements.toCollection(java.util.TreeSet(comparator)) - - internal fun Set.optimizeReadOnlySet() = when (size) { 0 -> emptySet() 1 -> setOf(iterator().next()) diff --git a/libraries/stdlib/src/kotlin/collections/SetsJVM.kt b/libraries/stdlib/src/kotlin/collections/SetsJVM.kt new file mode 100644 index 00000000000..9c3faa6cd7f --- /dev/null +++ b/libraries/stdlib/src/kotlin/collections/SetsJVM.kt @@ -0,0 +1,31 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +@file:kotlin.jvm.JvmMultifileClass +@file:kotlin.jvm.JvmName("SetsKt") + +package kotlin.collections + + +/** + * Returns an immutable set containing only the specified object [element]. + * The returned set is serializable. + */ +@JvmVersion +public fun setOf(element: T): Set = java.util.Collections.singleton(element) + + +/** + * Returns a new [java.util.SortedSet] with the given elements. + */ +@JvmVersion +public fun sortedSetOf(vararg elements: T): java.util.TreeSet = elements.toCollection(java.util.TreeSet()) + +/** + * Returns a new [java.util.SortedSet] with the given [comparator] and elements. + */ +@JvmVersion +public fun sortedSetOf(comparator: Comparator, vararg elements: T): java.util.TreeSet = elements.toCollection(java.util.TreeSet(comparator)) + diff --git a/libraries/stdlib/src/kotlin/coroutines/experimental/intrinsics/Intrinsics.kt b/libraries/stdlib/src/kotlin/coroutines/experimental/intrinsics/Intrinsics.kt index aebb2009d8c..a0cb4d93eb8 100644 --- a/libraries/stdlib/src/kotlin/coroutines/experimental/intrinsics/Intrinsics.kt +++ b/libraries/stdlib/src/kotlin/coroutines/experimental/intrinsics/Intrinsics.kt @@ -15,6 +15,7 @@ */ @file:kotlin.jvm.JvmName("IntrinsicsKt") +@file:kotlin.jvm.JvmMultifileClass package kotlin.coroutines.experimental.intrinsics @@ -89,75 +90,3 @@ public suspend inline val coroutineContext: CoroutineContext @SinceKotlin("1.1") public val COROUTINE_SUSPENDED: Any = Any() -// JVM declarations - -/** - * Creates a coroutine without receiver and with result type [T]. - * This function creates a new, fresh instance of suspendable computation every time it is invoked. - * - * To start executing the created coroutine, invoke `resume(Unit)` on the returned [Continuation] instance. - * The [completion] continuation is invoked when coroutine completes with result or exception. - * - * This function is _unchecked_. Repeated invocation of any resume function on the resulting continuation corrupts the - * state machine of the coroutine and may result in arbitrary behaviour or exception. - */ -@SinceKotlin("1.1") -@kotlin.jvm.JvmVersion -public fun (suspend () -> T).createCoroutineUnchecked( - completion: Continuation -): Continuation = - if (this !is kotlin.coroutines.experimental.jvm.internal.CoroutineImpl) - buildContinuationByInvokeCall(completion) { - @Suppress("UNCHECKED_CAST") - (this as Function1, Any?>).invoke(completion) - } - else - (this.create(completion) as kotlin.coroutines.experimental.jvm.internal.CoroutineImpl).facade - -/** - * Creates a coroutine with receiver type [R] and result type [T]. - * This function creates a new, fresh instance of suspendable computation every time it is invoked. - * - * To start executing the created coroutine, invoke `resume(Unit)` on the returned [Continuation] instance. - * The [completion] continuation is invoked when coroutine completes with result or exception. - * - * This function is _unchecked_. Repeated invocation of any resume function on the resulting continuation corrupts the - * state machine of the coroutine and may result in arbitrary behaviour or exception. - */ -@SinceKotlin("1.1") -@kotlin.jvm.JvmVersion -public fun (suspend R.() -> T).createCoroutineUnchecked( - receiver: R, - completion: Continuation -): Continuation = - if (this !is kotlin.coroutines.experimental.jvm.internal.CoroutineImpl) - buildContinuationByInvokeCall(completion) { - @Suppress("UNCHECKED_CAST") - (this as Function2, Any?>).invoke(receiver, completion) - } - else - (this.create(receiver, completion) as kotlin.coroutines.experimental.jvm.internal.CoroutineImpl).facade - -// INTERNAL DEFINITIONS - -@kotlin.jvm.JvmVersion -private inline fun buildContinuationByInvokeCall( - completion: Continuation, - crossinline block: () -> Any? -): Continuation { - val continuation = - object : Continuation { - override val context: CoroutineContext - get() = completion.context - - override fun resume(value: Unit) { - processBareContinuationResume(completion, block) - } - - override fun resumeWithException(exception: Throwable) { - completion.resumeWithException(exception) - } - } - - return kotlin.coroutines.experimental.jvm.internal.interceptContinuationIfNeeded(completion.context, continuation) -} diff --git a/libraries/stdlib/src/kotlin/coroutines/experimental/intrinsics/IntrinsicsJvm.kt b/libraries/stdlib/src/kotlin/coroutines/experimental/intrinsics/IntrinsicsJvm.kt index f51c8ce0ebe..5d6b8287bea 100644 --- a/libraries/stdlib/src/kotlin/coroutines/experimental/intrinsics/IntrinsicsJvm.kt +++ b/libraries/stdlib/src/kotlin/coroutines/experimental/intrinsics/IntrinsicsJvm.kt @@ -14,6 +14,8 @@ * limitations under the License. */ +@file:kotlin.jvm.JvmName("IntrinsicsKt") +@file:kotlin.jvm.JvmMultifileClass @file:kotlin.jvm.JvmVersion package kotlin.coroutines.experimental.intrinsics import kotlin.coroutines.experimental.* @@ -46,3 +48,77 @@ public inline fun (suspend R.() -> T).startCoroutineUninterceptedOrReturn receiver: R, completion: Continuation ): Any? = (this as Function2, Any?>).invoke(receiver, completion) + + +// JVM declarations + +/** + * Creates a coroutine without receiver and with result type [T]. + * This function creates a new, fresh instance of suspendable computation every time it is invoked. + * + * To start executing the created coroutine, invoke `resume(Unit)` on the returned [Continuation] instance. + * The [completion] continuation is invoked when coroutine completes with result or exception. + * + * This function is _unchecked_. Repeated invocation of any resume function on the resulting continuation corrupts the + * state machine of the coroutine and may result in arbitrary behaviour or exception. + */ +@SinceKotlin("1.1") +@kotlin.jvm.JvmVersion +public fun (suspend () -> T).createCoroutineUnchecked( + completion: Continuation +): Continuation = + if (this !is kotlin.coroutines.experimental.jvm.internal.CoroutineImpl) + buildContinuationByInvokeCall(completion) { + @Suppress("UNCHECKED_CAST") + (this as Function1, Any?>).invoke(completion) + } + else + (this.create(completion) as kotlin.coroutines.experimental.jvm.internal.CoroutineImpl).facade + +/** + * Creates a coroutine with receiver type [R] and result type [T]. + * This function creates a new, fresh instance of suspendable computation every time it is invoked. + * + * To start executing the created coroutine, invoke `resume(Unit)` on the returned [Continuation] instance. + * The [completion] continuation is invoked when coroutine completes with result or exception. + * + * This function is _unchecked_. Repeated invocation of any resume function on the resulting continuation corrupts the + * state machine of the coroutine and may result in arbitrary behaviour or exception. + */ +@SinceKotlin("1.1") +@kotlin.jvm.JvmVersion +public fun (suspend R.() -> T).createCoroutineUnchecked( + receiver: R, + completion: Continuation +): Continuation = + if (this !is kotlin.coroutines.experimental.jvm.internal.CoroutineImpl) + buildContinuationByInvokeCall(completion) { + @Suppress("UNCHECKED_CAST") + (this as Function2, Any?>).invoke(receiver, completion) + } + else + (this.create(receiver, completion) as kotlin.coroutines.experimental.jvm.internal.CoroutineImpl).facade + +// INTERNAL DEFINITIONS + +@kotlin.jvm.JvmVersion +private inline fun buildContinuationByInvokeCall( + completion: Continuation, + crossinline block: () -> Any? +): Continuation { + val continuation = + object : Continuation { + override val context: CoroutineContext + get() = completion.context + + override fun resume(value: Unit) { + processBareContinuationResume(completion, block) + } + + override fun resumeWithException(exception: Throwable) { + completion.resumeWithException(exception) + } + } + + return kotlin.coroutines.experimental.jvm.internal.interceptContinuationIfNeeded(completion.context, continuation) +} diff --git a/libraries/stdlib/src/kotlin/ranges/Ranges.kt b/libraries/stdlib/src/kotlin/ranges/Ranges.kt index eb6af2c70b5..d72850c8172 100644 --- a/libraries/stdlib/src/kotlin/ranges/Ranges.kt +++ b/libraries/stdlib/src/kotlin/ranges/Ranges.kt @@ -70,36 +70,6 @@ private class ClosedDoubleRange ( override fun toString(): String = "$_start..$_endInclusive" } -/** - * A closed range of values of type `Float`. - * - * Numbers are compared with the ends of this range according to IEEE-754. - */ -@JvmVersion -private class ClosedFloatRange ( - start: Float, - endInclusive: Float -): ClosedFloatingPointRange { - private val _start = start - private val _endInclusive = endInclusive - override val start: Float get() = _start - override val endInclusive: Float get() = _endInclusive - - override fun lessThanOrEquals(a: Float, b: Float): Boolean = a <= b - - override fun contains(value: Float): Boolean = value >= _start && value <= _endInclusive - override fun isEmpty(): Boolean = !(_start <= _endInclusive) - - override fun equals(other: Any?): Boolean { - return other is ClosedFloatRange && (isEmpty() && other.isEmpty() || - _start == other._start && _endInclusive == other._endInclusive) - } - - override fun hashCode(): Int { - return if (isEmpty()) -1 else 31 * _start.hashCode() + _endInclusive.hashCode() - } - override fun toString(): String = "$_start..$_endInclusive" -} /** * Creates a range from this [Comparable] value to the specified [that] value. @@ -118,16 +88,6 @@ public operator fun > T.rangeTo(that: T): ClosedRange = Comp @SinceKotlin("1.1") public operator fun Double.rangeTo(that: Double): ClosedFloatingPointRange = ClosedDoubleRange(this, that) -/** - * Creates a range from this [Float] value to the specified [that] value. - * - * Numbers are compared with the ends of this range according to IEEE-754. - * @sample samples.ranges.Ranges.rangeFromFloat - */ -@JvmVersion -@SinceKotlin("1.1") -public operator fun Float.rangeTo(that: Float): ClosedFloatingPointRange = ClosedFloatRange(this, that) - internal fun checkStepIsPositive(isPositive: Boolean, step: Number) { if (!isPositive) throw IllegalArgumentException("Step must be positive, was: $step.") diff --git a/libraries/stdlib/src/kotlin/ranges/RangesJVM.kt b/libraries/stdlib/src/kotlin/ranges/RangesJVM.kt new file mode 100644 index 00000000000..5474e5012e2 --- /dev/null +++ b/libraries/stdlib/src/kotlin/ranges/RangesJVM.kt @@ -0,0 +1,52 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +@file:kotlin.jvm.JvmMultifileClass +@file:kotlin.jvm.JvmName("RangesKt") +package kotlin.ranges + +import kotlin.* + +/** + * A closed range of values of type `Float`. + * + * Numbers are compared with the ends of this range according to IEEE-754. + */ +@JvmVersion +private class ClosedFloatRange ( + start: Float, + endInclusive: Float +): ClosedFloatingPointRange { + private val _start = start + private val _endInclusive = endInclusive + override val start: Float get() = _start + override val endInclusive: Float get() = _endInclusive + + override fun lessThanOrEquals(a: Float, b: Float): Boolean = a <= b + + override fun contains(value: Float): Boolean = value >= _start && value <= _endInclusive + override fun isEmpty(): Boolean = !(_start <= _endInclusive) + + override fun equals(other: Any?): Boolean { + return other is ClosedFloatRange && (isEmpty() && other.isEmpty() || + _start == other._start && _endInclusive == other._endInclusive) + } + + override fun hashCode(): Int { + return if (isEmpty()) -1 else 31 * _start.hashCode() + _endInclusive.hashCode() + } + override fun toString(): String = "$_start..$_endInclusive" +} + +/** + * Creates a range from this [Float] value to the specified [that] value. + * + * Numbers are compared with the ends of this range according to IEEE-754. + * @sample samples.ranges.Ranges.rangeFromFloat + */ +@JvmVersion +@SinceKotlin("1.1") +public operator fun Float.rangeTo(that: Float): ClosedFloatingPointRange = ClosedFloatRange(this, that) + diff --git a/libraries/stdlib/src/kotlin/text/StringBuilder.kt b/libraries/stdlib/src/kotlin/text/StringBuilder.kt index 0a09255c81f..7a65922a5fb 100644 --- a/libraries/stdlib/src/kotlin/text/StringBuilder.kt +++ b/libraries/stdlib/src/kotlin/text/StringBuilder.kt @@ -47,12 +47,6 @@ public fun StringBuilder.append(vararg value: Any?): StringBuilder { return this } -/** - * Sets the character at the specified [index] to the specified [value]. - */ -@kotlin.jvm.JvmVersion -@kotlin.internal.InlineOnly -public inline operator fun StringBuilder.set(index: Int, value: Char): Unit = this.setCharAt(index, value) internal fun Appendable.appendElement(element: T, transform: ((T) -> CharSequence)?) { diff --git a/libraries/stdlib/src/kotlin/text/StringBuilderJVM.kt b/libraries/stdlib/src/kotlin/text/StringBuilderJVM.kt index cb836dd45d9..5683022fef4 100644 --- a/libraries/stdlib/src/kotlin/text/StringBuilderJVM.kt +++ b/libraries/stdlib/src/kotlin/text/StringBuilderJVM.kt @@ -4,6 +4,14 @@ package kotlin.text +/** + * Sets the character at the specified [index] to the specified [value]. + */ +@kotlin.jvm.JvmVersion +@kotlin.internal.InlineOnly +public inline operator fun StringBuilder.set(index: Int, value: Char): Unit = this.setCharAt(index, value) + + private object SystemProperties { /** Line separator for current system. */ @JvmField diff --git a/libraries/stdlib/src/kotlin/text/StringNumberConversions.kt b/libraries/stdlib/src/kotlin/text/StringNumberConversions.kt index ff9be401164..362c6a11b0d 100644 --- a/libraries/stdlib/src/kotlin/text/StringNumberConversions.kt +++ b/libraries/stdlib/src/kotlin/text/StringNumberConversions.kt @@ -20,141 +20,7 @@ package kotlin.text -/** - * Returns a string representation of this [Byte] value in the specified [radix]. - * - * @throws IllegalArgumentException when [radix] is not a valid radix for number to string conversion. - */ -@SinceKotlin("1.1") -@kotlin.jvm.JvmVersion -@kotlin.internal.InlineOnly -public inline fun Byte.toString(radix: Int): String = this.toInt().toString(checkRadix(radix)) - -/** - * Returns a string representation of this [Short] value in the specified [radix]. - * - * @throws IllegalArgumentException when [radix] is not a valid radix for number to string conversion. - */ -@SinceKotlin("1.1") -@kotlin.jvm.JvmVersion -@kotlin.internal.InlineOnly -public inline fun Short.toString(radix: Int): String = this.toInt().toString(checkRadix(radix)) - -/** - * Returns a string representation of this [Int] value in the specified [radix]. - * - * @throws IllegalArgumentException when [radix] is not a valid radix for number to string conversion. - */ -@SinceKotlin("1.1") -@kotlin.jvm.JvmVersion -@kotlin.internal.InlineOnly -public inline fun Int.toString(radix: Int): String = java.lang.Integer.toString(this, checkRadix(radix)) - -/** - * Returns a string representation of this [Long] value in the specified [radix]. - * - * @throws IllegalArgumentException when [radix] is not a valid radix for number to string conversion. - */ -@SinceKotlin("1.1") -@kotlin.jvm.JvmVersion -@kotlin.internal.InlineOnly -public inline fun Long.toString(radix: Int): String = java.lang.Long.toString(this, checkRadix(radix)) - -/** - * Returns `true` if the contents of this string is equal to the word "true", ignoring case, and `false` otherwise. - */ -@kotlin.jvm.JvmVersion -@kotlin.internal.InlineOnly -public inline fun String.toBoolean(): Boolean = java.lang.Boolean.parseBoolean(this) - -/** - * Parses the string as a signed [Byte] number and returns the result. - * @throws NumberFormatException if the string is not a valid representation of a number. - */ -@kotlin.jvm.JvmVersion -@kotlin.internal.InlineOnly -public inline fun String.toByte(): Byte = java.lang.Byte.parseByte(this) - -/** - * Parses the string as a signed [Byte] number and returns the result. - * @throws NumberFormatException if the string is not a valid representation of a number. - * @throws IllegalArgumentException when [radix] is not a valid radix for string to number conversion. - */ -@SinceKotlin("1.1") -@kotlin.jvm.JvmVersion -@kotlin.internal.InlineOnly -public inline fun String.toByte(radix: Int): Byte = java.lang.Byte.parseByte(this, checkRadix(radix)) - - -/** - * Parses the string as a [Short] number and returns the result. - * @throws NumberFormatException if the string is not a valid representation of a number. - */ -@kotlin.jvm.JvmVersion -@kotlin.internal.InlineOnly -public inline fun String.toShort(): Short = java.lang.Short.parseShort(this) - -/** - * Parses the string as a [Short] number and returns the result. - * @throws NumberFormatException if the string is not a valid representation of a number. - * @throws IllegalArgumentException when [radix] is not a valid radix for string to number conversion. - */ -@SinceKotlin("1.1") -@kotlin.jvm.JvmVersion -@kotlin.internal.InlineOnly -public inline fun String.toShort(radix: Int): Short = java.lang.Short.parseShort(this, checkRadix(radix)) - -/** - * Parses the string as an [Int] number and returns the result. - * @throws NumberFormatException if the string is not a valid representation of a number. - */ -@kotlin.jvm.JvmVersion -@kotlin.internal.InlineOnly -public inline fun String.toInt(): Int = java.lang.Integer.parseInt(this) - -/** - * Parses the string as an [Int] number and returns the result. - * @throws NumberFormatException if the string is not a valid representation of a number. - * @throws IllegalArgumentException when [radix] is not a valid radix for string to number conversion. - */ -@SinceKotlin("1.1") -@kotlin.jvm.JvmVersion -@kotlin.internal.InlineOnly -public inline fun String.toInt(radix: Int): Int = java.lang.Integer.parseInt(this, checkRadix(radix)) - -/** - * Parses the string as a [Long] number and returns the result. - * @throws NumberFormatException if the string is not a valid representation of a number. - */ -@kotlin.jvm.JvmVersion -@kotlin.internal.InlineOnly -public inline fun String.toLong(): Long = java.lang.Long.parseLong(this) - -/** - * Parses the string as a [Long] number and returns the result. - * @throws NumberFormatException if the string is not a valid representation of a number. - * @throws IllegalArgumentException when [radix] is not a valid radix for string to number conversion. - */ -@SinceKotlin("1.1") -@kotlin.jvm.JvmVersion -@kotlin.internal.InlineOnly -public inline fun String.toLong(radix: Int): Long = java.lang.Long.parseLong(this, checkRadix(radix)) - -/** - * Parses the string as a [Float] number and returns the result. - * @throws NumberFormatException if the string is not a valid representation of a number. - */ -@kotlin.jvm.JvmVersion -@kotlin.internal.InlineOnly -public inline fun String.toFloat(): Float = java.lang.Float.parseFloat(this) - -/** - * Parses the string as a [Double] number and returns the result. - * @throws NumberFormatException if the string is not a valid representation of a number. - */ -@kotlin.jvm.JvmVersion -@kotlin.internal.InlineOnly -public inline fun String.toDouble(): Double = java.lang.Double.parseDouble(this) +import kotlin.* @@ -323,153 +189,3 @@ public fun String.toLongOrNull(radix: Int): Long? { return if (isNegative) result else -result } - -/** - * Parses the string as a [Float] number and returns the result - * or `null` if the string is not a valid representation of a number. - */ -@SinceKotlin("1.1") -@kotlin.jvm.JvmVersion -public fun String.toFloatOrNull(): Float? = screenFloatValue(this, java.lang.Float::parseFloat) - -/** - * Parses the string as a [Double] number and returns the result - * or `null` if the string is not a valid representation of a number. - */ -@SinceKotlin("1.1") -@kotlin.jvm.JvmVersion -public fun String.toDoubleOrNull(): Double? = screenFloatValue(this, java.lang.Double::parseDouble) - -/** - * Parses the string as a [java.math.BigInteger] number and returns the result. - * @throws NumberFormatException if the string is not a valid representation of a number. - */ -@SinceKotlin("1.2") -@kotlin.jvm.JvmVersion -@kotlin.internal.InlineOnly -public inline fun String.toBigInteger(): java.math.BigInteger = - java.math.BigInteger(this) - -/** - * Parses the string as a [java.math.BigInteger] number and returns the result. - * @throws NumberFormatException if the string is not a valid representation of a number. - * @throws IllegalArgumentException when [radix] is not a valid radix for string to number conversion. - */ -@SinceKotlin("1.2") -@kotlin.jvm.JvmVersion -@kotlin.internal.InlineOnly -public inline fun String.toBigInteger(radix: Int): java.math.BigInteger = - java.math.BigInteger(this, checkRadix(radix)) - -/** - * Parses the string as a [java.math.BigInteger] number and returns the result - * or `null` if the string is not a valid representation of a number. - */ -@SinceKotlin("1.2") -@kotlin.jvm.JvmVersion -public fun String.toBigIntegerOrNull(): java.math.BigInteger? = toBigIntegerOrNull(10) - -/** - * Parses the string as a [java.math.BigInteger] number and returns the result - * or `null` if the string is not a valid representation of a number. - * - * @throws IllegalArgumentException when [radix] is not a valid radix for string to number conversion. - */ -@SinceKotlin("1.2") -@kotlin.jvm.JvmVersion -public fun String.toBigIntegerOrNull(radix: Int): java.math.BigInteger? { - checkRadix(radix) - val length = this.length - when (length) { - 0 -> return null - 1 -> if (digitOf(this[0], radix) < 0) return null - else -> { - val start = if (this[0] == '-') 1 else 0 - for (index in start until length) { - if (digitOf(this[index], radix) < 0) - return null - } - } - } - return toBigInteger(radix) -} - - -/** - * Parses the string as a [java.math.BigDecimal] number and returns the result. - * @throws NumberFormatException if the string is not a valid representation of a number. - */ -@SinceKotlin("1.2") -@kotlin.jvm.JvmVersion -@kotlin.internal.InlineOnly -public inline fun String.toBigDecimal(): java.math.BigDecimal = - java.math.BigDecimal(this) - -/** - * Parses the string as a [java.math.BigDecimal] number and returns the result. - * @throws NumberFormatException if the string is not a valid representation of a number. - * - * @param mathContext specifies the precision and the rounding mode. - * @throws ArithmeticException if the rounding is needed, but the rounding mode is [java.math.RoundingMode.UNNECESSARY]. - */ -@SinceKotlin("1.2") -@kotlin.jvm.JvmVersion -@kotlin.internal.InlineOnly -public inline fun String.toBigDecimal(mathContext: java.math.MathContext): java.math.BigDecimal = - java.math.BigDecimal(this, mathContext) - -/** - * Parses the string as a [java.math.BigDecimal] number and returns the result - * or `null` if the string is not a valid representation of a number. - */ -@SinceKotlin("1.2") -@kotlin.jvm.JvmVersion -public fun String.toBigDecimalOrNull(): java.math.BigDecimal? = - screenFloatValue(this) { it.toBigDecimal() } - -/** - * Parses the string as a [java.math.BigDecimal] number and returns the result - * or `null` if the string is not a valid representation of a number. - * - * @param mathContext specifies the precision and the rounding mode. - * @throws ArithmeticException if the rounding is needed, but the rounding mode is [java.math.RoundingMode.UNNECESSARY]. - */ -@SinceKotlin("1.2") -@kotlin.jvm.JvmVersion -public fun String.toBigDecimalOrNull(mathContext: java.math.MathContext): java.math.BigDecimal? = - screenFloatValue(this) { it.toBigDecimal(mathContext) } - -/** - * Recommended floating point number validation RegEx from the javadoc of `java.lang.Double.valueOf(String)` - */ -@kotlin.jvm.JvmVersion -private object ScreenFloatValueRegEx { - @JvmField val value = run { - val Digits = "(\\p{Digit}+)" - val HexDigits = "(\\p{XDigit}+)" - val Exp = "[eE][+-]?$Digits" - - val HexString = "(0[xX]$HexDigits(\\.)?)|" + // 0[xX] HexDigits ._opt BinaryExponent FloatTypeSuffix_opt - "(0[xX]$HexDigits?(\\.)$HexDigits)" // 0[xX] HexDigits_opt . HexDigits BinaryExponent FloatTypeSuffix_opt - - val Number = "($Digits(\\.)?($Digits?)($Exp)?)|" + // Digits ._opt Digits_opt ExponentPart_opt FloatTypeSuffix_opt - "(\\.($Digits)($Exp)?)|" + // . Digits ExponentPart_opt FloatTypeSuffix_opt - "(($HexString)[pP][+-]?$Digits)" // HexSignificand BinaryExponent - - val fpRegex = "[\\x00-\\x20]*[+-]?(NaN|Infinity|(($Number)[fFdD]?))[\\x00-\\x20]*" - - Regex(fpRegex) - } -} - -@kotlin.jvm.JvmVersion -private inline fun screenFloatValue(str: String, parse: (String) -> T): T? { - return try { - if (ScreenFloatValueRegEx.value.matches(str)) - parse(str) - else - null - } catch(e: NumberFormatException) { // overflow - null - } -} diff --git a/libraries/stdlib/src/kotlin/text/StringNumberConversionsJVM.kt b/libraries/stdlib/src/kotlin/text/StringNumberConversionsJVM.kt new file mode 100644 index 00000000000..2372e9e82d1 --- /dev/null +++ b/libraries/stdlib/src/kotlin/text/StringNumberConversionsJVM.kt @@ -0,0 +1,300 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +@file:kotlin.jvm.JvmMultifileClass +@file:kotlin.jvm.JvmName("StringsKt") +@file:Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN") + +package kotlin.text + +import kotlin.* + + +/** + * Returns a string representation of this [Byte] value in the specified [radix]. + * + * @throws IllegalArgumentException when [radix] is not a valid radix for number to string conversion. + */ +@SinceKotlin("1.1") +@kotlin.jvm.JvmVersion +@kotlin.internal.InlineOnly +public inline fun Byte.toString(radix: Int): String = this.toInt().toString(checkRadix(radix)) + +/** + * Returns a string representation of this [Short] value in the specified [radix]. + * + * @throws IllegalArgumentException when [radix] is not a valid radix for number to string conversion. + */ +@SinceKotlin("1.1") +@kotlin.jvm.JvmVersion +@kotlin.internal.InlineOnly +public inline fun Short.toString(radix: Int): String = this.toInt().toString(checkRadix(radix)) + +/** + * Returns a string representation of this [Int] value in the specified [radix]. + * + * @throws IllegalArgumentException when [radix] is not a valid radix for number to string conversion. + */ +@SinceKotlin("1.1") +@kotlin.jvm.JvmVersion +@kotlin.internal.InlineOnly +public inline fun Int.toString(radix: Int): String = java.lang.Integer.toString(this, checkRadix(radix)) + +/** + * Returns a string representation of this [Long] value in the specified [radix]. + * + * @throws IllegalArgumentException when [radix] is not a valid radix for number to string conversion. + */ +@SinceKotlin("1.1") +@kotlin.jvm.JvmVersion +@kotlin.internal.InlineOnly +public inline fun Long.toString(radix: Int): String = java.lang.Long.toString(this, checkRadix(radix)) + +/** + * Returns `true` if the contents of this string is equal to the word "true", ignoring case, and `false` otherwise. + */ +@kotlin.jvm.JvmVersion +@kotlin.internal.InlineOnly +public inline fun String.toBoolean(): Boolean = java.lang.Boolean.parseBoolean(this) + +/** + * Parses the string as a signed [Byte] number and returns the result. + * @throws NumberFormatException if the string is not a valid representation of a number. + */ +@kotlin.jvm.JvmVersion +@kotlin.internal.InlineOnly +public inline fun String.toByte(): Byte = java.lang.Byte.parseByte(this) + +/** + * Parses the string as a signed [Byte] number and returns the result. + * @throws NumberFormatException if the string is not a valid representation of a number. + * @throws IllegalArgumentException when [radix] is not a valid radix for string to number conversion. + */ +@SinceKotlin("1.1") +@kotlin.jvm.JvmVersion +@kotlin.internal.InlineOnly +public inline fun String.toByte(radix: Int): Byte = java.lang.Byte.parseByte(this, checkRadix(radix)) + + +/** + * Parses the string as a [Short] number and returns the result. + * @throws NumberFormatException if the string is not a valid representation of a number. + */ +@kotlin.jvm.JvmVersion +@kotlin.internal.InlineOnly +public inline fun String.toShort(): Short = java.lang.Short.parseShort(this) + +/** + * Parses the string as a [Short] number and returns the result. + * @throws NumberFormatException if the string is not a valid representation of a number. + * @throws IllegalArgumentException when [radix] is not a valid radix for string to number conversion. + */ +@SinceKotlin("1.1") +@kotlin.jvm.JvmVersion +@kotlin.internal.InlineOnly +public inline fun String.toShort(radix: Int): Short = java.lang.Short.parseShort(this, checkRadix(radix)) + +/** + * Parses the string as an [Int] number and returns the result. + * @throws NumberFormatException if the string is not a valid representation of a number. + */ +@kotlin.jvm.JvmVersion +@kotlin.internal.InlineOnly +public inline fun String.toInt(): Int = java.lang.Integer.parseInt(this) + +/** + * Parses the string as an [Int] number and returns the result. + * @throws NumberFormatException if the string is not a valid representation of a number. + * @throws IllegalArgumentException when [radix] is not a valid radix for string to number conversion. + */ +@SinceKotlin("1.1") +@kotlin.jvm.JvmVersion +@kotlin.internal.InlineOnly +public inline fun String.toInt(radix: Int): Int = java.lang.Integer.parseInt(this, checkRadix(radix)) + +/** + * Parses the string as a [Long] number and returns the result. + * @throws NumberFormatException if the string is not a valid representation of a number. + */ +@kotlin.jvm.JvmVersion +@kotlin.internal.InlineOnly +public inline fun String.toLong(): Long = java.lang.Long.parseLong(this) + +/** + * Parses the string as a [Long] number and returns the result. + * @throws NumberFormatException if the string is not a valid representation of a number. + * @throws IllegalArgumentException when [radix] is not a valid radix for string to number conversion. + */ +@SinceKotlin("1.1") +@kotlin.jvm.JvmVersion +@kotlin.internal.InlineOnly +public inline fun String.toLong(radix: Int): Long = java.lang.Long.parseLong(this, checkRadix(radix)) + +/** + * Parses the string as a [Float] number and returns the result. + * @throws NumberFormatException if the string is not a valid representation of a number. + */ +@kotlin.jvm.JvmVersion +@kotlin.internal.InlineOnly +public inline fun String.toFloat(): Float = java.lang.Float.parseFloat(this) + +/** + * Parses the string as a [Double] number and returns the result. + * @throws NumberFormatException if the string is not a valid representation of a number. + */ +@kotlin.jvm.JvmVersion +@kotlin.internal.InlineOnly +public inline fun String.toDouble(): Double = java.lang.Double.parseDouble(this) + + +/** + * Parses the string as a [Float] number and returns the result + * or `null` if the string is not a valid representation of a number. + */ +@SinceKotlin("1.1") +@kotlin.jvm.JvmVersion +public fun String.toFloatOrNull(): Float? = screenFloatValue(this, java.lang.Float::parseFloat) + +/** + * Parses the string as a [Double] number and returns the result + * or `null` if the string is not a valid representation of a number. + */ +@SinceKotlin("1.1") +@kotlin.jvm.JvmVersion +public fun String.toDoubleOrNull(): Double? = screenFloatValue(this, java.lang.Double::parseDouble) + +/** + * Parses the string as a [java.math.BigInteger] number and returns the result. + * @throws NumberFormatException if the string is not a valid representation of a number. + */ +@SinceKotlin("1.2") +@kotlin.jvm.JvmVersion +@kotlin.internal.InlineOnly +public inline fun String.toBigInteger(): java.math.BigInteger = + java.math.BigInteger(this) + +/** + * Parses the string as a [java.math.BigInteger] number and returns the result. + * @throws NumberFormatException if the string is not a valid representation of a number. + * @throws IllegalArgumentException when [radix] is not a valid radix for string to number conversion. + */ +@SinceKotlin("1.2") +@kotlin.jvm.JvmVersion +@kotlin.internal.InlineOnly +public inline fun String.toBigInteger(radix: Int): java.math.BigInteger = + java.math.BigInteger(this, checkRadix(radix)) + +/** + * Parses the string as a [java.math.BigInteger] number and returns the result + * or `null` if the string is not a valid representation of a number. + */ +@SinceKotlin("1.2") +@kotlin.jvm.JvmVersion +public fun String.toBigIntegerOrNull(): java.math.BigInteger? = toBigIntegerOrNull(10) + +/** + * Parses the string as a [java.math.BigInteger] number and returns the result + * or `null` if the string is not a valid representation of a number. + * + * @throws IllegalArgumentException when [radix] is not a valid radix for string to number conversion. + */ +@SinceKotlin("1.2") +@kotlin.jvm.JvmVersion +public fun String.toBigIntegerOrNull(radix: Int): java.math.BigInteger? { + checkRadix(radix) + val length = this.length + when (length) { + 0 -> return null + 1 -> if (digitOf(this[0], radix) < 0) return null + else -> { + val start = if (this[0] == '-') 1 else 0 + for (index in start until length) { + if (digitOf(this[index], radix) < 0) + return null + } + } + } + return toBigInteger(radix) +} + + +/** + * Parses the string as a [java.math.BigDecimal] number and returns the result. + * @throws NumberFormatException if the string is not a valid representation of a number. + */ +@SinceKotlin("1.2") +@kotlin.jvm.JvmVersion +@kotlin.internal.InlineOnly +public inline fun String.toBigDecimal(): java.math.BigDecimal = + java.math.BigDecimal(this) + +/** + * Parses the string as a [java.math.BigDecimal] number and returns the result. + * @throws NumberFormatException if the string is not a valid representation of a number. + * + * @param mathContext specifies the precision and the rounding mode. + * @throws ArithmeticException if the rounding is needed, but the rounding mode is [java.math.RoundingMode.UNNECESSARY]. + */ +@SinceKotlin("1.2") +@kotlin.jvm.JvmVersion +@kotlin.internal.InlineOnly +public inline fun String.toBigDecimal(mathContext: java.math.MathContext): java.math.BigDecimal = + java.math.BigDecimal(this, mathContext) + +/** + * Parses the string as a [java.math.BigDecimal] number and returns the result + * or `null` if the string is not a valid representation of a number. + */ +@SinceKotlin("1.2") +@kotlin.jvm.JvmVersion +public fun String.toBigDecimalOrNull(): java.math.BigDecimal? = + screenFloatValue(this) { it.toBigDecimal() } + +/** + * Parses the string as a [java.math.BigDecimal] number and returns the result + * or `null` if the string is not a valid representation of a number. + * + * @param mathContext specifies the precision and the rounding mode. + * @throws ArithmeticException if the rounding is needed, but the rounding mode is [java.math.RoundingMode.UNNECESSARY]. + */ +@SinceKotlin("1.2") +@kotlin.jvm.JvmVersion +public fun String.toBigDecimalOrNull(mathContext: java.math.MathContext): java.math.BigDecimal? = + screenFloatValue(this) { it.toBigDecimal(mathContext) } + +/** + * Recommended floating point number validation RegEx from the javadoc of `java.lang.Double.valueOf(String)` + */ +@kotlin.jvm.JvmVersion +private object ScreenFloatValueRegEx { + @JvmField val value = run { + val Digits = "(\\p{Digit}+)" + val HexDigits = "(\\p{XDigit}+)" + val Exp = "[eE][+-]?$Digits" + + val HexString = "(0[xX]$HexDigits(\\.)?)|" + // 0[xX] HexDigits ._opt BinaryExponent FloatTypeSuffix_opt + "(0[xX]$HexDigits?(\\.)$HexDigits)" // 0[xX] HexDigits_opt . HexDigits BinaryExponent FloatTypeSuffix_opt + + val Number = "($Digits(\\.)?($Digits?)($Exp)?)|" + // Digits ._opt Digits_opt ExponentPart_opt FloatTypeSuffix_opt + "(\\.($Digits)($Exp)?)|" + // . Digits ExponentPart_opt FloatTypeSuffix_opt + "(($HexString)[pP][+-]?$Digits)" // HexSignificand BinaryExponent + + val fpRegex = "[\\x00-\\x20]*[+-]?(NaN|Infinity|(($Number)[fFdD]?))[\\x00-\\x20]*" + + Regex(fpRegex) + } +} + +@kotlin.jvm.JvmVersion +private inline fun screenFloatValue(str: String, parse: (String) -> T): T? { + return try { + if (ScreenFloatValueRegEx.value.matches(str)) + parse(str) + else + null + } catch(e: NumberFormatException) { // overflow + null + } +} diff --git a/libraries/stdlib/src/kotlin/text/regex/RegexExtensions.kt b/libraries/stdlib/src/kotlin/text/regex/RegexExtensions.kt index c1d38bcbc1c..3968e8ce31c 100644 --- a/libraries/stdlib/src/kotlin/text/regex/RegexExtensions.kt +++ b/libraries/stdlib/src/kotlin/text/regex/RegexExtensions.kt @@ -20,12 +20,3 @@ public inline fun String.toRegex(option: RegexOption): Regex = Regex(this, optio */ @kotlin.internal.InlineOnly public inline fun String.toRegex(options: Set): Regex = Regex(this, options) - -/** - * Converts this [java.util.regex.Pattern] to an instance of [Regex]. - * - * Provides the way to use Regex API on the instances of [java.util.regex.Pattern]. - */ -@JvmVersion -@kotlin.internal.InlineOnly -public inline fun java.util.regex.Pattern.toRegex(): Regex = Regex(this) \ No newline at end of file diff --git a/libraries/stdlib/src/kotlin/text/regex/RegexExtensionsJVM.kt b/libraries/stdlib/src/kotlin/text/regex/RegexExtensionsJVM.kt new file mode 100644 index 00000000000..970026d1a29 --- /dev/null +++ b/libraries/stdlib/src/kotlin/text/regex/RegexExtensionsJVM.kt @@ -0,0 +1,19 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +@file:kotlin.jvm.JvmMultifileClass +@file:kotlin.jvm.JvmName("StringsKt") + +package kotlin.text + + +/** + * Converts this [java.util.regex.Pattern] to an instance of [Regex]. + * + * Provides the way to use Regex API on the instances of [java.util.regex.Pattern]. + */ +@JvmVersion +@kotlin.internal.InlineOnly +public inline fun java.util.regex.Pattern.toRegex(): Regex = Regex(this) \ No newline at end of file diff --git a/libraries/stdlib/src/kotlin/util/Lazy.kt b/libraries/stdlib/src/kotlin/util/Lazy.kt index a7e52850d9f..a0b79e8eebf 100644 --- a/libraries/stdlib/src/kotlin/util/Lazy.kt +++ b/libraries/stdlib/src/kotlin/util/Lazy.kt @@ -1,4 +1,5 @@ @file:kotlin.jvm.JvmName("LazyKt") +@file:kotlin.jvm.JvmMultifileClass package kotlin @@ -27,50 +28,6 @@ public interface Lazy { */ public fun lazyOf(value: T): Lazy = InitializedLazyImpl(value) -/** - * Creates a new instance of the [Lazy] that uses the specified initialization function [initializer] - * and the default thread-safety mode [LazyThreadSafetyMode.SYNCHRONIZED]. - * - * If the initialization of a value throws an exception, it will attempt to reinitialize the value at next access. - * - * Note that the returned instance uses itself to synchronize on. Do not synchronize from external code on - * the returned instance as it may cause accidental deadlock. Also this behavior can be changed in the future. - */ -@kotlin.jvm.JvmVersion -public fun lazy(initializer: () -> T): Lazy = SynchronizedLazyImpl(initializer) - -/** - * Creates a new instance of the [Lazy] that uses the specified initialization function [initializer] - * and thread-safety [mode]. - * - * If the initialization of a value throws an exception, it will attempt to reinitialize the value at next access. - * - * Note that when the [LazyThreadSafetyMode.SYNCHRONIZED] mode is specified the returned instance uses itself - * to synchronize on. Do not synchronize from external code on the returned instance as it may cause accidental deadlock. - * Also this behavior can be changed in the future. - */ -@kotlin.jvm.JvmVersion -public fun lazy(mode: LazyThreadSafetyMode, initializer: () -> T): Lazy = - when (mode) { - LazyThreadSafetyMode.SYNCHRONIZED -> SynchronizedLazyImpl(initializer) - LazyThreadSafetyMode.PUBLICATION -> SafePublicationLazyImpl(initializer) - LazyThreadSafetyMode.NONE -> UnsafeLazyImpl(initializer) - } - -/** - * Creates a new instance of the [Lazy] that uses the specified initialization function [initializer] - * and the default thread-safety mode [LazyThreadSafetyMode.SYNCHRONIZED]. - * - * If the initialization of a value throws an exception, it will attempt to reinitialize the value at next access. - * - * The returned instance uses the specified [lock] object to synchronize on. - * When the [lock] is not specified the instance uses itself to synchronize on, - * in this case do not synchronize from external code on the returned instance as it may cause accidental deadlock. - * Also this behavior can be changed in the future. - */ -@kotlin.jvm.JvmVersion -public fun lazy(lock: Any?, initializer: () -> T): Lazy = SynchronizedLazyImpl(initializer, lock) - /** * An extension to delegate a read-only property of type [T] to an instance of [Lazy]. * @@ -105,43 +62,7 @@ public enum class LazyThreadSafetyMode { } -private object UNINITIALIZED_VALUE - -@JvmVersion -private class SynchronizedLazyImpl(initializer: () -> T, lock: Any? = null) : Lazy, Serializable { - private var initializer: (() -> T)? = initializer - @Volatile private var _value: Any? = UNINITIALIZED_VALUE - // final field is required to enable safe publication of constructed instance - private val lock = lock ?: this - - override val value: T - get() { - val _v1 = _value - if (_v1 !== UNINITIALIZED_VALUE) { - @Suppress("UNCHECKED_CAST") - return _v1 as T - } - - return synchronized(lock) { - val _v2 = _value - if (_v2 !== UNINITIALIZED_VALUE) { - @Suppress("UNCHECKED_CAST") (_v2 as T) - } - else { - val typedValue = initializer!!() - _value = typedValue - initializer = null - typedValue - } - } - } - - override fun isInitialized(): Boolean = _value !== UNINITIALIZED_VALUE - - override fun toString(): String = if (isInitialized()) value.toString() else "Lazy value not initialized yet." - - private fun writeReplace(): Any = InitializedLazyImpl(value) -} +internal object UNINITIALIZED_VALUE // internal to be called from lazy in JS internal class UnsafeLazyImpl(initializer: () -> T) : Lazy, Serializable { @@ -165,52 +86,10 @@ internal class UnsafeLazyImpl(initializer: () -> T) : Lazy, Serializab private fun writeReplace(): Any = InitializedLazyImpl(value) } -private class InitializedLazyImpl(override val value: T) : Lazy, Serializable { +internal class InitializedLazyImpl(override val value: T) : Lazy, Serializable { override fun isInitialized(): Boolean = true override fun toString(): String = value.toString() } - -@kotlin.jvm.JvmVersion -private class SafePublicationLazyImpl(initializer: () -> T) : Lazy, Serializable { - @Volatile private var initializer: (() -> T)? = initializer - @Volatile private var _value: Any? = UNINITIALIZED_VALUE - // this final field is required to enable safe publication of constructed instance - private val final: Any = UNINITIALIZED_VALUE - - override val value: T - get() { - val value = _value - if (value !== UNINITIALIZED_VALUE) { - @Suppress("UNCHECKED_CAST") - return value as T - } - - val initializerValue = initializer - // if we see null in initializer here, it means that the value is already set by another thread - if (initializerValue != null) { - val newValue = initializerValue() - if (valueUpdater.compareAndSet(this, UNINITIALIZED_VALUE, newValue)) { - initializer = null - return newValue - } - } - @Suppress("UNCHECKED_CAST") - return _value as T - } - - override fun isInitialized(): Boolean = _value !== UNINITIALIZED_VALUE - - override fun toString(): String = if (isInitialized()) value.toString() else "Lazy value not initialized yet." - - private fun writeReplace(): Any = InitializedLazyImpl(value) - - companion object { - private val valueUpdater = java.util.concurrent.atomic.AtomicReferenceFieldUpdater.newUpdater( - SafePublicationLazyImpl::class.java, - Any::class.java, - "_value") - } -} \ No newline at end of file diff --git a/libraries/stdlib/src/kotlin/util/LazyJVM.kt b/libraries/stdlib/src/kotlin/util/LazyJVM.kt new file mode 100644 index 00000000000..0446d030892 --- /dev/null +++ b/libraries/stdlib/src/kotlin/util/LazyJVM.kt @@ -0,0 +1,135 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +@file:kotlin.jvm.JvmName("LazyKt") +@file:kotlin.jvm.JvmMultifileClass + +package kotlin + + +/** + * Creates a new instance of the [Lazy] that uses the specified initialization function [initializer] + * and the default thread-safety mode [LazyThreadSafetyMode.SYNCHRONIZED]. + * + * If the initialization of a value throws an exception, it will attempt to reinitialize the value at next access. + * + * Note that the returned instance uses itself to synchronize on. Do not synchronize from external code on + * the returned instance as it may cause accidental deadlock. Also this behavior can be changed in the future. + */ +@kotlin.jvm.JvmVersion +public fun lazy(initializer: () -> T): Lazy = SynchronizedLazyImpl(initializer) + +/** + * Creates a new instance of the [Lazy] that uses the specified initialization function [initializer] + * and thread-safety [mode]. + * + * If the initialization of a value throws an exception, it will attempt to reinitialize the value at next access. + * + * Note that when the [LazyThreadSafetyMode.SYNCHRONIZED] mode is specified the returned instance uses itself + * to synchronize on. Do not synchronize from external code on the returned instance as it may cause accidental deadlock. + * Also this behavior can be changed in the future. + */ +@kotlin.jvm.JvmVersion +public fun lazy(mode: LazyThreadSafetyMode, initializer: () -> T): Lazy = + when (mode) { + LazyThreadSafetyMode.SYNCHRONIZED -> SynchronizedLazyImpl(initializer) + LazyThreadSafetyMode.PUBLICATION -> SafePublicationLazyImpl(initializer) + LazyThreadSafetyMode.NONE -> UnsafeLazyImpl(initializer) + } + +/** + * Creates a new instance of the [Lazy] that uses the specified initialization function [initializer] + * and the default thread-safety mode [LazyThreadSafetyMode.SYNCHRONIZED]. + * + * If the initialization of a value throws an exception, it will attempt to reinitialize the value at next access. + * + * The returned instance uses the specified [lock] object to synchronize on. + * When the [lock] is not specified the instance uses itself to synchronize on, + * in this case do not synchronize from external code on the returned instance as it may cause accidental deadlock. + * Also this behavior can be changed in the future. + */ +@kotlin.jvm.JvmVersion +public fun lazy(lock: Any?, initializer: () -> T): Lazy = SynchronizedLazyImpl(initializer, lock) + + + +@JvmVersion +private class SynchronizedLazyImpl(initializer: () -> T, lock: Any? = null) : Lazy, Serializable { + private var initializer: (() -> T)? = initializer + @Volatile private var _value: Any? = UNINITIALIZED_VALUE + // final field is required to enable safe publication of constructed instance + private val lock = lock ?: this + + override val value: T + get() { + val _v1 = _value + if (_v1 !== UNINITIALIZED_VALUE) { + @Suppress("UNCHECKED_CAST") + return _v1 as T + } + + return synchronized(lock) { + val _v2 = _value + if (_v2 !== UNINITIALIZED_VALUE) { + @Suppress("UNCHECKED_CAST") (_v2 as T) + } + else { + val typedValue = initializer!!() + _value = typedValue + initializer = null + typedValue + } + } + } + + override fun isInitialized(): Boolean = _value !== UNINITIALIZED_VALUE + + override fun toString(): String = if (isInitialized()) value.toString() else "Lazy value not initialized yet." + + private fun writeReplace(): Any = InitializedLazyImpl(value) +} + + +@kotlin.jvm.JvmVersion +private class SafePublicationLazyImpl(initializer: () -> T) : Lazy, Serializable { + @Volatile private var initializer: (() -> T)? = initializer + @Volatile private var _value: Any? = UNINITIALIZED_VALUE + // this final field is required to enable safe publication of constructed instance + private val final: Any = UNINITIALIZED_VALUE + + override val value: T + get() { + val value = _value + if (value !== UNINITIALIZED_VALUE) { + @Suppress("UNCHECKED_CAST") + return value as T + } + + val initializerValue = initializer + // if we see null in initializer here, it means that the value is already set by another thread + if (initializerValue != null) { + val newValue = initializerValue() + if (valueUpdater.compareAndSet(this, UNINITIALIZED_VALUE, newValue)) { + initializer = null + return newValue + } + } + @Suppress("UNCHECKED_CAST") + return _value as T + } + + override fun isInitialized(): Boolean = _value !== UNINITIALIZED_VALUE + + override fun toString(): String = if (isInitialized()) value.toString() else "Lazy value not initialized yet." + + private fun writeReplace(): Any = InitializedLazyImpl(value) + + companion object { + private val valueUpdater = java.util.concurrent.atomic.AtomicReferenceFieldUpdater.newUpdater( + SafePublicationLazyImpl::class.java, + Any::class.java, + "_value") + } +} \ No newline at end of file