Skip to content
This repository was archived by the owner on Mar 16, 2025. It is now read-only.

Commit e84576d

Browse files
committed
optimize performace when setting multiple variables at once (closes #4)
1 parent d29a620 commit e84576d

3 files changed

Lines changed: 76 additions & 17 deletions

File tree

pkg/builtin/lists/functions.go

Lines changed: 44 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -68,12 +68,17 @@ func rangeVectorFunction(ctx types.Context, data []any, namingVec ast.Expression
6868
)
6969

7070
for i, item := range data {
71-
// do not use separate contexts for each loop iteration, as the loop might build up a counter
72-
loopCtx = loopCtx.WithVariable(loopVarName, item)
71+
vars := map[string]any{
72+
loopVarName: item,
73+
}
74+
7375
if loopIndexName != "" {
74-
loopCtx = loopCtx.WithVariable(loopIndexName, i)
76+
vars[loopIndexName] = i
7577
}
7678

79+
// do not use separate contexts for each loop iteration, as the loop might build up a counter
80+
loopCtx = loopCtx.WithVariables(vars)
81+
7782
loopCtx, result, err = eval.EvalExpression(loopCtx, expr)
7883
if err != nil {
7984
return nil, err
@@ -98,12 +103,17 @@ func rangeObjectFunction(ctx types.Context, data map[string]any, namingVec ast.E
98103
)
99104

100105
for key, value := range data {
101-
// do not use separate contexts for each loop iteration, as the loop might build up a counter
102-
loopCtx = loopCtx.WithVariable(loopVarName, value)
106+
vars := map[string]any{
107+
loopVarName: value,
108+
}
109+
103110
if loopIndexName != "" {
104-
loopCtx = loopCtx.WithVariable(loopIndexName, key)
111+
vars[loopIndexName] = key
105112
}
106113

114+
// do not use separate contexts for each loop iteration, as the loop might build up a counter
115+
loopCtx = loopCtx.WithVariables(vars)
116+
107117
loopCtx, result, err = eval.EvalExpression(loopCtx, expr)
108118
if err != nil {
109119
return nil, err
@@ -140,11 +150,16 @@ func mapVectorExpressionFunction(ctx types.Context, data []any, namingVec ast.Ex
140150
}
141151

142152
mapHandler := func(ctx types.Context, index any, value any) (types.Context, any, error) {
143-
ctx = ctx.WithVariable(valueVarName, value)
153+
vars := map[string]any{
154+
valueVarName: value,
155+
}
156+
144157
if indexVarName != "" {
145-
ctx = ctx.WithVariable(indexVarName, index)
158+
vars[indexVarName] = index
146159
}
147160

161+
ctx = ctx.WithVariables(vars)
162+
148163
return eval.EvalExpression(ctx, expr)
149164
}
150165

@@ -197,11 +212,16 @@ func mapObjectExpressionFunction(ctx types.Context, data map[string]any, namingV
197212
}
198213

199214
mapHandler := func(ctx types.Context, key any, value any) (types.Context, any, error) {
200-
ctx = ctx.WithVariable(valueVarName, value)
215+
vars := map[string]any{
216+
valueVarName: value,
217+
}
218+
201219
if keyVarName != "" {
202-
ctx = ctx.WithVariable(keyVarName, key)
220+
vars[keyVarName] = key
203221
}
204222

223+
ctx = ctx.WithVariables(vars)
224+
205225
return eval.EvalExpression(ctx, expr)
206226
}
207227

@@ -254,11 +274,16 @@ func filterVectorExpressionFunction(ctx types.Context, data []any, namingVec ast
254274
}
255275

256276
mapHandler := func(ctx types.Context, index any, value any) (types.Context, any, error) {
257-
ctx = ctx.WithVariable(valueVarName, value)
277+
vars := map[string]any{
278+
valueVarName: value,
279+
}
280+
258281
if indexVarName != "" {
259-
ctx = ctx.WithVariable(indexVarName, index)
282+
vars[indexVarName] = index
260283
}
261284

285+
ctx = ctx.WithVariables(vars)
286+
262287
return eval.EvalExpression(ctx, expr)
263288
}
264289

@@ -317,11 +342,16 @@ func filterObjectExpressionFunction(ctx types.Context, data map[string]any, nami
317342
}
318343

319344
mapHandler := func(ctx types.Context, key any, value any) (types.Context, any, error) {
320-
ctx = ctx.WithVariable(valueVarName, value)
345+
vars := map[string]any{
346+
valueVarName: value,
347+
}
348+
321349
if keyVarName != "" {
322-
ctx = ctx.WithVariable(keyVarName, key)
350+
vars[keyVarName] = key
323351
}
324352

353+
ctx = ctx.WithVariables(vars)
354+
325355
return eval.EvalExpression(ctx, expr)
326356
}
327357

pkg/builtin/rudifunc/functions.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,17 +75,17 @@ func (f rudispaceFunc) Evaluate(ctx types.Context, args []ast.Expression) (any,
7575
return nil, fmt.Errorf("expected %d argument(s), got %d", len(f.params), len(args))
7676
}
7777

78-
funcCtx := ctx
78+
funcArgs := map[string]any{}
7979
for i, paramName := range f.params {
8080
_, arg, err := eval.EvalExpression(ctx, args[i])
8181
if err != nil {
8282
return nil, err
8383
}
8484

85-
funcCtx = funcCtx.WithVariable(paramName, arg)
85+
funcArgs[paramName] = arg
8686
}
8787

88-
_, result, err := eval.EvalExpression(funcCtx, f.body)
88+
_, result, err := eval.EvalExpression(ctx.WithVariables(funcArgs), f.body)
8989

9090
return result, err
9191
}

pkg/eval/types/context.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,21 @@ func (c Context) WithVariable(name string, val any) Context {
113113
}
114114
}
115115

116+
func (c Context) WithVariables(vars map[string]any) Context {
117+
if len(vars) == 0 {
118+
return c
119+
}
120+
121+
return Context{
122+
ctx: c.ctx,
123+
document: c.document,
124+
fixedFuncs: c.fixedFuncs,
125+
userFuncs: c.userFuncs,
126+
variables: c.variables.WithMany(vars),
127+
coalescer: c.coalescer,
128+
}
129+
}
130+
116131
func (c Context) WithCoalescer(coalescer coalescing.Coalescer) Context {
117132
return Context{
118133
ctx: c.ctx,
@@ -246,6 +261,20 @@ func (v Variables) With(name string, val any) Variables {
246261
return v.DeepCopy().Set(name, val)
247262
}
248263

264+
// WithMany is like With(), but for adding multiple new variables at once. This
265+
// should be preferred to With() to prevent unnecessary DeepCopies.
266+
func (v Variables) WithMany(vars map[string]any) Variables {
267+
if len(vars) == 0 {
268+
return v
269+
}
270+
271+
out := v.DeepCopy()
272+
for k, v := range vars {
273+
out.Set(k, v)
274+
}
275+
return out
276+
}
277+
249278
func (v Variables) DeepCopy() Variables {
250279
result := NewVariables()
251280
for key, val := range v {

0 commit comments

Comments
 (0)