From 664d3b9a8731c67700e89d932a0314f60d1294d3 Mon Sep 17 00:00:00 2001 From: mapkn3 <79608236848@ya.ru> Date: Sun, 15 Dec 2024 18:54:14 +0400 Subject: [PATCH 1/3] CustomAdt.parseInt(String) has been implemented. First, we validate the input string and parse correct string if no error. Otherwise, return founded error. --- src/main/kotlin/CustomAdt.kt | 54 +++++++++++++++++++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/CustomAdt.kt b/src/main/kotlin/CustomAdt.kt index c30e0c4..dc43928 100644 --- a/src/main/kotlin/CustomAdt.kt +++ b/src/main/kotlin/CustomAdt.kt @@ -1,15 +1,67 @@ package pro.azhidkov.training.functional_errors +import kotlin.math.pow + sealed interface ParseResult { @JvmInline value class Success(val value: Int) : ParseResult data class Failure(val pos: Int, val char: Char) : ParseResult } +sealed interface ValidationResult { + @JvmInline + value class Success(val value: String) : ValidationResult + data class Failure(val pos: Int, val char: Char) : ValidationResult +} + +data class Digit(val decimalRadix: Int, val char: Char) { + val value: Int + get() = char - '0' +} + +fun validateIntString(str: String): ValidationResult = + str + .asSequence() + .mapIndexedNotNull { index, char -> + when { + isCorrectIntStringChar(index, char, str.first()) -> null + else -> ValidationResult.Failure(index, char) + } + } + .firstOrNull() + ?: ValidationResult.Success(str) + +fun isCorrectIntStringChar(pos: Int, char: Char, firstChar: Char): Boolean = + when { + pos == 0 && char == '-' -> true + pos == 1 && char == '0' && firstChar == '-' -> false + pos == 1 && char == '0' && firstChar == '0' -> false + (pos < 10 || (firstChar == '-' && pos == 10)) && char.isDigit() -> true + else -> false + } + +fun parseCorrectInt(str: String): Int = + when (str.first()) { + '-' -> parseNegativeInt(str) + else -> parsePositiveInt(str) + } + +fun parseNegativeInt(str: String): Int = -1 * parsePositiveInt(str.drop(1)) + +fun parsePositiveInt(str: String): Int = str + .mapIndexed { index, digit -> Digit((10.0.pow(str.length - index - 1)).toInt(), digit) } + .sumOf { it.value * it.decimalRadix } + object CustomAdt { fun parseInt(str: String): ParseResult { - TODO() + return when { + str.isEmpty() -> ParseResult.Failure(-1, '\u0000') + else -> when (val validationResult = validateIntString(str)) { + is ValidationResult.Success -> ParseResult.Success(parseCorrectInt(validationResult.value)) + is ValidationResult.Failure -> ParseResult.Failure(validationResult.pos, validationResult.char) + } + } } } \ No newline at end of file From 1638f105c33094b946191c28e631fbe8961efbe5 Mon Sep 17 00:00:00 2001 From: mapkn3 <79608236848@ya.ru> Date: Sun, 15 Dec 2024 19:53:15 +0400 Subject: [PATCH 2/3] Some improvements and simplification have been added. --- src/main/kotlin/CustomAdt.kt | 43 +++++++++++------------------------- 1 file changed, 13 insertions(+), 30 deletions(-) diff --git a/src/main/kotlin/CustomAdt.kt b/src/main/kotlin/CustomAdt.kt index dc43928..b214954 100644 --- a/src/main/kotlin/CustomAdt.kt +++ b/src/main/kotlin/CustomAdt.kt @@ -1,35 +1,17 @@ package pro.azhidkov.training.functional_errors -import kotlin.math.pow - sealed interface ParseResult { @JvmInline value class Success(val value: Int) : ParseResult data class Failure(val pos: Int, val char: Char) : ParseResult } -sealed interface ValidationResult { - @JvmInline - value class Success(val value: String) : ValidationResult - data class Failure(val pos: Int, val char: Char) : ValidationResult -} - -data class Digit(val decimalRadix: Int, val char: Char) { - val value: Int - get() = char - '0' -} - -fun validateIntString(str: String): ValidationResult = - str +fun String.firstNonDigitCharOrNull(): IndexedValue? = + this .asSequence() - .mapIndexedNotNull { index, char -> - when { - isCorrectIntStringChar(index, char, str.first()) -> null - else -> ValidationResult.Failure(index, char) - } - } + .withIndex() + .filterNot { isCorrectIntStringChar(it.index, it.value, this.first()) } .firstOrNull() - ?: ValidationResult.Success(str) fun isCorrectIntStringChar(pos: Int, char: Char, firstChar: Char): Boolean = when { @@ -46,21 +28,22 @@ fun parseCorrectInt(str: String): Int = else -> parsePositiveInt(str) } -fun parseNegativeInt(str: String): Int = -1 * parsePositiveInt(str.drop(1)) +fun parseNegativeInt(str: String): Int = + -1 * parsePositiveInt(str.drop(1)) -fun parsePositiveInt(str: String): Int = str - .mapIndexed { index, digit -> Digit((10.0.pow(str.length - index - 1)).toInt(), digit) } - .sumOf { it.value * it.decimalRadix } +fun parsePositiveInt(str: String): Int = + str + .map { it - '0' } + .fold(0) { accumulator, digit -> accumulator * 10 + digit } object CustomAdt { fun parseInt(str: String): ParseResult { return when { str.isEmpty() -> ParseResult.Failure(-1, '\u0000') - else -> when (val validationResult = validateIntString(str)) { - is ValidationResult.Success -> ParseResult.Success(parseCorrectInt(validationResult.value)) - is ValidationResult.Failure -> ParseResult.Failure(validationResult.pos, validationResult.char) - } + else -> str.firstNonDigitCharOrNull() + ?.let { ParseResult.Failure(it.index, it.value) } + ?: ParseResult.Success(parseCorrectInt(str)) } } From c4e3c5ad51c2990abea065b777dfc3664416d7b9 Mon Sep 17 00:00:00 2001 From: mapkn3 <79608236848@ya.ru> Date: Sun, 15 Dec 2024 19:58:14 +0400 Subject: [PATCH 3/3] A magic constant has been excluded. --- src/main/kotlin/CustomAdt.kt | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/CustomAdt.kt b/src/main/kotlin/CustomAdt.kt index b214954..c94a08a 100644 --- a/src/main/kotlin/CustomAdt.kt +++ b/src/main/kotlin/CustomAdt.kt @@ -13,14 +13,17 @@ fun String.firstNonDigitCharOrNull(): IndexedValue? = .filterNot { isCorrectIntStringChar(it.index, it.value, this.first()) } .firstOrNull() -fun isCorrectIntStringChar(pos: Int, char: Char, firstChar: Char): Boolean = - when { +fun isCorrectIntStringChar(pos: Int, char: Char, firstChar: Char): Boolean { + val maxLengthOfPositiveIntString = Int.MAX_VALUE.toString().length + return when { pos == 0 && char == '-' -> true pos == 1 && char == '0' && firstChar == '-' -> false pos == 1 && char == '0' && firstChar == '0' -> false - (pos < 10 || (firstChar == '-' && pos == 10)) && char.isDigit() -> true + pos < maxLengthOfPositiveIntString && char.isDigit() -> true + pos == maxLengthOfPositiveIntString && char.isDigit() && firstChar == '-' -> true else -> false } +} fun parseCorrectInt(str: String): Int = when (str.first()) {