github.com/cockroachdb/pebble@v1.1.1-0.20240513155919-3622ade60459/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  }