github.com/egonelbre/exp@v0.0.0-20240430123955-ed1d3aa93911/brutecheck/main.go (about)

     1  package main
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"go/format"
     7  	"io/ioutil"
     8  	"os"
     9  	"path/filepath"
    10  	"strings"
    11  )
    12  
    13  func main() {
    14  	var keywords = []string{
    15  		"break", "case", "chan", "const", "continue",
    16  		"default", "defer", "else", "fallthrough", "for", "func", "go",
    17  		"goto", "if", "import", "interface", "map", "package", "range", "return",
    18  		"select", "struct", "switch", "type", "var",
    19  	}
    20  
    21  	allfuncs := []string{}
    22  
    23  	generators := []Generator{
    24  		LengthSingle{},
    25  		Uint64Switch{},
    26  		MapCheck{},
    27  		TwoHashShift{},
    28  		TwoHashShiftTable{},
    29  		TwoHashShiftAlt{},
    30  		TwoHashShiftTableAlt{},
    31  	}
    32  	for _, gen := range generators {
    33  		genname := strings.ToLower(fmt.Sprintf("%T", gen))
    34  		genname = strings.TrimPrefix(genname, "main.")
    35  
    36  		p := &BasicPrinter{}
    37  		p.F("package check\n\n")
    38  		gen.Generate(p, append([]string{}, keywords...))
    39  
    40  		emitfile(filepath.Join("check", genname)+".go", p.Bytes())
    41  
    42  		allfuncs = append(allfuncs, p.FuncNames()...)
    43  	}
    44  
    45  	{
    46  		p := &BasicPrinter{}
    47  		p.F("package main\n\n")
    48  		p.F("import . \"github.com/egonelbre/exp/brutecheck/check\"\n\n")
    49  		for _, fn := range allfuncs {
    50  			p.F("func Bench%s(words []string, repeat int) int {\n", fn)
    51  			p.F("var count int\n")
    52  			p.F("for i := 0; i < repeat; i++ {\n")
    53  			p.F("for _, word := range words {\n")
    54  			p.F("if %s(word) { count++ }\n", fn)
    55  			p.F("}\n")
    56  			p.F("}\n")
    57  			p.F("return count\n")
    58  			p.F("}\n\n")
    59  		}
    60  		emitfile(filepath.Join("bench", "bench.go"), p.Bytes())
    61  	}
    62  
    63  	{
    64  		p := &BasicPrinter{}
    65  		p.F("package main\n\n")
    66  		p.F("type Bench struct { Name string; Fn func([]string, int) int }\n\n")
    67  		p.F("var AllBenches = []Bench{\n")
    68  		for _, fn := range allfuncs {
    69  			p.F("{Name:%q, Fn: Bench%s},\n", fn, fn)
    70  		}
    71  		p.F("}")
    72  		emitfile(filepath.Join("bench", "list.go"), p.Bytes())
    73  	}
    74  }
    75  
    76  func emitfile(name string, data []byte) {
    77  	formatted, err := format.Source(data)
    78  	if err != nil {
    79  		fmt.Fprintf(os.Stderr, "failed to format: %v\n", err)
    80  		fmt.Fprintf(os.Stderr, "-----")
    81  		if len(data) > 1000 {
    82  			data = data[:1000]
    83  		}
    84  		fmt.Fprint(os.Stderr, string(data))
    85  		os.Exit(1)
    86  	}
    87  
    88  	err = ioutil.WriteFile(name, formatted, 0644)
    89  	if err != nil {
    90  		fmt.Fprintf(os.Stderr, "failed to write: %v\n", err)
    91  		os.Exit(1)
    92  	}
    93  }
    94  
    95  type Generator interface {
    96  	Generate(p Printer, keywords []string)
    97  }
    98  
    99  type Printer interface {
   100  	FuncName(fnname string)
   101  	FuncNames() []string
   102  
   103  	F(format string, args ...interface{})
   104  	Bytes() []byte
   105  }
   106  
   107  type BasicPrinter struct {
   108  	Funcs  []string
   109  	Buffer bytes.Buffer
   110  }
   111  
   112  func (p *BasicPrinter) FuncName(fnname string) {
   113  	p.Funcs = append(p.Funcs, fnname)
   114  }
   115  
   116  func (p *BasicPrinter) FuncNames() []string {
   117  	return p.Funcs
   118  }
   119  
   120  func (p *BasicPrinter) F(format string, args ...interface{}) {
   121  	fmt.Fprintf(&p.Buffer, format, args...)
   122  }
   123  
   124  func (p *BasicPrinter) Bytes() []byte {
   125  	return p.Buffer.Bytes()
   126  }