Dev #127
@ -5,42 +5,54 @@ import scientifik.kmath.operations.NumericAlgebra
|
||||
import scientifik.kmath.operations.RealField
|
||||
|
||||
/**
|
||||
* A Mathematical Syntax Tree node for mathematical expressions
|
||||
* A Mathematical Syntax Tree node for mathematical expressions.
|
||||
*/
|
||||
sealed class MST {
|
||||
|
||||
/**
|
||||
* A node containing unparsed string
|
||||
* A node containing raw string.
|
||||
*
|
||||
* @property value the value of this node.
|
||||
*/
|
||||
data class Symbolic(val value: String) : MST()
|
||||
|
||||
/**
|
||||
* A node containing a number
|
||||
* A node containing a numeric value or scalar.
|
||||
*
|
||||
* @property value the value of this number.
|
||||
*/
|
||||
data class Numeric(val value: Number) : MST()
|
||||
|
||||
/**
|
||||
* A node containing an unary operation
|
||||
* A node containing an unary operation.
|
||||
*
|
||||
* @property operation the identifier of operation.
|
||||
* @property value the argument of this operation.
|
||||
*/
|
||||
data class Unary(val operation: String, val value: MST) : MST() {
|
||||
companion object {
|
||||
const val ABS_OPERATION = "abs"
|
||||
//TODO add operations
|
||||
}
|
||||
companion object
|
||||
}
|
||||
|
||||
/**
|
||||
* A node containing binary operation
|
||||
* A node containing binary operation.
|
||||
*
|
||||
* @property operation the identifier operation.
|
||||
* @property left the left operand.
|
||||
* @property right the right operand.
|
||||
*/
|
||||
data class Binary(val operation: String, val left: MST, val right: MST) : MST() {
|
||||
companion object
|
||||
}
|
||||
}
|
||||
|
||||
//TODO add a function with positional arguments
|
||||
|
||||
// TODO add a function with named arguments
|
||||
|
||||
/**
|
||||
* Interprets the [MST] node with this [Algebra].
|
||||
*
|
||||
* @receiver the algebra that provides operations.
|
||||
* @param node the node to evaluate.
|
||||
* @return the value of expression.
|
||||
*/
|
||||
fun <T> Algebra<T>.evaluate(node: MST): T = when (node) {
|
||||
is MST.Numeric -> (this as? NumericAlgebra<T>)?.number(node.value)
|
||||
?: error("Numeric nodes are not supported by $this")
|
||||
@ -65,4 +77,11 @@ fun <T> Algebra<T>.evaluate(node: MST): T = when (node) {
|
||||
}
|
||||
}
|
||||
|
||||
fun <T> MST.compile(algebra: Algebra<T>): T = algebra.evaluate(this)
|
||||
/**
|
||||
* Interprets the [MST] node with this [Algebra].
|
||||
*
|
||||
* @receiver the node to evaluate.
|
||||
* @param algebra the algebra that provides operations.
|
||||
* @return the value of expression.
|
||||
*/
|
||||
fun <T> MST.interpret(algebra: Algebra<T>): T = algebra.evaluate(this)
|
||||
|
@ -2,6 +2,9 @@ package scientifik.kmath.ast
|
||||
|
||||
import scientifik.kmath.operations.*
|
||||
|
||||
/**
|
||||
* [Algebra] over [MST] nodes.
|
||||
*/
|
||||
object MstAlgebra : NumericAlgebra<MST> {
|
||||
override fun number(value: Number): MST = MST.Numeric(value)
|
||||
|
||||
@ -14,17 +17,16 @@ object MstAlgebra : NumericAlgebra<MST> {
|
||||
MST.Binary(operation, left, right)
|
||||
}
|
||||
|
||||
/**
|
||||
* [Space] over [MST] nodes.
|
||||
*/
|
||||
object MstSpace : Space<MST>, NumericAlgebra<MST> {
|
||||
override val zero: MST = number(0.0)
|
||||
|
||||
override fun number(value: Number): MST = MstAlgebra.number(value)
|
||||
override fun symbol(value: String): MST = MstAlgebra.symbol(value)
|
||||
|
||||
override fun add(a: MST, b: MST): MST =
|
||||
binaryOperation(SpaceOperations.PLUS_OPERATION, a, b)
|
||||
|
||||
override fun multiply(a: MST, k: Number): MST =
|
||||
binaryOperation(RingOperations.TIMES_OPERATION, a, number(k))
|
||||
override fun add(a: MST, b: MST): MST = binaryOperation(SpaceOperations.PLUS_OPERATION, a, b)
|
||||
override fun multiply(a: MST, k: Number): MST = binaryOperation(RingOperations.TIMES_OPERATION, a, number(k))
|
||||
|
||||
override fun binaryOperation(operation: String, left: MST, right: MST): MST =
|
||||
MstAlgebra.binaryOperation(operation, left, right)
|
||||
@ -32,41 +34,69 @@ object MstSpace : Space<MST>, NumericAlgebra<MST> {
|
||||
override fun unaryOperation(operation: String, arg: MST): MST = MstAlgebra.unaryOperation(operation, arg)
|
||||
}
|
||||
|
||||
/**
|
||||
* [Ring] over [MST] nodes.
|
||||
*/
|
||||
object MstRing : Ring<MST>, NumericAlgebra<MST> {
|
||||
override val zero: MST = number(0.0)
|
||||
override val one: MST = number(1.0)
|
||||
|
||||
override fun number(value: Number): MST = MstAlgebra.number(value)
|
||||
override fun symbol(value: String): MST = MstAlgebra.symbol(value)
|
||||
override fun add(a: MST, b: MST): MST = binaryOperation(SpaceOperations.PLUS_OPERATION, a, b)
|
||||
override fun number(value: Number): MST = MstSpace.number(value)
|
||||
override fun symbol(value: String): MST = MstSpace.symbol(value)
|
||||
override fun add(a: MST, b: MST): MST = MstSpace.add(a, b)
|
||||
|
||||
override fun multiply(a: MST, k: Number): MST =
|
||||
binaryOperation(RingOperations.TIMES_OPERATION, a, MstSpace.number(k))
|
||||
override fun multiply(a: MST, k: Number): MST = MstSpace.multiply(a, k)
|
||||
|
||||
override fun multiply(a: MST, b: MST): MST = binaryOperation(RingOperations.TIMES_OPERATION, a, b)
|
||||
|
||||
override fun binaryOperation(operation: String, left: MST, right: MST): MST =
|
||||
MstAlgebra.binaryOperation(operation, left, right)
|
||||
MstSpace.binaryOperation(operation, left, right)
|
||||
|
||||
override fun unaryOperation(operation: String, arg: MST): MST = MstAlgebra.unaryOperation(operation, arg)
|
||||
}
|
||||
|
||||
/**
|
||||
* [Field] over [MST] nodes.
|
||||
*/
|
||||
object MstField : Field<MST> {
|
||||
override val zero: MST = number(0.0)
|
||||
override val one: MST = number(1.0)
|
||||
|
||||
override fun symbol(value: String): MST = MstAlgebra.symbol(value)
|
||||
override fun number(value: Number): MST = MstAlgebra.number(value)
|
||||
override fun add(a: MST, b: MST): MST = binaryOperation(SpaceOperations.PLUS_OPERATION, a, b)
|
||||
|
||||
override fun multiply(a: MST, k: Number): MST =
|
||||
binaryOperation(RingOperations.TIMES_OPERATION, a, MstSpace.number(k))
|
||||
|
||||
override fun multiply(a: MST, b: MST): MST = binaryOperation(RingOperations.TIMES_OPERATION, a, b)
|
||||
override fun symbol(value: String): MST = MstRing.symbol(value)
|
||||
override fun number(value: Number): MST = MstRing.number(value)
|
||||
override fun add(a: MST, b: MST): MST = MstRing.add(a, b)
|
||||
override fun multiply(a: MST, k: Number): MST = MstRing.multiply(a, k)
|
||||
override fun multiply(a: MST, b: MST): MST = MstRing.multiply(a, b)
|
||||
override fun divide(a: MST, b: MST): MST = binaryOperation(FieldOperations.DIV_OPERATION, a, b)
|
||||
|
||||
override fun binaryOperation(operation: String, left: MST, right: MST): MST =
|
||||
MstAlgebra.binaryOperation(operation, left, right)
|
||||
MstRing.binaryOperation(operation, left, right)
|
||||
|
||||
override fun unaryOperation(operation: String, arg: MST): MST = MstAlgebra.unaryOperation(operation, arg)
|
||||
override fun unaryOperation(operation: String, arg: MST): MST = MstRing.unaryOperation(operation, arg)
|
||||
}
|
||||
|
||||
/**
|
||||
* [ExtendedField] over [MST] nodes.
|
||||
*/
|
||||
object MstExtendedField : ExtendedField<MST> {
|
||||
override val zero: MST = number(0.0)
|
||||
override val one: MST = number(1.0)
|
||||
|
||||
override fun sin(arg: MST): MST = unaryOperation(TrigonometricOperations.SIN_OPERATION, arg)
|
||||
override fun cos(arg: MST): MST = unaryOperation(TrigonometricOperations.COS_OPERATION, arg)
|
||||
override fun asin(arg: MST): MST = unaryOperation(InverseTrigonometricOperations.ASIN_OPERATION, arg)
|
||||
override fun acos(arg: MST): MST = unaryOperation(InverseTrigonometricOperations.ACOS_OPERATION, arg)
|
||||
override fun atan(arg: MST): MST = unaryOperation(InverseTrigonometricOperations.ATAN_OPERATION, arg)
|
||||
override fun add(a: MST, b: MST): MST = MstField.add(a, b)
|
||||
override fun multiply(a: MST, k: Number): MST = MstField.multiply(a, k)
|
||||
override fun multiply(a: MST, b: MST): MST = MstField.multiply(a, b)
|
||||
override fun divide(a: MST, b: MST): MST = MstField.divide(a, b)
|
||||
override fun power(arg: MST, pow: Number): MST = binaryOperation(PowerOperations.POW_OPERATION, arg, number(pow))
|
||||
override fun exp(arg: MST): MST = unaryOperation(ExponentialOperations.EXP_OPERATION, arg)
|
||||
override fun ln(arg: MST): MST = unaryOperation(ExponentialOperations.LN_OPERATION, arg)
|
||||
|
||||
override fun binaryOperation(operation: String, left: MST, right: MST): MST =
|
||||
MstField.binaryOperation(operation, left, right)
|
||||
|
||||
override fun unaryOperation(operation: String, arg: MST): MST = MstField.unaryOperation(operation, arg)
|
||||
}
|
||||
|
@ -1,19 +1,16 @@
|
||||
package scientifik.kmath.ast
|
||||
|
||||
import scientifik.kmath.expressions.Expression
|
||||
import scientifik.kmath.expressions.FunctionalExpressionField
|
||||
import scientifik.kmath.expressions.FunctionalExpressionRing
|
||||
import scientifik.kmath.expressions.FunctionalExpressionSpace
|
||||
import scientifik.kmath.expressions.*
|
||||
import scientifik.kmath.operations.*
|
||||
|
||||
/**
|
||||
* The expression evaluates MST on-flight. Should be much faster than functional expression, but slower than ASM-generated expressions.
|
||||
* The expression evaluates MST on-flight. Should be much faster than functional expression, but slower than
|
||||
* ASM-generated expressions.
|
||||
*
|
||||
* @property algebra the algebra that provides operations.
|
||||
* @property mst the [MST] node.
|
||||
*/
|
||||
class MstExpression<T>(val algebra: Algebra<T>, val mst: MST) : Expression<T> {
|
||||
|
||||
/**
|
||||
* Substitute algebra raw value
|
||||
*/
|
||||
private inner class InnerAlgebra(val arguments: Map<String, T>) : NumericAlgebra<T> {
|
||||
override fun symbol(value: String): T = arguments[value] ?: algebra.symbol(value)
|
||||
override fun unaryOperation(operation: String, arg: T): T = algebra.unaryOperation(operation, arg)
|
||||
@ -30,26 +27,62 @@ class MstExpression<T>(val algebra: Algebra<T>, val mst: MST) : Expression<T> {
|
||||
override fun invoke(arguments: Map<String, T>): T = InnerAlgebra(arguments).evaluate(mst)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Builds [MstExpression] over [Algebra].
|
||||
*/
|
||||
inline fun <reified T : Any, A : Algebra<T>, E : Algebra<MST>> A.mst(
|
||||
mstAlgebra: E,
|
||||
block: E.() -> MST
|
||||
): MstExpression<T> = MstExpression(this, mstAlgebra.block())
|
||||
|
||||
/**
|
||||
* Builds [MstExpression] over [Space].
|
||||
*/
|
||||
inline fun <reified T : Any> Space<T>.mstInSpace(block: MstSpace.() -> MST): MstExpression<T> =
|
||||
MstExpression(this, MstSpace.block())
|
||||
|
||||
/**
|
||||
* Builds [MstExpression] over [Ring].
|
||||
*/
|
||||
inline fun <reified T : Any> Ring<T>.mstInRing(block: MstRing.() -> MST): MstExpression<T> =
|
||||
MstExpression(this, MstRing.block())
|
||||
|
||||
/**
|
||||
* Builds [MstExpression] over [Field].
|
||||
*/
|
||||
inline fun <reified T : Any> Field<T>.mstInField(block: MstField.() -> MST): MstExpression<T> =
|
||||
MstExpression(this, MstField.block())
|
||||
|
||||
inline fun <reified T : Any, A : Space<T>> FunctionalExpressionSpace<T, A>.mstInSpace(block: MstSpace.() -> MST): MstExpression<T> =
|
||||
algebra.mstInSpace(block)
|
||||
/**
|
||||
* Builds [MstExpression] over [ExtendedField].
|
||||
*/
|
||||
inline fun <reified T : Any> Field<T>.mstInExtendedField(block: MstExtendedField.() -> MST): MstExpression<T> =
|
||||
MstExpression(this, MstExtendedField.block())
|
||||
|
||||
inline fun <reified T : Any, A : Ring<T>> FunctionalExpressionRing<T, A>.mstInRing(block: MstRing.() -> MST): MstExpression<T> =
|
||||
algebra.mstInRing(block)
|
||||
/**
|
||||
* Builds [MstExpression] over [FunctionalExpressionSpace].
|
||||
*/
|
||||
inline fun <reified T : Any, A : Space<T>> FunctionalExpressionSpace<T, A>.mstInSpace(
|
||||
block: MstSpace.() -> MST
|
||||
): MstExpression<T> = algebra.mstInSpace(block)
|
||||
|
||||
inline fun <reified T : Any, A : Field<T>> FunctionalExpressionField<T, A>.mstInField(block: MstField.() -> MST): MstExpression<T> =
|
||||
algebra.mstInField(block)
|
||||
/**
|
||||
* Builds [MstExpression] over [FunctionalExpressionRing].
|
||||
*/
|
||||
inline fun <reified T : Any, A : Ring<T>> FunctionalExpressionRing<T, A>.mstInRing(
|
||||
block: MstRing.() -> MST
|
||||
): MstExpression<T> = algebra.mstInRing(block)
|
||||
|
||||
/**
|
||||
* Builds [MstExpression] over [FunctionalExpressionField].
|
||||
*/
|
||||
inline fun <reified T : Any, A : Field<T>> FunctionalExpressionField<T, A>.mstInField(
|
||||
block: MstField.() -> MST
|
||||
): MstExpression<T> = algebra.mstInField(block)
|
||||
|
||||
/**
|
||||
* Builds [MstExpression] over [FunctionalExpressionExtendedField].
|
||||
*/
|
||||
inline fun <reified T : Any, A : ExtendedField<T>> FunctionalExpressionExtendedField<T, A>.mstInExtendedField(
|
||||
block: MstExtendedField.() -> MST
|
||||
): MstExpression<T> = algebra.mstInExtendedField(block)
|
||||
|
@ -80,5 +80,18 @@ object ArithmeticsEvaluator : Grammar<MST>() {
|
||||
override val rootParser: Parser<MST> by subSumChain
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to parse the string into [MST].
|
||||
*
|
||||
* @receiver the string to parse.
|
||||
* @return the [MST] node.
|
||||
*/
|
||||
fun String.tryParseMath(): ParseResult<MST> = ArithmeticsEvaluator.tryParseToEnd(this)
|
||||
|
||||
/**
|
||||
* Parses the string into [MST].
|
||||
*
|
||||
* @receiver the string to parse.
|
||||
* @return the [MST] node.
|
||||
*/
|
||||
fun String.parseMath(): MST = ArithmeticsEvaluator.parseToEnd(this)
|
||||
|
@ -1,5 +1,6 @@
|
||||
package scientifik.kmath.expressions
|
||||
|
||||
import scientifik.kmath.operations.ExtendedField
|
||||
import scientifik.kmath.operations.Field
|
||||
import scientifik.kmath.operations.Ring
|
||||
import scientifik.kmath.operations.Space
|
||||
@ -21,3 +22,10 @@ fun <T> Ring<T>.ringExpression(block: FunctionalExpressionRing<T, Ring<T>>.() ->
|
||||
*/
|
||||
fun <T> Field<T>.fieldExpression(block: FunctionalExpressionField<T, Field<T>>.() -> Expression<T>): Expression<T> =
|
||||
FunctionalExpressionField(this).run(block)
|
||||
|
||||
/**
|
||||
* Creates a functional expression with this [ExtendedField].
|
||||
*/
|
||||
fun <T> ExtendedField<T>.fieldExpression(
|
||||
block: FunctionalExpressionExtendedField<T, ExtendedField<T>>.() -> Expression<T>
|
||||
): Expression<T> = FunctionalExpressionExtendedField(this).run(block)
|
||||
|
@ -6,6 +6,12 @@ import scientifik.kmath.operations.Algebra
|
||||
* An elementary function that could be invoked on a map of arguments
|
||||
*/
|
||||
interface Expression<T> {
|
||||
/**
|
||||
* Calls this expression from arguments.
|
||||
*
|
||||
* @param arguments the map of arguments.
|
||||
* @return the value.
|
||||
*/
|
||||
operator fun invoke(arguments: Map<String, T>): T
|
||||
|
||||
companion object
|
||||
@ -19,6 +25,12 @@ fun <T> Algebra<T>.expression(block: Algebra<T>.(arguments: Map<String, T>) -> T
|
||||
override fun invoke(arguments: Map<String, T>): T = block(arguments)
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls this expression from arguments.
|
||||
*
|
||||
* @param pairs the pair of arguments' names to values.
|
||||
* @return the value.
|
||||
*/
|
||||
operator fun <T> Expression<T>.invoke(vararg pairs: Pair<String, T>): T = invoke(mapOf(*pairs))
|
||||
|
||||
/**
|
||||
|
@ -40,7 +40,6 @@ internal class FunctionalConstProductExpression<T>(
|
||||
* @param algebra The algebra to provide for Expressions built.
|
||||
*/
|
||||
abstract class FunctionalExpressionAlgebra<T, A : Algebra<T>>(val algebra: A) : ExpressionAlgebra<T, Expression<T>> {
|
||||
|
||||
/**
|
||||
* Builds an Expression of constant expression which does not depend on arguments.
|
||||
*/
|
||||
@ -69,14 +68,13 @@ abstract class FunctionalExpressionAlgebra<T, A : Algebra<T>>(val algebra: A) :
|
||||
*/
|
||||
open class FunctionalExpressionSpace<T, A : Space<T>>(algebra: A) :
|
||||
FunctionalExpressionAlgebra<T, A>(algebra), Space<Expression<T>> {
|
||||
|
||||
override val zero: Expression<T> get() = const(algebra.zero)
|
||||
|
||||
/**
|
||||
* Builds an Expression of addition of two another expressions.
|
||||
*/
|
||||
override fun add(a: Expression<T>, b: Expression<T>): Expression<T> =
|
||||
FunctionalBinaryOperation(algebra, SpaceOperations.PLUS_OPERATION, a, b)
|
||||
binaryOperation(SpaceOperations.PLUS_OPERATION, a, b)
|
||||
|
||||
/**
|
||||
* Builds an Expression of multiplication of expression by number.
|
||||
@ -105,7 +103,7 @@ open class FunctionalExpressionRing<T, A>(algebra: A) : FunctionalExpressionSpac
|
||||
* Builds an Expression of multiplication of two expressions.
|
||||
*/
|
||||
override fun multiply(a: Expression<T>, b: Expression<T>): Expression<T> =
|
||||
FunctionalBinaryOperation(algebra, RingOperations.TIMES_OPERATION, a, b)
|
||||
binaryOperation(RingOperations.TIMES_OPERATION, a, b)
|
||||
|
||||
operator fun Expression<T>.times(arg: T): Expression<T> = this * const(arg)
|
||||
operator fun T.times(arg: Expression<T>): Expression<T> = arg * this
|
||||
@ -124,7 +122,7 @@ open class FunctionalExpressionField<T, A>(algebra: A) :
|
||||
* Builds an Expression of division an expression by another one.
|
||||
*/
|
||||
override fun divide(a: Expression<T>, b: Expression<T>): Expression<T> =
|
||||
FunctionalBinaryOperation(algebra, FieldOperations.DIV_OPERATION, a, b)
|
||||
binaryOperation(FieldOperations.DIV_OPERATION, a, b)
|
||||
|
||||
operator fun Expression<T>.div(arg: T): Expression<T> = this / const(arg)
|
||||
operator fun T.div(arg: Expression<T>): Expression<T> = arg / this
|
||||
@ -136,6 +134,34 @@ open class FunctionalExpressionField<T, A>(algebra: A) :
|
||||
super<FunctionalExpressionRing>.binaryOperation(operation, left, right)
|
||||
}
|
||||
|
||||
open class FunctionalExpressionExtendedField<T, A>(algebra: A) :
|
||||
FunctionalExpressionField<T, A>(algebra),
|
||||
ExtendedField<Expression<T>> where A : ExtendedField<T>, A : NumericAlgebra<T> {
|
||||
override fun sin(arg: Expression<T>): Expression<T> = unaryOperation(TrigonometricOperations.SIN_OPERATION, arg)
|
||||
override fun cos(arg: Expression<T>): Expression<T> = unaryOperation(TrigonometricOperations.COS_OPERATION, arg)
|
||||
|
||||
override fun asin(arg: Expression<T>): Expression<T> =
|
||||
unaryOperation(InverseTrigonometricOperations.ASIN_OPERATION, arg)
|
||||
|
||||
override fun acos(arg: Expression<T>): Expression<T> =
|
||||
unaryOperation(InverseTrigonometricOperations.ACOS_OPERATION, arg)
|
||||
|
||||
override fun atan(arg: Expression<T>): Expression<T> =
|
||||
unaryOperation(InverseTrigonometricOperations.ATAN_OPERATION, arg)
|
||||
|
||||
override fun power(arg: Expression<T>, pow: Number): Expression<T> =
|
||||
binaryOperation(PowerOperations.POW_OPERATION, arg, number(pow))
|
||||
|
||||
override fun exp(arg: Expression<T>): Expression<T> = unaryOperation(ExponentialOperations.EXP_OPERATION, arg)
|
||||
override fun ln(arg: Expression<T>): Expression<T> = unaryOperation(ExponentialOperations.LN_OPERATION, arg)
|
||||
|
||||
override fun unaryOperation(operation: String, arg: Expression<T>): Expression<T> =
|
||||
super<FunctionalExpressionField>.unaryOperation(operation, arg)
|
||||
|
||||
override fun binaryOperation(operation: String, left: Expression<T>, right: Expression<T>): Expression<T> =
|
||||
super<FunctionalExpressionField>.binaryOperation(operation, left, right)
|
||||
}
|
||||
|
||||
inline fun <T, A : Space<T>> A.expressionInSpace(block: FunctionalExpressionSpace<T, A>.() -> Expression<T>): Expression<T> =
|
||||
FunctionalExpressionSpace(this).block()
|
||||
|
||||
@ -144,3 +170,6 @@ inline fun <T, A : Ring<T>> A.expressionInRing(block: FunctionalExpressionRing<T
|
||||
|
||||
inline fun <T, A : Field<T>> A.expressionInField(block: FunctionalExpressionField<T, A>.() -> Expression<T>): Expression<T> =
|
||||
FunctionalExpressionField(this).block()
|
||||
|
||||
inline fun <T, A : ExtendedField<T>> A.expressionInExtendedField(block: FunctionalExpressionExtendedField<T, A>.() -> Expression<T>): Expression<T> =
|
||||
FunctionalExpressionExtendedField(this).block()
|
||||
|
@ -11,7 +11,7 @@ import kotlin.reflect.KClass
|
||||
* Thread-safe ring buffer
|
||||
*/
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
internal class RingBuffer<T>(
|
||||
class RingBuffer<T>(
|
||||
private val buffer: MutableBuffer<T?>,
|
||||
private var startIndex: Int = 0,
|
||||
size: Int = 0
|
||||
|
Loading…
Reference in New Issue
Block a user