Skip to content

Commit

Permalink
Start on value tracking, add fixed length queue collection
Browse files Browse the repository at this point in the history
  • Loading branch information
gdude2002 committed Jun 24, 2024
1 parent 72dba4c commit e24ef8b
Show file tree
Hide file tree
Showing 8 changed files with 367 additions and 6 deletions.
53 changes: 51 additions & 2 deletions buildSrc/src/main/kotlin/types/XmlStyleHeaderComment.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package types

import dev.yumi.gradle.licenser.api.comment.CStyleHeaderComment
import dev.yumi.gradle.licenser.api.comment.HeaderComment

class XmlStyleHeaderComment : HeaderComment {
Expand All @@ -22,9 +23,12 @@ class XmlStyleHeaderComment : HeaderComment {
return HeaderComment.Result(0, 0, null, separator)
}

val result: List<String> = source.substring(start, end).split(separator)
val result: MutableList<String> = source.substring(start, end).split(separator).toMutableList()

return HeaderComment.Result(start, end, result, separator)
result.removeFirst()
result.removeLast()

return HeaderComment.Result(start, end, result.map { it.trimIndent() }, separator)
}

override fun writeHeaderComment(header: List<String>, separator: String): String =
Expand All @@ -45,3 +49,48 @@ class XmlStyleHeaderComment : HeaderComment {
val INSTANCE: XmlStyleHeaderComment = XmlStyleHeaderComment()
}
}

// Testing function, ensure a match
fun main() {
val xmlSource = """
<!--
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at https://mozilla.org/MPL/2.0/.
-->
<script lang="ts">
</script>
""".trimIndent()

val cSource = """
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package com.kotlindiscord.kord.extensions
""".trimIndent()

val xmlReader = XmlStyleHeaderComment()
val cReader = CStyleHeaderComment()

val xmlComment = xmlReader.readHeaderComment(xmlSource)
val cComment = cReader.readHeaderComment(cSource)

println("== XML style ==")
println(xmlComment.existing?.joinToString("\n"))

println()
println("== C style ==")
println(cComment.existing?.joinToString("\n"))

println()

if (xmlComment.existing == cComment.existing) {
println("PASS: Comments match!")
} else {
println("FAIL: Comments don't match.")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/

package com.kotlindiscord.kord.extensions.utils.collections

import java.util.*

/**
* Fixed-length FIFO Queue implementation based on a MutableList.
*
* Transparently adds data to the list in reverse (the queue's head is the end of the list), copying and reversing the
* list when retrieved via [getAll].
*
* If you need to be able to tell the difference between a null value and a missing value, consider using Kord's
* [dev.kord.common.entity.optional.Optional] as the element type.
*
* @param maxSize Maximum number of elements in this queue.
*/
public class FixedLengthQueue<E : Any?>(public val maxSize: Int) : Queue<E> {
init {
if (maxSize <= 0) {
throw IllegalArgumentException("maxSize must be > 0")
}
}

override val size: Int
get() = data.size

private val data: MutableList<E> = mutableListOf()

/**
* Add an element to the head of the queue, replacing the element at the tail if [maxSize] has been reached.
*/
public fun push(element: E): Boolean {
if (data.size == maxSize) {
pop()
}

return data.add(element)
}

/**
* Remove the last element and return it.
*
* Returns `null` if empty.
*/
public fun pop(): E? =
data.removeFirstOrNull()

/**
* Remove the first element and return it.
*
* Returns `null` if empty.
*/
public fun popFirst(): E? =
data.removeLastOrNull()

/**
* Retrieve the last element.
*
* Returns `null` if empty.
*/
public fun get(): E? =
data.firstOrNull()

/**
* Retrieve the first element.
*
* Returns `null` if empty.
*/
public fun getFirst(): E? =
data.lastOrNull()

/**
* Returns a list of all elements in this queue, in pushed order.
*/
public fun getAll(): List<E> =
data.reversed()

override fun add(element: E): Boolean {
check(data.size == maxSize) { "Queue is full (max size: $maxSize)" }

return data.add(element)
}

override fun addAll(elements: Collection<E>): Boolean =
if (elements.size >= maxSize) {
data.clear()

data.addAll(
elements.reversed()
.take(maxSize)
.reversed()
)
} else if (elements.size + data.size > maxSize) {
val totalSize = elements.size + data.size
val extraNumber = totalSize - maxSize

val result = data.addAll(elements)

repeat(extraNumber) { pop() }

result
} else {
data.addAll(elements)
}

override fun clear(): Unit =
data.clear()

override fun iterator(): MutableIterator<E> =
data.iterator()

override fun remove(): E? =
data.removeLast()

override fun isEmpty(): Boolean =
data.isEmpty()

override fun poll(): E? =
data.removeLastOrNull()

override fun element(): E? =
data.removeLast()

override fun peek(): E? =
data.removeLastOrNull()

override fun offer(element: E): Boolean =
push(element)

override fun containsAll(elements: Collection<E>): Boolean =
data.containsAll(elements)

override fun contains(element: E): Boolean =
data.contains(element)

override fun retainAll(elements: Collection<E>): Boolean =
data.retainAll(elements)

override fun removeAll(elements: Collection<E>): Boolean =
data.removeAll(elements)

override fun remove(element: E): Boolean =
data.remove(element)
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ private val logger = KotlinLogging.logger {}
*
* Schedulers are [CoroutineScope]s and thus can be cancelled to cancel all nested jobs, if required..
*/
public class Scheduler : CoroutineScope {
public open class Scheduler : CoroutineScope {
internal val tasks: MutableList<Task> = mutableListOf()

override val coroutineContext: CoroutineContext = Dispatchers.Default + SupervisorJob()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,12 @@ public open class Task(
}
}
} finally {
if (executions == ULong.MAX_VALUE) {
logger.debug { "Resetting execution counter as it has reached the maximum value." }

executions = 0UL
}

executions += 1UL
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/

@file:Suppress("UnnecessaryParentheses", "MagicNumber")

package dev.kordex.extra.web.values

import kotlinx.datetime.LocalDateTime

public typealias ValueCheck = (now: LocalDateTime) -> Boolean

public sealed class ValueInterval(public val translationKey: String, public val check: ValueCheck) {
public data object Second : ValueInterval("interval.second", {
true
})

public data object QuarterMinute : ValueInterval("interval.quarter-minute", { now ->
now.second % 15 == 0
})

public data object HalfMinute : ValueInterval("interval.half-minute", { now ->
now.second % 30 == 0
})

public data object Minute : ValueInterval("interval.minute", { now ->
now.second == 0
})

public data object QuarterHour : ValueInterval("interval.quarter-hour", { now ->
now.second == 0 && (now.minute % 15 == 0)
})

public data object HalfHour : ValueInterval("interval.half-hour", { now ->
now.second == 0 && (now.minute % 30 == 0)
})

public data object Hour : ValueInterval("interval.hour", { now ->
now.second == 0 && (now.minute == 0)
})

public data object QuarterDay : ValueInterval("interval.quarter-day", { now ->
now.second == 0 && (now.hour % 6 == 0)
})

public data object HalfDay : ValueInterval("interval.half-day", { now ->
now.second == 0 && (now.hour % 12 == 0)
})

public data object Day : ValueInterval("interval.day", { now ->
now.second == 0 && (now.hour == 0)
})

public companion object {
public val ALL: Set<ValueInterval> = setOf(
Second,
HalfMinute, Minute,
QuarterHour, HalfHour, Hour,
QuarterDay, HalfDay, Day,
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/

package dev.kordex.extra.web.values

import com.kotlindiscord.kord.extensions.utils.scheduling.Scheduler
import kotlinx.coroutines.launch
import kotlinx.datetime.Clock
import kotlinx.datetime.TimeZone
import kotlinx.datetime.toLocalDateTime

public class ValueRegistry {
private lateinit var scheduler: Scheduler
private val trackers: MutableMap<String, ValueTracker<*>> = mutableMapOf()

public suspend fun setup() {
scheduler = Scheduler()

scheduler.schedule(
seconds = 1,
startNow = true,
name = "ValueRegistry repeating task",
repeat = true
) {
val now = Clock.System.now()
.toLocalDateTime(TimeZone.UTC)

ValueInterval.ALL.forEach { interval ->
if (interval.check(now)) {
scheduler.launch {
trackers.values
.filter { it.precision == interval }
.forEach { it.update() }
}
}
}
}
}

public fun shutdown() {
trackers.clear()
scheduler.shutdown()
}

public fun register(tracker: ValueTracker<*>) {
if (trackers.contains(tracker.identifier)) {
error("Already tracking value with identifier: ${tracker.identifier}")
}

trackers[tracker.identifier] = tracker
}

public fun get(identifier: String): ValueTracker<*>? =
trackers[identifier]

public fun remove(tracker: ValueTracker<*>): ValueTracker<*>? =
remove(tracker.identifier)

public fun remove(identifier: String): ValueTracker<*>? =
trackers.remove(identifier)
}
Loading

0 comments on commit e24ef8b

Please sign in to comment.