Skip to content

Commit b41002a

Browse files
Improve Collections and Strings
1 parent 1188344 commit b41002a

File tree

6 files changed

+114
-18
lines changed

6 files changed

+114
-18
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66

77
### Changed
88

9+
- `emptyString()` to `String.Empty`
10+
911
### Deprecated
1012

1113
### Removed

kotlin-stdlib/api/kotlin-stdlib.api

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,17 +147,17 @@ public final class com/javiersc/kotlin/stdlib/CollectionsKt {
147147
public static final fun forth (Ljava/lang/Iterable;)Ljava/lang/Object;
148148
public static final fun forthOrNull (Ljava/lang/Iterable;)Ljava/lang/Object;
149149
public static final fun getIndex (Ljava/lang/Iterable;I)Ljava/lang/Object;
150+
public static final fun getIndexOrNull (Ljava/lang/Iterable;I)Ljava/lang/Object;
150151
public static final fun penultimate (Ljava/lang/Iterable;)Ljava/lang/Object;
151152
public static final fun penultimateOrNull (Ljava/lang/Iterable;)Ljava/lang/Object;
152153
public static final fun second (Ljava/lang/Iterable;)Ljava/lang/Object;
153154
public static final fun secondOrNull (Ljava/lang/Iterable;)Ljava/lang/Object;
154155
public static final fun third (Ljava/lang/Iterable;)Ljava/lang/Object;
155156
public static final fun thirdOrNull (Ljava/lang/Iterable;)Ljava/lang/Object;
156-
public static final fun throwNoSuchElementException (I)V
157157
}
158158

159159
public final class com/javiersc/kotlin/stdlib/StringsKt {
160-
public static final fun emptyString ()Ljava/lang/String;
160+
public static final fun getEmpty (Lkotlin/jvm/internal/StringCompanionObject;)Ljava/lang/String;
161161
public static final fun isNotNullNorBlank (Ljava/lang/CharSequence;)Z
162162
public static final fun isNotNullNorBlank (Ljava/lang/String;)Z
163163
public static final fun isNotNullNorEmpty (Ljava/lang/CharSequence;)Z

kotlin-stdlib/commonMain/kotlin/com/javiersc/kotlin/stdlib/Collections.kt

Lines changed: 52 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
@file:Suppress("MagicNumber")
1+
@file:Suppress("MagicNumber", "TooManyFunctions")
22

33
package com.javiersc.kotlin.stdlib
44

@@ -9,7 +9,7 @@ package com.javiersc.kotlin.stdlib
99
*/
1010
public inline fun <T> Iterable<T>.second(): T = getIndex(2)
1111

12-
public inline fun <T> Iterable<T>.secondOrNull(): T? = runCatching { second() }.getOrNull()
12+
public inline fun <T> Iterable<T>.secondOrNull(): T? = getIndexOrNull(2)
1313

1414
/**
1515
* Returns third element.
@@ -18,7 +18,7 @@ public inline fun <T> Iterable<T>.secondOrNull(): T? = runCatching { second() }.
1818
*/
1919
public inline fun <T> Iterable<T>.third(): T = getIndex(3)
2020

21-
public inline fun <T> Iterable<T>.thirdOrNull(): T? = runCatching { third() }.getOrNull()
21+
public inline fun <T> Iterable<T>.thirdOrNull(): T? = getIndexOrNull(3)
2222

2323
/**
2424
* Returns forth element.
@@ -27,7 +27,7 @@ public inline fun <T> Iterable<T>.thirdOrNull(): T? = runCatching { third() }.ge
2727
*/
2828
public inline fun <T> Iterable<T>.forth(): T = getIndex(4)
2929

30-
public inline fun <T> Iterable<T>.forthOrNull(): T? = runCatching { forth() }.getOrNull()
30+
public inline fun <T> Iterable<T>.forthOrNull(): T? = getIndexOrNull(4)
3131

3232
/**
3333
* Returns fifth element.
@@ -36,7 +36,7 @@ public inline fun <T> Iterable<T>.forthOrNull(): T? = runCatching { forth() }.ge
3636
*/
3737
public inline fun <T> Iterable<T>.fifth(): T = getIndex(5)
3838

39-
public inline fun <T> Iterable<T>.fifthOrNull(): T? = runCatching { fifth() }.getOrNull()
39+
public inline fun <T> Iterable<T>.fifthOrNull(): T? = getIndexOrNull(5)
4040

4141
/**
4242
* Returns penultimate element.
@@ -45,7 +45,12 @@ public inline fun <T> Iterable<T>.fifthOrNull(): T? = runCatching { fifth() }.ge
4545
*/
4646
public inline fun <T> Iterable<T>.penultimate(): T {
4747
return when (this) {
48-
is List -> this[size - 2]
48+
is List ->
49+
when (size) {
50+
0 -> throw NoSuchElementException("Collection is empty.")
51+
1 -> throw NoSuchElementException("Collection size is lower than 2.")
52+
else -> this[size - 2]
53+
}
4954
else -> {
5055
val iterator = iterator()
5156
if (!iterator.hasNext()) throw NoSuchElementException("Collection is empty.")
@@ -63,20 +68,41 @@ public inline fun <T> Iterable<T>.penultimate(): T {
6368
}
6469
}
6570

66-
public inline fun <T> Iterable<T>.penultimateOrNull(): T? =
67-
runCatching { penultimate() }.getOrNull()
71+
public inline fun <T> Iterable<T>.penultimateOrNull(): T? {
72+
return when (this) {
73+
is List -> getOrNull(size - 2)
74+
else -> {
75+
val iterator = iterator()
76+
77+
if (!iterator.hasNext()) return null
78+
iterator.next()
79+
if (!iterator.hasNext()) return null
80+
81+
var penultimate: T = iterator.next()
82+
while (iterator.hasNext()) {
83+
val next: T = iterator.next()
84+
if (iterator.hasNext()) penultimate = next
85+
}
86+
return penultimate
87+
}
88+
}
89+
}
6890

6991
@PublishedApi
7092
internal inline fun <T> Iterable<T>.getIndex(index: Int): T {
7193
return when (this) {
72-
is List -> this[index - 1]
94+
is List ->
95+
if (size >= index - 1) this[index - 1]
96+
else throw NoSuchElementException("Collection size is lower than $index.")
7397
else -> {
7498
val iterator = iterator()
75-
if (!iterator.hasNext()) throwNoSuchElementException(index)
99+
if (!iterator.hasNext())
100+
throw NoSuchElementException("Collection size is lower than $index.")
76101
var value: T = iterator.next()
77102

78103
for (i in 0 until index - 1) {
79-
if (!iterator.hasNext()) throwNoSuchElementException(index)
104+
if (!iterator.hasNext())
105+
throw NoSuchElementException("Collection size is lower than $index.")
80106
else value = iterator.next()
81107
}
82108
value
@@ -85,5 +111,18 @@ internal inline fun <T> Iterable<T>.getIndex(index: Int): T {
85111
}
86112

87113
@PublishedApi
88-
internal inline fun throwNoSuchElementException(size: Int): Unit =
89-
throw NoSuchElementException("Collection size is lower than $size.")
114+
internal inline fun <T> Iterable<T>.getIndexOrNull(index: Int): T? {
115+
return when (this) {
116+
is List -> getOrNull(index - 1)
117+
else -> {
118+
val iterator = iterator()
119+
if (!iterator.hasNext()) return null
120+
var value: T = iterator.next()
121+
122+
for (i in 0 until index - 1) {
123+
if (!iterator.hasNext()) return null else value = iterator.next()
124+
}
125+
value
126+
}
127+
}
128+
}

kotlin-stdlib/commonMain/kotlin/com/javiersc/kotlin/stdlib/Strings.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,5 @@ public inline fun String?.isNotNullNorEmpty(): Boolean {
3737
return (this != null) && isNotEmpty()
3838
}
3939

40-
public inline fun emptyString(): String = ""
40+
public inline val String.Companion.Empty: String
41+
get() = ""

kotlin-stdlib/commonTest/kotlin/com/javiersc/kotlin/stdlib/CollectionsTest.kt

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,35 +2,87 @@
22

33
package com.javiersc.kotlin.stdlib
44

5+
import io.kotest.assertions.throwables.shouldThrow
56
import io.kotest.matchers.shouldBe
67
import kotlin.test.Test
78

89
class CollectionsTest {
910

10-
private val numbers = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
11+
private val numbers: List<Int> = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
12+
private val chars: Iterable<Char> = listOf('A', 'B', 'C', 'D', 'E', 'F').asIterable()
13+
private val empty: List<String> = emptyList()
14+
private val emptyIterable: Iterable<String> = emptyList<String>().asIterable()
1115

1216
@Test
1317
fun collection_second() {
1418
numbers.second().shouldBe(2)
19+
numbers.secondOrNull().shouldBe(2)
20+
21+
chars.second().shouldBe('B')
22+
chars.secondOrNull().shouldBe('B')
23+
24+
shouldThrow<NoSuchElementException> { empty.second() }
25+
shouldThrow<NoSuchElementException> { emptyIterable.second() }
26+
empty.secondOrNull().shouldBe(null)
27+
emptyIterable.secondOrNull().shouldBe(null)
1528
}
1629

1730
@Test
1831
fun collection_third() {
1932
numbers.third().shouldBe(3)
33+
numbers.thirdOrNull().shouldBe(3)
34+
35+
chars.third().shouldBe('C')
36+
chars.thirdOrNull().shouldBe('C')
37+
38+
shouldThrow<NoSuchElementException> { empty.third() }
39+
shouldThrow<NoSuchElementException> { emptyIterable.third() }
40+
empty.thirdOrNull().shouldBe(null)
41+
emptyIterable.thirdOrNull().shouldBe(null)
2042
}
2143

2244
@Test
2345
fun collection_forth() {
2446
numbers.forth().shouldBe(4)
47+
numbers.forthOrNull().shouldBe(4)
48+
49+
chars.forth().shouldBe('D')
50+
chars.forthOrNull().shouldBe('D')
51+
52+
shouldThrow<NoSuchElementException> { empty.forth() }
53+
shouldThrow<NoSuchElementException> { emptyIterable.forth() }
54+
empty.forthOrNull().shouldBe(null)
55+
emptyIterable.forthOrNull().shouldBe(null)
2556
}
2657

2758
@Test
2859
fun collection_fifth() {
2960
numbers.fifth().shouldBe(5)
61+
numbers.fifthOrNull().shouldBe(5)
62+
63+
chars.fifth().shouldBe('E')
64+
chars.fifthOrNull().shouldBe('E')
65+
66+
shouldThrow<NoSuchElementException> { empty.fifth() }
67+
shouldThrow<NoSuchElementException> { emptyIterable.fifth() }
68+
empty.fifthOrNull().shouldBe(null)
69+
emptyIterable.fifthOrNull().shouldBe(null)
3070
}
3171

3272
@Test
3373
fun collection_penultimate() {
3474
numbers.penultimate().shouldBe(9)
75+
numbers.penultimateOrNull().shouldBe(9)
76+
77+
chars.penultimate().shouldBe('E')
78+
chars.penultimateOrNull().shouldBe('E')
79+
80+
shouldThrow<NoSuchElementException> { empty.penultimate() }
81+
shouldThrow<NoSuchElementException> { emptyIterable.penultimate() }
82+
empty.penultimateOrNull().shouldBe(null)
83+
emptyIterable.penultimateOrNull().shouldBe(null)
84+
85+
shouldThrow<NoSuchElementException> { listOf(1).penultimate() }
86+
shouldThrow<NoSuchElementException> { listOf(1).asIterable().penultimate() }
3587
}
3688
}

kotlin-stdlib/commonTest/kotlin/com/javiersc/kotlin/stdlib/StringsTest.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,15 @@ package com.javiersc.kotlin.stdlib
33
import io.kotest.matchers.booleans.shouldBeFalse
44
import io.kotest.matchers.booleans.shouldBeTrue
55
import io.kotest.matchers.shouldBe
6+
import io.kotest.matchers.string.shouldBeEmpty
67
import kotlin.test.Test
78

89
class StringsTest {
910

1011
@Test
1112
fun string_remove() {
1213
"Hello, World".remove("Hello, ").shouldBe("World")
14+
"Hello, World".remove("bla").shouldBe("Hello, World")
1315
}
1416

1517
@Test
@@ -31,6 +33,6 @@ class StringsTest {
3133

3234
@Test
3335
fun empty_string() {
34-
emptyString().shouldBe("")
36+
String.Empty.shouldBeEmpty()
3537
}
3638
}

0 commit comments

Comments
 (0)