diff --git a/compiler-plugin/runtime-components/src/main/kotlin/ExportIr.kt b/compiler-plugin/runtime-components/src/main/kotlin/ExportIr.kt index bb72c43..4b7ec2e 100644 --- a/compiler-plugin/runtime-components/src/main/kotlin/ExportIr.kt +++ b/compiler-plugin/runtime-components/src/main/kotlin/ExportIr.kt @@ -1,3 +1,4 @@ -package sschr15.aoc.annotations +package com.sschr15.aoc.annotations +@Retention(AnnotationRetention.SOURCE) annotation class ExportIr diff --git a/compiler-plugin/runtime-components/src/main/kotlin/Memoize.kt b/compiler-plugin/runtime-components/src/main/kotlin/Memoize.kt index 9198954..7ed8252 100644 --- a/compiler-plugin/runtime-components/src/main/kotlin/Memoize.kt +++ b/compiler-plugin/runtime-components/src/main/kotlin/Memoize.kt @@ -1,7 +1,8 @@ -package sschr15.aoc.annotations +package com.sschr15.aoc.annotations /** * Marks a function to be memoized by the compiler plugin. */ @Target(AnnotationTarget.FUNCTION) +@Retention(AnnotationRetention.SOURCE) annotation class Memoize diff --git a/compiler-plugin/runtime-components/src/main/kotlin/OverflowUnderflowCheck.kt b/compiler-plugin/runtime-components/src/main/kotlin/OverflowUnderflowCheck.kt index b8416b0..a398b0b 100644 --- a/compiler-plugin/runtime-components/src/main/kotlin/OverflowUnderflowCheck.kt +++ b/compiler-plugin/runtime-components/src/main/kotlin/OverflowUnderflowCheck.kt @@ -1,6 +1,6 @@ @file:Suppress("NOTHING_TO_INLINE") -package sschr15.aoc.annotations +package com.sschr15.aoc.annotations inline fun plus(a: Int, b: Int): Int = Math.addExact(a, b) inline fun minus(a: Int, b: Int): Int = Math.subtractExact(a, b) diff --git a/compiler-plugin/src/main/kotlin/Memoizer.kt b/compiler-plugin/src/main/kotlin/Memoizer.kt index cab843f..09ed371 100644 --- a/compiler-plugin/src/main/kotlin/Memoizer.kt +++ b/compiler-plugin/src/main/kotlin/Memoizer.kt @@ -45,7 +45,7 @@ class Memoizer(private val context: IrPluginContext) : IrElementTransformerVoid( private val pair = context.referenceClass(ClassId(FqName("kotlin"), FqName("Pair"), false))!! private val triple = context.referenceClass(ClassId(FqName("kotlin"), FqName("Triple"), false))!! - private val memoizeAnnotation = FqName("sschr15.aoc.annotations.Memoize") + private val memoizeAnnotation = FqName("com.sschr15.aoc.annotations.Memoize") private fun IrPluginContext.keyFor(declaration: IrFunction): IrType = when (declaration.valueParameters.size) { 1 -> declaration.valueParameters.single().type diff --git a/compiler-plugin/src/main/kotlin/OverflowUnderflowChecker.kt b/compiler-plugin/src/main/kotlin/OverflowUnderflowChecker.kt index 3c2cd35..014297c 100644 --- a/compiler-plugin/src/main/kotlin/OverflowUnderflowChecker.kt +++ b/compiler-plugin/src/main/kotlin/OverflowUnderflowChecker.kt @@ -28,7 +28,7 @@ import org.jetbrains.kotlin.name.Name @OptIn(UnsafeDuringIrConstructionAPI::class) class OverflowUnderflowChecker(private val context: IrPluginContext, private val config: CompilerConfiguration) : IrElementTransformerVoid() { - val skipCheckAnnotation = FqName("sschr15.aoc.annotations.SkipOverflowUnderflowCheck") + val skipCheckAnnotation = FqName("com.sschr15.aoc.annotations.SkipOverflowUnderflowCheck") val singleTypeChecks = setOf( "plus", "minus", "times", @@ -48,7 +48,7 @@ class OverflowUnderflowChecker(private val context: IrPluginContext, private val .irCall( context.referenceFunctions( CallableId( - FqName("sschr15.aoc.annotations"), + FqName("com.sschr15.aoc.annotations"), null, expression.symbol.owner.name, ) @@ -67,7 +67,7 @@ class OverflowUnderflowChecker(private val context: IrPluginContext, private val if (owner.name != absoluteValueName) return null return context.irBuiltIns.createIrBuilder(expression.symbol, expression.startOffset, expression.endOffset) .irCall(context.referenceFunctions(CallableId( - FqName("sschr15.aoc.annotations"), + FqName("com.sschr15.aoc.annotations"), null, Name.identifier("abs"), )).single { it.owner.valueParameters.single().type == extension.type }) @@ -80,7 +80,7 @@ class OverflowUnderflowChecker(private val context: IrPluginContext, private val if (declaration.annotations.any { it.isAnnotationWithEqualFqName(skipCheckAnnotation) }) return declaration // skip checking this and all children - if (declaration.annotations.any { it.isAnnotationWithEqualFqName(FqName("sschr15.aoc.annotations.ExportIr")) }) { + if (declaration.annotations.any { it.isAnnotationWithEqualFqName(FqName("com.sschr15.aoc.annotations.ExportIr")) }) { config.report(CompilerMessageSeverity.WARNING, declaration.dumpKotlinLike()) config.report(CompilerMessageSeverity.WARNING, declaration.dump()) } @@ -119,7 +119,7 @@ class OverflowUnderflowChecker(private val context: IrPluginContext, private val return context.irBuiltIns.createIrBuilder(expression.symbol, expression.startOffset, expression.endOffset) .irCall(context.referenceFunctions(CallableId( - FqName("sschr15.aoc.annotations"), + FqName("com.sschr15.aoc.annotations"), null, expression.symbol.owner.name, )).single { it.owner.valueParameters.first().type == expression.type }).apply { diff --git a/src/main/kotlin/sschr15/aocsolutions/util/Graphs.kt b/src/main/kotlin/sschr15/aocsolutions/util/Graphs.kt index 920b14f..7a543dc 100644 --- a/src/main/kotlin/sschr15/aocsolutions/util/Graphs.kt +++ b/src/main/kotlin/sschr15/aocsolutions/util/Graphs.kt @@ -16,7 +16,13 @@ import kotlin.collections.ArrayDeque */ class Graph { inner class Node internal constructor(val name: String? = null, val value: T) { - val edges = mutableListOf() + private val _edges = mutableListOf() + private val _incoming = mutableListOf() + private val _outgoing = mutableListOf() + + val edges: List get() = _edges + val incomingEdges: List get() = _incoming + val outgoingEdges: List get() = _outgoing /** * Connects the current node to another node, creating a bidirectional edge between them. @@ -26,8 +32,15 @@ class Graph { * edge list are updated to include this new connection. */ fun connectTo(other: Node, weight: Int? = null) = Edge(this, other, weight).also { - edges.add(it) - other.edges.add(it.reversed()) + _edges.add(it) + _incoming.add(it) + other._outgoing.add(it) + + val rev = it.reversed() + _outgoing.add(rev) + other._edges.add(rev) + other._incoming.add(rev) + this@Graph.edges.add(it) } @@ -39,7 +52,9 @@ class Graph { * and the parent graph's edge list. */ fun oneWayConnectTo(other: Node, weight: Int? = null) = Edge(this, other, weight).also { - edges.add(it) + _edges.add(it) + _outgoing.add(it) + other._incoming.add(it) this@Graph.edges.add(it) } @@ -79,18 +94,6 @@ class Graph { override fun toString() = "Graph(nodes=$nodes, edges=$edges)" - fun removeNode(node: Node) { - nodes.remove(node) - edges.removeAll(node.edges.toSet()) - node.edges.forEach { it.to.edges.remove(it.reversed()) } - } - - fun removeEdge(edge: Edge) { - edges.remove(edge) - edge.from.edges.remove(edge) - edge.to.edges.remove(edge.reversed()) - } - /** * Converts the graph represented by the current instance into a Graphviz DOT format string. * diff --git a/src/main/kotlin/sschr15/aocsolutions/util/IterableUtils.kt b/src/main/kotlin/sschr15/aocsolutions/util/IterableUtils.kt index 0481a6d..51efe47 100644 --- a/src/main/kotlin/sschr15/aocsolutions/util/IterableUtils.kt +++ b/src/main/kotlin/sschr15/aocsolutions/util/IterableUtils.kt @@ -359,3 +359,137 @@ inline fun Iterable.noneIndexed(predicate: (Int, T) -> Boolean): Boolean } return true } + +inline fun List.indexOfMin(): Int { + if (isEmpty()) return -1 + if (size == 1) return 0 + + var min = Int.MAX_VALUE + var minIndex = -1 + for ((i, value) in this.withIndex()) { + if (value < min) { + min = value + minIndex = i + } + } + if (minIndex == -1) return 0 // All values are Int.MAX_VALUE + return minIndex +} + +@JvmName("longIndexOfMin") +inline fun List.indexOfMin(): Int { + if (isEmpty()) return -1 + if (size == 1) return 0 + + var min = Long.MAX_VALUE + var minIndex = -1 + for ((i, value) in this.withIndex()) { + if (value < min) { + min = value + minIndex = i + } + } + if (minIndex == -1) return 0 + return minIndex +} + +@JvmName("floatIndexOfMin") +inline fun List.indexOfMin(): Int { + if (isEmpty()) return -1 + if (size == 1) return 0 + + var min = Float.POSITIVE_INFINITY + var minIndex = -1 + for ((i, value) in this.withIndex()) { + if (value < min) { + min = value + minIndex = i + } + } + if (minIndex == -1) return 0 + return minIndex +} + +@JvmName("doubleIndexOfMin") +inline fun List.indexOfMin(): Int { + if (isEmpty()) return -1 + if (size == 1) return 0 + + var min = Double.POSITIVE_INFINITY + var minIndex = -1 + for ((i, value) in this.withIndex()) { + if (value < min) { + min = value + minIndex = i + } + } + if (minIndex == -1) return 0 + return minIndex +} + +inline fun List.indexOfMax(): Int { + if (isEmpty()) return -1 + if (size == 1) return 0 + + var max = Int.MIN_VALUE + var maxIndex = -1 + for ((i, value) in this.withIndex()) { + if (value > max) { + max = value + maxIndex = i + } + } + if (maxIndex == -1) return 0 + return maxIndex +} + +@JvmName("longIndexOfMax") +inline fun List.indexOfMax(): Int { + if (isEmpty()) return -1 + if (size == 1) return 0 + + var max = Long.MIN_VALUE + var maxIndex = -1 + for ((i, value) in this.withIndex()) { + if (value > max) { + max = value + maxIndex = i + } + } + if (maxIndex == -1) return 0 + return maxIndex +} + +@JvmName("floatIndexOfMax") +inline fun List.indexOfMax(): Int { + if (isEmpty()) return -1 + if (size == 1) return 0 + + var max = Float.NEGATIVE_INFINITY + var maxIndex = -1 + for ((i, value) in this.withIndex()) { + if (value > max) { + max = value + maxIndex = i + } + } + if (maxIndex == -1) return 0 + return maxIndex +} + +@JvmName("doubleIndexOfMax") +inline fun List.indexOfMax(): Int { + if (isEmpty()) return -1 + if (size == 1) return 0 + + var max = Double.NEGATIVE_INFINITY + var maxIndex = -1 + for ((i, value) in this.withIndex()) { + if (value > max) { + max = value + maxIndex = i + } + } + if (maxIndex == -1) return 0 + return maxIndex +}