github.com/bytedance/gopkg@v0.0.0-20240514070511-01b2cbcf35e1/collection/skipset/types_gen.go (about)

     1  // Copyright 2021 ByteDance Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  //go:build ignore
    16  // +build ignore
    17  
    18  package main
    19  
    20  import (
    21  	"bytes"
    22  	"go/format"
    23  	"io/ioutil"
    24  	"os"
    25  	"strings"
    26  )
    27  
    28  func main() {
    29  	f, err := os.Open("skipset.go")
    30  	if err != nil {
    31  		panic(err)
    32  	}
    33  	filedata, err := ioutil.ReadAll(f)
    34  	if err != nil {
    35  		panic(err)
    36  	}
    37  
    38  	w := new(bytes.Buffer)
    39  	w.WriteString(`// Copyright 2021 ByteDance Inc.
    40  //
    41  // Licensed under the Apache License, Version 2.0 (the "License");
    42  // you may not use this file except in compliance with the License.
    43  // You may obtain a copy of the License at
    44  //
    45  //     http://www.apache.org/licenses/LICENSE-2.0
    46  //
    47  // Unless required by applicable law or agreed to in writing, software
    48  // distributed under the License is distributed on an "AS IS" BASIS,
    49  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    50  // See the License for the specific language governing permissions and
    51  // limitations under the License.
    52  
    53  `)
    54  	// Step 1. Add file header
    55  	w.WriteString(`// Code generated by go run types_gen.go; DO NOT EDIT.` + "\r\n")
    56  	// Step 2. Add imports and package statement
    57  	w.WriteString(string(filedata)[strings.Index(string(filedata), "package skipset") : strings.Index(string(filedata), ")\n")+1])
    58  	// Step 3. Generate code for all basic types
    59  	ts := []string{"Float32", "Float64", "Int32", "Int16", "Int", "Uint64", "Uint32", "Uint16", "Uint"} // all types need to be converted
    60  	for _, upper := range ts {
    61  		data := string(filedata)
    62  		// Step 4-1. Remove all string before import
    63  		data = data[strings.Index(data, ")\n")+1:]
    64  		// Step 4-2. Replace all cases
    65  		dataDesc := replace(data, upper, true)
    66  		dataAsc := replace(data, upper, false)
    67  		w.WriteString(dataAsc)
    68  		w.WriteString("\r\n")
    69  		w.WriteString(dataDesc)
    70  		w.WriteString("\r\n")
    71  	}
    72  	// Step 5. Generate string set
    73  	data := string(filedata)
    74  	data = data[strings.Index(data, ")\n")+1:]
    75  	datastring := replaceString(data)
    76  	w.WriteString(datastring)
    77  	w.WriteString("\r\n")
    78  
    79  	out, err := format.Source(w.Bytes())
    80  	if err != nil {
    81  		panic(err)
    82  	}
    83  
    84  	if err := ioutil.WriteFile("types.go", out, 0660); err != nil {
    85  		panic(err)
    86  	}
    87  }
    88  
    89  func replace(data string, upper string, desc bool) string {
    90  	lower := strings.ToLower(upper)
    91  
    92  	var descstr string
    93  	if desc {
    94  		descstr = "Desc"
    95  	}
    96  	data = strings.Replace(data, "NewInt64", "New"+upper+descstr, -1)
    97  	data = strings.Replace(data, "newInt64Node", "new"+upper+"Node"+descstr, -1)
    98  	data = strings.Replace(data, "unlockInt64", "unlock"+upper+descstr, -1)
    99  	data = strings.Replace(data, "Int64Set", upper+"Set"+descstr, -1)
   100  	data = strings.Replace(data, "int64Node", lower+"Node"+descstr, -1)
   101  	data = strings.Replace(data, "value int64", "value "+lower, -1)
   102  	data = strings.Replace(data, "int64 skip set", lower+" skip set", -1) // comment
   103  
   104  	if desc {
   105  		// Special cases for DESC.
   106  		data = strings.Replace(data, "ascending", "descending", -1)
   107  		data = strings.Replace(data, "return n.value < value", "return n.value > value", -1)
   108  	}
   109  	return data
   110  }
   111  
   112  func replaceString(data string) string {
   113  	const (
   114  		upper = "String"
   115  		lower = "string"
   116  	)
   117  
   118  	// Add `score uint64` field.
   119  	data = strings.Replace(data,
   120  		`type int64Node struct {
   121  	value int64`,
   122  		`type int64Node struct {
   123  	value int64
   124  	score uint64`, -1)
   125  
   126  	data = strings.Replace(data,
   127  		`&int64Node{`,
   128  		`&int64Node{
   129  		score: hash(value),`, -1)
   130  
   131  	// Refactor comparison.
   132  	data = data + "\n"
   133  	data += `// Return 1 if n is bigger, 0 if equal, else -1.
   134  func (n *stringNode) cmp(score uint64, value string) int {
   135  	if n.score > score {
   136  		return 1
   137  	} else if n.score == score {
   138  		return cmpstring(n.value, value)
   139  	}
   140  	return -1
   141  }`
   142  
   143  	data = strings.Replace(data,
   144  		`.lessthan(value)`,
   145  		`.cmp(score, value) < 0`, -1)
   146  	data = strings.Replace(data,
   147  		`.equal(value)`,
   148  		`.cmp(score, value) == 0`, -1)
   149  
   150  	// Remove `lessthan` and `equal`
   151  	data = strings.Replace(data,
   152  		`func (n *int64Node) lessthan(value int64) bool {
   153  	return n.value < value
   154  }`, "", -1)
   155  	data = strings.Replace(data,
   156  		`func (n *int64Node) equal(value int64) bool {
   157  	return n.value == value
   158  }`, "", -1)
   159  
   160  	// Add "score := hash(value)"
   161  	data = addLineAfter(data, "func (s *Int64Set) findNodeRemove", "score := hash(value)")
   162  	data = addLineAfter(data, "func (s *Int64Set) findNodeAdd", "score := hash(value)")
   163  	data = addLineAfter(data, "func (s *Int64Set) Contains", "score := hash(value)")
   164  
   165  	// Update new value "newInt64Node(0"
   166  	data = strings.Replace(data,
   167  		"newInt64Node(0", `newInt64Node(""`, -1)
   168  
   169  	data = strings.Replace(data, "NewInt64", "New"+upper, -1)
   170  	data = strings.Replace(data, "newInt64Node", "new"+upper+"Node", -1)
   171  	data = strings.Replace(data, "unlockInt64", "unlock"+upper, -1)
   172  	data = strings.Replace(data, "Int64Set", upper+"Set", -1)
   173  	data = strings.Replace(data, "int64Node", lower+"Node", -1)
   174  	data = strings.Replace(data, "value int64", "value "+lower, -1)
   175  	data = strings.Replace(data, "int64 skip set", lower+" skip set", -1) // comment
   176  	data = strings.Replace(data, " in ascending order", "", -1)           // comment
   177  
   178  	return data
   179  }
   180  
   181  func lowerSlice(s []string) []string {
   182  	n := make([]string, len(s))
   183  	for i, v := range s {
   184  		n[i] = strings.ToLower(v)
   185  	}
   186  	return n
   187  }
   188  
   189  func inSlice(s []string, val string) bool {
   190  	for _, v := range s {
   191  		if v == val {
   192  			return true
   193  		}
   194  	}
   195  	return false
   196  }
   197  
   198  func addLineAfter(src string, after string, added string) string {
   199  	all := strings.Split(string(src), "\n")
   200  	for i, v := range all {
   201  		if strings.Index(v, after) != -1 {
   202  			res := make([]string, len(all)+1)
   203  			for j := 0; j <= i; j++ {
   204  				res[j] = all[j]
   205  			}
   206  			res[i+1] = added
   207  			for j := i + 1; j < len(all); j++ {
   208  				res[j+1] = all[j]
   209  			}
   210  			return strings.Join(res, "\n")
   211  		}
   212  	}
   213  	panic("can not find:" + after)
   214  }