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

commonMain.space.kscience.kmath.structures.Buffer.kt Maven / Gradle / Ivy

package space.kscience.kmath.structures

import kotlin.reflect.KClass

/**
 * Function that produces [Buffer] from its size and function that supplies values.
 *
 * @param T the type of buffer.
 */
public typealias BufferFactory = (Int, (Int) -> T) -> Buffer

/**
 * Function that produces [MutableBuffer] from its size and function that supplies values.
 *
 * @param T the type of buffer.
 */
public typealias MutableBufferFactory = (Int, (Int) -> T) -> MutableBuffer

/**
 * A generic immutable random-access structure for both primitives and objects.
 *
 * @param T the type of elements contained in the buffer.
 */
public interface Buffer {
    /**
     * The size of this buffer.
     */
    public val size: Int

    /**
     * Gets element at given index.
     */
    public operator fun get(index: Int): T

    /**
     * Iterates over all elements.
     */
    public operator fun iterator(): Iterator

    /**
     * Checks content equality with another buffer.
     */
    public fun contentEquals(other: Buffer<*>): Boolean =
        asSequence().mapIndexed { index, value -> value == other[index] }.all { it }

    public companion object {
        /**
         * Creates a [RealBuffer] with the specified [size], where each element is calculated by calling the specified
         * [initializer] function.
         */
        public inline fun real(size: Int, initializer: (Int) -> Double): RealBuffer =
            RealBuffer(size) { initializer(it) }

        /**
         * Creates a [ListBuffer] of given type [T] with given [size]. Each element is calculated by calling the
         * specified [initializer] function.
         */
        public inline fun  boxing(size: Int, initializer: (Int) -> T): Buffer =
            ListBuffer(List(size, initializer))

        // TODO add resolution based on Annotation or companion resolution

        /**
         * Creates a [Buffer] of given [type]. If the type is primitive, specialized buffers are used ([IntBuffer],
         * [RealBuffer], etc.), [ListBuffer] is returned otherwise.
         *
         * The [size] is specified, and each element is calculated by calling the specified [initializer] function.
         */
        @Suppress("UNCHECKED_CAST")
        public inline fun  auto(type: KClass, size: Int, initializer: (Int) -> T): Buffer =
            when (type) {
                Double::class -> RealBuffer(size) { initializer(it) as Double } as Buffer
                Short::class -> ShortBuffer(size) { initializer(it) as Short } as Buffer
                Int::class -> IntBuffer(size) { initializer(it) as Int } as Buffer
                Long::class -> LongBuffer(size) { initializer(it) as Long } as Buffer
                Float::class -> FloatBuffer(size) { initializer(it) as Float } as Buffer
                else -> boxing(size, initializer)
            }

        /**
         * Creates a [Buffer] of given type [T]. If the type is primitive, specialized buffers are used ([IntBuffer],
         * [RealBuffer], etc.), [ListBuffer] is returned otherwise.
         *
         * The [size] is specified, and each element is calculated by calling the specified [initializer] function.
         */
        @Suppress("UNCHECKED_CAST")
        public inline fun  auto(size: Int, initializer: (Int) -> T): Buffer =
            auto(T::class, size, initializer)
    }
}

/**
 * Creates a sequence that returns all elements from this [Buffer].
 */
public fun  Buffer.asSequence(): Sequence = Sequence(::iterator)

/**
 * Creates an iterable that returns all elements from this [Buffer].
 */
public fun  Buffer.asIterable(): Iterable = Iterable(::iterator)

/**
 * Converts this [Buffer] to a new [List]
 */
public fun  Buffer.toList(): List = asSequence().toList()

/**
 * Returns an [IntRange] of the valid indices for this [Buffer].
 */
public val Buffer<*>.indices: IntRange get() = 0 until size

/**
 * A generic mutable random-access structure for both primitives and objects.
 *
 * @param T the type of elements contained in the buffer.
 */
public interface MutableBuffer : Buffer {
    /**
     * Sets the array element at the specified [index] to the specified [value].
     */
    public operator fun set(index: Int, value: T)

    /**
     * Returns a shallow copy of the buffer.
     */
    public fun copy(): MutableBuffer

    public companion object {
        /**
         * Create a boxing mutable buffer of given type
         */
        public inline fun  boxing(size: Int, initializer: (Int) -> T): MutableBuffer =
            MutableListBuffer(MutableList(size, initializer))

        /**
         * Creates a [MutableBuffer] of given [type]. If the type is primitive, specialized buffers are used
         * ([IntBuffer], [RealBuffer], etc.), [ListBuffer] is returned otherwise.
         *
         * The [size] is specified, and each element is calculated by calling the specified [initializer] function.
         */
        @Suppress("UNCHECKED_CAST")
        public inline fun  auto(type: KClass, size: Int, initializer: (Int) -> T): MutableBuffer =
            when (type) {
                Double::class -> RealBuffer(size) { initializer(it) as Double } as MutableBuffer
                Short::class -> ShortBuffer(size) { initializer(it) as Short } as MutableBuffer
                Int::class -> IntBuffer(size) { initializer(it) as Int } as MutableBuffer
                Float::class -> FloatBuffer(size) { initializer(it) as Float } as MutableBuffer
                Long::class -> LongBuffer(size) { initializer(it) as Long } as MutableBuffer
                else -> boxing(size, initializer)
            }

        /**
         * Creates a [MutableBuffer] of given type [T]. If the type is primitive, specialized buffers are used
         * ([IntBuffer], [RealBuffer], etc.), [ListBuffer] is returned otherwise.
         *
         * The [size] is specified, and each element is calculated by calling the specified [initializer] function.
         */
        @Suppress("UNCHECKED_CAST")
        public inline fun  auto(size: Int, initializer: (Int) -> T): MutableBuffer =
            auto(T::class, size, initializer)

        /**
         * Creates a [RealBuffer] with the specified [size], where each element is calculated by calling the specified
         * [initializer] function.
         */
        public inline fun real(size: Int, initializer: (Int) -> Double): RealBuffer =
            RealBuffer(size) { initializer(it) }
    }
}

/**
 * [Buffer] implementation over [List].
 *
 * @param T the type of elements contained in the buffer.
 * @property list The underlying list.
 */
public inline class ListBuffer(public val list: List) : Buffer {
    override val size: Int
        get() = list.size

    override operator fun get(index: Int): T = list[index]
    override operator fun iterator(): Iterator = list.iterator()
}

/**
 * Returns an [ListBuffer] that wraps the original list.
 */
public fun  List.asBuffer(): ListBuffer = ListBuffer(this)

/**
 * Creates a new [ListBuffer] with the specified [size], where each element is calculated by calling the specified
 * [init] function.
 *
 * The function [init] is called for each array element sequentially starting from the first one.
 * It should return the value for an array element given its index.
 */
public inline fun  ListBuffer(size: Int, init: (Int) -> T): ListBuffer = List(size, init).asBuffer()

/**
 * [MutableBuffer] implementation over [MutableList].
 *
 * @param T the type of elements contained in the buffer.
 * @property list The underlying list.
 */
public inline class MutableListBuffer(public val list: MutableList) : MutableBuffer {
    override val size: Int
        get() = list.size

    override operator fun get(index: Int): T = list[index]

    override operator fun set(index: Int, value: T) {
        list[index] = value
    }

    override operator fun iterator(): Iterator = list.iterator()
    override fun copy(): MutableBuffer = MutableListBuffer(ArrayList(list))
}

/**
 * [MutableBuffer] implementation over [Array].
 *
 * @param T the type of elements contained in the buffer.
 * @property array The underlying array.
 */
public class ArrayBuffer(private val array: Array) : MutableBuffer {
    // Can't inline because array is invariant
    override val size: Int
        get() = array.size

    override operator fun get(index: Int): T = array[index]

    override operator fun set(index: Int, value: T) {
        array[index] = value
    }

    override operator fun iterator(): Iterator = array.iterator()
    override fun copy(): MutableBuffer = ArrayBuffer(array.copyOf())
}


/**
 * Returns an [ArrayBuffer] that wraps the original array.
 */
public fun  Array.asBuffer(): ArrayBuffer = ArrayBuffer(this)

/**
 * Creates a new [ArrayBuffer] with the specified [size], where each element is calculated by calling the specified
 * [init] function.
 *
 * The function [init] is called for each array element sequentially starting from the first one.
 * It should return the value for an array element given its index.
 */
public inline fun  ArrayBuffer(size: Int, init: (Int) -> T): ArrayBuffer =
    Array(size) { i -> init(i) }.asBuffer()

/**
 * Immutable wrapper for [MutableBuffer].
 *
 * @param T the type of elements contained in the buffer.
 * @property buffer The underlying buffer.
 */
public inline class ReadOnlyBuffer(public val buffer: MutableBuffer) : Buffer {
    override val size: Int get() = buffer.size

    override operator fun get(index: Int): T = buffer[index]

    override operator fun iterator(): Iterator = buffer.iterator()
}

/**
 * A buffer with content calculated on-demand. The calculated content is not stored, so it is recalculated on each call.
 * Useful when one needs single element from the buffer.
 *
 * @param T the type of elements provided by the buffer.
 */
public class VirtualBuffer(override val size: Int, private val generator: (Int) -> T) : Buffer {
    override operator fun get(index: Int): T {
        if (index < 0 || index >= size) throw IndexOutOfBoundsException("Expected index from 0 to ${size - 1}, but found $index")
        return generator(index)
    }

    override operator fun iterator(): Iterator = (0 until size).asSequence().map(generator).iterator()

    override fun contentEquals(other: Buffer<*>): Boolean {
        return if (other is VirtualBuffer) {
            this.size == other.size && this.generator == other.generator
        } else {
            super.contentEquals(other)
        }
    }
}

/**
 * Convert this buffer to read-only buffer.
 */
public fun  Buffer.asReadOnly(): Buffer = if (this is MutableBuffer) ReadOnlyBuffer(this) else this

/**
 * Typealias for buffer transformations.
 */
public typealias BufferTransform = (Buffer) -> Buffer

/**
 * Typealias for buffer transformations with suspend function.
 */
public typealias SuspendBufferTransform = suspend (Buffer) -> Buffer




© 2015 - 2025 Weber Informatics LLC | Privacy Policy