github.com/cockroachdb/pebble@v0.0.0-20231214172447-ab4952c5f87b/internal/dsl/predicates.go (about) 1 // Copyright 2023 The LevelDB-Go and Pebble Authors. All rights reserved. Use 2 // of this source code is governed by a BSD-style license that can be found in 3 // the LICENSE file. 4 5 package dsl 6 7 import ( 8 "fmt" 9 "go/token" 10 "strconv" 11 "strings" 12 "sync/atomic" 13 14 "github.com/cockroachdb/errors" 15 ) 16 17 // Predicate encodes conditional logic that yields a boolean. 18 type Predicate[E any] interface { 19 Evaluate(E) bool 20 String() string 21 } 22 23 // Not returns a Predicate that negates the provided predicate. 24 func Not[E any](p Predicate[E]) Predicate[E] { return not[E]{Predicate: p} } 25 26 // And returns a Predicate that evaluates to true if all its operands evaluate 27 // to true. 28 func And[E any](preds ...Predicate[E]) Predicate[E] { return and[E](preds) } 29 30 // Or returns a Predicate that evaluates to true if any of its operands evaluate 31 // true. 32 func Or[E any](preds ...Predicate[E]) Predicate[E] { return or[E](preds) } 33 34 // OnIndex returns a Predicate that evaluates to true on its N-th call. 35 func OnIndex[E any](n int32) *Index[E] { 36 p := new(Index[E]) 37 p.Int32.Store(n) 38 return p 39 } 40 41 // Index is a Predicate that evaluates to true only on its N-th invocation. 42 type Index[E any] struct { 43 atomic.Int32 44 } 45 46 // String implements fmt.Stringer. 47 func (p *Index[E]) String() string { 48 return fmt.Sprintf("(OnIndex %d)", p.Int32.Load()) 49 } 50 51 // Evaluate implements Predicate. 52 func (p *Index[E]) Evaluate(E) bool { return p.Int32.Add(-1) == -1 } 53 54 type not[E any] struct { 55 Predicate[E] 56 } 57 58 func (p not[E]) String() string { return fmt.Sprintf("(Not %s)", p.Predicate.String()) } 59 func (p not[E]) Evaluate(e E) bool { return !p.Predicate.Evaluate(e) } 60 61 type and[E any] []Predicate[E] 62 63 func (p and[E]) String() string { 64 var sb strings.Builder 65 sb.WriteString("(And") 66 for i := 0; i < len(p); i++ { 67 sb.WriteRune(' ') 68 sb.WriteString(p[i].String()) 69 } 70 sb.WriteRune(')') 71 return sb.String() 72 } 73 74 func (p and[E]) Evaluate(e E) bool { 75 ok := true 76 for i := range p { 77 ok = ok && p[i].Evaluate(e) 78 } 79 return ok 80 } 81 82 type or[E any] []Predicate[E] 83 84 func (p or[E]) String() string { 85 var sb strings.Builder 86 sb.WriteString("(Or") 87 for i := 0; i < len(p); i++ { 88 sb.WriteRune(' ') 89 sb.WriteString(p[i].String()) 90 } 91 sb.WriteRune(')') 92 return sb.String() 93 } 94 95 func (p or[E]) Evaluate(e E) bool { 96 ok := false 97 for i := range p { 98 ok = ok || p[i].Evaluate(e) 99 } 100 return ok 101 } 102 103 func parseNot[E any](p *Parser[Predicate[E]], s *Scanner) Predicate[E] { 104 preds := parseVariadicPredicate(p, s) 105 if len(preds) != 1 { 106 panic(errors.Newf("dsl: not accepts exactly 1 argument, given %d", len(preds))) 107 } 108 return not[E]{Predicate: preds[0]} 109 } 110 111 func parseAnd[E any](p *Parser[Predicate[E]], s *Scanner) Predicate[E] { 112 return And[E](parseVariadicPredicate[E](p, s)...) 113 } 114 115 func parseOr[E any](p *Parser[Predicate[E]], s *Scanner) Predicate[E] { 116 return Or[E](parseVariadicPredicate[E](p, s)...) 117 } 118 119 func parseOnIndex[E any](p *Parser[Predicate[E]], s *Scanner) Predicate[E] { 120 i, err := strconv.ParseInt(s.Consume(token.INT).Lit, 10, 32) 121 if err != nil { 122 panic(err) 123 } 124 s.Consume(token.RPAREN) 125 return OnIndex[E](int32(i)) 126 } 127 128 func parseVariadicPredicate[E any](p *Parser[Predicate[E]], s *Scanner) (ret []Predicate[E]) { 129 tok := s.Scan() 130 for tok.Kind == token.LPAREN || tok.Kind == token.IDENT { 131 ret = append(ret, p.ParseFromPos(s, tok)) 132 tok = s.Scan() 133 } 134 assertTok(tok, token.RPAREN) 135 return ret 136 }