Skip to content

Commit b090905

Browse files
authored
Merge branch 'google:master' into master
2 parents cf3b953 + 1aae83a commit b090905

File tree

2 files changed

+87
-0
lines changed

2 files changed

+87
-0
lines changed

checker/cost.go

+26
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,15 @@ func (c *coster) sizeEstimate(t AstNode) SizeEstimate {
476476
if l := c.estimator.EstimateSize(t); l != nil {
477477
return *l
478478
}
479+
// return an estimate of 1 for return types of set
480+
// lengths, since strings/bytes/more complex objects could be of
481+
// variable length
482+
if isScalar(t.Type()) {
483+
// TODO: since the logic for size estimation is split between
484+
// ComputedSize and isScalar, changing one will likely require changing
485+
// the other, so they should be merged in the future if possible
486+
return SizeEstimate{Min: 1, Max: 1}
487+
}
479488
return SizeEstimate{Min: 0, Max: math.MaxUint64}
480489
}
481490

@@ -599,3 +608,20 @@ func (c *coster) newAstNode(e *exprpb.Expr) *astNode {
599608
}
600609
return &astNode{path: path, t: c.getType(e), expr: e, derivedSize: derivedSize}
601610
}
611+
612+
// isScalar returns true if the given type is known to be of a constant size at
613+
// compile time. isScalar will return false for strings (they are variable-width)
614+
// in addition to protobuf.Any and protobuf.Value (their size is not knowable at compile time).
615+
func isScalar(t *exprpb.Type) bool {
616+
switch kindOf(t) {
617+
case kindPrimitive:
618+
if t.GetPrimitive() != exprpb.Type_STRING && t.GetPrimitive() != exprpb.Type_BYTES {
619+
return true
620+
}
621+
case kindWellKnown:
622+
if t.GetWellKnown() == exprpb.Type_DURATION || t.GetWellKnown() == exprpb.Type_TIMESTAMP {
623+
return true
624+
}
625+
}
626+
return false
627+
}

checker/cost_test.go

+61
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,67 @@ func TestCost(t *testing.T) {
354354
hints: map[string]int64{"str1": 10, "str2": 10},
355355
wanted: CostEstimate{Min: 2, Max: 6},
356356
},
357+
{
358+
name: "list size comparison",
359+
expr: `list1.size() == list2.size()`,
360+
decls: []*exprpb.Decl{
361+
decls.NewVar("list1", decls.NewListType(decls.Int)),
362+
decls.NewVar("list2", decls.NewListType(decls.Int)),
363+
},
364+
wanted: CostEstimate{Min: 5, Max: 5},
365+
},
366+
{
367+
name: "list size from ternary",
368+
expr: `x > y ? list1.size() : list2.size()`,
369+
decls: []*exprpb.Decl{
370+
decls.NewVar("x", decls.Int),
371+
decls.NewVar("y", decls.Int),
372+
decls.NewVar("list1", decls.NewListType(decls.Int)),
373+
decls.NewVar("list2", decls.NewListType(decls.Int)),
374+
},
375+
wanted: CostEstimate{Min: 5, Max: 5},
376+
},
377+
{
378+
name: "str endsWith equality",
379+
expr: `str1.endsWith("abcdefghijklmnopqrstuvwxyz") == str2.endsWith("abcdefghijklmnopqrstuvwxyz")`,
380+
decls: []*exprpb.Decl{
381+
decls.NewVar("str1", decls.String),
382+
decls.NewVar("str2", decls.String),
383+
},
384+
wanted: CostEstimate{Min: 9, Max: 9},
385+
},
386+
{
387+
name: "nested subexpression operators",
388+
expr: `((5 != 6) == (1 == 2)) == ((3 <= 4) == (9 != 9))`,
389+
wanted: CostEstimate{Min: 7, Max: 7},
390+
},
391+
{
392+
name: "str size estimate",
393+
expr: `string(timestamp1) == string(timestamp2)`,
394+
decls: []*exprpb.Decl{
395+
decls.NewVar("timestamp1", decls.Timestamp),
396+
decls.NewVar("timestamp2", decls.Timestamp),
397+
},
398+
wanted: CostEstimate{Min: 5, Max: 1844674407370955268},
399+
},
400+
{
401+
name: "timestamp equality check",
402+
expr: `timestamp1 == timestamp2`,
403+
decls: []*exprpb.Decl{
404+
decls.NewVar("timestamp1", decls.Timestamp),
405+
decls.NewVar("timestamp2", decls.Timestamp),
406+
},
407+
wanted: CostEstimate{Min: 3, Max: 3},
408+
},
409+
{
410+
name: "duration inequality check",
411+
expr: `duration1 != duration2`,
412+
decls: []*exprpb.Decl{
413+
decls.NewVar("duration1", decls.Duration),
414+
decls.NewVar("duration2", decls.Duration),
415+
},
416+
wanted: CostEstimate{Min: 3, Max: 3},
417+
},
357418
}
358419

359420
for _, tc := range cases {

0 commit comments

Comments
 (0)