Skip to content

Commit 3aed16e

Browse files
authored
Implement vector in expressions (#5517)
1 parent 3284256 commit 3aed16e

File tree

5 files changed

+140
-6
lines changed

5 files changed

+140
-6
lines changed

compiler/kernel/vexpr.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,8 @@ func (b *Builder) compileVamBinary(e *dag.BinaryExpr) (vamexpr.Evaluator, error)
100100
return vamexpr.NewLogicalAnd(b.zctx(), lhs, rhs), nil
101101
case "or":
102102
return vamexpr.NewLogicalOr(b.zctx(), lhs, rhs), nil
103-
//case "in": XXX TBD
104-
// return vamexpr.NewIn(b.zctx(), lhs, rhs), nil
103+
case "in":
104+
return vamexpr.NewIn(b.zctx(), lhs, rhs), nil
105105
case "==", "!=", "<", "<=", ">", ">=":
106106
return vamexpr.NewCompare(b.zctx(), lhs, rhs, op), nil
107107
case "+", "-", "*", "/", "%":

runtime/vam/expr/logic.go

+101
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package expr
22

33
import (
4+
"slices"
5+
46
"github.com/brimdata/super"
57
"github.com/brimdata/super/vector"
68
)
@@ -177,6 +179,18 @@ func toBool(vec vector.Any) *vector.Bool {
177179
} else {
178180
return vector.NewBoolEmpty(vec.Len(), vec.Nulls)
179181
}
182+
case *vector.Dynamic:
183+
nulls := vector.NewBoolEmpty(vec.Len(), nil)
184+
out := vector.NewBoolEmpty(vec.Len(), nulls)
185+
for i := range vec.Len() {
186+
v, null := vector.BoolValue(vec, i)
187+
if null {
188+
nulls.Set(i)
189+
} else if v {
190+
out.Set(i)
191+
}
192+
}
193+
return out
180194
case *vector.Bool:
181195
return vec
182196
default:
@@ -191,3 +205,90 @@ func trueBool(n uint32) *vector.Bool {
191205
}
192206
return vec
193207
}
208+
209+
type In struct {
210+
zctx *super.Context
211+
lhs Evaluator
212+
rhs Evaluator
213+
eq *Compare
214+
}
215+
216+
func NewIn(zctx *super.Context, lhs, rhs Evaluator) *In {
217+
return &In{zctx, lhs, rhs, NewCompare(zctx, nil, nil, "==")}
218+
}
219+
220+
func (i *In) Eval(this vector.Any) vector.Any {
221+
return vector.Apply(true, i.eval, i.lhs.Eval(this), i.rhs.Eval(this))
222+
}
223+
224+
func (i *In) eval(vecs ...vector.Any) vector.Any {
225+
lhs, rhs := vecs[0], vecs[1]
226+
if lhs.Type().Kind() == super.ErrorKind {
227+
return lhs
228+
}
229+
if rhs.Type().Kind() == super.ErrorKind {
230+
return rhs
231+
}
232+
return i.evalResursive(lhs, rhs)
233+
}
234+
235+
func (i *In) evalResursive(vecs ...vector.Any) vector.Any {
236+
lhs, rhs := vecs[0], vecs[1]
237+
rhs = vector.Under(rhs)
238+
var index []uint32
239+
if view, ok := rhs.(*vector.View); ok {
240+
rhs = view.Any
241+
index = view.Index
242+
}
243+
switch rhs := rhs.(type) {
244+
case *vector.Record:
245+
out := vector.NewBoolEmpty(lhs.Len(), nil)
246+
for _, f := range rhs.Fields {
247+
if index != nil {
248+
f = vector.NewView(f, index)
249+
}
250+
out = vector.Or(out, toBool(i.evalResursive(lhs, f)))
251+
}
252+
return out
253+
case *vector.Array:
254+
return i.evalForList(lhs, rhs.Values, rhs.Offsets, index)
255+
case *vector.Set:
256+
return i.evalForList(lhs, rhs.Values, rhs.Offsets, index)
257+
case *vector.Map:
258+
return vector.Or(i.evalForList(lhs, rhs.Keys, rhs.Offsets, index),
259+
i.evalForList(lhs, rhs.Values, rhs.Offsets, index))
260+
case *vector.Union:
261+
return vector.Apply(true, i.evalResursive, lhs, rhs)
262+
case *vector.Error:
263+
return i.evalResursive(lhs, rhs.Vals)
264+
default:
265+
return i.eq.eval(lhs, rhs)
266+
}
267+
}
268+
269+
func (i *In) evalForList(lhs, rhs vector.Any, offsets, index []uint32) *vector.Bool {
270+
out := vector.NewBoolEmpty(lhs.Len(), nil)
271+
var lhsIndex, rhsIndex []uint32
272+
for j := range lhs.Len() {
273+
if index != nil {
274+
j = index[j]
275+
}
276+
start, end := offsets[j], offsets[j+1]
277+
if start == end {
278+
continue
279+
}
280+
n := end - start
281+
lhsIndex = slices.Grow(lhsIndex[:0], int(n))[:n]
282+
rhsIndex = slices.Grow(rhsIndex[:0], int(n))[:n]
283+
for k := range n {
284+
lhsIndex[k] = k
285+
rhsIndex[k] = k + start
286+
}
287+
lhsView := vector.NewView(lhs, lhsIndex)
288+
rhsView := vector.NewView(rhs, rhsIndex)
289+
if toBool(i.evalResursive(lhsView, rhsView)).TrueCount() > 0 {
290+
out.Set(j)
291+
}
292+
}
293+
return out
294+
}

runtime/sam/expr/ztests/in-field.yaml runtime/ztests/expr/in-field.yaml

+2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
zed: 2 in a
22

3+
vector: true
4+
35
input: |
46
{a:[1(uint32),2(uint32)]}
57
{a:[1(uint32)]}

runtime/ztests/expr/in.yaml

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
zed: |
2+
yield [1 in this, 9 in this]
3+
4+
vector: true
5+
6+
input: |
7+
1
8+
{a:1}
9+
[0,1,2]
10+
|[0,1,2]|
11+
|{1:null}|
12+
|{null:1}|
13+
1((int64,string))
14+
{a:[0,1]([(int64,string)])}
15+
[error(0),error(1)]
16+
error(0)
17+
18+
output: |
19+
[true,false]
20+
[true,false]
21+
[true,false]
22+
[true,false]
23+
[true,false]
24+
[true,false]
25+
[true,false]
26+
[true,false]
27+
[true,false]
28+
[error(0),error(0)]

vector/bool.go

+7-4
Original file line numberDiff line numberDiff line change
@@ -146,21 +146,24 @@ func And(a, b *Bool) *Bool {
146146

147147
// BoolValue returns the value of slot in vec if the value is a Boolean. It
148148
// returns false otherwise.
149-
func BoolValue(vec Any, slot uint32) bool {
149+
func BoolValue(vec Any, slot uint32) (bool, bool) {
150150
switch vec := Under(vec).(type) {
151151
case *Bool:
152-
return vec.Value(slot)
152+
return vec.Value(slot), vec.Nulls.Value(slot)
153153
case *Const:
154-
return vec.Value().Ptr().AsBool()
154+
return vec.Value().Ptr().AsBool(), vec.Nulls.Value(slot)
155155
case *Dict:
156+
if vec.Nulls.Value(slot) {
157+
return false, true
158+
}
156159
return BoolValue(vec.Any, uint32(vec.Index[slot]))
157160
case *Dynamic:
158161
tag := vec.Tags[slot]
159162
return BoolValue(vec.Values[tag], vec.TagMap.Forward[slot])
160163
case *View:
161164
return BoolValue(vec.Any, vec.Index[slot])
162165
}
163-
return false
166+
panic(vec)
164167
}
165168

166169
func NullsOf(v Any) *Bool {

0 commit comments

Comments
 (0)