Skip to content

Commit

Permalink
Do not copy when adding annotations to Expression instances; use an e…
Browse files Browse the repository at this point in the history
…xpression pool during evaluation in addition to parsing.
  • Loading branch information
tgregg committed Jan 28, 2025
1 parent 403e648 commit 8c64373
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 43 deletions.
70 changes: 56 additions & 14 deletions src/main/java/com/amazon/ion/impl/macro/Expression.kt
Original file line number Diff line number Diff line change
Expand Up @@ -101,12 +101,18 @@ sealed interface Expression {

// Scalars
data class NullValue(override var annotations: List<SymbolToken> = emptyList(), override var type: IonType) : DataModelValue {
override fun withAnnotations(annotations: List<SymbolToken>) = copy(annotations = annotations)
override fun withAnnotations(annotations: List<SymbolToken>): NullValue {
this.annotations = annotations
return this
}
}

data class BoolValue(override var annotations: List<SymbolToken> = emptyList(), var value: Boolean) : DataModelValue {
override val type: IonType get() = IonType.BOOL
override fun withAnnotations(annotations: List<SymbolToken>) = copy(annotations = annotations)
override fun withAnnotations(annotations: List<SymbolToken>): BoolValue {
this.annotations = annotations
return this
}
}

sealed interface IntValue : DataModelValue {
Expand All @@ -116,31 +122,46 @@ sealed interface Expression {

data class LongIntValue(override var annotations: List<SymbolToken> = emptyList(), var value: Long) : IntValue {
override val type: IonType get() = IonType.INT
override fun withAnnotations(annotations: List<SymbolToken>) = copy(annotations = annotations)
override fun withAnnotations(annotations: List<SymbolToken>): LongIntValue {
this.annotations = annotations
return this
}
override val bigIntegerValue: BigInteger get() = BigInteger.valueOf(value)
override val longValue: Long get() = value
}

data class BigIntValue(override var annotations: List<SymbolToken> = emptyList(), var value: BigInteger) : IntValue {
override val type: IonType get() = IonType.INT
override fun withAnnotations(annotations: List<SymbolToken>) = copy(annotations = annotations)
override fun withAnnotations(annotations: List<SymbolToken>): BigIntValue {
this.annotations = annotations
return this
}
override val bigIntegerValue: BigInteger get() = value
override val longValue: Long get() = value.longValueExact()
}

data class FloatValue(override var annotations: List<SymbolToken> = emptyList(), var value: Double) : DataModelValue {
override val type: IonType get() = IonType.FLOAT
override fun withAnnotations(annotations: List<SymbolToken>) = copy(annotations = annotations)
override fun withAnnotations(annotations: List<SymbolToken>): FloatValue {
this.annotations = annotations
return this
}
}

data class DecimalValue(override var annotations: List<SymbolToken> = emptyList(), var value: BigDecimal) : DataModelValue {
override val type: IonType get() = IonType.DECIMAL
override fun withAnnotations(annotations: List<SymbolToken>) = copy(annotations = annotations)
override fun withAnnotations(annotations: List<SymbolToken>): DecimalValue {
this.annotations = annotations
return this
}
}

data class TimestampValue(override var annotations: List<SymbolToken> = emptyList(), var value: Timestamp) : DataModelValue {
override val type: IonType get() = IonType.TIMESTAMP
override fun withAnnotations(annotations: List<SymbolToken>) = copy(annotations = annotations)
override fun withAnnotations(annotations: List<SymbolToken>): TimestampValue {
this.annotations = annotations
return this
}
}

sealed interface TextValue : DataModelValue {
Expand All @@ -150,13 +171,19 @@ sealed interface Expression {
data class StringValue(override var annotations: List<SymbolToken> = emptyList(), var value: String) : TextValue {
override val type: IonType get() = IonType.STRING
override val stringValue: String get() = value
override fun withAnnotations(annotations: List<SymbolToken>) = copy(annotations = annotations)
override fun withAnnotations(annotations: List<SymbolToken>): StringValue {
this.annotations = annotations
return this
}
}

data class SymbolValue(override var annotations: List<SymbolToken> = emptyList(), var value: SymbolToken) : TextValue {
override val type: IonType get() = IonType.SYMBOL
override val stringValue: String get() = value.assumeText()
override fun withAnnotations(annotations: List<SymbolToken>) = copy(annotations = annotations)
override fun withAnnotations(annotations: List<SymbolToken>): SymbolValue {
this.annotations = annotations
return this
}
}

sealed interface LobValue : DataModelValue {
Expand All @@ -168,7 +195,10 @@ sealed interface Expression {
// We must override hashcode and equals in the lob types because `value` is a `byte[]`
data class BlobValue(override var annotations: List<SymbolToken> = emptyList(), override var value: ByteArray) : LobValue {
override val type: IonType get() = IonType.BLOB
override fun withAnnotations(annotations: List<SymbolToken>) = copy(annotations = annotations)
override fun withAnnotations(annotations: List<SymbolToken>): BlobValue {
this.annotations = annotations
return this
}
override fun hashCode(): Int = annotations.hashCode() * 31 + value.contentHashCode()
override fun equals(other: Any?): Boolean {
if (this === other) return true
Expand All @@ -180,7 +210,10 @@ sealed interface Expression {

data class ClobValue(override var annotations: List<SymbolToken> = emptyList(), override var value: ByteArray) : LobValue {
override val type: IonType get() = IonType.CLOB
override fun withAnnotations(annotations: List<SymbolToken>) = copy(annotations = annotations)
override fun withAnnotations(annotations: List<SymbolToken>): ClobValue {
this.annotations = annotations
return this
}
override fun hashCode(): Int = annotations.hashCode() * 31 + value.contentHashCode()
override fun equals(other: Any?): Boolean {
if (this === other) return true
Expand All @@ -202,7 +235,10 @@ sealed interface Expression {
override var endExclusive: Int
) : DataModelContainer {
override val type: IonType get() = IonType.LIST
override fun withAnnotations(annotations: List<SymbolToken>) = copy(annotations = annotations)
override fun withAnnotations(annotations: List<SymbolToken>): ListValue {
this.annotations = annotations
return this
}
}

/**
Expand All @@ -214,7 +250,10 @@ sealed interface Expression {
override var endExclusive: Int
) : DataModelContainer {
override val type: IonType get() = IonType.SEXP
override fun withAnnotations(annotations: List<SymbolToken>) = copy(annotations = annotations)
override fun withAnnotations(annotations: List<SymbolToken>): SExpValue {
this.annotations = annotations
return this
}
}

/**
Expand All @@ -227,7 +266,10 @@ sealed interface Expression {
val templateStructIndex: Map<String, List<Int>>
) : DataModelContainer {
override val type: IonType get() = IonType.STRUCT
override fun withAnnotations(annotations: List<SymbolToken>) = copy(annotations = annotations)
override fun withAnnotations(annotations: List<SymbolToken>): StructValue {
this.annotations = annotations
return this
}
}

data class FieldName(var value: SymbolToken) : DataModelExpression
Expand Down
29 changes: 18 additions & 11 deletions src/main/java/com/amazon/ion/impl/macro/MacroEvaluator.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import com.amazon.ion.util.unreachable
import java.io.ByteArrayOutputStream
import java.math.BigDecimal
import java.math.BigInteger
import java.util.*
import kotlin.collections.ArrayList

/**
* Evaluates an EExpression from a List of [EExpressionBodyExpression] and the [TemplateBodyExpression]s
Expand Down Expand Up @@ -52,6 +54,8 @@ class MacroEvaluator {
private var numExpandedExpressions = 0
/** Pool of [ExpansionInfo] to minimize allocation and garbage collection. */
private val expanderPool: ArrayList<ExpansionInfo> = ArrayList(32)
/** Pool of [Expression] to minimize allocation and garbage collection. */
val expressionPool: PooledExpressionFactory = PooledExpressionFactory()

/** Gets an [ExpansionInfo] from the pool (or allocates a new one if necessary), initializing it with the provided values. */
fun getExpander(expansionKind: ExpansionKind, expressions: List<Expression>, startInclusive: Int, endExclusive: Int, environment: Environment): ExpansionInfo {
Expand Down Expand Up @@ -87,6 +91,7 @@ class MacroEvaluator {

fun reset() {
numExpandedExpressions = 0
expressionPool.clear()
}
}

Expand Down Expand Up @@ -279,7 +284,7 @@ class MacroEvaluator {
}
}
thisExpansion.expansionKind = Empty
return StringValue(value = sb.toString())
return thisExpansion.session.expressionPool.createStringValue(Collections.emptyList(), sb.toString())
}
},
MakeSymbol {
Expand All @@ -298,7 +303,7 @@ class MacroEvaluator {
is FieldName -> unreachable()
}
}
return SymbolValue(value = newSymbolToken(sb.toString()))
return thisExpansion.session.expressionPool.createSymbolValue(Collections.emptyList(), newSymbolToken(sb.toString()))
}
},
MakeBlob {
Expand All @@ -314,7 +319,7 @@ class MacroEvaluator {
}
}
thisExpansion.expansionKind = Empty
return BlobValue(value = baos.toByteArray())
return thisExpansion.session.expressionPool.createBlobValue(Collections.emptyList(), baos.toByteArray())
}
},
MakeDecimal {
Expand All @@ -325,7 +330,7 @@ class MacroEvaluator {
val coefficient = thisExpansion.readExactlyOneArgument<IntValue>(COEFFICIENT_ARG).bigIntegerValue
val exponent = thisExpansion.readExactlyOneArgument<IntValue>(EXPONENT_ARG).bigIntegerValue
thisExpansion.expansionKind = Empty
return DecimalValue(value = BigDecimal(coefficient, -1 * exponent.intValueExact()))
return thisExpansion.session.expressionPool.createDecimalValue(Collections.emptyList(), BigDecimal(coefficient, -1 * exponent.intValueExact()))
}
},
MakeTimestamp {
Expand Down Expand Up @@ -379,7 +384,7 @@ class MacroEvaluator {
}
}
thisExpansion.expansionKind = Empty
return TimestampValue(value = ts)
return thisExpansion.session.expressionPool.createTimestampValue(Collections.emptyList(), ts)
} catch (e: IllegalArgumentException) {
throw IonException(e.message)
}
Expand All @@ -391,10 +396,12 @@ class MacroEvaluator {

override fun produceNext(thisExpansion: ExpansionInfo): ExpansionOutputExpressionOrContinue {
val fieldName = thisExpansion.readExactlyOneArgument<TextValue>(FIELD_NAME)
val fieldNameExpression = when (fieldName) {
is SymbolValue -> FieldName(fieldName.value)
is StringValue -> FieldName(newSymbolToken(fieldName.value))
}
val fieldNameExpression = thisExpansion.session.expressionPool.createFieldName(
when (fieldName) {
is SymbolValue -> fieldName.value
is StringValue -> newSymbolToken(fieldName.value)
}
)

thisExpansion.readExactlyOneArgument<DataModelValue>(FIELD_VALUE)

Expand Down Expand Up @@ -490,7 +497,7 @@ class MacroEvaluator {
val a = thisExpansion.readExactlyOneArgument<IntValue>(ARG_A).bigIntegerValue
val b = thisExpansion.readExactlyOneArgument<IntValue>(ARG_B).bigIntegerValue
thisExpansion.expansionKind = Empty
return BigIntValue(value = a + b)
return thisExpansion.session.expressionPool.createBigIntValue(Collections.emptyList(), a + b)
}
},
Delta {
Expand All @@ -510,7 +517,7 @@ class MacroEvaluator {
val nextDelta = nextExpandedArg.bigIntegerValue
val nextOutput = runningTotal + nextDelta
thisExpansion.additionalState = nextOutput
return BigIntValue(value = nextOutput)
return thisExpansion.session.expressionPool.createBigIntValue(Collections.emptyList(), nextOutput)
}
EndOfExpansion -> return EndOfExpansion
else -> throw IonException("delta arguments must be integers")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,25 +19,25 @@
*/
public class PooledExpressionFactory {

private static final int POOL_SIZE = 32;
private static final int INITIAL_POOL_SIZE = 32;

private Expression.NullValue[] nullValues = new Expression.NullValue[POOL_SIZE];
private Expression.BoolValue[] boolValues = new Expression.BoolValue[POOL_SIZE];
private Expression.LongIntValue[] longIntValues = new Expression.LongIntValue[POOL_SIZE];
private Expression.BigIntValue[] bigIntValues = new Expression.BigIntValue[POOL_SIZE];
private Expression.FloatValue[] floatValues = new Expression.FloatValue[POOL_SIZE];
private Expression.DecimalValue[] decimalValues = new Expression.DecimalValue[POOL_SIZE];
private Expression.TimestampValue[] timestampValues = new Expression.TimestampValue[POOL_SIZE];
private Expression.SymbolValue[] symbolValues = new Expression.SymbolValue[POOL_SIZE];
private Expression.StringValue[] stringValues = new Expression.StringValue[POOL_SIZE];
private Expression.ClobValue[] clobValues = new Expression.ClobValue[POOL_SIZE];
private Expression.BlobValue[] blobValues = new Expression.BlobValue[POOL_SIZE];
private Expression.FieldName[] fieldNames = new Expression.FieldName[POOL_SIZE];
private Expression.EExpression[] eExpressions = new Expression.EExpression[POOL_SIZE];
private Expression.ExpressionGroup[] expressionGroups = new Expression.ExpressionGroup[POOL_SIZE];
private Expression.ListValue[] listValues = new Expression.ListValue[POOL_SIZE];
private Expression.StructValue[] structValues = new Expression.StructValue[POOL_SIZE];
private Expression.SExpValue[] sexpValues = new Expression.SExpValue[POOL_SIZE];
private Expression.NullValue[] nullValues = new Expression.NullValue[INITIAL_POOL_SIZE];
private Expression.BoolValue[] boolValues = new Expression.BoolValue[INITIAL_POOL_SIZE];
private Expression.LongIntValue[] longIntValues = new Expression.LongIntValue[INITIAL_POOL_SIZE];
private Expression.BigIntValue[] bigIntValues = new Expression.BigIntValue[INITIAL_POOL_SIZE];
private Expression.FloatValue[] floatValues = new Expression.FloatValue[INITIAL_POOL_SIZE];
private Expression.DecimalValue[] decimalValues = new Expression.DecimalValue[INITIAL_POOL_SIZE];
private Expression.TimestampValue[] timestampValues = new Expression.TimestampValue[INITIAL_POOL_SIZE];
private Expression.SymbolValue[] symbolValues = new Expression.SymbolValue[INITIAL_POOL_SIZE];
private Expression.StringValue[] stringValues = new Expression.StringValue[INITIAL_POOL_SIZE];
private Expression.ClobValue[] clobValues = new Expression.ClobValue[INITIAL_POOL_SIZE];
private Expression.BlobValue[] blobValues = new Expression.BlobValue[INITIAL_POOL_SIZE];
private Expression.FieldName[] fieldNames = new Expression.FieldName[INITIAL_POOL_SIZE];
private Expression.EExpression[] eExpressions = new Expression.EExpression[INITIAL_POOL_SIZE];
private Expression.ExpressionGroup[] expressionGroups = new Expression.ExpressionGroup[INITIAL_POOL_SIZE];
private Expression.ListValue[] listValues = new Expression.ListValue[INITIAL_POOL_SIZE];
private Expression.StructValue[] structValues = new Expression.StructValue[INITIAL_POOL_SIZE];
private Expression.SExpValue[] sexpValues = new Expression.SExpValue[INITIAL_POOL_SIZE];

private int nullValuesIndex = 0;
private int boolValuesIndex = 0;
Expand Down

0 comments on commit 8c64373

Please sign in to comment.