All Downloads are FREE. Search and download functionalities are using the official Maven repository.

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