
org.fernice.std.Ordinal.kt Maven / Gradle / Ivy
/*
* 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 http://mozilla.org/MPL/2.0/.
*/
package org.fernice.std
import kotlin.reflect.KClass
interface Ordinal> {
val ordinal: Int
}
interface OrdinalUniverse> : List> {
operator fun contains(element: O): Boolean = contains(element::class)
fun indexOf(element: O): Int = indexOf(element::class)
}
inline fun > ordinalUniverse(): OrdinalUniverse {
return ordinalUniverse { O::class.sealedSubclasses.toTypedArray() as Array> }
}
inline fun enumUniverse(): OrdinalUniverse where O : Ordinal, O : Enum {
return ordinalUniverse { enumValues().map { it::class }.toTypedArray() as Array> }
}
fun > ordinalUniverse(entriesProvider: () -> Array>): OrdinalUniverse {
return OrdinalUniverseList(entriesProvider)
}
private class OrdinalUniverseList>(
private val entriesProvider: () -> Array>,
) : OrdinalUniverse, AbstractList>() {
@Volatile
private var _entries: Array>? = null
private val entries: Array>
get() {
var entries = _entries
if (entries == null) {
entries = entriesProvider()
_entries = entries
}
return entries
}
override val size: Int
get() = entries.size
override fun get(index: Int): KClass {
val entries = entries
checkElementIndex(index, entries.size)
return entries[index]
}
private fun checkElementIndex(index: Int, size: Int) {
if (index < 0 || index >= size) {
throw IndexOutOfBoundsException("index: $index, size: $size")
}
}
}
class PerOrdinal, E : Any>(
private val universe: OrdinalUniverse,
private val initializer: (O) -> E,
) : Iterable> {
private val values = Array(universe.size) { null }
fun get(ordinal: O): E {
check(universe.contains(ordinal)) { "unknown ordinal $ordinal" }
var value = values[ordinal.ordinal]
if (value == null) {
value = initializer.invoke(ordinal)
values[ordinal.ordinal] = value
}
@Suppress("UNCHECKED_CAST")
return value as E
}
fun find(ordinal: O): E? {
check(universe.contains(ordinal)) { "unknown ordinal $ordinal" }
@Suppress("UNCHECKED_CAST")
return values[ordinal.ordinal] as E?
}
override fun iterator(): Iterator> = EntryIterator()
private inner class EntryIterator : Iterator> {
private var index = 0
override fun hasNext(): Boolean {
var index = 0
while (index < universe.size) {
if (values[index] != null) return true
index++
}
return false
}
override fun next(): Entry {
if (!hasNext()) throw NoSuchElementException()
val ordinal = universe[index]
val value = values[index] as E
return Entry(ordinal, value)
}
}
data class Entry, E : Any>(val ordinal: KClass, val value: E)
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy