/* * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package org.jetbrains.kotlin.generators.builtins.numbers import org.jetbrains.kotlin.generators.builtins.PrimitiveType import org.jetbrains.kotlin.generators.builtins.convert import org.jetbrains.kotlin.generators.builtins.generateBuiltIns.BuiltInsSourceGenerator import org.jetbrains.kotlin.generators.builtins.numbers.primitives.BasePrimitivesGenerator import org.jetbrains.kotlin.generators.builtins.printDoc import java.io.PrintWriter class GenerateFloorDivMod(out: PrintWriter) : BuiltInsSourceGenerator(out) { override fun getMultifileClassName() = "NumbersKt" override fun generateBody() { out.println("import kotlin.math.sign") out.println() val integerTypes = PrimitiveType.integral intersect PrimitiveType.onlyNumeric for (thisType in integerTypes) { for (otherType in integerTypes) { generateFloorDiv(thisType, otherType) generateMod(thisType, otherType) } } val fpTypes = PrimitiveType.floatingPoint for (thisType in fpTypes) { for (otherType in fpTypes) { generateFpMod(thisType, otherType) } } } private fun generateFloorDiv(thisKind: PrimitiveType, otherKind: PrimitiveType) { val returnType = getOperatorReturnType(thisKind, otherKind) val returnTypeName = returnType.capitalized out.printDoc(BasePrimitivesGenerator.binaryOperatorDoc("floorDiv", thisKind, otherKind), "") out.println("""@SinceKotlin("1.5")""") out.println("@kotlin.internal.InlineOnly") out.println("@kotlin.internal.IntrinsicConstEvaluation") val declaration = "public inline fun ${thisKind.capitalized}.floorDiv(other: ${otherKind.capitalized}): $returnTypeName" if (thisKind == otherKind && thisKind >= PrimitiveType.INT) { out.println( """ $declaration { var q = this / other if (this xor other < 0 && q * other != this) q-- return q } """.trimIndent() ) } else { out.println("$declaration = ") out.println(" ${ convert("this", thisKind, returnType)}.floorDiv(${convert("other", otherKind, returnType)})") } out.println() } private fun generateMod(thisKind: PrimitiveType, otherKind: PrimitiveType) { val operationType = getOperatorReturnType(thisKind, otherKind) val returnType = otherKind out.printDoc(BasePrimitivesGenerator.binaryOperatorDoc("mod", thisKind, otherKind),"") out.println("""@SinceKotlin("1.5")""") out.println("@kotlin.internal.InlineOnly") out.println("@kotlin.internal.IntrinsicConstEvaluation") val declaration = "public inline fun ${thisKind.capitalized}.mod(other: ${otherKind.capitalized}): ${returnType.capitalized}" if (thisKind == otherKind && thisKind >= PrimitiveType.INT) { out.println( """ $declaration { val r = this % other return r + (other and (((r xor other) and (r or -r)) shr ${operationType.bitSize - 1})) } """.trimIndent() ) } else { out.println("$declaration = ") out.println(" " + convert( "${convert("this", thisKind, operationType)}.mod(${convert("other", otherKind, operationType)})", operationType, returnType )) } out.println() } private fun generateFpMod(thisKind: PrimitiveType, otherKind: PrimitiveType) { val operationType = getOperatorReturnType(thisKind, otherKind) out.printDoc(BasePrimitivesGenerator.binaryOperatorDoc("mod", thisKind, otherKind), "") out.println("""@SinceKotlin("1.5")""") out.println("@kotlin.internal.InlineOnly") out.println("@kotlin.internal.IntrinsicConstEvaluation") val declaration = "public inline fun ${thisKind.capitalized}.mod(other: ${otherKind.capitalized}): ${operationType.capitalized}" if (thisKind == otherKind && thisKind >= PrimitiveType.INT) { out.println( """ $declaration { val r = this % other return if (r != ${convert("0.0", PrimitiveType.DOUBLE, operationType)} && r.sign != other.sign) r + other else r } """.trimIndent() ) } else { out.println("$declaration = ") out.println(" ${convert("this", thisKind, operationType)}.mod(${convert("other", otherKind, operationType)})") } out.println() } } private fun maxByDomainCapacity(type1: PrimitiveType, type2: PrimitiveType): PrimitiveType = if (type1.ordinal > type2.ordinal) type1 else type2 private fun getOperatorReturnType(kind1: PrimitiveType, kind2: PrimitiveType): PrimitiveType { require(kind1 != PrimitiveType.BOOLEAN) { "kind1 must not be BOOLEAN" } require(kind2 != PrimitiveType.BOOLEAN) { "kind2 must not be BOOLEAN" } return maxByDomainCapacity(maxByDomainCapacity(kind1, kind2), PrimitiveType.INT) }