├── .github └── workflows │ └── tests.yml ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── automaton.go ├── builder.go ├── builder_test.go ├── cmd └── vellum │ ├── cmd │ ├── dot.go │ ├── dump.go │ ├── fuzzy.go │ ├── grep.go │ ├── info.go │ ├── map.go │ ├── range.go │ ├── root.go │ ├── set.go │ └── svg.go │ └── main.go ├── common.go ├── common_test.go ├── data └── words-1000.txt ├── decoder_v1.go ├── decoder_v1_test.go ├── docs ├── demo1.png ├── demo1.svg ├── demo2.png ├── demo2.svg ├── demo3.png ├── demo3.svg ├── demo4.png ├── demo4.svg ├── format.md └── logo.png ├── encoder_v1.go ├── encoder_v1_test.go ├── encoding.go ├── example_test.go ├── fst.go ├── fst_iterator.go ├── fst_iterator_test.go ├── go.mod ├── go.sum ├── levenshtein ├── LICENSE ├── README.md ├── alphabet.go ├── alphabet_test.go ├── benchmark_test.go ├── dfa.go ├── dfa_test.go ├── levenshtein.go ├── levenshtein_nfa.go ├── levenshtein_test.go └── parametric_dfa.go ├── merge_iterator.go ├── merge_iterator_test.go ├── pack.go ├── pack_test.go ├── regexp ├── compile.go ├── compile_test.go ├── dfa.go ├── inst.go ├── regexp.go ├── regexp_test.go ├── sparse.go └── sparse_test.go ├── registry.go ├── registry_test.go ├── transducer.go ├── utf8 ├── utf8.go └── utf8_test.go ├── vellum.go ├── vellum_mmap.go ├── vellum_nommap.go ├── vellum_test.go ├── vendor ├── github.com │ ├── edsrzf │ │ └── mmap-go │ │ │ ├── LICENSE │ │ │ ├── mmap.go │ │ │ ├── mmap_unix.go │ │ │ ├── mmap_windows.go │ │ │ ├── msync_netbsd.go │ │ │ └── msync_unix.go │ ├── inconshreveable │ │ └── mousetrap │ │ │ ├── LICENSE │ │ │ ├── trap_others.go │ │ │ ├── trap_windows.go │ │ │ └── trap_windows_1.4.go │ ├── spf13 │ │ ├── cobra │ │ │ ├── LICENSE.txt │ │ │ ├── bash_completions.go │ │ │ ├── cobra.go │ │ │ ├── command.go │ │ │ ├── command_notwin.go │ │ │ ├── command_win.go │ │ │ └── doc │ │ │ │ ├── man_docs.go │ │ │ │ ├── md_docs.go │ │ │ │ ├── util.go │ │ │ │ └── yaml_docs.go │ │ └── pflag │ │ │ ├── LICENSE │ │ │ ├── bool.go │ │ │ ├── bool_slice.go │ │ │ ├── count.go │ │ │ ├── duration.go │ │ │ ├── flag.go │ │ │ ├── float32.go │ │ │ ├── float64.go │ │ │ ├── golangflag.go │ │ │ ├── int.go │ │ │ ├── int32.go │ │ │ ├── int64.go │ │ │ ├── int8.go │ │ │ ├── int_slice.go │ │ │ ├── ip.go │ │ │ ├── ip_slice.go │ │ │ ├── ipmask.go │ │ │ ├── ipnet.go │ │ │ ├── string.go │ │ │ ├── string_array.go │ │ │ ├── string_slice.go │ │ │ ├── uint.go │ │ │ ├── uint16.go │ │ │ ├── uint32.go │ │ │ ├── uint64.go │ │ │ ├── uint8.go │ │ │ └── uint_slice.go │ └── willf │ │ └── bitset │ │ ├── LICENSE │ │ ├── bitset.go │ │ ├── popcnt.go │ │ ├── popcnt_amd64.go │ │ ├── popcnt_amd64.s │ │ └── popcnt_generic.go └── manifest ├── writer.go └── writer_test.go /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: 4 | - master 5 | pull_request: 6 | name: Tests 7 | jobs: 8 | test: 9 | strategy: 10 | matrix: 11 | go-version: [1.13.x, 1.14.x] 12 | platform: [ubuntu-latest, macos-latest, windows-latest] 13 | runs-on: ${{ matrix.platform }} 14 | steps: 15 | - name: Install Go 16 | uses: actions/setup-go@v1 17 | with: 18 | go-version: ${{ matrix.go-version }} 19 | - name: Checkout code 20 | uses: actions/checkout@v2 21 | - name: Test 22 | run: | 23 | go version 24 | go test -race ./... 25 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to Vellum 2 | 3 | We look forward to your contributions, but ask that you first review these guidelines. 4 | 5 | ### Sign the CLA 6 | 7 | As Vellum is a Couchbase project we require contributors accept the [Couchbase Contributor License Agreement](http://review.couchbase.org/static/individual_agreement.html). To sign this agreement log into the Couchbase [code review tool](http://review.couchbase.org/). The Vellum project does not use this code review tool but it is still used to track acceptance of the contributor license agreements. 8 | 9 | ### Submitting a Pull Request 10 | 11 | All types of contributions are welcome, but please keep the following in mind: 12 | 13 | - If you're planning a large change, you should really discuss it in a github issue first. This helps avoid duplicate effort and spending time on something that may not be merged. 14 | - Existing tests should continue to pass, new tests for the contribution are nice to have. 15 | - All code should have gone through `go fmt` 16 | - All code should pass `go vet` 17 | -------------------------------------------------------------------------------- /automaton.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Couchbase, 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 | package vellum 16 | 17 | // Automaton represents the general contract of a byte-based finite automaton 18 | type Automaton interface { 19 | 20 | // Start returns the start state 21 | Start() int 22 | 23 | // IsMatch returns true if and only if the state is a match 24 | IsMatch(int) bool 25 | 26 | // CanMatch returns true if and only if it is possible to reach a match 27 | // in zero or more steps 28 | CanMatch(int) bool 29 | 30 | // WillAlwaysMatch returns true if and only if the current state matches 31 | // and will always match no matter what steps are taken 32 | WillAlwaysMatch(int) bool 33 | 34 | // Accept returns the next state given the input to the specified state 35 | Accept(int, byte) int 36 | } 37 | 38 | // AutomatonContains implements an generic Contains() method which works 39 | // on any implementation of Automaton 40 | func AutomatonContains(a Automaton, k []byte) bool { 41 | i := 0 42 | curr := a.Start() 43 | for a.CanMatch(curr) && i < len(k) { 44 | curr = a.Accept(curr, k[i]) 45 | if curr == noneAddr { 46 | break 47 | } 48 | i++ 49 | } 50 | if i != len(k) { 51 | return false 52 | } 53 | return a.IsMatch(curr) 54 | } 55 | 56 | // AlwaysMatch is an Automaton implementation which always matches 57 | type AlwaysMatch struct{} 58 | 59 | // Start returns the AlwaysMatch start state 60 | func (m *AlwaysMatch) Start() int { 61 | return 0 62 | } 63 | 64 | // IsMatch always returns true 65 | func (m *AlwaysMatch) IsMatch(int) bool { 66 | return true 67 | } 68 | 69 | // CanMatch always returns true 70 | func (m *AlwaysMatch) CanMatch(int) bool { 71 | return true 72 | } 73 | 74 | // WillAlwaysMatch always returns true 75 | func (m *AlwaysMatch) WillAlwaysMatch(int) bool { 76 | return true 77 | } 78 | 79 | // Accept returns the next AlwaysMatch state 80 | func (m *AlwaysMatch) Accept(int, byte) int { 81 | return 0 82 | } 83 | 84 | // creating an alwaysMatchAutomaton to avoid unnecessary repeated allocations. 85 | var alwaysMatchAutomaton = &AlwaysMatch{} 86 | -------------------------------------------------------------------------------- /cmd/vellum/cmd/dot.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Couchbase, 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 | package cmd 16 | 17 | import ( 18 | "fmt" 19 | "io" 20 | "os" 21 | 22 | "github.com/couchbase/vellum" 23 | "github.com/spf13/cobra" 24 | ) 25 | 26 | var dotCmd = &cobra.Command{ 27 | Use: "dot", 28 | Short: "Dot prints the contents of this vellum FST file in the dot format", 29 | Long: `Dot prints the contents of this vellum FST file in the dot format.`, 30 | PreRunE: func(cmd *cobra.Command, args []string) error { 31 | if len(args) < 1 { 32 | return fmt.Errorf("path is required") 33 | } 34 | return nil 35 | }, 36 | RunE: func(cmd *cobra.Command, args []string) error { 37 | fst, err := vellum.Open(args[0]) 38 | if err != nil { 39 | return err 40 | } 41 | 42 | return dotToWriter(fst, os.Stdout) 43 | }, 44 | } 45 | 46 | func dotToWriter(fst *vellum.FST, w io.Writer) error { 47 | _, err := fmt.Fprint(w, dotHeader) 48 | if err != nil { 49 | return err 50 | } 51 | err = fst.Debug(func(n int, state interface{}) error { 52 | if d, ok := state.(dotStringer); ok { 53 | _, err = fmt.Fprintf(w, "%s", d.DotString(n)) 54 | if err != nil { 55 | return err 56 | } 57 | } 58 | return nil 59 | }) 60 | if err != nil { 61 | return err 62 | } 63 | _, err = fmt.Fprint(w, dotFooter) 64 | if err != nil { 65 | return err 66 | } 67 | return nil 68 | } 69 | 70 | const dotHeader = ` 71 | digraph automaton { 72 | labelloc="l"; 73 | labeljust="l"; 74 | rankdir="LR"; 75 | 76 | ` 77 | const dotFooter = `} 78 | ` 79 | 80 | type dotStringer interface { 81 | DotString(int) string 82 | } 83 | 84 | func init() { 85 | RootCmd.AddCommand(dotCmd) 86 | } 87 | -------------------------------------------------------------------------------- /cmd/vellum/cmd/dump.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Couchbase, 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 | package cmd 16 | 17 | import ( 18 | "fmt" 19 | 20 | "github.com/couchbase/vellum" 21 | "github.com/spf13/cobra" 22 | ) 23 | 24 | // dumpCmd represents the dump command 25 | var dumpCmd = &cobra.Command{ 26 | Use: "dump", 27 | Short: "Dumps the contents of this vellum FST file", 28 | Long: `Dumps the contents of this vellum FST file.`, 29 | PreRunE: func(cmd *cobra.Command, args []string) error { 30 | if len(args) < 1 { 31 | return fmt.Errorf("path is required") 32 | } 33 | return nil 34 | }, 35 | RunE: func(cmd *cobra.Command, args []string) error { 36 | fst, err := vellum.Open(args[0]) 37 | if err != nil { 38 | return err 39 | } 40 | return fst.Debug(debugPrint) 41 | }, 42 | } 43 | 44 | func debugPrint(n int, state interface{}) error { 45 | fmt.Printf("%v\n", state) 46 | return nil 47 | } 48 | 49 | func init() { 50 | RootCmd.AddCommand(dumpCmd) 51 | } 52 | -------------------------------------------------------------------------------- /cmd/vellum/cmd/fuzzy.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Couchbase, 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 | package cmd 16 | 17 | import ( 18 | "fmt" 19 | 20 | "github.com/couchbase/vellum" 21 | "github.com/couchbase/vellum/levenshtein" 22 | "github.com/spf13/cobra" 23 | ) 24 | 25 | var query string 26 | var distance int 27 | 28 | var fuzzyCmd = &cobra.Command{ 29 | Use: "fuzzy", 30 | Short: "Fuzzy runs a fuzzy query over the contents of this vellum FST file", 31 | Long: `Fuzzy runs a fuzzy query over the contents of this vellum FST file.`, 32 | PreRunE: func(cmd *cobra.Command, args []string) error { 33 | if len(args) < 1 { 34 | return fmt.Errorf("path is required") 35 | } 36 | if len(args) > 1 { 37 | query = args[1] 38 | } 39 | 40 | return nil 41 | }, 42 | RunE: func(cmd *cobra.Command, args []string) error { 43 | fst, err := vellum.Open(args[0]) 44 | if err != nil { 45 | return err 46 | } 47 | lb, err := levenshtein.NewLevenshteinAutomatonBuilder(uint8(distance), false) 48 | if err != nil { 49 | return err 50 | } 51 | 52 | fuzzy, err := lb.BuildDfa(query, uint8(distance)) 53 | if err != nil { 54 | return err 55 | } 56 | var startKeyB, endKeyB []byte 57 | if startKey != "" { 58 | startKeyB = []byte(startKey) 59 | } 60 | if endKey != "" { 61 | endKeyB = []byte(endKey) 62 | } 63 | itr, err := fst.Search(fuzzy, startKeyB, endKeyB) 64 | for err == nil { 65 | key, val := itr.Current() 66 | fmt.Printf("%s - %d\n", key, val) 67 | err = itr.Next() 68 | } 69 | 70 | return nil 71 | }, 72 | } 73 | 74 | func init() { 75 | RootCmd.AddCommand(fuzzyCmd) 76 | fuzzyCmd.Flags().StringVar(&startKey, "start", "", "start key inclusive") 77 | fuzzyCmd.Flags().StringVar(&endKey, "end", "", "end key inclusive") 78 | fuzzyCmd.Flags().IntVar(&distance, "distance", 1, "edit distance in Unicode codepoints") 79 | } 80 | -------------------------------------------------------------------------------- /cmd/vellum/cmd/grep.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Couchbase, 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 | package cmd 16 | 17 | import ( 18 | "fmt" 19 | 20 | "github.com/couchbase/vellum" 21 | "github.com/couchbase/vellum/regexp" 22 | "github.com/spf13/cobra" 23 | ) 24 | 25 | var grepCmd = &cobra.Command{ 26 | Use: "grep", 27 | Short: "Grep runs regular expression searches over the contents of this " + 28 | "vellum FST file.", 29 | Long: `Grep runs regular expression searches over the contents of this ` + 30 | `vellum FST file.`, 31 | PreRunE: func(cmd *cobra.Command, args []string) error { 32 | if len(args) < 1 { 33 | return fmt.Errorf("path is required") 34 | } 35 | if len(args) > 1 { 36 | query = args[1] 37 | } 38 | 39 | return nil 40 | }, 41 | RunE: func(cmd *cobra.Command, args []string) error { 42 | fst, err := vellum.Open(args[0]) 43 | if err != nil { 44 | return err 45 | } 46 | r, err := regexp.New(query) 47 | if err != nil { 48 | return err 49 | } 50 | var startKeyB, endKeyB []byte 51 | if startKey != "" { 52 | startKeyB = []byte(startKey) 53 | } 54 | if endKey != "" { 55 | endKeyB = []byte(endKey) 56 | } 57 | itr, err := fst.Search(r, startKeyB, endKeyB) 58 | for err == nil { 59 | key, val := itr.Current() 60 | fmt.Printf("%s - %d\n", key, val) 61 | err = itr.Next() 62 | } 63 | 64 | return nil 65 | }, 66 | } 67 | 68 | func init() { 69 | RootCmd.AddCommand(grepCmd) 70 | grepCmd.Flags().StringVar(&startKey, "start", "", "start key inclusive") 71 | grepCmd.Flags().StringVar(&endKey, "end", "", "end key inclusive") 72 | } 73 | -------------------------------------------------------------------------------- /cmd/vellum/cmd/info.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Couchbase, 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 | package cmd 16 | 17 | import ( 18 | "fmt" 19 | 20 | "github.com/couchbase/vellum" 21 | "github.com/spf13/cobra" 22 | ) 23 | 24 | var infoCmd = &cobra.Command{ 25 | Use: "info", 26 | Short: "Prints info about this vellum FST file", 27 | Long: `Prints info about this vellum FST file.`, 28 | PreRunE: func(cmd *cobra.Command, args []string) error { 29 | if len(args) < 1 { 30 | return fmt.Errorf("path is required") 31 | } 32 | return nil 33 | }, 34 | RunE: func(cmd *cobra.Command, args []string) error { 35 | fst, err := vellum.Open(args[0]) 36 | if err != nil { 37 | return err 38 | } 39 | fmt.Printf("version: %d\n", fst.Version()) 40 | fmt.Printf("length: %d\n", fst.Len()) 41 | return nil 42 | }, 43 | } 44 | 45 | func init() { 46 | RootCmd.AddCommand(infoCmd) 47 | } 48 | -------------------------------------------------------------------------------- /cmd/vellum/cmd/map.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Couchbase, 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 | package cmd 16 | 17 | import ( 18 | "encoding/csv" 19 | "fmt" 20 | "io" 21 | "log" 22 | "os" 23 | "strconv" 24 | 25 | "github.com/couchbase/vellum" 26 | "github.com/spf13/cobra" 27 | ) 28 | 29 | var mapCmd = &cobra.Command{ 30 | Use: "map", 31 | Short: "Map builds a new FST from a CSV file containing key,val pairs", 32 | Long: `Map builds a new FST from a CSV file containing key,val pairs.`, 33 | PreRunE: func(cmd *cobra.Command, args []string) error { 34 | if len(args) < 1 { 35 | return fmt.Errorf("source and target paths are required") 36 | } 37 | if len(args) < 2 { 38 | return fmt.Errorf("target path is required") 39 | } 40 | return nil 41 | }, 42 | RunE: func(cmd *cobra.Command, args []string) error { 43 | 44 | if !sorted { 45 | return fmt.Errorf("only sorted input supported at this time") 46 | } 47 | 48 | file, err := os.Open(args[0]) 49 | if err != nil { 50 | log.Fatal(err) 51 | } 52 | defer file.Close() 53 | 54 | f, err := os.Create(args[1]) 55 | if err != nil { 56 | return err 57 | } 58 | 59 | b, err := vellum.New(f, nil) 60 | if err != nil { 61 | return err 62 | } 63 | 64 | reader := csv.NewReader(file) 65 | reader.FieldsPerRecord = 2 66 | 67 | var record []string 68 | record, err = reader.Read() 69 | for err == nil { 70 | var v uint64 71 | v, err = strconv.ParseUint(record[1], 10, 64) 72 | if err != nil { 73 | return err 74 | } 75 | err = b.Insert([]byte(record[0]), v) 76 | if err != nil { 77 | return err 78 | } 79 | 80 | record, err = reader.Read() 81 | } 82 | if err != io.EOF { 83 | return err 84 | } 85 | 86 | err = b.Close() 87 | if err != nil { 88 | return err 89 | } 90 | 91 | return nil 92 | }, 93 | } 94 | 95 | func init() { 96 | RootCmd.AddCommand(mapCmd) 97 | mapCmd.Flags().BoolVar(&sorted, "sorted", false, "input already sorted") 98 | } 99 | -------------------------------------------------------------------------------- /cmd/vellum/cmd/range.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Couchbase, 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 | package cmd 16 | 17 | import ( 18 | "fmt" 19 | 20 | "github.com/couchbase/vellum" 21 | "github.com/spf13/cobra" 22 | ) 23 | 24 | var startKey string 25 | var endKey string 26 | 27 | var rangeCmd = &cobra.Command{ 28 | Use: "range", 29 | Short: "Range iterates over the contents of this vellum FST file", 30 | Long: `Range iterates over the contents of this vellum FST file. You can optionally specify start/end keys after the filename.`, 31 | PreRunE: func(cmd *cobra.Command, args []string) error { 32 | if len(args) < 1 { 33 | return fmt.Errorf("path is required") 34 | } 35 | return nil 36 | }, 37 | RunE: func(cmd *cobra.Command, args []string) error { 38 | fst, err := vellum.Open(args[0]) 39 | if err != nil { 40 | return err 41 | } 42 | var startKeyB, endKeyB []byte 43 | if startKey != "" { 44 | startKeyB = []byte(startKey) 45 | } 46 | if endKey != "" { 47 | endKeyB = []byte(endKey) 48 | } 49 | itr, err := fst.Iterator(startKeyB, endKeyB) 50 | for err == nil { 51 | key, val := itr.Current() 52 | fmt.Printf("%s - %d\n", key, val) 53 | err = itr.Next() 54 | } 55 | 56 | return nil 57 | }, 58 | } 59 | 60 | func init() { 61 | RootCmd.AddCommand(rangeCmd) 62 | rangeCmd.Flags().StringVar(&startKey, "start", "", "start key inclusive") 63 | rangeCmd.Flags().StringVar(&endKey, "end", "", "end key inclusive") 64 | } 65 | -------------------------------------------------------------------------------- /cmd/vellum/cmd/root.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Couchbase, 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 | package cmd 16 | 17 | import ( 18 | "fmt" 19 | "net/http" 20 | "os" 21 | 22 | "github.com/spf13/cobra" 23 | ) 24 | 25 | var expvarBind string 26 | 27 | // RootCmd represents the base command when called without any subcommands 28 | var RootCmd = &cobra.Command{ 29 | Use: "vellum", 30 | Short: "A utility to work with vellum FST files", 31 | Long: `A utility to work with vellum FST files.`, 32 | PersistentPreRunE: func(cmd *cobra.Command, args []string) error { 33 | if expvarBind != "" { 34 | go http.ListenAndServe(expvarBind, nil) 35 | } 36 | return nil 37 | }, 38 | } 39 | 40 | // Execute adds all child commands to the root command sets flags appropriately. 41 | // This is called by main.main(). It only needs to happen once to the rootCmd. 42 | func Execute() { 43 | if err := RootCmd.Execute(); err != nil { 44 | fmt.Println(err) 45 | os.Exit(-1) 46 | } 47 | } 48 | 49 | func init() { 50 | RootCmd.PersistentFlags().StringVar(&expvarBind, "expvar", "", "bind address for expvar, default none") 51 | } 52 | -------------------------------------------------------------------------------- /cmd/vellum/cmd/set.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Couchbase, 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 | package cmd 16 | 17 | import ( 18 | "bufio" 19 | "fmt" 20 | "log" 21 | "os" 22 | 23 | "github.com/couchbase/vellum" 24 | "github.com/spf13/cobra" 25 | ) 26 | 27 | var sorted bool 28 | 29 | var setCmd = &cobra.Command{ 30 | Use: "set", 31 | Short: "Set builds a new FST from a file containing new-line separated values", 32 | Long: `Set builds a new FST from a file containing new-line separated values.`, 33 | PreRunE: func(cmd *cobra.Command, args []string) error { 34 | if len(args) < 1 { 35 | return fmt.Errorf("source and target paths are required") 36 | } 37 | if len(args) < 2 { 38 | return fmt.Errorf("target path is required") 39 | } 40 | return nil 41 | }, 42 | RunE: func(cmd *cobra.Command, args []string) error { 43 | 44 | if !sorted { 45 | return fmt.Errorf("only sorted input supported at this time") 46 | } 47 | 48 | file, err := os.Open(args[0]) 49 | if err != nil { 50 | log.Fatal(err) 51 | } 52 | defer file.Close() 53 | 54 | f, err := os.Create(args[1]) 55 | if err != nil { 56 | return err 57 | } 58 | 59 | b, err := vellum.New(f, nil) 60 | if err != nil { 61 | return err 62 | } 63 | 64 | scanner := bufio.NewScanner(file) 65 | for scanner.Scan() { 66 | word := append([]byte(nil), scanner.Bytes()...) 67 | err = b.Insert(word, 0) 68 | if err != nil { 69 | return err 70 | } 71 | } 72 | 73 | if err = scanner.Err(); err != nil { 74 | log.Fatal(err) 75 | } 76 | 77 | err = b.Close() 78 | if err != nil { 79 | return err 80 | } 81 | 82 | return nil 83 | }, 84 | } 85 | 86 | func init() { 87 | RootCmd.AddCommand(setCmd) 88 | setCmd.Flags().BoolVar(&sorted, "sorted", false, "input already sorted") 89 | } 90 | -------------------------------------------------------------------------------- /cmd/vellum/cmd/svg.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Couchbase, 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 | package cmd 16 | 17 | import ( 18 | "fmt" 19 | "io" 20 | "io/ioutil" 21 | "os" 22 | "os/exec" 23 | 24 | "github.com/couchbase/vellum" 25 | "github.com/spf13/cobra" 26 | ) 27 | 28 | var svgCmd = &cobra.Command{ 29 | Use: "svg", 30 | Short: "SVG prints the contents of this vellum FST file in the SVG format", 31 | Long: `SVG prints the contents of this vellum FST file in the SVG format.`, 32 | PreRunE: func(cmd *cobra.Command, args []string) error { 33 | if len(args) < 1 { 34 | return fmt.Errorf("path is required") 35 | } 36 | return nil 37 | }, 38 | RunE: func(cmd *cobra.Command, args []string) error { 39 | fst, err := vellum.Open(args[0]) 40 | if err != nil { 41 | return err 42 | } 43 | 44 | return svgToWriter(fst, os.Stdout) 45 | }, 46 | } 47 | 48 | func svgToWriter(fst *vellum.FST, w io.Writer) error { 49 | pr, pw := io.Pipe() 50 | go func() { 51 | defer func() { 52 | _ = pw.Close() 53 | }() 54 | _ = dotToWriter(fst, pw) 55 | }() 56 | cmd := exec.Command("dot", "-Tsvg") 57 | cmd.Stdin = pr 58 | cmd.Stdout = w 59 | cmd.Stderr = ioutil.Discard 60 | err := cmd.Run() 61 | if err != nil { 62 | return err 63 | } 64 | return nil 65 | } 66 | 67 | func init() { 68 | RootCmd.AddCommand(svgCmd) 69 | } 70 | -------------------------------------------------------------------------------- /cmd/vellum/main.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Couchbase, 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 | package main 16 | 17 | import ( 18 | _ "expvar" 19 | 20 | "github.com/couchbase/vellum/cmd/vellum/cmd" 21 | ) 22 | 23 | func main() { 24 | cmd.Execute() 25 | } 26 | -------------------------------------------------------------------------------- /common_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Couchbase, 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 | package vellum 16 | 17 | import "testing" 18 | 19 | func TestCommonInputs(t *testing.T) { 20 | 21 | // first ensure items that can be encoded round trip properly 22 | for i := 0; i < 256; i++ { 23 | roundTrip(t, byte(i)) 24 | } 25 | 26 | // G maps to 62, +1 is 63, which is highest 6-bit value we can encode 27 | enc := encodeCommon('G') 28 | if enc != 63 { 29 | t.Errorf("expected G to encode to 63, got %d", enc) 30 | } 31 | 32 | // W encodes to 63, +1 is 64, which is too big to fit 33 | enc = encodeCommon('W') 34 | if enc != 0 { 35 | t.Errorf("expected W to encode to 0, got %d", enc) 36 | } 37 | } 38 | 39 | func roundTrip(t *testing.T, b byte) { 40 | enc := encodeCommon(b) 41 | if enc > 0 { 42 | dec := decodeCommon(enc) 43 | if dec != b { 44 | t.Errorf("error round trip common input: %d", b) 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /docs/demo1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/couchbase/vellum/abd0418dd6c7952bc327f5f2ec44072fa787bba5/docs/demo1.png -------------------------------------------------------------------------------- /docs/demo1.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | g 11 | 12 | 13 | 0 14 | 15 | 0 16 | 17 | 18 | 1 19 | 20 | 1 21 | 22 | 23 | 0->1 24 | 25 | 26 | a/4 27 | 28 | 29 | 2 30 | 31 | 2 32 | 33 | 34 | 1->2 35 | 36 | 37 | r 38 | 39 | 40 | 3 41 | 42 | 43 | 3 44 | 45 | 46 | 2->3 47 | 48 | 49 | e 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /docs/demo2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/couchbase/vellum/abd0418dd6c7952bc327f5f2ec44072fa787bba5/docs/demo2.png -------------------------------------------------------------------------------- /docs/demo2.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | g 11 | 12 | 13 | 0 14 | 15 | 0 16 | 17 | 18 | 1 19 | 20 | 1 21 | 22 | 23 | 0->1 24 | 25 | 26 | a/2 27 | 28 | 29 | 2 30 | 31 | 2 32 | 33 | 34 | 1->2 35 | 36 | 37 | r/2 38 | 39 | 40 | 4 41 | 42 | 4 43 | 44 | 45 | 1->4 46 | 47 | 48 | t 49 | 50 | 51 | 3 52 | 53 | 54 | 3 55 | 56 | 57 | 2->3 58 | 59 | 60 | e 61 | 62 | 63 | 5 64 | 65 | 66 | 5 67 | 68 | 69 | 4->5 70 | 71 | 72 | e 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /docs/demo3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/couchbase/vellum/abd0418dd6c7952bc327f5f2ec44072fa787bba5/docs/demo3.png -------------------------------------------------------------------------------- /docs/demo4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/couchbase/vellum/abd0418dd6c7952bc327f5f2ec44072fa787bba5/docs/demo4.png -------------------------------------------------------------------------------- /docs/demo4.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | g 11 | 12 | 13 | 0 14 | 15 | 0 16 | 17 | 18 | 1 19 | 20 | 1 21 | 22 | 23 | 0->1 24 | 25 | 26 | a/2 27 | 28 | 29 | 6 30 | 31 | 6 32 | 33 | 34 | 0->6 35 | 36 | 37 | s/3 38 | 39 | 40 | 2 41 | 42 | 2 43 | 44 | 45 | 1->2 46 | 47 | 48 | r/2 49 | 50 | 51 | 1->2 52 | 53 | 54 | t 55 | 56 | 57 | 6->2 58 | 59 | 60 | e 61 | 62 | 63 | 3 64 | 65 | 66 | 3 67 | 68 | 69 | 2->3 70 | 71 | 72 | e 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /docs/format.md: -------------------------------------------------------------------------------- 1 | # vellum file format v1 2 | 3 | The v1 file format for vellum has been designed by trying to understand the file format used by [BurntSushi/fst](https://github.com/BurntSushi/fst) library. It should be binary compatible, but no attempt has been made to verify this. 4 | 5 | ## Overview 6 | 7 | The file has 3 sections: 8 | - header 9 | - edge/transition data 10 | - footer 11 | 12 | ### Header 13 | 14 | The header is 16 bytes in total. 15 | - 8 bytes version, uint64 little-endian 16 | - 8 bytes type, uint64 little-endian (currently always 0, no meaning assigned) 17 | 18 | A side-effect of this header is that when computing transition target addresses at runtime, any address < 16 is invalid. 19 | 20 | ### State/Transition Data 21 | 22 | A state is encoded with the following sections, HOWEVER, many sections are optional and omitted for various combinations of settings. In the order they occur: 23 | 24 | - node final output value (packed integer of the computed output size for this node) 25 | - n transition output values (packed integers, of the computed output size for this node, in REVERSE transition order) 26 | - n transition addresses (delta encoded, relative the lowest byte of this node, packed at the computed transition address size for this node, in REVERSE transition order) 27 | - n transition bytes (1 byte for each transition, in REVERSE transition order) 28 | - pack sizes, 1 byte, high 4 bits transition address size, low 4 bits output size 29 | - number of transitions, 1 byte (ONLY if it didn't fit in the top byte), value of 1 in this byte means 256 (1 would have fit into the top byte) 30 | - single transition byte, 1 byte (ONLY if it didn't fit in the top byte) 31 | - top byte, encodes various flags, and uses remaining bits depending on those flags, broken out separate below 32 | 33 | #### State Top Byte 34 | 35 | - high bit 36 | - 1 means, this edge has just 1 transition 37 | - 0 means, this edge has multiple transitions 38 | 39 | ##### 1 transition States 40 | 41 | - second bit flags jump to previous 42 | - 1 means this transition target is the immediately preceding state 43 | - 0 means there will transition address in the rest of the data 44 | 45 | - remaining 6 bits attempt to encode the transition byte 46 | - Obviously this requires 8 bits, but we map the most frequently used bytes into the lowest 6 bits (see common.go). If the byte we need to encode doesn't fit, we encode 0, and read it fully in the following byte. This allows the most common bytes in a single transition edge to fit into just a single byte. 47 | 48 | ##### Multiple Transition States 49 | 50 | - second bit flags final states 51 | - 1 means this is a final state 52 | - 0 means this is not a final state 53 | 54 | - remaining 6 bits attempt to encode the number of transitions 55 | - Obviously, this can require 8 bits, be we assume that many states have fewer transition, and will fit. If the number won't fit, we encode 0 here, and read it fully in the following byte. Because we could 256 transitions, that full byte still isn't enough, so we reuse the value 1 to mean 256. The value of 1 would never naturally occur in this position, since 1 transition would have fit into the top byte (NOTE: single transition states that are final are encoded as multi-transition states, but the value of 1 would fit in the top 6 bytes). 56 | 57 | ### Single Transition Jump To Previous 58 | 59 | The flag marking that a single transition state should jump to the previous state works because we encode all of the node data backwards (ie, we start processing state date with the last byte). Since, at runtime, we can always compute the lowest byte of the state we're in, we can trivially compute the start address of the previous node, just by subtracting one. This allows saving another set of bytes in many cases which would have otherwise been needed to encode that address. 60 | 61 | ### Delta Addresses 62 | 63 | All transition target addresses are delta encoded, relative to the lowest byte in the current state. 64 | 65 | ### Packed Integer Encoding 66 | 67 | For both the output values and transition target addresses, we choose a fixed size number of bytes that will work for encoding all the appropriate values in this state. Because this length will be recorded (in the pack sizes section), we don't need to use varint encoding, we can instead simply use the minimum number of bytes required. So, 8-bit values take just 1 byte, etc. This has the advantage that small values take less space, but the sizes are still fixed, so we can easily navigate without excessive computation. 68 | 69 | 70 | ### Footer 71 | 72 | The footer is 16 bytes in total. 73 | - 8 bytes number of keys, uint64 little-endian 74 | - 8 bytes root address (absolute, not delta encoded like other addresses in file), uint64 little-endian 75 | 76 | ## Encoding Streaming 77 | 78 | States are written out to the underlying writer as soon as possible. This allows us to get an early start on I/O while still building the FST, reducing the overall time to build, and it also allows us to reduce the memory consumed during the build process. 79 | 80 | Because of this, the root node will always be the last node written in the file. 81 | -------------------------------------------------------------------------------- /docs/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/couchbase/vellum/abd0418dd6c7952bc327f5f2ec44072fa787bba5/docs/logo.png -------------------------------------------------------------------------------- /encoding.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Couchbase, 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 | package vellum 16 | 17 | import ( 18 | "encoding/binary" 19 | "fmt" 20 | "io" 21 | ) 22 | 23 | const headerSize = 16 24 | 25 | type encoderConstructor func(w io.Writer) encoder 26 | type decoderConstructor func([]byte) decoder 27 | 28 | var encoders = map[int]encoderConstructor{} 29 | var decoders = map[int]decoderConstructor{} 30 | 31 | type encoder interface { 32 | start() error 33 | encodeState(s *builderNode, addr int) (int, error) 34 | finish(count, rootAddr int) error 35 | reset(w io.Writer) 36 | } 37 | 38 | func loadEncoder(ver int, w io.Writer) (encoder, error) { 39 | if cons, ok := encoders[ver]; ok { 40 | return cons(w), nil 41 | } 42 | return nil, fmt.Errorf("no encoder for version %d registered", ver) 43 | } 44 | 45 | func registerEncoder(ver int, cons encoderConstructor) { 46 | encoders[ver] = cons 47 | } 48 | 49 | type decoder interface { 50 | getRoot() int 51 | getLen() int 52 | stateAt(addr int, prealloc fstState) (fstState, error) 53 | } 54 | 55 | func loadDecoder(ver int, data []byte) (decoder, error) { 56 | if cons, ok := decoders[ver]; ok { 57 | return cons(data), nil 58 | } 59 | return nil, fmt.Errorf("no decoder for version %d registered", ver) 60 | } 61 | 62 | func registerDecoder(ver int, cons decoderConstructor) { 63 | decoders[ver] = cons 64 | } 65 | 66 | func decodeHeader(header []byte) (ver int, typ int, err error) { 67 | if len(header) < headerSize { 68 | err = fmt.Errorf("invalid header < 16 bytes") 69 | return 70 | } 71 | ver = int(binary.LittleEndian.Uint64(header[0:8])) 72 | typ = int(binary.LittleEndian.Uint64(header[8:16])) 73 | return 74 | } 75 | 76 | // fstState represents a state inside the FTS runtime 77 | // It is the main contract between the FST impl and the decoder 78 | // The FST impl should work only with this interface, while only the decoder 79 | // impl knows the physical representation. 80 | type fstState interface { 81 | Address() int 82 | Final() bool 83 | FinalOutput() uint64 84 | NumTransitions() int 85 | TransitionFor(b byte) (int, int, uint64) 86 | TransitionAt(i int) byte 87 | } 88 | -------------------------------------------------------------------------------- /example_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Couchbase, 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 | package vellum_test 16 | 17 | import ( 18 | "bytes" 19 | "fmt" 20 | "log" 21 | 22 | "github.com/couchbase/vellum" 23 | ) 24 | 25 | func Example() { 26 | 27 | var buf bytes.Buffer 28 | builder, err := vellum.New(&buf, nil) 29 | if err != nil { 30 | log.Fatal(err) 31 | } 32 | 33 | err = builder.Insert([]byte("cat"), 1) 34 | if err != nil { 35 | log.Fatal(err) 36 | } 37 | 38 | err = builder.Insert([]byte("dog"), 2) 39 | if err != nil { 40 | log.Fatal(err) 41 | } 42 | 43 | err = builder.Insert([]byte("fish"), 3) 44 | if err != nil { 45 | log.Fatal(err) 46 | } 47 | 48 | err = builder.Close() 49 | if err != nil { 50 | log.Fatal(err) 51 | } 52 | 53 | fst, err := vellum.Load(buf.Bytes()) 54 | if err != nil { 55 | log.Fatal(err) 56 | } 57 | 58 | val, exists, err := fst.Get([]byte("cat")) 59 | if err != nil { 60 | log.Fatal(err) 61 | } 62 | if exists { 63 | fmt.Println(val) 64 | } 65 | 66 | val, exists, err = fst.Get([]byte("dog")) 67 | if err != nil { 68 | log.Fatal(err) 69 | } 70 | if exists { 71 | fmt.Println(val) 72 | } 73 | 74 | val, exists, err = fst.Get([]byte("fish")) 75 | if err != nil { 76 | log.Fatal(err) 77 | } 78 | if exists { 79 | fmt.Println(val) 80 | } 81 | 82 | // Output: 1 83 | // 2 84 | // 3 85 | } 86 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/couchbase/vellum 2 | 3 | go 1.12 4 | 5 | require ( 6 | github.com/blevesearch/mmap-go v1.0.2 7 | github.com/spf13/cobra v0.0.5 8 | github.com/willf/bitset v1.1.10 9 | golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a // indirect 10 | ) 11 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 2 | github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= 3 | github.com/blevesearch/mmap-go v1.0.2 h1:JtMHb+FgQCTTYIhtMvimw15dJwu1Y5lrZDMOFXVWPk0= 4 | github.com/blevesearch/mmap-go v1.0.2/go.mod h1:ol2qBqYaOUsGdm7aRMRrYGgPvnwLe6Y+7LMvAB5IbSA= 5 | github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= 6 | github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= 7 | github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= 8 | github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= 9 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 10 | github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= 11 | github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= 12 | github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= 13 | github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= 14 | github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= 15 | github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= 16 | github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= 17 | github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= 18 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 19 | github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= 20 | github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= 21 | github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= 22 | github.com/spf13/cobra v0.0.5 h1:f0B+LkLX6DtmRH1isoNA9VTtNUK9K8xYd28JNNfOv/s= 23 | github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= 24 | github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= 25 | github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= 26 | github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= 27 | github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= 28 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 29 | github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= 30 | github.com/willf/bitset v1.1.10 h1:NotGKqX0KwQ72NUzqrjZq5ipPNDQex9lo3WpaS8L2sc= 31 | github.com/willf/bitset v1.1.10/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= 32 | github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= 33 | golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 34 | golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 35 | golang.org/x/sys v0.0.0-20181221143128-b4a75ba826a6/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 36 | golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a h1:aYOabOQFp6Vj6W1F80affTUvO9UxmJRx8K0gsfABByQ= 37 | golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 38 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 39 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 40 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 41 | -------------------------------------------------------------------------------- /levenshtein/README.md: -------------------------------------------------------------------------------- 1 | # levenshtein 2 | levenshtein automaton 3 | 4 | This package makes it fast and simple to build a finite determinic automaton that computes the levenshtein distance from a given string. 5 | 6 | # Sample usage: 7 | 8 | ``` 9 | // build a re-usable builder 10 | lb := NewLevenshteinAutomatonBuilder(2, false) 11 | 12 | origTerm := "couchbasefts" 13 | dfa := lb.BuildDfa("couchbases", 2) 14 | ed := dfa.eval([]byte(origTerm)) 15 | if ed.distance() != 2 { 16 | log.Errorf("expected distance 2, actual: %d", ed.distance()) 17 | } 18 | 19 | ``` 20 | 21 | This implementation is inspired by [blog post](https://fulmicoton.com/posts/levenshtein/) and is intended to be 22 | a port of original rust implementation: https://github.com/tantivy-search/levenshtein-automata 23 | 24 | 25 | Micro Benchmark Results against the current vellum/levenshtein is as below. 26 | 27 | ``` 28 | BenchmarkNewEditDistance1-8 30000 52684 ns/op 89985 B/op 295 allocs/op 29 | BenchmarkOlderEditDistance1-8 10000 132931 ns/op 588892 B/op 363 allocs/op 30 | 31 | BenchmarkNewEditDistance2-8 10000 199127 ns/op 377532 B/op 1019 allocs/op 32 | BenchmarkOlderEditDistance2-8 2000 988109 ns/op 4236609 B/op 1898 allocs/op 33 | ``` 34 | -------------------------------------------------------------------------------- /levenshtein/alphabet.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Couchbase, 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 | package levenshtein 16 | 17 | import ( 18 | "fmt" 19 | "sort" 20 | "unicode/utf8" 21 | ) 22 | 23 | type FullCharacteristicVector []uint32 24 | 25 | func (fcv FullCharacteristicVector) shiftAndMask(offset, mask uint32) uint32 { 26 | bucketID := offset / 32 27 | align := offset - bucketID*32 28 | if align == 0 { 29 | return fcv[bucketID] & mask 30 | } 31 | left := fcv[bucketID] >> align 32 | right := fcv[bucketID+1] << (32 - align) 33 | return (left | right) & mask 34 | } 35 | 36 | type tuple struct { 37 | char rune 38 | fcv FullCharacteristicVector 39 | } 40 | 41 | type sortRunes []rune 42 | 43 | func (s sortRunes) Less(i, j int) bool { 44 | return s[i] < s[j] 45 | } 46 | 47 | func (s sortRunes) Swap(i, j int) { 48 | s[i], s[j] = s[j], s[i] 49 | } 50 | 51 | func (s sortRunes) Len() int { 52 | return len(s) 53 | } 54 | 55 | func sortRune(r []rune) []rune { 56 | sort.Sort(sortRunes(r)) 57 | return r 58 | } 59 | 60 | type Alphabet struct { 61 | charset []tuple 62 | index uint32 63 | } 64 | 65 | func (a *Alphabet) resetNext() { 66 | a.index = 0 67 | } 68 | 69 | func (a *Alphabet) next() (rune, FullCharacteristicVector, error) { 70 | if int(a.index) >= len(a.charset) { 71 | return 0, nil, fmt.Errorf("eof") 72 | } 73 | 74 | rv := a.charset[a.index] 75 | a.index++ 76 | return rv.char, rv.fcv, nil 77 | } 78 | 79 | func dedupe(in string) string { 80 | lookUp := make(map[rune]struct{}, len(in)) 81 | var rv string 82 | for len(in) > 0 { 83 | r, size := utf8.DecodeRuneInString(in) 84 | in = in[size:] 85 | if _, ok := lookUp[r]; !ok { 86 | rv += string(r) 87 | lookUp[r] = struct{}{} 88 | } 89 | } 90 | return rv 91 | } 92 | 93 | func queryChars(qChars string) Alphabet { 94 | chars := dedupe(qChars) 95 | inChars := sortRune([]rune(chars)) 96 | charsets := make([]tuple, 0, len(inChars)) 97 | 98 | for _, c := range inChars { 99 | tempChars := qChars 100 | var bits []uint32 101 | for len(tempChars) > 0 { 102 | var chunk string 103 | if len(tempChars) > 32 { 104 | chunk = tempChars[0:32] 105 | tempChars = tempChars[32:] 106 | } else { 107 | chunk = tempChars 108 | tempChars = tempChars[:0] 109 | } 110 | 111 | chunkBits := uint32(0) 112 | bit := uint32(1) 113 | for _, chr := range chunk { 114 | if chr == c { 115 | chunkBits |= bit 116 | } 117 | bit <<= 1 118 | } 119 | bits = append(bits, chunkBits) 120 | } 121 | bits = append(bits, 0) 122 | charsets = append(charsets, tuple{char: c, fcv: FullCharacteristicVector(bits)}) 123 | } 124 | return Alphabet{charset: charsets} 125 | } 126 | -------------------------------------------------------------------------------- /levenshtein/alphabet_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Couchbase, 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 | package levenshtein 16 | 17 | import "testing" 18 | 19 | func TestAlphabet(t *testing.T) { 20 | chars := "happy" 21 | alphabet := queryChars(chars) 22 | 23 | c, chi, _ := alphabet.next() 24 | if c != 'a' { 25 | t.Errorf("expecting 'a', got: %v", c) 26 | } 27 | 28 | if chi[0] != 2 { 29 | t.Errorf("expecting 2, got: %v", chi[0]) 30 | } 31 | 32 | c, chi, _ = alphabet.next() 33 | if c != 'h' { 34 | t.Errorf("expecting 'h', got: %v", c) 35 | } 36 | 37 | if chi[0] != 1 { 38 | t.Errorf("expecting 1, got: %v", chi[0]) 39 | } 40 | 41 | c, chi, _ = alphabet.next() 42 | if c != 'p' { 43 | t.Errorf("expecting 'p', got: %v", c) 44 | } 45 | 46 | if chi[0] != 12 { 47 | t.Errorf("expecting 12, got: %v", chi[0]) 48 | } 49 | 50 | c, chi, _ = alphabet.next() 51 | if c != 'y' { 52 | t.Errorf("expecting 'y', got: %v", c) 53 | } 54 | 55 | if chi[0] != 16 { 56 | t.Errorf("expecting 16, got: %v", chi[0]) 57 | } 58 | } 59 | 60 | func TestFullCharacteristic(t *testing.T) { 61 | fcv := FullCharacteristicVector([]uint32{2, 0}) 62 | if fcv.shiftAndMask(1, 1) != 1 { 63 | t.Errorf("expected 1, got: %v", fcv.shiftAndMask(1, 1)) 64 | } 65 | 66 | fcv = FullCharacteristicVector([]uint32{1<<5 + 1<<10, 0}) 67 | if fcv.shiftAndMask(3, 63) != 4 { 68 | t.Errorf("expected 4, got: %v", fcv.shiftAndMask(3, 63)) 69 | } 70 | } 71 | 72 | func TestLongCharacteristic(t *testing.T) { 73 | qChars := "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaabcabewa" 74 | alphabet := queryChars(qChars) 75 | 76 | c, chi, _ := alphabet.next() 77 | if c != 'a' { 78 | t.Errorf("expecting 'a', got: %v", c) 79 | } 80 | if chi.shiftAndMask(0, 7) != 7 { 81 | t.Errorf("expecting 7 , got: %v", chi.shiftAndMask(0, 7)) 82 | } 83 | 84 | if chi.shiftAndMask(28, 7) != 3 { 85 | t.Errorf("expecting 3 , got: %v", chi.shiftAndMask(28, 7)) 86 | } 87 | 88 | if chi.shiftAndMask(28, 127) != 1+2+16 { 89 | t.Errorf("expecting 19 , got: %v", chi.shiftAndMask(28, 127)) 90 | } 91 | 92 | if chi.shiftAndMask(28, 4095) != 1+2+16+256 { 93 | t.Errorf("expecting 275 , got: %v", chi.shiftAndMask(28, 4095)) 94 | } 95 | 96 | c, chi, _ = alphabet.next() 97 | if c != 'b' { 98 | t.Errorf("expecting 'b', got: %v", c) 99 | } 100 | if chi.shiftAndMask(0, 7) != 0 { 101 | t.Errorf("expecting 0 , got: %v", chi.shiftAndMask(0, 7)) 102 | } 103 | 104 | if chi.shiftAndMask(28, 15) != 4 { 105 | t.Errorf("expecting 4 , got: %v", chi.shiftAndMask(28, 15)) 106 | } 107 | 108 | if chi.shiftAndMask(28, 63) != 4+32 { 109 | t.Errorf("expecting 36 , got: %v", chi.shiftAndMask(28, 63)) 110 | } 111 | 112 | } 113 | -------------------------------------------------------------------------------- /levenshtein/benchmark_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Couchbase, 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 | package levenshtein 16 | 17 | import ( 18 | "testing" 19 | ) 20 | 21 | func BenchmarkNewEvalEditDistance1(b *testing.B) { 22 | lb, _ := NewLevenshteinAutomatonBuilder(1, true) 23 | 24 | query := "coucibase" 25 | for i := 0; i < b.N; i++ { 26 | dfa, _ := lb.BuildDfa("couchbase", 1) 27 | ed := dfa.eval([]byte(query)) 28 | if ed.distance() != 1 { 29 | b.Errorf("expected distance 1, actual: %d", ed.distance()) 30 | } 31 | 32 | } 33 | } 34 | 35 | func BenchmarkNewEvalEditDistance2(b *testing.B) { 36 | lb, _ := NewLevenshteinAutomatonBuilder(2, false) 37 | 38 | query := "couchbasefts" 39 | for i := 0; i < b.N; i++ { 40 | dfa, _ := lb.BuildDfa("couchbases", 2) 41 | ed := dfa.eval([]byte(query)) 42 | if ed.distance() != 2 { 43 | b.Errorf("expected distance 2, actual: %d", ed.distance()) 44 | } 45 | } 46 | } 47 | 48 | func BenchmarkNewEditDistance1(b *testing.B) { 49 | lb, _ := NewLevenshteinAutomatonBuilder(1, true) 50 | 51 | query := "coucibase" 52 | for i := 0; i < b.N; i++ { 53 | dfa, _ := lb.BuildDfa("couchbase", 1) 54 | 55 | state := dfa.initialState() 56 | for _, b := range []byte(query) { 57 | state = dfa.transition(state, b) 58 | } 59 | 60 | if !dfa.IsMatch(state) { 61 | b.Errorf("expected isMatch %t, got %t", true, !dfa.IsMatch(state)) 62 | } 63 | 64 | } 65 | } 66 | 67 | func BenchmarkNewEditDistance2(b *testing.B) { 68 | lb, _ := NewLevenshteinAutomatonBuilder(2, false) 69 | 70 | query := "couchbasefts" 71 | for i := 0; i < b.N; i++ { 72 | dfa, _ := lb.BuildDfa("couchbases", 2) 73 | 74 | state := dfa.initialState() 75 | for _, b := range []byte(query) { 76 | state = dfa.transition(state, b) 77 | } 78 | 79 | if !dfa.IsMatch(state) { 80 | b.Errorf("expected isMatch %t, got %t", true, !dfa.IsMatch(state)) 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /levenshtein/dfa_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Couchbase, 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 | package levenshtein 16 | 17 | import ( 18 | "testing" 19 | ) 20 | 21 | func TestLevenshtein2(t *testing.T) { 22 | dfaBuilder := withMaxStates(2) 23 | dfaBuilder.addState(0, 1, Exact{d: 1}) 24 | dfaBuilder.addState(1, 0, Exact{d: 0}) 25 | dfaBuilder.setInitialState(1) 26 | _ = dfaBuilder.build(1) 27 | } 28 | -------------------------------------------------------------------------------- /levenshtein/levenshtein.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Couchbase, 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 | package levenshtein 16 | 17 | import "fmt" 18 | 19 | // StateLimit is the maximum number of states allowed 20 | const StateLimit = 10000 21 | 22 | // ErrTooManyStates is returned if you attempt to build a Levenshtein 23 | // automaton which requires too many states. 24 | var ErrTooManyStates = fmt.Errorf("dfa contains more than %d states", 25 | StateLimit) 26 | 27 | // LevenshteinAutomatonBuilder wraps a precomputed 28 | // datastructure that allows to produce small (but not minimal) DFA. 29 | type LevenshteinAutomatonBuilder struct { 30 | pDfa *ParametricDFA 31 | } 32 | 33 | // NewLevenshteinAutomatonBuilder creates a 34 | // reusable, threadsafe Levenshtein automaton builder. 35 | // `maxDistance` - maximum distance considered by the automaton. 36 | // `transposition` - assign a distance of 1 for transposition 37 | // 38 | // Building this automaton builder is computationally intensive. 39 | // While it takes only a few milliseconds for `d=2`, it grows 40 | // exponentially with `d`. It is only reasonable to `d <= 5`. 41 | func NewLevenshteinAutomatonBuilder(maxDistance uint8, 42 | transposition bool) (*LevenshteinAutomatonBuilder, error) { 43 | lnfa := newLevenshtein(maxDistance, transposition) 44 | 45 | pdfa, err := fromNfa(lnfa) 46 | if err != nil { 47 | return nil, err 48 | } 49 | 50 | return &LevenshteinAutomatonBuilder{pDfa: pdfa}, nil 51 | } 52 | 53 | // BuildDfa builds the levenshtein automaton for serving 54 | // queries with a given edit distance. 55 | func (lab *LevenshteinAutomatonBuilder) BuildDfa(query string, 56 | fuzziness uint8) (*DFA, error) { 57 | return lab.pDfa.buildDfa(query, fuzziness, false) 58 | } 59 | 60 | // MaxDistance returns the MaxEdit distance supported by the 61 | // LevenshteinAutomatonBuilder builder. 62 | func (lab *LevenshteinAutomatonBuilder) MaxDistance() uint8 { 63 | return lab.pDfa.maxDistance 64 | } 65 | -------------------------------------------------------------------------------- /pack.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Couchbase, 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 | package vellum 16 | 17 | func deltaAddr(base, trans uint64) uint64 { 18 | // transition dest of 0 is special case 19 | if trans == 0 { 20 | return 0 21 | } 22 | return base - trans 23 | } 24 | 25 | const packOutMask = 1<<4 - 1 26 | 27 | func encodePackSize(transSize, outSize int) byte { 28 | var rv byte 29 | rv = byte(transSize << 4) 30 | rv |= byte(outSize) 31 | return rv 32 | } 33 | 34 | func decodePackSize(pack byte) (transSize int, packSize int) { 35 | transSize = int(pack >> 4) 36 | packSize = int(pack & packOutMask) 37 | return 38 | } 39 | 40 | const maxNumTrans = 1<<6 - 1 41 | 42 | func encodeNumTrans(n int) byte { 43 | if n <= maxNumTrans { 44 | return byte(n) 45 | } 46 | return 0 47 | } 48 | 49 | func readPackedUint(data []byte) (rv uint64) { 50 | for i := range data { 51 | shifted := uint64(data[i]) << uint(i*8) 52 | rv |= shifted 53 | } 54 | return 55 | } 56 | -------------------------------------------------------------------------------- /pack_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Couchbase, 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 | package vellum 16 | 17 | import ( 18 | "fmt" 19 | "testing" 20 | ) 21 | 22 | func TestEncodeDecodePackSize(t *testing.T) { 23 | 24 | for i := 0; i <= 8; i++ { 25 | for j := 0; j <= 8; j++ { 26 | got := encodePackSize(i, j) 27 | goti, gotj := decodePackSize(got) 28 | if goti != i || gotj != j { 29 | t.Errorf("failed to round trip %d,%d packed as %b to %d,%d", i, j, got, goti, gotj) 30 | } 31 | } 32 | } 33 | } 34 | 35 | func TestEncodeNumTrans(t *testing.T) { 36 | tests := []struct { 37 | input int 38 | want byte 39 | }{ 40 | {0, 0}, 41 | {5, 5}, 42 | {1<<6 - 1, 1<<6 - 1}, 43 | {1 << 6, 0}, 44 | } 45 | 46 | for _, test := range tests { 47 | t.Run(fmt.Sprintf("input %d", test.input), func(t *testing.T) { 48 | got := encodeNumTrans(test.input) 49 | if got != test.want { 50 | t.Errorf("wanted: %d, got: %d", test.want, got) 51 | } 52 | }) 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /regexp/dfa.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Couchbase, 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 | package regexp 16 | 17 | import ( 18 | "encoding/binary" 19 | "fmt" 20 | ) 21 | 22 | // StateLimit is the maximum number of states allowed 23 | const StateLimit = 10000 24 | 25 | // ErrTooManyStates is returned if you attempt to build a Levenshtein 26 | // automaton which requires too many states. 27 | var ErrTooManyStates = fmt.Errorf("dfa contains more than %d states", 28 | StateLimit) 29 | 30 | type dfaBuilder struct { 31 | dfa *dfa 32 | cache map[string]int 33 | keyBuf []byte 34 | } 35 | 36 | func newDfaBuilder(insts prog) *dfaBuilder { 37 | d := &dfaBuilder{ 38 | dfa: &dfa{ 39 | insts: insts, 40 | states: make([]state, 0, 16), 41 | }, 42 | cache: make(map[string]int, 1024), 43 | } 44 | // add 0 state that is invalid 45 | d.dfa.states = append(d.dfa.states, state{ 46 | next: make([]int, 256), 47 | match: false, 48 | }) 49 | return d 50 | } 51 | 52 | func (d *dfaBuilder) build() (*dfa, error) { 53 | cur := newSparseSet(uint(len(d.dfa.insts))) 54 | next := newSparseSet(uint(len(d.dfa.insts))) 55 | 56 | d.dfa.add(cur, 0) 57 | ns, instsReuse := d.cachedState(cur, nil) 58 | states := intStack{ns} 59 | seen := make(map[int]struct{}) 60 | var s int 61 | states, s = states.Pop() 62 | for s != 0 { 63 | for b := 0; b < 256; b++ { 64 | var ns int 65 | ns, instsReuse = d.runState(cur, next, s, byte(b), instsReuse) 66 | if ns != 0 { 67 | if _, ok := seen[ns]; !ok { 68 | seen[ns] = struct{}{} 69 | states = states.Push(ns) 70 | } 71 | } 72 | if len(d.dfa.states) > StateLimit { 73 | return nil, ErrTooManyStates 74 | } 75 | } 76 | states, s = states.Pop() 77 | } 78 | return d.dfa, nil 79 | } 80 | 81 | func (d *dfaBuilder) runState(cur, next *sparseSet, state int, b byte, instsReuse []uint) ( 82 | int, []uint) { 83 | cur.Clear() 84 | for _, ip := range d.dfa.states[state].insts { 85 | cur.Add(ip) 86 | } 87 | d.dfa.run(cur, next, b) 88 | var nextState int 89 | nextState, instsReuse = d.cachedState(next, instsReuse) 90 | d.dfa.states[state].next[b] = nextState 91 | return nextState, instsReuse 92 | } 93 | 94 | func instsKey(insts []uint, buf []byte) []byte { 95 | if cap(buf) < 8*len(insts) { 96 | buf = make([]byte, 8*len(insts)) 97 | } else { 98 | buf = buf[0 : 8*len(insts)] 99 | } 100 | for i, inst := range insts { 101 | binary.LittleEndian.PutUint64(buf[i*8:], uint64(inst)) 102 | } 103 | return buf 104 | } 105 | 106 | func (d *dfaBuilder) cachedState(set *sparseSet, 107 | instsReuse []uint) (int, []uint) { 108 | insts := instsReuse[:0] 109 | if cap(insts) == 0 { 110 | insts = make([]uint, 0, set.Len()) 111 | } 112 | var isMatch bool 113 | for i := uint(0); i < uint(set.Len()); i++ { 114 | ip := set.Get(i) 115 | switch d.dfa.insts[ip].op { 116 | case OpRange: 117 | insts = append(insts, ip) 118 | case OpMatch: 119 | isMatch = true 120 | insts = append(insts, ip) 121 | } 122 | } 123 | if len(insts) == 0 { 124 | return 0, insts 125 | } 126 | d.keyBuf = instsKey(insts, d.keyBuf) 127 | v, ok := d.cache[string(d.keyBuf)] 128 | if ok { 129 | return v, insts 130 | } 131 | d.dfa.states = append(d.dfa.states, state{ 132 | insts: insts, 133 | next: make([]int, 256), 134 | match: isMatch, 135 | }) 136 | newV := len(d.dfa.states) - 1 137 | d.cache[string(d.keyBuf)] = newV 138 | return newV, nil 139 | } 140 | 141 | type dfa struct { 142 | insts prog 143 | states []state 144 | } 145 | 146 | func (d *dfa) add(set *sparseSet, ip uint) { 147 | if set.Contains(ip) { 148 | return 149 | } 150 | set.Add(ip) 151 | switch d.insts[ip].op { 152 | case OpJmp: 153 | d.add(set, d.insts[ip].to) 154 | case OpSplit: 155 | d.add(set, d.insts[ip].splitA) 156 | d.add(set, d.insts[ip].splitB) 157 | } 158 | } 159 | 160 | func (d *dfa) run(from, to *sparseSet, b byte) bool { 161 | to.Clear() 162 | var isMatch bool 163 | for i := uint(0); i < uint(from.Len()); i++ { 164 | ip := from.Get(i) 165 | switch d.insts[ip].op { 166 | case OpMatch: 167 | isMatch = true 168 | case OpRange: 169 | if d.insts[ip].rangeStart <= b && 170 | b <= d.insts[ip].rangeEnd { 171 | d.add(to, ip+1) 172 | } 173 | } 174 | } 175 | return isMatch 176 | } 177 | 178 | type state struct { 179 | insts []uint 180 | next []int 181 | match bool 182 | } 183 | 184 | type intStack []int 185 | 186 | func (s intStack) Push(v int) intStack { 187 | return append(s, v) 188 | } 189 | 190 | func (s intStack) Pop() (intStack, int) { 191 | l := len(s) 192 | if l < 1 { 193 | return s, 0 194 | } 195 | return s[:l-1], s[l-1] 196 | } 197 | -------------------------------------------------------------------------------- /regexp/inst.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Couchbase, 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 | package regexp 16 | 17 | import "fmt" 18 | 19 | // instOp represents a instruction operation 20 | type instOp int 21 | 22 | // the enumeration of operations 23 | const ( 24 | OpMatch instOp = iota 25 | OpJmp 26 | OpSplit 27 | OpRange 28 | ) 29 | 30 | // instSize is the approximate size of the an inst struct in bytes 31 | const instSize = 40 32 | 33 | type inst struct { 34 | op instOp 35 | to uint 36 | splitA uint 37 | splitB uint 38 | rangeStart byte 39 | rangeEnd byte 40 | } 41 | 42 | func (i *inst) String() string { 43 | switch i.op { 44 | case OpJmp: 45 | return fmt.Sprintf("JMP: %d", i.to) 46 | case OpSplit: 47 | return fmt.Sprintf("SPLIT: %d - %d", i.splitA, i.splitB) 48 | case OpRange: 49 | return fmt.Sprintf("RANGE: %x - %x", i.rangeStart, i.rangeEnd) 50 | } 51 | return "MATCH" 52 | } 53 | 54 | type prog []*inst 55 | 56 | func (p prog) String() string { 57 | rv := "\n" 58 | for i, pi := range p { 59 | rv += fmt.Sprintf("%d %v\n", i, pi) 60 | } 61 | return rv 62 | } 63 | -------------------------------------------------------------------------------- /regexp/regexp.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Couchbase, 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 | package regexp 16 | 17 | import ( 18 | "fmt" 19 | "regexp/syntax" 20 | ) 21 | 22 | // ErrNoEmpty returned when "zero width assertions" are used 23 | var ErrNoEmpty = fmt.Errorf("zero width assertions not allowed") 24 | 25 | // ErrNoWordBoundary returned when word boundaries are used 26 | var ErrNoWordBoundary = fmt.Errorf("word boundaries are not allowed") 27 | 28 | // ErrNoBytes returned when byte literals are used 29 | var ErrNoBytes = fmt.Errorf("byte literals are not allowed") 30 | 31 | // ErrNoLazy returned when lazy quantifiers are used 32 | var ErrNoLazy = fmt.Errorf("lazy quantifiers are not allowed") 33 | 34 | // ErrCompiledTooBig returned when regular expression parses into 35 | // too many instructions 36 | var ErrCompiledTooBig = fmt.Errorf("too many instructions") 37 | 38 | var DefaultLimit = uint(10 * (1 << 20)) 39 | 40 | // Regexp implements the vellum.Automaton interface for matcing a user 41 | // specified regular expression. 42 | type Regexp struct { 43 | orig string 44 | dfa *dfa 45 | } 46 | 47 | // NewRegexp creates a new Regular Expression automaton with the specified 48 | // expression. By default it is limited to approximately 10MB for the 49 | // compiled finite state automaton. If this size is exceeded, 50 | // ErrCompiledTooBig will be returned. 51 | func New(expr string) (*Regexp, error) { 52 | return NewWithLimit(expr, DefaultLimit) 53 | } 54 | 55 | // NewRegexpWithLimit creates a new Regular Expression automaton with 56 | // the specified expression. The size of the compiled finite state 57 | // automaton exceeds the user specified size, ErrCompiledTooBig will be 58 | // returned. 59 | func NewWithLimit(expr string, size uint) (*Regexp, error) { 60 | parsed, err := syntax.Parse(expr, syntax.Perl) 61 | if err != nil { 62 | return nil, err 63 | } 64 | return NewParsedWithLimit(expr, parsed, size) 65 | } 66 | 67 | func NewParsedWithLimit(expr string, parsed *syntax.Regexp, size uint) (*Regexp, error) { 68 | compiler := newCompiler(size) 69 | insts, err := compiler.compile(parsed) 70 | if err != nil { 71 | return nil, err 72 | } 73 | dfaBuilder := newDfaBuilder(insts) 74 | dfa, err := dfaBuilder.build() 75 | if err != nil { 76 | return nil, err 77 | } 78 | return &Regexp{ 79 | orig: expr, 80 | dfa: dfa, 81 | }, nil 82 | } 83 | 84 | // Start returns the start state of this automaton. 85 | func (r *Regexp) Start() int { 86 | return 1 87 | } 88 | 89 | // IsMatch returns if the specified state is a matching state. 90 | func (r *Regexp) IsMatch(s int) bool { 91 | if s < len(r.dfa.states) { 92 | return r.dfa.states[s].match 93 | } 94 | return false 95 | } 96 | 97 | // CanMatch returns if the specified state can ever transition to a matching 98 | // state. 99 | func (r *Regexp) CanMatch(s int) bool { 100 | if s < len(r.dfa.states) && s > 0 { 101 | return true 102 | } 103 | return false 104 | } 105 | 106 | // WillAlwaysMatch returns if the specified state will always end in a 107 | // matching state. 108 | func (r *Regexp) WillAlwaysMatch(int) bool { 109 | return false 110 | } 111 | 112 | // Accept returns the new state, resulting from the transition byte b 113 | // when currently in the state s. 114 | func (r *Regexp) Accept(s int, b byte) int { 115 | if s < len(r.dfa.states) { 116 | return r.dfa.states[s].next[b] 117 | } 118 | return 0 119 | } 120 | -------------------------------------------------------------------------------- /regexp/sparse.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Couchbase, 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 | package regexp 16 | 17 | type sparseSet struct { 18 | dense []uint 19 | sparse []uint 20 | size uint 21 | } 22 | 23 | func newSparseSet(size uint) *sparseSet { 24 | return &sparseSet{ 25 | dense: make([]uint, size), 26 | sparse: make([]uint, size), 27 | size: 0, 28 | } 29 | } 30 | 31 | func (s *sparseSet) Len() int { 32 | return int(s.size) 33 | } 34 | 35 | func (s *sparseSet) Add(ip uint) uint { 36 | i := s.size 37 | s.dense[i] = ip 38 | s.sparse[ip] = i 39 | s.size++ 40 | return i 41 | } 42 | 43 | func (s *sparseSet) Get(i uint) uint { 44 | return s.dense[i] 45 | } 46 | 47 | func (s *sparseSet) Contains(ip uint) bool { 48 | i := s.sparse[ip] 49 | return i < s.size && s.dense[i] == ip 50 | } 51 | 52 | func (s *sparseSet) Clear() { 53 | s.size = 0 54 | } 55 | -------------------------------------------------------------------------------- /regexp/sparse_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Couchbase, 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 | package regexp 16 | 17 | import "testing" 18 | 19 | func TestSparse(t *testing.T) { 20 | 21 | s := newSparseSet(10) 22 | if s.Contains(0) { 23 | t.Errorf("expected not to contain 0") 24 | } 25 | 26 | s.Add(3) 27 | if !s.Contains(3) { 28 | t.Errorf("expected to contains 3, did not") 29 | } 30 | 31 | if s.Len() != 1 { 32 | t.Errorf("expected len 1, got %d", s.Len()) 33 | } 34 | 35 | if s.Get(0) != 3 { 36 | t.Errorf("expected 10, got %d", s.Get(0)) 37 | } 38 | 39 | s.Clear() 40 | 41 | if s.Len() != 0 { 42 | t.Errorf("expected len 0, got %d", s.Len()) 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /registry.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Couchbase, 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 | package vellum 16 | 17 | type registryCell struct { 18 | addr int 19 | node *builderNode 20 | } 21 | 22 | type registry struct { 23 | builderNodePool *builderNodePool 24 | table []registryCell 25 | tableSize uint 26 | mruSize uint 27 | } 28 | 29 | func newRegistry(p *builderNodePool, tableSize, mruSize int) *registry { 30 | nsize := tableSize * mruSize 31 | rv := ®istry{ 32 | builderNodePool: p, 33 | table: make([]registryCell, nsize), 34 | tableSize: uint(tableSize), 35 | mruSize: uint(mruSize), 36 | } 37 | return rv 38 | } 39 | 40 | func (r *registry) Reset() { 41 | var empty registryCell 42 | for i := range r.table { 43 | r.builderNodePool.Put(r.table[i].node) 44 | r.table[i] = empty 45 | } 46 | } 47 | 48 | func (r *registry) entry(node *builderNode) (bool, int, *registryCell) { 49 | if len(r.table) == 0 { 50 | return false, 0, nil 51 | } 52 | bucket := r.hash(node) 53 | start := r.mruSize * uint(bucket) 54 | end := start + r.mruSize 55 | rc := registryCache(r.table[start:end]) 56 | return rc.entry(node, r.builderNodePool) 57 | } 58 | 59 | const fnvPrime = 1099511628211 60 | 61 | func (r *registry) hash(b *builderNode) int { 62 | var final uint64 63 | if b.final { 64 | final = 1 65 | } 66 | 67 | var h uint64 = 14695981039346656037 68 | h = (h ^ final) * fnvPrime 69 | h = (h ^ b.finalOutput) * fnvPrime 70 | for _, t := range b.trans { 71 | h = (h ^ uint64(t.in)) * fnvPrime 72 | h = (h ^ t.out) * fnvPrime 73 | h = (h ^ uint64(t.addr)) * fnvPrime 74 | } 75 | return int(h % uint64(r.tableSize)) 76 | } 77 | 78 | type registryCache []registryCell 79 | 80 | func (r registryCache) entry(node *builderNode, pool *builderNodePool) (bool, int, *registryCell) { 81 | if len(r) == 1 { 82 | if r[0].node != nil && r[0].node.equiv(node) { 83 | return true, r[0].addr, nil 84 | } 85 | pool.Put(r[0].node) 86 | r[0].node = node 87 | return false, 0, &r[0] 88 | } 89 | for i := range r { 90 | if r[i].node != nil && r[i].node.equiv(node) { 91 | addr := r[i].addr 92 | r.promote(i) 93 | return true, addr, nil 94 | } 95 | } 96 | // no match 97 | last := len(r) - 1 98 | pool.Put(r[last].node) 99 | r[last].node = node // discard LRU 100 | r.promote(last) 101 | return false, 0, &r[0] 102 | 103 | } 104 | 105 | func (r registryCache) promote(i int) { 106 | for i > 0 { 107 | r.swap(i-1, i) 108 | i-- 109 | } 110 | } 111 | 112 | func (r registryCache) swap(i, j int) { 113 | r[i], r[j] = r[j], r[i] 114 | } 115 | -------------------------------------------------------------------------------- /registry_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Couchbase, 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 | package vellum 16 | 17 | import "testing" 18 | 19 | // FIXME add tests for MRU 20 | 21 | func TestRegistry(t *testing.T) { 22 | p := &builderNodePool{} 23 | r := newRegistry(p, 10, 1) 24 | 25 | n1 := &builderNode{ 26 | trans: []transition{ 27 | { 28 | in: 'a', 29 | addr: 1, 30 | }, 31 | { 32 | in: 'b', 33 | addr: 2, 34 | }, 35 | { 36 | in: 'c', 37 | addr: 3, 38 | }, 39 | }, 40 | } 41 | 42 | // first look, doesn't exist 43 | found, _, cell := r.entry(n1) 44 | if found { 45 | t.Errorf("expected empty registry to not have equivalent") 46 | } 47 | 48 | cell.addr = 276 49 | 50 | // second look, does 51 | var nowAddr int 52 | found, nowAddr, _ = r.entry(n1) 53 | if !found { 54 | t.Errorf("expected to find equivalent after registering it") 55 | } 56 | if nowAddr != 276 { 57 | t.Errorf("expected to get addr 276, got %d", nowAddr) 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /transducer.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Couchbase, 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 | package vellum 16 | 17 | // Transducer represents the general contract of a byte-based finite transducer 18 | type Transducer interface { 19 | 20 | // all transducers are also automatons 21 | Automaton 22 | 23 | // IsMatchWithValue returns true if and only if the state is a match 24 | // additionally it returns a states final value (if any) 25 | IsMatchWithVal(int) (bool, uint64) 26 | 27 | // Accept returns the next state given the input to the specified state 28 | // additionally it returns the value associated with the transition 29 | AcceptWithVal(int, byte) (int, uint64) 30 | } 31 | 32 | // TransducerGet implements an generic Get() method which works 33 | // on any implementation of Transducer 34 | // The caller MUST check the boolean return value for a match. 35 | // Zero is a valid value regardless of match status, 36 | // and if it is NOT a match, the value collected so far is returned. 37 | func TransducerGet(t Transducer, k []byte) (bool, uint64) { 38 | var total uint64 39 | i := 0 40 | curr := t.Start() 41 | for t.CanMatch(curr) && i < len(k) { 42 | var transVal uint64 43 | curr, transVal = t.AcceptWithVal(curr, k[i]) 44 | if curr == noneAddr { 45 | break 46 | } 47 | total += transVal 48 | i++ 49 | } 50 | if i != len(k) { 51 | return false, total 52 | } 53 | match, finalVal := t.IsMatchWithVal(curr) 54 | return match, total + finalVal 55 | } 56 | -------------------------------------------------------------------------------- /utf8/utf8_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Couchbase, 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 | package utf8 16 | 17 | import ( 18 | "fmt" 19 | "reflect" 20 | "testing" 21 | "unicode/utf8" 22 | ) 23 | 24 | func TestUtf8Sequences(t *testing.T) { 25 | 26 | want := Sequences{ 27 | Sequence{ 28 | Range{0x0, 0x7f}, 29 | }, 30 | Sequence{ 31 | Range{0xc2, 0xdf}, 32 | Range{0x80, 0xbf}, 33 | }, 34 | Sequence{ 35 | Range{0xe0, 0xe0}, 36 | Range{0xa0, 0xbf}, 37 | Range{0x80, 0xbf}, 38 | }, 39 | Sequence{ 40 | Range{0xe1, 0xec}, 41 | Range{0x80, 0xbf}, 42 | Range{0x80, 0xbf}, 43 | }, 44 | Sequence{ 45 | Range{0xed, 0xed}, 46 | Range{0x80, 0x9f}, 47 | Range{0x80, 0xbf}, 48 | }, 49 | Sequence{ 50 | Range{0xee, 0xef}, 51 | Range{0x80, 0xbf}, 52 | Range{0x80, 0xbf}, 53 | }, 54 | } 55 | 56 | got, err := NewSequences(0, 0xffff) 57 | if err != nil { 58 | t.Fatal(err) 59 | } 60 | if !reflect.DeepEqual(want, got) { 61 | t.Errorf("wanted: %v, got %v", want, got) 62 | } 63 | } 64 | 65 | func TestCodepointsNoSurrogates(t *testing.T) { 66 | neverAcceptsSurrogateCodepoints(0x0, 0xFFFF) 67 | neverAcceptsSurrogateCodepoints(0x0, 0x10FFFF) 68 | neverAcceptsSurrogateCodepoints(0x0, 0x10FFFE) 69 | neverAcceptsSurrogateCodepoints(0x80, 0x10FFFF) 70 | neverAcceptsSurrogateCodepoints(0xD7FF, 0xE000) 71 | } 72 | 73 | func neverAcceptsSurrogateCodepoints(start, end rune) error { 74 | var buf = make([]byte, utf8.UTFMax) 75 | sequences, err := NewSequences(start, end) 76 | if err != nil { 77 | return err 78 | } 79 | for i := start; i < end; i++ { 80 | n := utf8.EncodeRune(buf, i) 81 | for _, seq := range sequences { 82 | if seq.Matches(buf[:n]) { 83 | return fmt.Errorf("utf8 seq: %v matches surrogate %d", seq, i) 84 | } 85 | } 86 | } 87 | return nil 88 | } 89 | -------------------------------------------------------------------------------- /vellum.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Couchbase, 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 | /* 16 | Package vellum is a library for building, serializing and executing an FST (finite 17 | state transducer). 18 | 19 | There are two distinct phases, building an FST and using it. 20 | 21 | When building an FST, you insert keys ([]byte) and their associated value 22 | (uint64). Insert operations MUST be done in lexicographic order. While 23 | building the FST, data is streamed to an underlying Writer. At the conclusion 24 | of building, you MUST call Close() on the builder. 25 | 26 | After completion of the build phase, you can either Open() the FST if you 27 | serialized it to disk. Alternatively, if you already have the bytes in 28 | memory, you can use Load(). By default, Open() will use mmap to avoid loading 29 | the entire file into memory. 30 | 31 | Once the FST is ready, you can use the Contains() method to see if a keys is 32 | in the FST. You can use the Get() method to see if a key is in the FST and 33 | retrieve it's associated value. And, you can use the Iterator method to 34 | enumerate key/value pairs within a specified range. 35 | 36 | */ 37 | package vellum 38 | 39 | import ( 40 | "errors" 41 | "io" 42 | ) 43 | 44 | // ErrOutOfOrder is returned when values are not inserted in 45 | // lexicographic order. 46 | var ErrOutOfOrder = errors.New("values not inserted in lexicographic order") 47 | 48 | // ErrIteratorDone is returned by Iterator/Next/Seek methods when the 49 | // Current() value pointed to by the iterator is greater than the last 50 | // key in this FST, or outside the configured startKeyInclusive/endKeyExclusive 51 | // range of the Iterator. 52 | var ErrIteratorDone = errors.New("iterator-done") 53 | 54 | // BuilderOpts is a structure to let advanced users customize the behavior 55 | // of the builder and some aspects of the generated FST. 56 | type BuilderOpts struct { 57 | Encoder int 58 | RegistryTableSize int 59 | RegistryMRUSize int 60 | } 61 | 62 | // New returns a new Builder which will stream out the 63 | // underlying representation to the provided Writer as the set is built. 64 | func New(w io.Writer, opts *BuilderOpts) (*Builder, error) { 65 | return newBuilder(w, opts) 66 | } 67 | 68 | // Open loads the FST stored in the provided path 69 | func Open(path string) (*FST, error) { 70 | return open(path) 71 | } 72 | 73 | // Load will return the FST represented by the provided byte slice. 74 | func Load(data []byte) (*FST, error) { 75 | return new(data, nil) 76 | } 77 | 78 | // Merge will iterate through the provided Iterators, merge duplicate keys 79 | // with the provided MergeFunc, and build a new FST to the provided Writer. 80 | func Merge(w io.Writer, opts *BuilderOpts, itrs []Iterator, f MergeFunc) error { 81 | builder, err := New(w, opts) 82 | if err != nil { 83 | return err 84 | } 85 | 86 | itr, err := NewMergeIterator(itrs, f) 87 | for err == nil { 88 | k, v := itr.Current() 89 | err = builder.Insert(k, v) 90 | if err != nil { 91 | return err 92 | } 93 | err = itr.Next() 94 | } 95 | 96 | if err != nil && err != ErrIteratorDone { 97 | return err 98 | } 99 | 100 | err = itr.Close() 101 | if err != nil { 102 | return err 103 | } 104 | 105 | err = builder.Close() 106 | if err != nil { 107 | return err 108 | } 109 | 110 | return nil 111 | } 112 | -------------------------------------------------------------------------------- /vellum_mmap.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Couchbase, 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 | // +build !nommap 16 | 17 | package vellum 18 | 19 | import ( 20 | "os" 21 | 22 | mmap "github.com/blevesearch/mmap-go" 23 | ) 24 | 25 | type mmapWrapper struct { 26 | f *os.File 27 | mm mmap.MMap 28 | } 29 | 30 | func (m *mmapWrapper) Close() (err error) { 31 | if m.mm != nil { 32 | err = m.mm.Unmap() 33 | } 34 | // try to close file even if unmap failed 35 | if m.f != nil { 36 | err2 := m.f.Close() 37 | if err == nil { 38 | // try to return first error 39 | err = err2 40 | } 41 | } 42 | return 43 | } 44 | 45 | func open(path string) (*FST, error) { 46 | f, err := os.Open(path) 47 | if err != nil { 48 | return nil, err 49 | } 50 | mm, err := mmap.Map(f, mmap.RDONLY, 0) 51 | if err != nil { 52 | // mmap failed, try to close the file 53 | _ = f.Close() 54 | return nil, err 55 | } 56 | return new(mm, &mmapWrapper{ 57 | f: f, 58 | mm: mm, 59 | }) 60 | } 61 | -------------------------------------------------------------------------------- /vellum_nommap.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Couchbase, 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 | // +build nommap 16 | 17 | package vellum 18 | 19 | import "io/ioutil" 20 | 21 | func open(path string) (*FST, error) { 22 | data, err := ioutil.ReadFile(string) 23 | if err != nil { 24 | return nil, err 25 | } 26 | return new(data, nil) 27 | } 28 | -------------------------------------------------------------------------------- /vendor/github.com/edsrzf/mmap-go/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011, Evan Shaw 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | * Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | * Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | * Neither the name of the copyright holder nor the 12 | names of its contributors may be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 19 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | 26 | -------------------------------------------------------------------------------- /vendor/github.com/edsrzf/mmap-go/mmap.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Evan Shaw. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // This file defines the common package interface and contains a little bit of 6 | // factored out logic. 7 | 8 | // Package mmap allows mapping files into memory. It tries to provide a simple, reasonably portable interface, 9 | // but doesn't go out of its way to abstract away every little platform detail. 10 | // This specifically means: 11 | // * forked processes may or may not inherit mappings 12 | // * a file's timestamp may or may not be updated by writes through mappings 13 | // * specifying a size larger than the file's actual size can increase the file's size 14 | // * If the mapped file is being modified by another process while your program's running, don't expect consistent results between platforms 15 | package mmap 16 | 17 | import ( 18 | "errors" 19 | "os" 20 | "reflect" 21 | "unsafe" 22 | ) 23 | 24 | const ( 25 | // RDONLY maps the memory read-only. 26 | // Attempts to write to the MMap object will result in undefined behavior. 27 | RDONLY = 0 28 | // RDWR maps the memory as read-write. Writes to the MMap object will update the 29 | // underlying file. 30 | RDWR = 1 << iota 31 | // COPY maps the memory as copy-on-write. Writes to the MMap object will affect 32 | // memory, but the underlying file will remain unchanged. 33 | COPY 34 | // If EXEC is set, the mapped memory is marked as executable. 35 | EXEC 36 | ) 37 | 38 | const ( 39 | // If the ANON flag is set, the mapped memory will not be backed by a file. 40 | ANON = 1 << iota 41 | ) 42 | 43 | // MMap represents a file mapped into memory. 44 | type MMap []byte 45 | 46 | // Map maps an entire file into memory. 47 | // If ANON is set in flags, f is ignored. 48 | func Map(f *os.File, prot, flags int) (MMap, error) { 49 | return MapRegion(f, -1, prot, flags, 0) 50 | } 51 | 52 | // MapRegion maps part of a file into memory. 53 | // The offset parameter must be a multiple of the system's page size. 54 | // If length < 0, the entire file will be mapped. 55 | // If ANON is set in flags, f is ignored. 56 | func MapRegion(f *os.File, length int, prot, flags int, offset int64) (MMap, error) { 57 | var fd uintptr 58 | if flags&ANON == 0 { 59 | fd = uintptr(f.Fd()) 60 | if length < 0 { 61 | fi, err := f.Stat() 62 | if err != nil { 63 | return nil, err 64 | } 65 | length = int(fi.Size()) 66 | } 67 | } else { 68 | if length <= 0 { 69 | return nil, errors.New("anonymous mapping requires non-zero length") 70 | } 71 | fd = ^uintptr(0) 72 | } 73 | return mmap(length, uintptr(prot), uintptr(flags), fd, offset) 74 | } 75 | 76 | func (m *MMap) header() *reflect.SliceHeader { 77 | return (*reflect.SliceHeader)(unsafe.Pointer(m)) 78 | } 79 | 80 | // Lock keeps the mapped region in physical memory, ensuring that it will not be 81 | // swapped out. 82 | func (m MMap) Lock() error { 83 | dh := m.header() 84 | return lock(dh.Data, uintptr(dh.Len)) 85 | } 86 | 87 | // Unlock reverses the effect of Lock, allowing the mapped region to potentially 88 | // be swapped out. 89 | // If m is already unlocked, aan error will result. 90 | func (m MMap) Unlock() error { 91 | dh := m.header() 92 | return unlock(dh.Data, uintptr(dh.Len)) 93 | } 94 | 95 | // Flush synchronizes the mapping's contents to the file's contents on disk. 96 | func (m MMap) Flush() error { 97 | dh := m.header() 98 | return flush(dh.Data, uintptr(dh.Len)) 99 | } 100 | 101 | // Unmap deletes the memory mapped region, flushes any remaining changes, and sets 102 | // m to nil. 103 | // Trying to read or write any remaining references to m after Unmap is called will 104 | // result in undefined behavior. 105 | // Unmap should only be called on the slice value that was originally returned from 106 | // a call to Map. Calling Unmap on a derived slice may cause errors. 107 | func (m *MMap) Unmap() error { 108 | dh := m.header() 109 | err := unmap(dh.Data, uintptr(dh.Len)) 110 | *m = nil 111 | return err 112 | } 113 | -------------------------------------------------------------------------------- /vendor/github.com/edsrzf/mmap-go/mmap_unix.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Evan Shaw. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build darwin dragonfly freebsd linux openbsd solaris netbsd 6 | 7 | package mmap 8 | 9 | import ( 10 | "syscall" 11 | ) 12 | 13 | func mmap(len int, inprot, inflags, fd uintptr, off int64) ([]byte, error) { 14 | flags := syscall.MAP_SHARED 15 | prot := syscall.PROT_READ 16 | switch { 17 | case inprot© != 0: 18 | prot |= syscall.PROT_WRITE 19 | flags = syscall.MAP_PRIVATE 20 | case inprot&RDWR != 0: 21 | prot |= syscall.PROT_WRITE 22 | } 23 | if inprot&EXEC != 0 { 24 | prot |= syscall.PROT_EXEC 25 | } 26 | if inflags&ANON != 0 { 27 | flags |= syscall.MAP_ANON 28 | } 29 | 30 | b, err := syscall.Mmap(int(fd), off, len, prot, flags) 31 | if err != nil { 32 | return nil, err 33 | } 34 | return b, nil 35 | } 36 | 37 | func flush(addr, len uintptr) error { 38 | _, _, errno := syscall.Syscall(_SYS_MSYNC, addr, len, _MS_SYNC) 39 | if errno != 0 { 40 | return syscall.Errno(errno) 41 | } 42 | return nil 43 | } 44 | 45 | func lock(addr, len uintptr) error { 46 | _, _, errno := syscall.Syscall(syscall.SYS_MLOCK, addr, len, 0) 47 | if errno != 0 { 48 | return syscall.Errno(errno) 49 | } 50 | return nil 51 | } 52 | 53 | func unlock(addr, len uintptr) error { 54 | _, _, errno := syscall.Syscall(syscall.SYS_MUNLOCK, addr, len, 0) 55 | if errno != 0 { 56 | return syscall.Errno(errno) 57 | } 58 | return nil 59 | } 60 | 61 | func unmap(addr, len uintptr) error { 62 | _, _, errno := syscall.Syscall(syscall.SYS_MUNMAP, addr, len, 0) 63 | if errno != 0 { 64 | return syscall.Errno(errno) 65 | } 66 | return nil 67 | } 68 | -------------------------------------------------------------------------------- /vendor/github.com/edsrzf/mmap-go/mmap_windows.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Evan Shaw. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package mmap 6 | 7 | import ( 8 | "errors" 9 | "os" 10 | "sync" 11 | "syscall" 12 | ) 13 | 14 | // mmap on Windows is a two-step process. 15 | // First, we call CreateFileMapping to get a handle. 16 | // Then, we call MapviewToFile to get an actual pointer into memory. 17 | // Because we want to emulate a POSIX-style mmap, we don't want to expose 18 | // the handle -- only the pointer. We also want to return only a byte slice, 19 | // not a struct, so it's convenient to manipulate. 20 | 21 | // We keep this map so that we can get back the original handle from the memory address. 22 | var handleLock sync.Mutex 23 | var handleMap = map[uintptr]syscall.Handle{} 24 | 25 | func mmap(len int, prot, flags, hfile uintptr, off int64) ([]byte, error) { 26 | flProtect := uint32(syscall.PAGE_READONLY) 27 | dwDesiredAccess := uint32(syscall.FILE_MAP_READ) 28 | switch { 29 | case prot© != 0: 30 | flProtect = syscall.PAGE_WRITECOPY 31 | dwDesiredAccess = syscall.FILE_MAP_COPY 32 | case prot&RDWR != 0: 33 | flProtect = syscall.PAGE_READWRITE 34 | dwDesiredAccess = syscall.FILE_MAP_WRITE 35 | } 36 | if prot&EXEC != 0 { 37 | flProtect <<= 4 38 | dwDesiredAccess |= syscall.FILE_MAP_EXECUTE 39 | } 40 | 41 | // The maximum size is the area of the file, starting from 0, 42 | // that we wish to allow to be mappable. It is the sum of 43 | // the length the user requested, plus the offset where that length 44 | // is starting from. This does not map the data into memory. 45 | maxSizeHigh := uint32((off + int64(len)) >> 32) 46 | maxSizeLow := uint32((off + int64(len)) & 0xFFFFFFFF) 47 | // TODO: Do we need to set some security attributes? It might help portability. 48 | h, errno := syscall.CreateFileMapping(syscall.Handle(hfile), nil, flProtect, maxSizeHigh, maxSizeLow, nil) 49 | if h == 0 { 50 | return nil, os.NewSyscallError("CreateFileMapping", errno) 51 | } 52 | 53 | // Actually map a view of the data into memory. The view's size 54 | // is the length the user requested. 55 | fileOffsetHigh := uint32(off >> 32) 56 | fileOffsetLow := uint32(off & 0xFFFFFFFF) 57 | addr, errno := syscall.MapViewOfFile(h, dwDesiredAccess, fileOffsetHigh, fileOffsetLow, uintptr(len)) 58 | if addr == 0 { 59 | return nil, os.NewSyscallError("MapViewOfFile", errno) 60 | } 61 | handleLock.Lock() 62 | handleMap[addr] = h 63 | handleLock.Unlock() 64 | 65 | m := MMap{} 66 | dh := m.header() 67 | dh.Data = addr 68 | dh.Len = len 69 | dh.Cap = dh.Len 70 | 71 | return m, nil 72 | } 73 | 74 | func flush(addr, len uintptr) error { 75 | errno := syscall.FlushViewOfFile(addr, len) 76 | if errno != nil { 77 | return os.NewSyscallError("FlushViewOfFile", errno) 78 | } 79 | 80 | handleLock.Lock() 81 | defer handleLock.Unlock() 82 | handle, ok := handleMap[addr] 83 | if !ok { 84 | // should be impossible; we would've errored above 85 | return errors.New("unknown base address") 86 | } 87 | 88 | errno = syscall.FlushFileBuffers(handle) 89 | return os.NewSyscallError("FlushFileBuffers", errno) 90 | } 91 | 92 | func lock(addr, len uintptr) error { 93 | errno := syscall.VirtualLock(addr, len) 94 | return os.NewSyscallError("VirtualLock", errno) 95 | } 96 | 97 | func unlock(addr, len uintptr) error { 98 | errno := syscall.VirtualUnlock(addr, len) 99 | return os.NewSyscallError("VirtualUnlock", errno) 100 | } 101 | 102 | func unmap(addr, len uintptr) error { 103 | flush(addr, len) 104 | // Lock the UnmapViewOfFile along with the handleMap deletion. 105 | // As soon as we unmap the view, the OS is free to give the 106 | // same addr to another new map. We don't want another goroutine 107 | // to insert and remove the same addr into handleMap while 108 | // we're trying to remove our old addr/handle pair. 109 | handleLock.Lock() 110 | defer handleLock.Unlock() 111 | err := syscall.UnmapViewOfFile(addr) 112 | if err != nil { 113 | return err 114 | } 115 | 116 | handle, ok := handleMap[addr] 117 | if !ok { 118 | // should be impossible; we would've errored above 119 | return errors.New("unknown base address") 120 | } 121 | delete(handleMap, addr) 122 | 123 | e := syscall.CloseHandle(syscall.Handle(handle)) 124 | return os.NewSyscallError("CloseHandle", e) 125 | } 126 | -------------------------------------------------------------------------------- /vendor/github.com/edsrzf/mmap-go/msync_netbsd.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Evan Shaw. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package mmap 6 | 7 | const _SYS_MSYNC = 277 8 | const _MS_SYNC = 0x04 9 | -------------------------------------------------------------------------------- /vendor/github.com/edsrzf/mmap-go/msync_unix.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Evan Shaw. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build darwin dragonfly freebsd linux openbsd solaris 6 | 7 | package mmap 8 | 9 | import ( 10 | "syscall" 11 | ) 12 | 13 | const _SYS_MSYNC = syscall.SYS_MSYNC 14 | const _MS_SYNC = syscall.MS_SYNC 15 | -------------------------------------------------------------------------------- /vendor/github.com/inconshreveable/mousetrap/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2014 Alan Shreve 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 | -------------------------------------------------------------------------------- /vendor/github.com/inconshreveable/mousetrap/trap_others.go: -------------------------------------------------------------------------------- 1 | // +build !windows 2 | 3 | package mousetrap 4 | 5 | // StartedByExplorer returns true if the program was invoked by the user 6 | // double-clicking on the executable from explorer.exe 7 | // 8 | // It is conservative and returns false if any of the internal calls fail. 9 | // It does not guarantee that the program was run from a terminal. It only can tell you 10 | // whether it was launched from explorer.exe 11 | // 12 | // On non-Windows platforms, it always returns false. 13 | func StartedByExplorer() bool { 14 | return false 15 | } 16 | -------------------------------------------------------------------------------- /vendor/github.com/inconshreveable/mousetrap/trap_windows.go: -------------------------------------------------------------------------------- 1 | // +build windows 2 | // +build !go1.4 3 | 4 | package mousetrap 5 | 6 | import ( 7 | "fmt" 8 | "os" 9 | "syscall" 10 | "unsafe" 11 | ) 12 | 13 | const ( 14 | // defined by the Win32 API 15 | th32cs_snapprocess uintptr = 0x2 16 | ) 17 | 18 | var ( 19 | kernel = syscall.MustLoadDLL("kernel32.dll") 20 | CreateToolhelp32Snapshot = kernel.MustFindProc("CreateToolhelp32Snapshot") 21 | Process32First = kernel.MustFindProc("Process32FirstW") 22 | Process32Next = kernel.MustFindProc("Process32NextW") 23 | ) 24 | 25 | // ProcessEntry32 structure defined by the Win32 API 26 | type processEntry32 struct { 27 | dwSize uint32 28 | cntUsage uint32 29 | th32ProcessID uint32 30 | th32DefaultHeapID int 31 | th32ModuleID uint32 32 | cntThreads uint32 33 | th32ParentProcessID uint32 34 | pcPriClassBase int32 35 | dwFlags uint32 36 | szExeFile [syscall.MAX_PATH]uint16 37 | } 38 | 39 | func getProcessEntry(pid int) (pe *processEntry32, err error) { 40 | snapshot, _, e1 := CreateToolhelp32Snapshot.Call(th32cs_snapprocess, uintptr(0)) 41 | if snapshot == uintptr(syscall.InvalidHandle) { 42 | err = fmt.Errorf("CreateToolhelp32Snapshot: %v", e1) 43 | return 44 | } 45 | defer syscall.CloseHandle(syscall.Handle(snapshot)) 46 | 47 | var processEntry processEntry32 48 | processEntry.dwSize = uint32(unsafe.Sizeof(processEntry)) 49 | ok, _, e1 := Process32First.Call(snapshot, uintptr(unsafe.Pointer(&processEntry))) 50 | if ok == 0 { 51 | err = fmt.Errorf("Process32First: %v", e1) 52 | return 53 | } 54 | 55 | for { 56 | if processEntry.th32ProcessID == uint32(pid) { 57 | pe = &processEntry 58 | return 59 | } 60 | 61 | ok, _, e1 = Process32Next.Call(snapshot, uintptr(unsafe.Pointer(&processEntry))) 62 | if ok == 0 { 63 | err = fmt.Errorf("Process32Next: %v", e1) 64 | return 65 | } 66 | } 67 | } 68 | 69 | func getppid() (pid int, err error) { 70 | pe, err := getProcessEntry(os.Getpid()) 71 | if err != nil { 72 | return 73 | } 74 | 75 | pid = int(pe.th32ParentProcessID) 76 | return 77 | } 78 | 79 | // StartedByExplorer returns true if the program was invoked by the user double-clicking 80 | // on the executable from explorer.exe 81 | // 82 | // It is conservative and returns false if any of the internal calls fail. 83 | // It does not guarantee that the program was run from a terminal. It only can tell you 84 | // whether it was launched from explorer.exe 85 | func StartedByExplorer() bool { 86 | ppid, err := getppid() 87 | if err != nil { 88 | return false 89 | } 90 | 91 | pe, err := getProcessEntry(ppid) 92 | if err != nil { 93 | return false 94 | } 95 | 96 | name := syscall.UTF16ToString(pe.szExeFile[:]) 97 | return name == "explorer.exe" 98 | } 99 | -------------------------------------------------------------------------------- /vendor/github.com/inconshreveable/mousetrap/trap_windows_1.4.go: -------------------------------------------------------------------------------- 1 | // +build windows 2 | // +build go1.4 3 | 4 | package mousetrap 5 | 6 | import ( 7 | "os" 8 | "syscall" 9 | "unsafe" 10 | ) 11 | 12 | func getProcessEntry(pid int) (*syscall.ProcessEntry32, error) { 13 | snapshot, err := syscall.CreateToolhelp32Snapshot(syscall.TH32CS_SNAPPROCESS, 0) 14 | if err != nil { 15 | return nil, err 16 | } 17 | defer syscall.CloseHandle(snapshot) 18 | var procEntry syscall.ProcessEntry32 19 | procEntry.Size = uint32(unsafe.Sizeof(procEntry)) 20 | if err = syscall.Process32First(snapshot, &procEntry); err != nil { 21 | return nil, err 22 | } 23 | for { 24 | if procEntry.ProcessID == uint32(pid) { 25 | return &procEntry, nil 26 | } 27 | err = syscall.Process32Next(snapshot, &procEntry) 28 | if err != nil { 29 | return nil, err 30 | } 31 | } 32 | } 33 | 34 | // StartedByExplorer returns true if the program was invoked by the user double-clicking 35 | // on the executable from explorer.exe 36 | // 37 | // It is conservative and returns false if any of the internal calls fail. 38 | // It does not guarantee that the program was run from a terminal. It only can tell you 39 | // whether it was launched from explorer.exe 40 | func StartedByExplorer() bool { 41 | pe, err := getProcessEntry(os.Getppid()) 42 | if err != nil { 43 | return false 44 | } 45 | return "explorer.exe" == syscall.UTF16ToString(pe.ExeFile[:]) 46 | } 47 | -------------------------------------------------------------------------------- /vendor/github.com/spf13/cobra/command_notwin.go: -------------------------------------------------------------------------------- 1 | // +build !windows 2 | 3 | package cobra 4 | 5 | var preExecHookFn func(*Command) 6 | -------------------------------------------------------------------------------- /vendor/github.com/spf13/cobra/command_win.go: -------------------------------------------------------------------------------- 1 | // +build windows 2 | 3 | package cobra 4 | 5 | import ( 6 | "os" 7 | "time" 8 | 9 | "github.com/inconshreveable/mousetrap" 10 | ) 11 | 12 | var preExecHookFn = preExecHook 13 | 14 | // enables an information splash screen on Windows if the CLI is started from explorer.exe. 15 | var MousetrapHelpText string = `This is a command line tool 16 | 17 | You need to open cmd.exe and run it from there. 18 | ` 19 | 20 | func preExecHook(c *Command) { 21 | if mousetrap.StartedByExplorer() { 22 | c.Print(MousetrapHelpText) 23 | time.Sleep(5 * time.Second) 24 | os.Exit(1) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /vendor/github.com/spf13/cobra/doc/util.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 Red Hat Inc. All rights reserved. 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 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // 8 | // Unless required by applicable law or agreed to in writing, software 9 | // distributed under the License is distributed on an "AS IS" BASIS, 10 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package doc 15 | 16 | import ( 17 | "strings" 18 | 19 | "github.com/spf13/cobra" 20 | ) 21 | 22 | // Test to see if we have a reason to print See Also information in docs 23 | // Basically this is a test for a parent commend or a subcommand which is 24 | // both not deprecated and not the autogenerated help command. 25 | func hasSeeAlso(cmd *cobra.Command) bool { 26 | if cmd.HasParent() { 27 | return true 28 | } 29 | for _, c := range cmd.Commands() { 30 | if !c.IsAvailableCommand() || c.IsAdditionalHelpTopicCommand() { 31 | continue 32 | } 33 | return true 34 | } 35 | return false 36 | } 37 | 38 | // Temporary workaround for yaml lib generating incorrect yaml with long strings 39 | // that do not contain \n. 40 | func forceMultiLine(s string) string { 41 | if len(s) > 60 && !strings.Contains(s, "\n") { 42 | s = s + "\n" 43 | } 44 | return s 45 | } 46 | 47 | type byName []*cobra.Command 48 | 49 | func (s byName) Len() int { return len(s) } 50 | func (s byName) Swap(i, j int) { s[i], s[j] = s[j], s[i] } 51 | func (s byName) Less(i, j int) bool { return s[i].Name() < s[j].Name() } 52 | -------------------------------------------------------------------------------- /vendor/github.com/spf13/pflag/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 Alex Ogier. All rights reserved. 2 | Copyright (c) 2012 The Go Authors. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are 6 | met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above 11 | copyright notice, this list of conditions and the following disclaimer 12 | in the documentation and/or other materials provided with the 13 | distribution. 14 | * Neither the name of Google Inc. nor the names of its 15 | contributors may be used to endorse or promote products derived from 16 | this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | -------------------------------------------------------------------------------- /vendor/github.com/spf13/pflag/bool.go: -------------------------------------------------------------------------------- 1 | package pflag 2 | 3 | import "strconv" 4 | 5 | // optional interface to indicate boolean flags that can be 6 | // supplied without "=value" text 7 | type boolFlag interface { 8 | Value 9 | IsBoolFlag() bool 10 | } 11 | 12 | // -- bool Value 13 | type boolValue bool 14 | 15 | func newBoolValue(val bool, p *bool) *boolValue { 16 | *p = val 17 | return (*boolValue)(p) 18 | } 19 | 20 | func (b *boolValue) Set(s string) error { 21 | v, err := strconv.ParseBool(s) 22 | *b = boolValue(v) 23 | return err 24 | } 25 | 26 | func (b *boolValue) Type() string { 27 | return "bool" 28 | } 29 | 30 | func (b *boolValue) String() string { return strconv.FormatBool(bool(*b)) } 31 | 32 | func (b *boolValue) IsBoolFlag() bool { return true } 33 | 34 | func boolConv(sval string) (interface{}, error) { 35 | return strconv.ParseBool(sval) 36 | } 37 | 38 | // GetBool return the bool value of a flag with the given name 39 | func (f *FlagSet) GetBool(name string) (bool, error) { 40 | val, err := f.getFlagType(name, "bool", boolConv) 41 | if err != nil { 42 | return false, err 43 | } 44 | return val.(bool), nil 45 | } 46 | 47 | // BoolVar defines a bool flag with specified name, default value, and usage string. 48 | // The argument p points to a bool variable in which to store the value of the flag. 49 | func (f *FlagSet) BoolVar(p *bool, name string, value bool, usage string) { 50 | f.BoolVarP(p, name, "", value, usage) 51 | } 52 | 53 | // BoolVarP is like BoolVar, but accepts a shorthand letter that can be used after a single dash. 54 | func (f *FlagSet) BoolVarP(p *bool, name, shorthand string, value bool, usage string) { 55 | flag := f.VarPF(newBoolValue(value, p), name, shorthand, usage) 56 | flag.NoOptDefVal = "true" 57 | } 58 | 59 | // BoolVar defines a bool flag with specified name, default value, and usage string. 60 | // The argument p points to a bool variable in which to store the value of the flag. 61 | func BoolVar(p *bool, name string, value bool, usage string) { 62 | BoolVarP(p, name, "", value, usage) 63 | } 64 | 65 | // BoolVarP is like BoolVar, but accepts a shorthand letter that can be used after a single dash. 66 | func BoolVarP(p *bool, name, shorthand string, value bool, usage string) { 67 | flag := CommandLine.VarPF(newBoolValue(value, p), name, shorthand, usage) 68 | flag.NoOptDefVal = "true" 69 | } 70 | 71 | // Bool defines a bool flag with specified name, default value, and usage string. 72 | // The return value is the address of a bool variable that stores the value of the flag. 73 | func (f *FlagSet) Bool(name string, value bool, usage string) *bool { 74 | return f.BoolP(name, "", value, usage) 75 | } 76 | 77 | // BoolP is like Bool, but accepts a shorthand letter that can be used after a single dash. 78 | func (f *FlagSet) BoolP(name, shorthand string, value bool, usage string) *bool { 79 | p := new(bool) 80 | f.BoolVarP(p, name, shorthand, value, usage) 81 | return p 82 | } 83 | 84 | // Bool defines a bool flag with specified name, default value, and usage string. 85 | // The return value is the address of a bool variable that stores the value of the flag. 86 | func Bool(name string, value bool, usage string) *bool { 87 | return BoolP(name, "", value, usage) 88 | } 89 | 90 | // BoolP is like Bool, but accepts a shorthand letter that can be used after a single dash. 91 | func BoolP(name, shorthand string, value bool, usage string) *bool { 92 | b := CommandLine.BoolP(name, shorthand, value, usage) 93 | return b 94 | } 95 | -------------------------------------------------------------------------------- /vendor/github.com/spf13/pflag/bool_slice.go: -------------------------------------------------------------------------------- 1 | package pflag 2 | 3 | import ( 4 | "io" 5 | "strconv" 6 | "strings" 7 | ) 8 | 9 | // -- boolSlice Value 10 | type boolSliceValue struct { 11 | value *[]bool 12 | changed bool 13 | } 14 | 15 | func newBoolSliceValue(val []bool, p *[]bool) *boolSliceValue { 16 | bsv := new(boolSliceValue) 17 | bsv.value = p 18 | *bsv.value = val 19 | return bsv 20 | } 21 | 22 | // Set converts, and assigns, the comma-separated boolean argument string representation as the []bool value of this flag. 23 | // If Set is called on a flag that already has a []bool assigned, the newly converted values will be appended. 24 | func (s *boolSliceValue) Set(val string) error { 25 | 26 | // remove all quote characters 27 | rmQuote := strings.NewReplacer(`"`, "", `'`, "", "`", "") 28 | 29 | // read flag arguments with CSV parser 30 | boolStrSlice, err := readAsCSV(rmQuote.Replace(val)) 31 | if err != nil && err != io.EOF { 32 | return err 33 | } 34 | 35 | // parse boolean values into slice 36 | out := make([]bool, 0, len(boolStrSlice)) 37 | for _, boolStr := range boolStrSlice { 38 | b, err := strconv.ParseBool(strings.TrimSpace(boolStr)) 39 | if err != nil { 40 | return err 41 | } 42 | out = append(out, b) 43 | } 44 | 45 | if !s.changed { 46 | *s.value = out 47 | } else { 48 | *s.value = append(*s.value, out...) 49 | } 50 | 51 | s.changed = true 52 | 53 | return nil 54 | } 55 | 56 | // Type returns a string that uniquely represents this flag's type. 57 | func (s *boolSliceValue) Type() string { 58 | return "boolSlice" 59 | } 60 | 61 | // String defines a "native" format for this boolean slice flag value. 62 | func (s *boolSliceValue) String() string { 63 | 64 | boolStrSlice := make([]string, len(*s.value)) 65 | for i, b := range *s.value { 66 | boolStrSlice[i] = strconv.FormatBool(b) 67 | } 68 | 69 | out, _ := writeAsCSV(boolStrSlice) 70 | 71 | return "[" + out + "]" 72 | } 73 | 74 | func boolSliceConv(val string) (interface{}, error) { 75 | val = strings.Trim(val, "[]") 76 | // Empty string would cause a slice with one (empty) entry 77 | if len(val) == 0 { 78 | return []bool{}, nil 79 | } 80 | ss := strings.Split(val, ",") 81 | out := make([]bool, len(ss)) 82 | for i, t := range ss { 83 | var err error 84 | out[i], err = strconv.ParseBool(t) 85 | if err != nil { 86 | return nil, err 87 | } 88 | } 89 | return out, nil 90 | } 91 | 92 | // GetBoolSlice returns the []bool value of a flag with the given name. 93 | func (f *FlagSet) GetBoolSlice(name string) ([]bool, error) { 94 | val, err := f.getFlagType(name, "boolSlice", boolSliceConv) 95 | if err != nil { 96 | return []bool{}, err 97 | } 98 | return val.([]bool), nil 99 | } 100 | 101 | // BoolSliceVar defines a boolSlice flag with specified name, default value, and usage string. 102 | // The argument p points to a []bool variable in which to store the value of the flag. 103 | func (f *FlagSet) BoolSliceVar(p *[]bool, name string, value []bool, usage string) { 104 | f.VarP(newBoolSliceValue(value, p), name, "", usage) 105 | } 106 | 107 | // BoolSliceVarP is like BoolSliceVar, but accepts a shorthand letter that can be used after a single dash. 108 | func (f *FlagSet) BoolSliceVarP(p *[]bool, name, shorthand string, value []bool, usage string) { 109 | f.VarP(newBoolSliceValue(value, p), name, shorthand, usage) 110 | } 111 | 112 | // BoolSliceVar defines a []bool flag with specified name, default value, and usage string. 113 | // The argument p points to a []bool variable in which to store the value of the flag. 114 | func BoolSliceVar(p *[]bool, name string, value []bool, usage string) { 115 | CommandLine.VarP(newBoolSliceValue(value, p), name, "", usage) 116 | } 117 | 118 | // BoolSliceVarP is like BoolSliceVar, but accepts a shorthand letter that can be used after a single dash. 119 | func BoolSliceVarP(p *[]bool, name, shorthand string, value []bool, usage string) { 120 | CommandLine.VarP(newBoolSliceValue(value, p), name, shorthand, usage) 121 | } 122 | 123 | // BoolSlice defines a []bool flag with specified name, default value, and usage string. 124 | // The return value is the address of a []bool variable that stores the value of the flag. 125 | func (f *FlagSet) BoolSlice(name string, value []bool, usage string) *[]bool { 126 | p := []bool{} 127 | f.BoolSliceVarP(&p, name, "", value, usage) 128 | return &p 129 | } 130 | 131 | // BoolSliceP is like BoolSlice, but accepts a shorthand letter that can be used after a single dash. 132 | func (f *FlagSet) BoolSliceP(name, shorthand string, value []bool, usage string) *[]bool { 133 | p := []bool{} 134 | f.BoolSliceVarP(&p, name, shorthand, value, usage) 135 | return &p 136 | } 137 | 138 | // BoolSlice defines a []bool flag with specified name, default value, and usage string. 139 | // The return value is the address of a []bool variable that stores the value of the flag. 140 | func BoolSlice(name string, value []bool, usage string) *[]bool { 141 | return CommandLine.BoolSliceP(name, "", value, usage) 142 | } 143 | 144 | // BoolSliceP is like BoolSlice, but accepts a shorthand letter that can be used after a single dash. 145 | func BoolSliceP(name, shorthand string, value []bool, usage string) *[]bool { 146 | return CommandLine.BoolSliceP(name, shorthand, value, usage) 147 | } 148 | -------------------------------------------------------------------------------- /vendor/github.com/spf13/pflag/count.go: -------------------------------------------------------------------------------- 1 | package pflag 2 | 3 | import "strconv" 4 | 5 | // -- count Value 6 | type countValue int 7 | 8 | func newCountValue(val int, p *int) *countValue { 9 | *p = val 10 | return (*countValue)(p) 11 | } 12 | 13 | func (i *countValue) Set(s string) error { 14 | v, err := strconv.ParseInt(s, 0, 64) 15 | // -1 means that no specific value was passed, so increment 16 | if v == -1 { 17 | *i = countValue(*i + 1) 18 | } else { 19 | *i = countValue(v) 20 | } 21 | return err 22 | } 23 | 24 | func (i *countValue) Type() string { 25 | return "count" 26 | } 27 | 28 | func (i *countValue) String() string { return strconv.Itoa(int(*i)) } 29 | 30 | func countConv(sval string) (interface{}, error) { 31 | i, err := strconv.Atoi(sval) 32 | if err != nil { 33 | return nil, err 34 | } 35 | return i, nil 36 | } 37 | 38 | // GetCount return the int value of a flag with the given name 39 | func (f *FlagSet) GetCount(name string) (int, error) { 40 | val, err := f.getFlagType(name, "count", countConv) 41 | if err != nil { 42 | return 0, err 43 | } 44 | return val.(int), nil 45 | } 46 | 47 | // CountVar defines a count flag with specified name, default value, and usage string. 48 | // The argument p points to an int variable in which to store the value of the flag. 49 | // A count flag will add 1 to its value evey time it is found on the command line 50 | func (f *FlagSet) CountVar(p *int, name string, usage string) { 51 | f.CountVarP(p, name, "", usage) 52 | } 53 | 54 | // CountVarP is like CountVar only take a shorthand for the flag name. 55 | func (f *FlagSet) CountVarP(p *int, name, shorthand string, usage string) { 56 | flag := f.VarPF(newCountValue(0, p), name, shorthand, usage) 57 | flag.NoOptDefVal = "-1" 58 | } 59 | 60 | // CountVar like CountVar only the flag is placed on the CommandLine instead of a given flag set 61 | func CountVar(p *int, name string, usage string) { 62 | CommandLine.CountVar(p, name, usage) 63 | } 64 | 65 | // CountVarP is like CountVar only take a shorthand for the flag name. 66 | func CountVarP(p *int, name, shorthand string, usage string) { 67 | CommandLine.CountVarP(p, name, shorthand, usage) 68 | } 69 | 70 | // Count defines a count flag with specified name, default value, and usage string. 71 | // The return value is the address of an int variable that stores the value of the flag. 72 | // A count flag will add 1 to its value evey time it is found on the command line 73 | func (f *FlagSet) Count(name string, usage string) *int { 74 | p := new(int) 75 | f.CountVarP(p, name, "", usage) 76 | return p 77 | } 78 | 79 | // CountP is like Count only takes a shorthand for the flag name. 80 | func (f *FlagSet) CountP(name, shorthand string, usage string) *int { 81 | p := new(int) 82 | f.CountVarP(p, name, shorthand, usage) 83 | return p 84 | } 85 | 86 | // Count like Count only the flag is placed on the CommandLine isntead of a given flag set 87 | func Count(name string, usage string) *int { 88 | return CommandLine.CountP(name, "", usage) 89 | } 90 | 91 | // CountP is like Count only takes a shorthand for the flag name. 92 | func CountP(name, shorthand string, usage string) *int { 93 | return CommandLine.CountP(name, shorthand, usage) 94 | } 95 | -------------------------------------------------------------------------------- /vendor/github.com/spf13/pflag/duration.go: -------------------------------------------------------------------------------- 1 | package pflag 2 | 3 | import ( 4 | "time" 5 | ) 6 | 7 | // -- time.Duration Value 8 | type durationValue time.Duration 9 | 10 | func newDurationValue(val time.Duration, p *time.Duration) *durationValue { 11 | *p = val 12 | return (*durationValue)(p) 13 | } 14 | 15 | func (d *durationValue) Set(s string) error { 16 | v, err := time.ParseDuration(s) 17 | *d = durationValue(v) 18 | return err 19 | } 20 | 21 | func (d *durationValue) Type() string { 22 | return "duration" 23 | } 24 | 25 | func (d *durationValue) String() string { return (*time.Duration)(d).String() } 26 | 27 | func durationConv(sval string) (interface{}, error) { 28 | return time.ParseDuration(sval) 29 | } 30 | 31 | // GetDuration return the duration value of a flag with the given name 32 | func (f *FlagSet) GetDuration(name string) (time.Duration, error) { 33 | val, err := f.getFlagType(name, "duration", durationConv) 34 | if err != nil { 35 | return 0, err 36 | } 37 | return val.(time.Duration), nil 38 | } 39 | 40 | // DurationVar defines a time.Duration flag with specified name, default value, and usage string. 41 | // The argument p points to a time.Duration variable in which to store the value of the flag. 42 | func (f *FlagSet) DurationVar(p *time.Duration, name string, value time.Duration, usage string) { 43 | f.VarP(newDurationValue(value, p), name, "", usage) 44 | } 45 | 46 | // DurationVarP is like DurationVar, but accepts a shorthand letter that can be used after a single dash. 47 | func (f *FlagSet) DurationVarP(p *time.Duration, name, shorthand string, value time.Duration, usage string) { 48 | f.VarP(newDurationValue(value, p), name, shorthand, usage) 49 | } 50 | 51 | // DurationVar defines a time.Duration flag with specified name, default value, and usage string. 52 | // The argument p points to a time.Duration variable in which to store the value of the flag. 53 | func DurationVar(p *time.Duration, name string, value time.Duration, usage string) { 54 | CommandLine.VarP(newDurationValue(value, p), name, "", usage) 55 | } 56 | 57 | // DurationVarP is like DurationVar, but accepts a shorthand letter that can be used after a single dash. 58 | func DurationVarP(p *time.Duration, name, shorthand string, value time.Duration, usage string) { 59 | CommandLine.VarP(newDurationValue(value, p), name, shorthand, usage) 60 | } 61 | 62 | // Duration defines a time.Duration flag with specified name, default value, and usage string. 63 | // The return value is the address of a time.Duration variable that stores the value of the flag. 64 | func (f *FlagSet) Duration(name string, value time.Duration, usage string) *time.Duration { 65 | p := new(time.Duration) 66 | f.DurationVarP(p, name, "", value, usage) 67 | return p 68 | } 69 | 70 | // DurationP is like Duration, but accepts a shorthand letter that can be used after a single dash. 71 | func (f *FlagSet) DurationP(name, shorthand string, value time.Duration, usage string) *time.Duration { 72 | p := new(time.Duration) 73 | f.DurationVarP(p, name, shorthand, value, usage) 74 | return p 75 | } 76 | 77 | // Duration defines a time.Duration flag with specified name, default value, and usage string. 78 | // The return value is the address of a time.Duration variable that stores the value of the flag. 79 | func Duration(name string, value time.Duration, usage string) *time.Duration { 80 | return CommandLine.DurationP(name, "", value, usage) 81 | } 82 | 83 | // DurationP is like Duration, but accepts a shorthand letter that can be used after a single dash. 84 | func DurationP(name, shorthand string, value time.Duration, usage string) *time.Duration { 85 | return CommandLine.DurationP(name, shorthand, value, usage) 86 | } 87 | -------------------------------------------------------------------------------- /vendor/github.com/spf13/pflag/float32.go: -------------------------------------------------------------------------------- 1 | package pflag 2 | 3 | import "strconv" 4 | 5 | // -- float32 Value 6 | type float32Value float32 7 | 8 | func newFloat32Value(val float32, p *float32) *float32Value { 9 | *p = val 10 | return (*float32Value)(p) 11 | } 12 | 13 | func (f *float32Value) Set(s string) error { 14 | v, err := strconv.ParseFloat(s, 32) 15 | *f = float32Value(v) 16 | return err 17 | } 18 | 19 | func (f *float32Value) Type() string { 20 | return "float32" 21 | } 22 | 23 | func (f *float32Value) String() string { return strconv.FormatFloat(float64(*f), 'g', -1, 32) } 24 | 25 | func float32Conv(sval string) (interface{}, error) { 26 | v, err := strconv.ParseFloat(sval, 32) 27 | if err != nil { 28 | return 0, err 29 | } 30 | return float32(v), nil 31 | } 32 | 33 | // GetFloat32 return the float32 value of a flag with the given name 34 | func (f *FlagSet) GetFloat32(name string) (float32, error) { 35 | val, err := f.getFlagType(name, "float32", float32Conv) 36 | if err != nil { 37 | return 0, err 38 | } 39 | return val.(float32), nil 40 | } 41 | 42 | // Float32Var defines a float32 flag with specified name, default value, and usage string. 43 | // The argument p points to a float32 variable in which to store the value of the flag. 44 | func (f *FlagSet) Float32Var(p *float32, name string, value float32, usage string) { 45 | f.VarP(newFloat32Value(value, p), name, "", usage) 46 | } 47 | 48 | // Float32VarP is like Float32Var, but accepts a shorthand letter that can be used after a single dash. 49 | func (f *FlagSet) Float32VarP(p *float32, name, shorthand string, value float32, usage string) { 50 | f.VarP(newFloat32Value(value, p), name, shorthand, usage) 51 | } 52 | 53 | // Float32Var defines a float32 flag with specified name, default value, and usage string. 54 | // The argument p points to a float32 variable in which to store the value of the flag. 55 | func Float32Var(p *float32, name string, value float32, usage string) { 56 | CommandLine.VarP(newFloat32Value(value, p), name, "", usage) 57 | } 58 | 59 | // Float32VarP is like Float32Var, but accepts a shorthand letter that can be used after a single dash. 60 | func Float32VarP(p *float32, name, shorthand string, value float32, usage string) { 61 | CommandLine.VarP(newFloat32Value(value, p), name, shorthand, usage) 62 | } 63 | 64 | // Float32 defines a float32 flag with specified name, default value, and usage string. 65 | // The return value is the address of a float32 variable that stores the value of the flag. 66 | func (f *FlagSet) Float32(name string, value float32, usage string) *float32 { 67 | p := new(float32) 68 | f.Float32VarP(p, name, "", value, usage) 69 | return p 70 | } 71 | 72 | // Float32P is like Float32, but accepts a shorthand letter that can be used after a single dash. 73 | func (f *FlagSet) Float32P(name, shorthand string, value float32, usage string) *float32 { 74 | p := new(float32) 75 | f.Float32VarP(p, name, shorthand, value, usage) 76 | return p 77 | } 78 | 79 | // Float32 defines a float32 flag with specified name, default value, and usage string. 80 | // The return value is the address of a float32 variable that stores the value of the flag. 81 | func Float32(name string, value float32, usage string) *float32 { 82 | return CommandLine.Float32P(name, "", value, usage) 83 | } 84 | 85 | // Float32P is like Float32, but accepts a shorthand letter that can be used after a single dash. 86 | func Float32P(name, shorthand string, value float32, usage string) *float32 { 87 | return CommandLine.Float32P(name, shorthand, value, usage) 88 | } 89 | -------------------------------------------------------------------------------- /vendor/github.com/spf13/pflag/float64.go: -------------------------------------------------------------------------------- 1 | package pflag 2 | 3 | import "strconv" 4 | 5 | // -- float64 Value 6 | type float64Value float64 7 | 8 | func newFloat64Value(val float64, p *float64) *float64Value { 9 | *p = val 10 | return (*float64Value)(p) 11 | } 12 | 13 | func (f *float64Value) Set(s string) error { 14 | v, err := strconv.ParseFloat(s, 64) 15 | *f = float64Value(v) 16 | return err 17 | } 18 | 19 | func (f *float64Value) Type() string { 20 | return "float64" 21 | } 22 | 23 | func (f *float64Value) String() string { return strconv.FormatFloat(float64(*f), 'g', -1, 64) } 24 | 25 | func float64Conv(sval string) (interface{}, error) { 26 | return strconv.ParseFloat(sval, 64) 27 | } 28 | 29 | // GetFloat64 return the float64 value of a flag with the given name 30 | func (f *FlagSet) GetFloat64(name string) (float64, error) { 31 | val, err := f.getFlagType(name, "float64", float64Conv) 32 | if err != nil { 33 | return 0, err 34 | } 35 | return val.(float64), nil 36 | } 37 | 38 | // Float64Var defines a float64 flag with specified name, default value, and usage string. 39 | // The argument p points to a float64 variable in which to store the value of the flag. 40 | func (f *FlagSet) Float64Var(p *float64, name string, value float64, usage string) { 41 | f.VarP(newFloat64Value(value, p), name, "", usage) 42 | } 43 | 44 | // Float64VarP is like Float64Var, but accepts a shorthand letter that can be used after a single dash. 45 | func (f *FlagSet) Float64VarP(p *float64, name, shorthand string, value float64, usage string) { 46 | f.VarP(newFloat64Value(value, p), name, shorthand, usage) 47 | } 48 | 49 | // Float64Var defines a float64 flag with specified name, default value, and usage string. 50 | // The argument p points to a float64 variable in which to store the value of the flag. 51 | func Float64Var(p *float64, name string, value float64, usage string) { 52 | CommandLine.VarP(newFloat64Value(value, p), name, "", usage) 53 | } 54 | 55 | // Float64VarP is like Float64Var, but accepts a shorthand letter that can be used after a single dash. 56 | func Float64VarP(p *float64, name, shorthand string, value float64, usage string) { 57 | CommandLine.VarP(newFloat64Value(value, p), name, shorthand, usage) 58 | } 59 | 60 | // Float64 defines a float64 flag with specified name, default value, and usage string. 61 | // The return value is the address of a float64 variable that stores the value of the flag. 62 | func (f *FlagSet) Float64(name string, value float64, usage string) *float64 { 63 | p := new(float64) 64 | f.Float64VarP(p, name, "", value, usage) 65 | return p 66 | } 67 | 68 | // Float64P is like Float64, but accepts a shorthand letter that can be used after a single dash. 69 | func (f *FlagSet) Float64P(name, shorthand string, value float64, usage string) *float64 { 70 | p := new(float64) 71 | f.Float64VarP(p, name, shorthand, value, usage) 72 | return p 73 | } 74 | 75 | // Float64 defines a float64 flag with specified name, default value, and usage string. 76 | // The return value is the address of a float64 variable that stores the value of the flag. 77 | func Float64(name string, value float64, usage string) *float64 { 78 | return CommandLine.Float64P(name, "", value, usage) 79 | } 80 | 81 | // Float64P is like Float64, but accepts a shorthand letter that can be used after a single dash. 82 | func Float64P(name, shorthand string, value float64, usage string) *float64 { 83 | return CommandLine.Float64P(name, shorthand, value, usage) 84 | } 85 | -------------------------------------------------------------------------------- /vendor/github.com/spf13/pflag/golangflag.go: -------------------------------------------------------------------------------- 1 | // Copyright 2009 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package pflag 6 | 7 | import ( 8 | goflag "flag" 9 | "reflect" 10 | "strings" 11 | ) 12 | 13 | // flagValueWrapper implements pflag.Value around a flag.Value. The main 14 | // difference here is the addition of the Type method that returns a string 15 | // name of the type. As this is generally unknown, we approximate that with 16 | // reflection. 17 | type flagValueWrapper struct { 18 | inner goflag.Value 19 | flagType string 20 | } 21 | 22 | // We are just copying the boolFlag interface out of goflag as that is what 23 | // they use to decide if a flag should get "true" when no arg is given. 24 | type goBoolFlag interface { 25 | goflag.Value 26 | IsBoolFlag() bool 27 | } 28 | 29 | func wrapFlagValue(v goflag.Value) Value { 30 | // If the flag.Value happens to also be a pflag.Value, just use it directly. 31 | if pv, ok := v.(Value); ok { 32 | return pv 33 | } 34 | 35 | pv := &flagValueWrapper{ 36 | inner: v, 37 | } 38 | 39 | t := reflect.TypeOf(v) 40 | if t.Kind() == reflect.Interface || t.Kind() == reflect.Ptr { 41 | t = t.Elem() 42 | } 43 | 44 | pv.flagType = strings.TrimSuffix(t.Name(), "Value") 45 | return pv 46 | } 47 | 48 | func (v *flagValueWrapper) String() string { 49 | return v.inner.String() 50 | } 51 | 52 | func (v *flagValueWrapper) Set(s string) error { 53 | return v.inner.Set(s) 54 | } 55 | 56 | func (v *flagValueWrapper) Type() string { 57 | return v.flagType 58 | } 59 | 60 | // PFlagFromGoFlag will return a *pflag.Flag given a *flag.Flag 61 | // If the *flag.Flag.Name was a single character (ex: `v`) it will be accessiblei 62 | // with both `-v` and `--v` in flags. If the golang flag was more than a single 63 | // character (ex: `verbose`) it will only be accessible via `--verbose` 64 | func PFlagFromGoFlag(goflag *goflag.Flag) *Flag { 65 | // Remember the default value as a string; it won't change. 66 | flag := &Flag{ 67 | Name: goflag.Name, 68 | Usage: goflag.Usage, 69 | Value: wrapFlagValue(goflag.Value), 70 | // Looks like golang flags don't set DefValue correctly :-( 71 | //DefValue: goflag.DefValue, 72 | DefValue: goflag.Value.String(), 73 | } 74 | // Ex: if the golang flag was -v, allow both -v and --v to work 75 | if len(flag.Name) == 1 { 76 | flag.Shorthand = flag.Name 77 | } 78 | if fv, ok := goflag.Value.(goBoolFlag); ok && fv.IsBoolFlag() { 79 | flag.NoOptDefVal = "true" 80 | } 81 | return flag 82 | } 83 | 84 | // AddGoFlag will add the given *flag.Flag to the pflag.FlagSet 85 | func (f *FlagSet) AddGoFlag(goflag *goflag.Flag) { 86 | if f.Lookup(goflag.Name) != nil { 87 | return 88 | } 89 | newflag := PFlagFromGoFlag(goflag) 90 | f.AddFlag(newflag) 91 | } 92 | 93 | // AddGoFlagSet will add the given *flag.FlagSet to the pflag.FlagSet 94 | func (f *FlagSet) AddGoFlagSet(newSet *goflag.FlagSet) { 95 | if newSet == nil { 96 | return 97 | } 98 | newSet.VisitAll(func(goflag *goflag.Flag) { 99 | f.AddGoFlag(goflag) 100 | }) 101 | } 102 | -------------------------------------------------------------------------------- /vendor/github.com/spf13/pflag/int.go: -------------------------------------------------------------------------------- 1 | package pflag 2 | 3 | import "strconv" 4 | 5 | // -- int Value 6 | type intValue int 7 | 8 | func newIntValue(val int, p *int) *intValue { 9 | *p = val 10 | return (*intValue)(p) 11 | } 12 | 13 | func (i *intValue) Set(s string) error { 14 | v, err := strconv.ParseInt(s, 0, 64) 15 | *i = intValue(v) 16 | return err 17 | } 18 | 19 | func (i *intValue) Type() string { 20 | return "int" 21 | } 22 | 23 | func (i *intValue) String() string { return strconv.Itoa(int(*i)) } 24 | 25 | func intConv(sval string) (interface{}, error) { 26 | return strconv.Atoi(sval) 27 | } 28 | 29 | // GetInt return the int value of a flag with the given name 30 | func (f *FlagSet) GetInt(name string) (int, error) { 31 | val, err := f.getFlagType(name, "int", intConv) 32 | if err != nil { 33 | return 0, err 34 | } 35 | return val.(int), nil 36 | } 37 | 38 | // IntVar defines an int flag with specified name, default value, and usage string. 39 | // The argument p points to an int variable in which to store the value of the flag. 40 | func (f *FlagSet) IntVar(p *int, name string, value int, usage string) { 41 | f.VarP(newIntValue(value, p), name, "", usage) 42 | } 43 | 44 | // IntVarP is like IntVar, but accepts a shorthand letter that can be used after a single dash. 45 | func (f *FlagSet) IntVarP(p *int, name, shorthand string, value int, usage string) { 46 | f.VarP(newIntValue(value, p), name, shorthand, usage) 47 | } 48 | 49 | // IntVar defines an int flag with specified name, default value, and usage string. 50 | // The argument p points to an int variable in which to store the value of the flag. 51 | func IntVar(p *int, name string, value int, usage string) { 52 | CommandLine.VarP(newIntValue(value, p), name, "", usage) 53 | } 54 | 55 | // IntVarP is like IntVar, but accepts a shorthand letter that can be used after a single dash. 56 | func IntVarP(p *int, name, shorthand string, value int, usage string) { 57 | CommandLine.VarP(newIntValue(value, p), name, shorthand, usage) 58 | } 59 | 60 | // Int defines an int flag with specified name, default value, and usage string. 61 | // The return value is the address of an int variable that stores the value of the flag. 62 | func (f *FlagSet) Int(name string, value int, usage string) *int { 63 | p := new(int) 64 | f.IntVarP(p, name, "", value, usage) 65 | return p 66 | } 67 | 68 | // IntP is like Int, but accepts a shorthand letter that can be used after a single dash. 69 | func (f *FlagSet) IntP(name, shorthand string, value int, usage string) *int { 70 | p := new(int) 71 | f.IntVarP(p, name, shorthand, value, usage) 72 | return p 73 | } 74 | 75 | // Int defines an int flag with specified name, default value, and usage string. 76 | // The return value is the address of an int variable that stores the value of the flag. 77 | func Int(name string, value int, usage string) *int { 78 | return CommandLine.IntP(name, "", value, usage) 79 | } 80 | 81 | // IntP is like Int, but accepts a shorthand letter that can be used after a single dash. 82 | func IntP(name, shorthand string, value int, usage string) *int { 83 | return CommandLine.IntP(name, shorthand, value, usage) 84 | } 85 | -------------------------------------------------------------------------------- /vendor/github.com/spf13/pflag/int32.go: -------------------------------------------------------------------------------- 1 | package pflag 2 | 3 | import "strconv" 4 | 5 | // -- int32 Value 6 | type int32Value int32 7 | 8 | func newInt32Value(val int32, p *int32) *int32Value { 9 | *p = val 10 | return (*int32Value)(p) 11 | } 12 | 13 | func (i *int32Value) Set(s string) error { 14 | v, err := strconv.ParseInt(s, 0, 32) 15 | *i = int32Value(v) 16 | return err 17 | } 18 | 19 | func (i *int32Value) Type() string { 20 | return "int32" 21 | } 22 | 23 | func (i *int32Value) String() string { return strconv.FormatInt(int64(*i), 10) } 24 | 25 | func int32Conv(sval string) (interface{}, error) { 26 | v, err := strconv.ParseInt(sval, 0, 32) 27 | if err != nil { 28 | return 0, err 29 | } 30 | return int32(v), nil 31 | } 32 | 33 | // GetInt32 return the int32 value of a flag with the given name 34 | func (f *FlagSet) GetInt32(name string) (int32, error) { 35 | val, err := f.getFlagType(name, "int32", int32Conv) 36 | if err != nil { 37 | return 0, err 38 | } 39 | return val.(int32), nil 40 | } 41 | 42 | // Int32Var defines an int32 flag with specified name, default value, and usage string. 43 | // The argument p points to an int32 variable in which to store the value of the flag. 44 | func (f *FlagSet) Int32Var(p *int32, name string, value int32, usage string) { 45 | f.VarP(newInt32Value(value, p), name, "", usage) 46 | } 47 | 48 | // Int32VarP is like Int32Var, but accepts a shorthand letter that can be used after a single dash. 49 | func (f *FlagSet) Int32VarP(p *int32, name, shorthand string, value int32, usage string) { 50 | f.VarP(newInt32Value(value, p), name, shorthand, usage) 51 | } 52 | 53 | // Int32Var defines an int32 flag with specified name, default value, and usage string. 54 | // The argument p points to an int32 variable in which to store the value of the flag. 55 | func Int32Var(p *int32, name string, value int32, usage string) { 56 | CommandLine.VarP(newInt32Value(value, p), name, "", usage) 57 | } 58 | 59 | // Int32VarP is like Int32Var, but accepts a shorthand letter that can be used after a single dash. 60 | func Int32VarP(p *int32, name, shorthand string, value int32, usage string) { 61 | CommandLine.VarP(newInt32Value(value, p), name, shorthand, usage) 62 | } 63 | 64 | // Int32 defines an int32 flag with specified name, default value, and usage string. 65 | // The return value is the address of an int32 variable that stores the value of the flag. 66 | func (f *FlagSet) Int32(name string, value int32, usage string) *int32 { 67 | p := new(int32) 68 | f.Int32VarP(p, name, "", value, usage) 69 | return p 70 | } 71 | 72 | // Int32P is like Int32, but accepts a shorthand letter that can be used after a single dash. 73 | func (f *FlagSet) Int32P(name, shorthand string, value int32, usage string) *int32 { 74 | p := new(int32) 75 | f.Int32VarP(p, name, shorthand, value, usage) 76 | return p 77 | } 78 | 79 | // Int32 defines an int32 flag with specified name, default value, and usage string. 80 | // The return value is the address of an int32 variable that stores the value of the flag. 81 | func Int32(name string, value int32, usage string) *int32 { 82 | return CommandLine.Int32P(name, "", value, usage) 83 | } 84 | 85 | // Int32P is like Int32, but accepts a shorthand letter that can be used after a single dash. 86 | func Int32P(name, shorthand string, value int32, usage string) *int32 { 87 | return CommandLine.Int32P(name, shorthand, value, usage) 88 | } 89 | -------------------------------------------------------------------------------- /vendor/github.com/spf13/pflag/int64.go: -------------------------------------------------------------------------------- 1 | package pflag 2 | 3 | import "strconv" 4 | 5 | // -- int64 Value 6 | type int64Value int64 7 | 8 | func newInt64Value(val int64, p *int64) *int64Value { 9 | *p = val 10 | return (*int64Value)(p) 11 | } 12 | 13 | func (i *int64Value) Set(s string) error { 14 | v, err := strconv.ParseInt(s, 0, 64) 15 | *i = int64Value(v) 16 | return err 17 | } 18 | 19 | func (i *int64Value) Type() string { 20 | return "int64" 21 | } 22 | 23 | func (i *int64Value) String() string { return strconv.FormatInt(int64(*i), 10) } 24 | 25 | func int64Conv(sval string) (interface{}, error) { 26 | return strconv.ParseInt(sval, 0, 64) 27 | } 28 | 29 | // GetInt64 return the int64 value of a flag with the given name 30 | func (f *FlagSet) GetInt64(name string) (int64, error) { 31 | val, err := f.getFlagType(name, "int64", int64Conv) 32 | if err != nil { 33 | return 0, err 34 | } 35 | return val.(int64), nil 36 | } 37 | 38 | // Int64Var defines an int64 flag with specified name, default value, and usage string. 39 | // The argument p points to an int64 variable in which to store the value of the flag. 40 | func (f *FlagSet) Int64Var(p *int64, name string, value int64, usage string) { 41 | f.VarP(newInt64Value(value, p), name, "", usage) 42 | } 43 | 44 | // Int64VarP is like Int64Var, but accepts a shorthand letter that can be used after a single dash. 45 | func (f *FlagSet) Int64VarP(p *int64, name, shorthand string, value int64, usage string) { 46 | f.VarP(newInt64Value(value, p), name, shorthand, usage) 47 | } 48 | 49 | // Int64Var defines an int64 flag with specified name, default value, and usage string. 50 | // The argument p points to an int64 variable in which to store the value of the flag. 51 | func Int64Var(p *int64, name string, value int64, usage string) { 52 | CommandLine.VarP(newInt64Value(value, p), name, "", usage) 53 | } 54 | 55 | // Int64VarP is like Int64Var, but accepts a shorthand letter that can be used after a single dash. 56 | func Int64VarP(p *int64, name, shorthand string, value int64, usage string) { 57 | CommandLine.VarP(newInt64Value(value, p), name, shorthand, usage) 58 | } 59 | 60 | // Int64 defines an int64 flag with specified name, default value, and usage string. 61 | // The return value is the address of an int64 variable that stores the value of the flag. 62 | func (f *FlagSet) Int64(name string, value int64, usage string) *int64 { 63 | p := new(int64) 64 | f.Int64VarP(p, name, "", value, usage) 65 | return p 66 | } 67 | 68 | // Int64P is like Int64, but accepts a shorthand letter that can be used after a single dash. 69 | func (f *FlagSet) Int64P(name, shorthand string, value int64, usage string) *int64 { 70 | p := new(int64) 71 | f.Int64VarP(p, name, shorthand, value, usage) 72 | return p 73 | } 74 | 75 | // Int64 defines an int64 flag with specified name, default value, and usage string. 76 | // The return value is the address of an int64 variable that stores the value of the flag. 77 | func Int64(name string, value int64, usage string) *int64 { 78 | return CommandLine.Int64P(name, "", value, usage) 79 | } 80 | 81 | // Int64P is like Int64, but accepts a shorthand letter that can be used after a single dash. 82 | func Int64P(name, shorthand string, value int64, usage string) *int64 { 83 | return CommandLine.Int64P(name, shorthand, value, usage) 84 | } 85 | -------------------------------------------------------------------------------- /vendor/github.com/spf13/pflag/int8.go: -------------------------------------------------------------------------------- 1 | package pflag 2 | 3 | import "strconv" 4 | 5 | // -- int8 Value 6 | type int8Value int8 7 | 8 | func newInt8Value(val int8, p *int8) *int8Value { 9 | *p = val 10 | return (*int8Value)(p) 11 | } 12 | 13 | func (i *int8Value) Set(s string) error { 14 | v, err := strconv.ParseInt(s, 0, 8) 15 | *i = int8Value(v) 16 | return err 17 | } 18 | 19 | func (i *int8Value) Type() string { 20 | return "int8" 21 | } 22 | 23 | func (i *int8Value) String() string { return strconv.FormatInt(int64(*i), 10) } 24 | 25 | func int8Conv(sval string) (interface{}, error) { 26 | v, err := strconv.ParseInt(sval, 0, 8) 27 | if err != nil { 28 | return 0, err 29 | } 30 | return int8(v), nil 31 | } 32 | 33 | // GetInt8 return the int8 value of a flag with the given name 34 | func (f *FlagSet) GetInt8(name string) (int8, error) { 35 | val, err := f.getFlagType(name, "int8", int8Conv) 36 | if err != nil { 37 | return 0, err 38 | } 39 | return val.(int8), nil 40 | } 41 | 42 | // Int8Var defines an int8 flag with specified name, default value, and usage string. 43 | // The argument p points to an int8 variable in which to store the value of the flag. 44 | func (f *FlagSet) Int8Var(p *int8, name string, value int8, usage string) { 45 | f.VarP(newInt8Value(value, p), name, "", usage) 46 | } 47 | 48 | // Int8VarP is like Int8Var, but accepts a shorthand letter that can be used after a single dash. 49 | func (f *FlagSet) Int8VarP(p *int8, name, shorthand string, value int8, usage string) { 50 | f.VarP(newInt8Value(value, p), name, shorthand, usage) 51 | } 52 | 53 | // Int8Var defines an int8 flag with specified name, default value, and usage string. 54 | // The argument p points to an int8 variable in which to store the value of the flag. 55 | func Int8Var(p *int8, name string, value int8, usage string) { 56 | CommandLine.VarP(newInt8Value(value, p), name, "", usage) 57 | } 58 | 59 | // Int8VarP is like Int8Var, but accepts a shorthand letter that can be used after a single dash. 60 | func Int8VarP(p *int8, name, shorthand string, value int8, usage string) { 61 | CommandLine.VarP(newInt8Value(value, p), name, shorthand, usage) 62 | } 63 | 64 | // Int8 defines an int8 flag with specified name, default value, and usage string. 65 | // The return value is the address of an int8 variable that stores the value of the flag. 66 | func (f *FlagSet) Int8(name string, value int8, usage string) *int8 { 67 | p := new(int8) 68 | f.Int8VarP(p, name, "", value, usage) 69 | return p 70 | } 71 | 72 | // Int8P is like Int8, but accepts a shorthand letter that can be used after a single dash. 73 | func (f *FlagSet) Int8P(name, shorthand string, value int8, usage string) *int8 { 74 | p := new(int8) 75 | f.Int8VarP(p, name, shorthand, value, usage) 76 | return p 77 | } 78 | 79 | // Int8 defines an int8 flag with specified name, default value, and usage string. 80 | // The return value is the address of an int8 variable that stores the value of the flag. 81 | func Int8(name string, value int8, usage string) *int8 { 82 | return CommandLine.Int8P(name, "", value, usage) 83 | } 84 | 85 | // Int8P is like Int8, but accepts a shorthand letter that can be used after a single dash. 86 | func Int8P(name, shorthand string, value int8, usage string) *int8 { 87 | return CommandLine.Int8P(name, shorthand, value, usage) 88 | } 89 | -------------------------------------------------------------------------------- /vendor/github.com/spf13/pflag/int_slice.go: -------------------------------------------------------------------------------- 1 | package pflag 2 | 3 | import ( 4 | "fmt" 5 | "strconv" 6 | "strings" 7 | ) 8 | 9 | // -- intSlice Value 10 | type intSliceValue struct { 11 | value *[]int 12 | changed bool 13 | } 14 | 15 | func newIntSliceValue(val []int, p *[]int) *intSliceValue { 16 | isv := new(intSliceValue) 17 | isv.value = p 18 | *isv.value = val 19 | return isv 20 | } 21 | 22 | func (s *intSliceValue) Set(val string) error { 23 | ss := strings.Split(val, ",") 24 | out := make([]int, len(ss)) 25 | for i, d := range ss { 26 | var err error 27 | out[i], err = strconv.Atoi(d) 28 | if err != nil { 29 | return err 30 | } 31 | 32 | } 33 | if !s.changed { 34 | *s.value = out 35 | } else { 36 | *s.value = append(*s.value, out...) 37 | } 38 | s.changed = true 39 | return nil 40 | } 41 | 42 | func (s *intSliceValue) Type() string { 43 | return "intSlice" 44 | } 45 | 46 | func (s *intSliceValue) String() string { 47 | out := make([]string, len(*s.value)) 48 | for i, d := range *s.value { 49 | out[i] = fmt.Sprintf("%d", d) 50 | } 51 | return "[" + strings.Join(out, ",") + "]" 52 | } 53 | 54 | func intSliceConv(val string) (interface{}, error) { 55 | val = strings.Trim(val, "[]") 56 | // Empty string would cause a slice with one (empty) entry 57 | if len(val) == 0 { 58 | return []int{}, nil 59 | } 60 | ss := strings.Split(val, ",") 61 | out := make([]int, len(ss)) 62 | for i, d := range ss { 63 | var err error 64 | out[i], err = strconv.Atoi(d) 65 | if err != nil { 66 | return nil, err 67 | } 68 | 69 | } 70 | return out, nil 71 | } 72 | 73 | // GetIntSlice return the []int value of a flag with the given name 74 | func (f *FlagSet) GetIntSlice(name string) ([]int, error) { 75 | val, err := f.getFlagType(name, "intSlice", intSliceConv) 76 | if err != nil { 77 | return []int{}, err 78 | } 79 | return val.([]int), nil 80 | } 81 | 82 | // IntSliceVar defines a intSlice flag with specified name, default value, and usage string. 83 | // The argument p points to a []int variable in which to store the value of the flag. 84 | func (f *FlagSet) IntSliceVar(p *[]int, name string, value []int, usage string) { 85 | f.VarP(newIntSliceValue(value, p), name, "", usage) 86 | } 87 | 88 | // IntSliceVarP is like IntSliceVar, but accepts a shorthand letter that can be used after a single dash. 89 | func (f *FlagSet) IntSliceVarP(p *[]int, name, shorthand string, value []int, usage string) { 90 | f.VarP(newIntSliceValue(value, p), name, shorthand, usage) 91 | } 92 | 93 | // IntSliceVar defines a int[] flag with specified name, default value, and usage string. 94 | // The argument p points to a int[] variable in which to store the value of the flag. 95 | func IntSliceVar(p *[]int, name string, value []int, usage string) { 96 | CommandLine.VarP(newIntSliceValue(value, p), name, "", usage) 97 | } 98 | 99 | // IntSliceVarP is like IntSliceVar, but accepts a shorthand letter that can be used after a single dash. 100 | func IntSliceVarP(p *[]int, name, shorthand string, value []int, usage string) { 101 | CommandLine.VarP(newIntSliceValue(value, p), name, shorthand, usage) 102 | } 103 | 104 | // IntSlice defines a []int flag with specified name, default value, and usage string. 105 | // The return value is the address of a []int variable that stores the value of the flag. 106 | func (f *FlagSet) IntSlice(name string, value []int, usage string) *[]int { 107 | p := []int{} 108 | f.IntSliceVarP(&p, name, "", value, usage) 109 | return &p 110 | } 111 | 112 | // IntSliceP is like IntSlice, but accepts a shorthand letter that can be used after a single dash. 113 | func (f *FlagSet) IntSliceP(name, shorthand string, value []int, usage string) *[]int { 114 | p := []int{} 115 | f.IntSliceVarP(&p, name, shorthand, value, usage) 116 | return &p 117 | } 118 | 119 | // IntSlice defines a []int flag with specified name, default value, and usage string. 120 | // The return value is the address of a []int variable that stores the value of the flag. 121 | func IntSlice(name string, value []int, usage string) *[]int { 122 | return CommandLine.IntSliceP(name, "", value, usage) 123 | } 124 | 125 | // IntSliceP is like IntSlice, but accepts a shorthand letter that can be used after a single dash. 126 | func IntSliceP(name, shorthand string, value []int, usage string) *[]int { 127 | return CommandLine.IntSliceP(name, shorthand, value, usage) 128 | } 129 | -------------------------------------------------------------------------------- /vendor/github.com/spf13/pflag/ip.go: -------------------------------------------------------------------------------- 1 | package pflag 2 | 3 | import ( 4 | "fmt" 5 | "net" 6 | "strings" 7 | ) 8 | 9 | // -- net.IP value 10 | type ipValue net.IP 11 | 12 | func newIPValue(val net.IP, p *net.IP) *ipValue { 13 | *p = val 14 | return (*ipValue)(p) 15 | } 16 | 17 | func (i *ipValue) String() string { return net.IP(*i).String() } 18 | func (i *ipValue) Set(s string) error { 19 | ip := net.ParseIP(strings.TrimSpace(s)) 20 | if ip == nil { 21 | return fmt.Errorf("failed to parse IP: %q", s) 22 | } 23 | *i = ipValue(ip) 24 | return nil 25 | } 26 | 27 | func (i *ipValue) Type() string { 28 | return "ip" 29 | } 30 | 31 | func ipConv(sval string) (interface{}, error) { 32 | ip := net.ParseIP(sval) 33 | if ip != nil { 34 | return ip, nil 35 | } 36 | return nil, fmt.Errorf("invalid string being converted to IP address: %s", sval) 37 | } 38 | 39 | // GetIP return the net.IP value of a flag with the given name 40 | func (f *FlagSet) GetIP(name string) (net.IP, error) { 41 | val, err := f.getFlagType(name, "ip", ipConv) 42 | if err != nil { 43 | return nil, err 44 | } 45 | return val.(net.IP), nil 46 | } 47 | 48 | // IPVar defines an net.IP flag with specified name, default value, and usage string. 49 | // The argument p points to an net.IP variable in which to store the value of the flag. 50 | func (f *FlagSet) IPVar(p *net.IP, name string, value net.IP, usage string) { 51 | f.VarP(newIPValue(value, p), name, "", usage) 52 | } 53 | 54 | // IPVarP is like IPVar, but accepts a shorthand letter that can be used after a single dash. 55 | func (f *FlagSet) IPVarP(p *net.IP, name, shorthand string, value net.IP, usage string) { 56 | f.VarP(newIPValue(value, p), name, shorthand, usage) 57 | } 58 | 59 | // IPVar defines an net.IP flag with specified name, default value, and usage string. 60 | // The argument p points to an net.IP variable in which to store the value of the flag. 61 | func IPVar(p *net.IP, name string, value net.IP, usage string) { 62 | CommandLine.VarP(newIPValue(value, p), name, "", usage) 63 | } 64 | 65 | // IPVarP is like IPVar, but accepts a shorthand letter that can be used after a single dash. 66 | func IPVarP(p *net.IP, name, shorthand string, value net.IP, usage string) { 67 | CommandLine.VarP(newIPValue(value, p), name, shorthand, usage) 68 | } 69 | 70 | // IP defines an net.IP flag with specified name, default value, and usage string. 71 | // The return value is the address of an net.IP variable that stores the value of the flag. 72 | func (f *FlagSet) IP(name string, value net.IP, usage string) *net.IP { 73 | p := new(net.IP) 74 | f.IPVarP(p, name, "", value, usage) 75 | return p 76 | } 77 | 78 | // IPP is like IP, but accepts a shorthand letter that can be used after a single dash. 79 | func (f *FlagSet) IPP(name, shorthand string, value net.IP, usage string) *net.IP { 80 | p := new(net.IP) 81 | f.IPVarP(p, name, shorthand, value, usage) 82 | return p 83 | } 84 | 85 | // IP defines an net.IP flag with specified name, default value, and usage string. 86 | // The return value is the address of an net.IP variable that stores the value of the flag. 87 | func IP(name string, value net.IP, usage string) *net.IP { 88 | return CommandLine.IPP(name, "", value, usage) 89 | } 90 | 91 | // IPP is like IP, but accepts a shorthand letter that can be used after a single dash. 92 | func IPP(name, shorthand string, value net.IP, usage string) *net.IP { 93 | return CommandLine.IPP(name, shorthand, value, usage) 94 | } 95 | -------------------------------------------------------------------------------- /vendor/github.com/spf13/pflag/ipmask.go: -------------------------------------------------------------------------------- 1 | package pflag 2 | 3 | import ( 4 | "fmt" 5 | "net" 6 | "strconv" 7 | ) 8 | 9 | // -- net.IPMask value 10 | type ipMaskValue net.IPMask 11 | 12 | func newIPMaskValue(val net.IPMask, p *net.IPMask) *ipMaskValue { 13 | *p = val 14 | return (*ipMaskValue)(p) 15 | } 16 | 17 | func (i *ipMaskValue) String() string { return net.IPMask(*i).String() } 18 | func (i *ipMaskValue) Set(s string) error { 19 | ip := ParseIPv4Mask(s) 20 | if ip == nil { 21 | return fmt.Errorf("failed to parse IP mask: %q", s) 22 | } 23 | *i = ipMaskValue(ip) 24 | return nil 25 | } 26 | 27 | func (i *ipMaskValue) Type() string { 28 | return "ipMask" 29 | } 30 | 31 | // ParseIPv4Mask written in IP form (e.g. 255.255.255.0). 32 | // This function should really belong to the net package. 33 | func ParseIPv4Mask(s string) net.IPMask { 34 | mask := net.ParseIP(s) 35 | if mask == nil { 36 | if len(s) != 8 { 37 | return nil 38 | } 39 | // net.IPMask.String() actually outputs things like ffffff00 40 | // so write a horrible parser for that as well :-( 41 | m := []int{} 42 | for i := 0; i < 4; i++ { 43 | b := "0x" + s[2*i:2*i+2] 44 | d, err := strconv.ParseInt(b, 0, 0) 45 | if err != nil { 46 | return nil 47 | } 48 | m = append(m, int(d)) 49 | } 50 | s := fmt.Sprintf("%d.%d.%d.%d", m[0], m[1], m[2], m[3]) 51 | mask = net.ParseIP(s) 52 | if mask == nil { 53 | return nil 54 | } 55 | } 56 | return net.IPv4Mask(mask[12], mask[13], mask[14], mask[15]) 57 | } 58 | 59 | func parseIPv4Mask(sval string) (interface{}, error) { 60 | mask := ParseIPv4Mask(sval) 61 | if mask == nil { 62 | return nil, fmt.Errorf("unable to parse %s as net.IPMask", sval) 63 | } 64 | return mask, nil 65 | } 66 | 67 | // GetIPv4Mask return the net.IPv4Mask value of a flag with the given name 68 | func (f *FlagSet) GetIPv4Mask(name string) (net.IPMask, error) { 69 | val, err := f.getFlagType(name, "ipMask", parseIPv4Mask) 70 | if err != nil { 71 | return nil, err 72 | } 73 | return val.(net.IPMask), nil 74 | } 75 | 76 | // IPMaskVar defines an net.IPMask flag with specified name, default value, and usage string. 77 | // The argument p points to an net.IPMask variable in which to store the value of the flag. 78 | func (f *FlagSet) IPMaskVar(p *net.IPMask, name string, value net.IPMask, usage string) { 79 | f.VarP(newIPMaskValue(value, p), name, "", usage) 80 | } 81 | 82 | // IPMaskVarP is like IPMaskVar, but accepts a shorthand letter that can be used after a single dash. 83 | func (f *FlagSet) IPMaskVarP(p *net.IPMask, name, shorthand string, value net.IPMask, usage string) { 84 | f.VarP(newIPMaskValue(value, p), name, shorthand, usage) 85 | } 86 | 87 | // IPMaskVar defines an net.IPMask flag with specified name, default value, and usage string. 88 | // The argument p points to an net.IPMask variable in which to store the value of the flag. 89 | func IPMaskVar(p *net.IPMask, name string, value net.IPMask, usage string) { 90 | CommandLine.VarP(newIPMaskValue(value, p), name, "", usage) 91 | } 92 | 93 | // IPMaskVarP is like IPMaskVar, but accepts a shorthand letter that can be used after a single dash. 94 | func IPMaskVarP(p *net.IPMask, name, shorthand string, value net.IPMask, usage string) { 95 | CommandLine.VarP(newIPMaskValue(value, p), name, shorthand, usage) 96 | } 97 | 98 | // IPMask defines an net.IPMask flag with specified name, default value, and usage string. 99 | // The return value is the address of an net.IPMask variable that stores the value of the flag. 100 | func (f *FlagSet) IPMask(name string, value net.IPMask, usage string) *net.IPMask { 101 | p := new(net.IPMask) 102 | f.IPMaskVarP(p, name, "", value, usage) 103 | return p 104 | } 105 | 106 | // IPMaskP is like IPMask, but accepts a shorthand letter that can be used after a single dash. 107 | func (f *FlagSet) IPMaskP(name, shorthand string, value net.IPMask, usage string) *net.IPMask { 108 | p := new(net.IPMask) 109 | f.IPMaskVarP(p, name, shorthand, value, usage) 110 | return p 111 | } 112 | 113 | // IPMask defines an net.IPMask flag with specified name, default value, and usage string. 114 | // The return value is the address of an net.IPMask variable that stores the value of the flag. 115 | func IPMask(name string, value net.IPMask, usage string) *net.IPMask { 116 | return CommandLine.IPMaskP(name, "", value, usage) 117 | } 118 | 119 | // IPMaskP is like IP, but accepts a shorthand letter that can be used after a single dash. 120 | func IPMaskP(name, shorthand string, value net.IPMask, usage string) *net.IPMask { 121 | return CommandLine.IPMaskP(name, shorthand, value, usage) 122 | } 123 | -------------------------------------------------------------------------------- /vendor/github.com/spf13/pflag/ipnet.go: -------------------------------------------------------------------------------- 1 | package pflag 2 | 3 | import ( 4 | "fmt" 5 | "net" 6 | "strings" 7 | ) 8 | 9 | // IPNet adapts net.IPNet for use as a flag. 10 | type ipNetValue net.IPNet 11 | 12 | func (ipnet ipNetValue) String() string { 13 | n := net.IPNet(ipnet) 14 | return n.String() 15 | } 16 | 17 | func (ipnet *ipNetValue) Set(value string) error { 18 | _, n, err := net.ParseCIDR(strings.TrimSpace(value)) 19 | if err != nil { 20 | return err 21 | } 22 | *ipnet = ipNetValue(*n) 23 | return nil 24 | } 25 | 26 | func (*ipNetValue) Type() string { 27 | return "ipNet" 28 | } 29 | 30 | func newIPNetValue(val net.IPNet, p *net.IPNet) *ipNetValue { 31 | *p = val 32 | return (*ipNetValue)(p) 33 | } 34 | 35 | func ipNetConv(sval string) (interface{}, error) { 36 | _, n, err := net.ParseCIDR(strings.TrimSpace(sval)) 37 | if err == nil { 38 | return *n, nil 39 | } 40 | return nil, fmt.Errorf("invalid string being converted to IPNet: %s", sval) 41 | } 42 | 43 | // GetIPNet return the net.IPNet value of a flag with the given name 44 | func (f *FlagSet) GetIPNet(name string) (net.IPNet, error) { 45 | val, err := f.getFlagType(name, "ipNet", ipNetConv) 46 | if err != nil { 47 | return net.IPNet{}, err 48 | } 49 | return val.(net.IPNet), nil 50 | } 51 | 52 | // IPNetVar defines an net.IPNet flag with specified name, default value, and usage string. 53 | // The argument p points to an net.IPNet variable in which to store the value of the flag. 54 | func (f *FlagSet) IPNetVar(p *net.IPNet, name string, value net.IPNet, usage string) { 55 | f.VarP(newIPNetValue(value, p), name, "", usage) 56 | } 57 | 58 | // IPNetVarP is like IPNetVar, but accepts a shorthand letter that can be used after a single dash. 59 | func (f *FlagSet) IPNetVarP(p *net.IPNet, name, shorthand string, value net.IPNet, usage string) { 60 | f.VarP(newIPNetValue(value, p), name, shorthand, usage) 61 | } 62 | 63 | // IPNetVar defines an net.IPNet flag with specified name, default value, and usage string. 64 | // The argument p points to an net.IPNet variable in which to store the value of the flag. 65 | func IPNetVar(p *net.IPNet, name string, value net.IPNet, usage string) { 66 | CommandLine.VarP(newIPNetValue(value, p), name, "", usage) 67 | } 68 | 69 | // IPNetVarP is like IPNetVar, but accepts a shorthand letter that can be used after a single dash. 70 | func IPNetVarP(p *net.IPNet, name, shorthand string, value net.IPNet, usage string) { 71 | CommandLine.VarP(newIPNetValue(value, p), name, shorthand, usage) 72 | } 73 | 74 | // IPNet defines an net.IPNet flag with specified name, default value, and usage string. 75 | // The return value is the address of an net.IPNet variable that stores the value of the flag. 76 | func (f *FlagSet) IPNet(name string, value net.IPNet, usage string) *net.IPNet { 77 | p := new(net.IPNet) 78 | f.IPNetVarP(p, name, "", value, usage) 79 | return p 80 | } 81 | 82 | // IPNetP is like IPNet, but accepts a shorthand letter that can be used after a single dash. 83 | func (f *FlagSet) IPNetP(name, shorthand string, value net.IPNet, usage string) *net.IPNet { 84 | p := new(net.IPNet) 85 | f.IPNetVarP(p, name, shorthand, value, usage) 86 | return p 87 | } 88 | 89 | // IPNet defines an net.IPNet flag with specified name, default value, and usage string. 90 | // The return value is the address of an net.IPNet variable that stores the value of the flag. 91 | func IPNet(name string, value net.IPNet, usage string) *net.IPNet { 92 | return CommandLine.IPNetP(name, "", value, usage) 93 | } 94 | 95 | // IPNetP is like IPNet, but accepts a shorthand letter that can be used after a single dash. 96 | func IPNetP(name, shorthand string, value net.IPNet, usage string) *net.IPNet { 97 | return CommandLine.IPNetP(name, shorthand, value, usage) 98 | } 99 | -------------------------------------------------------------------------------- /vendor/github.com/spf13/pflag/string.go: -------------------------------------------------------------------------------- 1 | package pflag 2 | 3 | // -- string Value 4 | type stringValue string 5 | 6 | func newStringValue(val string, p *string) *stringValue { 7 | *p = val 8 | return (*stringValue)(p) 9 | } 10 | 11 | func (s *stringValue) Set(val string) error { 12 | *s = stringValue(val) 13 | return nil 14 | } 15 | func (s *stringValue) Type() string { 16 | return "string" 17 | } 18 | 19 | func (s *stringValue) String() string { return string(*s) } 20 | 21 | func stringConv(sval string) (interface{}, error) { 22 | return sval, nil 23 | } 24 | 25 | // GetString return the string value of a flag with the given name 26 | func (f *FlagSet) GetString(name string) (string, error) { 27 | val, err := f.getFlagType(name, "string", stringConv) 28 | if err != nil { 29 | return "", err 30 | } 31 | return val.(string), nil 32 | } 33 | 34 | // StringVar defines a string flag with specified name, default value, and usage string. 35 | // The argument p points to a string variable in which to store the value of the flag. 36 | func (f *FlagSet) StringVar(p *string, name string, value string, usage string) { 37 | f.VarP(newStringValue(value, p), name, "", usage) 38 | } 39 | 40 | // StringVarP is like StringVar, but accepts a shorthand letter that can be used after a single dash. 41 | func (f *FlagSet) StringVarP(p *string, name, shorthand string, value string, usage string) { 42 | f.VarP(newStringValue(value, p), name, shorthand, usage) 43 | } 44 | 45 | // StringVar defines a string flag with specified name, default value, and usage string. 46 | // The argument p points to a string variable in which to store the value of the flag. 47 | func StringVar(p *string, name string, value string, usage string) { 48 | CommandLine.VarP(newStringValue(value, p), name, "", usage) 49 | } 50 | 51 | // StringVarP is like StringVar, but accepts a shorthand letter that can be used after a single dash. 52 | func StringVarP(p *string, name, shorthand string, value string, usage string) { 53 | CommandLine.VarP(newStringValue(value, p), name, shorthand, usage) 54 | } 55 | 56 | // String defines a string flag with specified name, default value, and usage string. 57 | // The return value is the address of a string variable that stores the value of the flag. 58 | func (f *FlagSet) String(name string, value string, usage string) *string { 59 | p := new(string) 60 | f.StringVarP(p, name, "", value, usage) 61 | return p 62 | } 63 | 64 | // StringP is like String, but accepts a shorthand letter that can be used after a single dash. 65 | func (f *FlagSet) StringP(name, shorthand string, value string, usage string) *string { 66 | p := new(string) 67 | f.StringVarP(p, name, shorthand, value, usage) 68 | return p 69 | } 70 | 71 | // String defines a string flag with specified name, default value, and usage string. 72 | // The return value is the address of a string variable that stores the value of the flag. 73 | func String(name string, value string, usage string) *string { 74 | return CommandLine.StringP(name, "", value, usage) 75 | } 76 | 77 | // StringP is like String, but accepts a shorthand letter that can be used after a single dash. 78 | func StringP(name, shorthand string, value string, usage string) *string { 79 | return CommandLine.StringP(name, shorthand, value, usage) 80 | } 81 | -------------------------------------------------------------------------------- /vendor/github.com/spf13/pflag/string_array.go: -------------------------------------------------------------------------------- 1 | package pflag 2 | 3 | // -- stringArray Value 4 | type stringArrayValue struct { 5 | value *[]string 6 | changed bool 7 | } 8 | 9 | func newStringArrayValue(val []string, p *[]string) *stringArrayValue { 10 | ssv := new(stringArrayValue) 11 | ssv.value = p 12 | *ssv.value = val 13 | return ssv 14 | } 15 | 16 | func (s *stringArrayValue) Set(val string) error { 17 | if !s.changed { 18 | *s.value = []string{val} 19 | s.changed = true 20 | } else { 21 | *s.value = append(*s.value, val) 22 | } 23 | return nil 24 | } 25 | 26 | func (s *stringArrayValue) Type() string { 27 | return "stringArray" 28 | } 29 | 30 | func (s *stringArrayValue) String() string { 31 | str, _ := writeAsCSV(*s.value) 32 | return "[" + str + "]" 33 | } 34 | 35 | func stringArrayConv(sval string) (interface{}, error) { 36 | sval = sval[1 : len(sval)-1] 37 | // An empty string would cause a array with one (empty) string 38 | if len(sval) == 0 { 39 | return []string{}, nil 40 | } 41 | return readAsCSV(sval) 42 | } 43 | 44 | // GetStringArray return the []string value of a flag with the given name 45 | func (f *FlagSet) GetStringArray(name string) ([]string, error) { 46 | val, err := f.getFlagType(name, "stringArray", stringArrayConv) 47 | if err != nil { 48 | return []string{}, err 49 | } 50 | return val.([]string), nil 51 | } 52 | 53 | // StringArrayVar defines a string flag with specified name, default value, and usage string. 54 | // The argument p points to a []string variable in which to store the values of the multiple flags. 55 | // The value of each argument will not try to be separated by comma 56 | func (f *FlagSet) StringArrayVar(p *[]string, name string, value []string, usage string) { 57 | f.VarP(newStringArrayValue(value, p), name, "", usage) 58 | } 59 | 60 | // StringArrayVarP is like StringArrayVar, but accepts a shorthand letter that can be used after a single dash. 61 | func (f *FlagSet) StringArrayVarP(p *[]string, name, shorthand string, value []string, usage string) { 62 | f.VarP(newStringArrayValue(value, p), name, shorthand, usage) 63 | } 64 | 65 | // StringArrayVar defines a string flag with specified name, default value, and usage string. 66 | // The argument p points to a []string variable in which to store the value of the flag. 67 | // The value of each argument will not try to be separated by comma 68 | func StringArrayVar(p *[]string, name string, value []string, usage string) { 69 | CommandLine.VarP(newStringArrayValue(value, p), name, "", usage) 70 | } 71 | 72 | // StringArrayVarP is like StringArrayVar, but accepts a shorthand letter that can be used after a single dash. 73 | func StringArrayVarP(p *[]string, name, shorthand string, value []string, usage string) { 74 | CommandLine.VarP(newStringArrayValue(value, p), name, shorthand, usage) 75 | } 76 | 77 | // StringArray defines a string flag with specified name, default value, and usage string. 78 | // The return value is the address of a []string variable that stores the value of the flag. 79 | // The value of each argument will not try to be separated by comma 80 | func (f *FlagSet) StringArray(name string, value []string, usage string) *[]string { 81 | p := []string{} 82 | f.StringArrayVarP(&p, name, "", value, usage) 83 | return &p 84 | } 85 | 86 | // StringArrayP is like StringArray, but accepts a shorthand letter that can be used after a single dash. 87 | func (f *FlagSet) StringArrayP(name, shorthand string, value []string, usage string) *[]string { 88 | p := []string{} 89 | f.StringArrayVarP(&p, name, shorthand, value, usage) 90 | return &p 91 | } 92 | 93 | // StringArray defines a string flag with specified name, default value, and usage string. 94 | // The return value is the address of a []string variable that stores the value of the flag. 95 | // The value of each argument will not try to be separated by comma 96 | func StringArray(name string, value []string, usage string) *[]string { 97 | return CommandLine.StringArrayP(name, "", value, usage) 98 | } 99 | 100 | // StringArrayP is like StringArray, but accepts a shorthand letter that can be used after a single dash. 101 | func StringArrayP(name, shorthand string, value []string, usage string) *[]string { 102 | return CommandLine.StringArrayP(name, shorthand, value, usage) 103 | } 104 | -------------------------------------------------------------------------------- /vendor/github.com/spf13/pflag/string_slice.go: -------------------------------------------------------------------------------- 1 | package pflag 2 | 3 | import ( 4 | "bytes" 5 | "encoding/csv" 6 | "strings" 7 | ) 8 | 9 | // -- stringSlice Value 10 | type stringSliceValue struct { 11 | value *[]string 12 | changed bool 13 | } 14 | 15 | func newStringSliceValue(val []string, p *[]string) *stringSliceValue { 16 | ssv := new(stringSliceValue) 17 | ssv.value = p 18 | *ssv.value = val 19 | return ssv 20 | } 21 | 22 | func readAsCSV(val string) ([]string, error) { 23 | if val == "" { 24 | return []string{}, nil 25 | } 26 | stringReader := strings.NewReader(val) 27 | csvReader := csv.NewReader(stringReader) 28 | return csvReader.Read() 29 | } 30 | 31 | func writeAsCSV(vals []string) (string, error) { 32 | b := &bytes.Buffer{} 33 | w := csv.NewWriter(b) 34 | err := w.Write(vals) 35 | if err != nil { 36 | return "", err 37 | } 38 | w.Flush() 39 | return strings.TrimSuffix(b.String(), "\n"), nil 40 | } 41 | 42 | func (s *stringSliceValue) Set(val string) error { 43 | v, err := readAsCSV(val) 44 | if err != nil { 45 | return err 46 | } 47 | if !s.changed { 48 | *s.value = v 49 | } else { 50 | *s.value = append(*s.value, v...) 51 | } 52 | s.changed = true 53 | return nil 54 | } 55 | 56 | func (s *stringSliceValue) Type() string { 57 | return "stringSlice" 58 | } 59 | 60 | func (s *stringSliceValue) String() string { 61 | str, _ := writeAsCSV(*s.value) 62 | return "[" + str + "]" 63 | } 64 | 65 | func stringSliceConv(sval string) (interface{}, error) { 66 | sval = sval[1 : len(sval)-1] 67 | // An empty string would cause a slice with one (empty) string 68 | if len(sval) == 0 { 69 | return []string{}, nil 70 | } 71 | return readAsCSV(sval) 72 | } 73 | 74 | // GetStringSlice return the []string value of a flag with the given name 75 | func (f *FlagSet) GetStringSlice(name string) ([]string, error) { 76 | val, err := f.getFlagType(name, "stringSlice", stringSliceConv) 77 | if err != nil { 78 | return []string{}, err 79 | } 80 | return val.([]string), nil 81 | } 82 | 83 | // StringSliceVar defines a string flag with specified name, default value, and usage string. 84 | // The argument p points to a []string variable in which to store the value of the flag. 85 | func (f *FlagSet) StringSliceVar(p *[]string, name string, value []string, usage string) { 86 | f.VarP(newStringSliceValue(value, p), name, "", usage) 87 | } 88 | 89 | // StringSliceVarP is like StringSliceVar, but accepts a shorthand letter that can be used after a single dash. 90 | func (f *FlagSet) StringSliceVarP(p *[]string, name, shorthand string, value []string, usage string) { 91 | f.VarP(newStringSliceValue(value, p), name, shorthand, usage) 92 | } 93 | 94 | // StringSliceVar defines a string flag with specified name, default value, and usage string. 95 | // The argument p points to a []string variable in which to store the value of the flag. 96 | func StringSliceVar(p *[]string, name string, value []string, usage string) { 97 | CommandLine.VarP(newStringSliceValue(value, p), name, "", usage) 98 | } 99 | 100 | // StringSliceVarP is like StringSliceVar, but accepts a shorthand letter that can be used after a single dash. 101 | func StringSliceVarP(p *[]string, name, shorthand string, value []string, usage string) { 102 | CommandLine.VarP(newStringSliceValue(value, p), name, shorthand, usage) 103 | } 104 | 105 | // StringSlice defines a string flag with specified name, default value, and usage string. 106 | // The return value is the address of a []string variable that stores the value of the flag. 107 | func (f *FlagSet) StringSlice(name string, value []string, usage string) *[]string { 108 | p := []string{} 109 | f.StringSliceVarP(&p, name, "", value, usage) 110 | return &p 111 | } 112 | 113 | // StringSliceP is like StringSlice, but accepts a shorthand letter that can be used after a single dash. 114 | func (f *FlagSet) StringSliceP(name, shorthand string, value []string, usage string) *[]string { 115 | p := []string{} 116 | f.StringSliceVarP(&p, name, shorthand, value, usage) 117 | return &p 118 | } 119 | 120 | // StringSlice defines a string flag with specified name, default value, and usage string. 121 | // The return value is the address of a []string variable that stores the value of the flag. 122 | func StringSlice(name string, value []string, usage string) *[]string { 123 | return CommandLine.StringSliceP(name, "", value, usage) 124 | } 125 | 126 | // StringSliceP is like StringSlice, but accepts a shorthand letter that can be used after a single dash. 127 | func StringSliceP(name, shorthand string, value []string, usage string) *[]string { 128 | return CommandLine.StringSliceP(name, shorthand, value, usage) 129 | } 130 | -------------------------------------------------------------------------------- /vendor/github.com/spf13/pflag/uint.go: -------------------------------------------------------------------------------- 1 | package pflag 2 | 3 | import "strconv" 4 | 5 | // -- uint Value 6 | type uintValue uint 7 | 8 | func newUintValue(val uint, p *uint) *uintValue { 9 | *p = val 10 | return (*uintValue)(p) 11 | } 12 | 13 | func (i *uintValue) Set(s string) error { 14 | v, err := strconv.ParseUint(s, 0, 64) 15 | *i = uintValue(v) 16 | return err 17 | } 18 | 19 | func (i *uintValue) Type() string { 20 | return "uint" 21 | } 22 | 23 | func (i *uintValue) String() string { return strconv.FormatUint(uint64(*i), 10) } 24 | 25 | func uintConv(sval string) (interface{}, error) { 26 | v, err := strconv.ParseUint(sval, 0, 0) 27 | if err != nil { 28 | return 0, err 29 | } 30 | return uint(v), nil 31 | } 32 | 33 | // GetUint return the uint value of a flag with the given name 34 | func (f *FlagSet) GetUint(name string) (uint, error) { 35 | val, err := f.getFlagType(name, "uint", uintConv) 36 | if err != nil { 37 | return 0, err 38 | } 39 | return val.(uint), nil 40 | } 41 | 42 | // UintVar defines a uint flag with specified name, default value, and usage string. 43 | // The argument p points to a uint variable in which to store the value of the flag. 44 | func (f *FlagSet) UintVar(p *uint, name string, value uint, usage string) { 45 | f.VarP(newUintValue(value, p), name, "", usage) 46 | } 47 | 48 | // UintVarP is like UintVar, but accepts a shorthand letter that can be used after a single dash. 49 | func (f *FlagSet) UintVarP(p *uint, name, shorthand string, value uint, usage string) { 50 | f.VarP(newUintValue(value, p), name, shorthand, usage) 51 | } 52 | 53 | // UintVar defines a uint flag with specified name, default value, and usage string. 54 | // The argument p points to a uint variable in which to store the value of the flag. 55 | func UintVar(p *uint, name string, value uint, usage string) { 56 | CommandLine.VarP(newUintValue(value, p), name, "", usage) 57 | } 58 | 59 | // UintVarP is like UintVar, but accepts a shorthand letter that can be used after a single dash. 60 | func UintVarP(p *uint, name, shorthand string, value uint, usage string) { 61 | CommandLine.VarP(newUintValue(value, p), name, shorthand, usage) 62 | } 63 | 64 | // Uint defines a uint flag with specified name, default value, and usage string. 65 | // The return value is the address of a uint variable that stores the value of the flag. 66 | func (f *FlagSet) Uint(name string, value uint, usage string) *uint { 67 | p := new(uint) 68 | f.UintVarP(p, name, "", value, usage) 69 | return p 70 | } 71 | 72 | // UintP is like Uint, but accepts a shorthand letter that can be used after a single dash. 73 | func (f *FlagSet) UintP(name, shorthand string, value uint, usage string) *uint { 74 | p := new(uint) 75 | f.UintVarP(p, name, shorthand, value, usage) 76 | return p 77 | } 78 | 79 | // Uint defines a uint flag with specified name, default value, and usage string. 80 | // The return value is the address of a uint variable that stores the value of the flag. 81 | func Uint(name string, value uint, usage string) *uint { 82 | return CommandLine.UintP(name, "", value, usage) 83 | } 84 | 85 | // UintP is like Uint, but accepts a shorthand letter that can be used after a single dash. 86 | func UintP(name, shorthand string, value uint, usage string) *uint { 87 | return CommandLine.UintP(name, shorthand, value, usage) 88 | } 89 | -------------------------------------------------------------------------------- /vendor/github.com/spf13/pflag/uint16.go: -------------------------------------------------------------------------------- 1 | package pflag 2 | 3 | import "strconv" 4 | 5 | // -- uint16 value 6 | type uint16Value uint16 7 | 8 | func newUint16Value(val uint16, p *uint16) *uint16Value { 9 | *p = val 10 | return (*uint16Value)(p) 11 | } 12 | 13 | func (i *uint16Value) Set(s string) error { 14 | v, err := strconv.ParseUint(s, 0, 16) 15 | *i = uint16Value(v) 16 | return err 17 | } 18 | 19 | func (i *uint16Value) Type() string { 20 | return "uint16" 21 | } 22 | 23 | func (i *uint16Value) String() string { return strconv.FormatUint(uint64(*i), 10) } 24 | 25 | func uint16Conv(sval string) (interface{}, error) { 26 | v, err := strconv.ParseUint(sval, 0, 16) 27 | if err != nil { 28 | return 0, err 29 | } 30 | return uint16(v), nil 31 | } 32 | 33 | // GetUint16 return the uint16 value of a flag with the given name 34 | func (f *FlagSet) GetUint16(name string) (uint16, error) { 35 | val, err := f.getFlagType(name, "uint16", uint16Conv) 36 | if err != nil { 37 | return 0, err 38 | } 39 | return val.(uint16), nil 40 | } 41 | 42 | // Uint16Var defines a uint flag with specified name, default value, and usage string. 43 | // The argument p points to a uint variable in which to store the value of the flag. 44 | func (f *FlagSet) Uint16Var(p *uint16, name string, value uint16, usage string) { 45 | f.VarP(newUint16Value(value, p), name, "", usage) 46 | } 47 | 48 | // Uint16VarP is like Uint16Var, but accepts a shorthand letter that can be used after a single dash. 49 | func (f *FlagSet) Uint16VarP(p *uint16, name, shorthand string, value uint16, usage string) { 50 | f.VarP(newUint16Value(value, p), name, shorthand, usage) 51 | } 52 | 53 | // Uint16Var defines a uint flag with specified name, default value, and usage string. 54 | // The argument p points to a uint variable in which to store the value of the flag. 55 | func Uint16Var(p *uint16, name string, value uint16, usage string) { 56 | CommandLine.VarP(newUint16Value(value, p), name, "", usage) 57 | } 58 | 59 | // Uint16VarP is like Uint16Var, but accepts a shorthand letter that can be used after a single dash. 60 | func Uint16VarP(p *uint16, name, shorthand string, value uint16, usage string) { 61 | CommandLine.VarP(newUint16Value(value, p), name, shorthand, usage) 62 | } 63 | 64 | // Uint16 defines a uint flag with specified name, default value, and usage string. 65 | // The return value is the address of a uint variable that stores the value of the flag. 66 | func (f *FlagSet) Uint16(name string, value uint16, usage string) *uint16 { 67 | p := new(uint16) 68 | f.Uint16VarP(p, name, "", value, usage) 69 | return p 70 | } 71 | 72 | // Uint16P is like Uint16, but accepts a shorthand letter that can be used after a single dash. 73 | func (f *FlagSet) Uint16P(name, shorthand string, value uint16, usage string) *uint16 { 74 | p := new(uint16) 75 | f.Uint16VarP(p, name, shorthand, value, usage) 76 | return p 77 | } 78 | 79 | // Uint16 defines a uint flag with specified name, default value, and usage string. 80 | // The return value is the address of a uint variable that stores the value of the flag. 81 | func Uint16(name string, value uint16, usage string) *uint16 { 82 | return CommandLine.Uint16P(name, "", value, usage) 83 | } 84 | 85 | // Uint16P is like Uint16, but accepts a shorthand letter that can be used after a single dash. 86 | func Uint16P(name, shorthand string, value uint16, usage string) *uint16 { 87 | return CommandLine.Uint16P(name, shorthand, value, usage) 88 | } 89 | -------------------------------------------------------------------------------- /vendor/github.com/spf13/pflag/uint32.go: -------------------------------------------------------------------------------- 1 | package pflag 2 | 3 | import "strconv" 4 | 5 | // -- uint32 value 6 | type uint32Value uint32 7 | 8 | func newUint32Value(val uint32, p *uint32) *uint32Value { 9 | *p = val 10 | return (*uint32Value)(p) 11 | } 12 | 13 | func (i *uint32Value) Set(s string) error { 14 | v, err := strconv.ParseUint(s, 0, 32) 15 | *i = uint32Value(v) 16 | return err 17 | } 18 | 19 | func (i *uint32Value) Type() string { 20 | return "uint32" 21 | } 22 | 23 | func (i *uint32Value) String() string { return strconv.FormatUint(uint64(*i), 10) } 24 | 25 | func uint32Conv(sval string) (interface{}, error) { 26 | v, err := strconv.ParseUint(sval, 0, 32) 27 | if err != nil { 28 | return 0, err 29 | } 30 | return uint32(v), nil 31 | } 32 | 33 | // GetUint32 return the uint32 value of a flag with the given name 34 | func (f *FlagSet) GetUint32(name string) (uint32, error) { 35 | val, err := f.getFlagType(name, "uint32", uint32Conv) 36 | if err != nil { 37 | return 0, err 38 | } 39 | return val.(uint32), nil 40 | } 41 | 42 | // Uint32Var defines a uint32 flag with specified name, default value, and usage string. 43 | // The argument p points to a uint32 variable in which to store the value of the flag. 44 | func (f *FlagSet) Uint32Var(p *uint32, name string, value uint32, usage string) { 45 | f.VarP(newUint32Value(value, p), name, "", usage) 46 | } 47 | 48 | // Uint32VarP is like Uint32Var, but accepts a shorthand letter that can be used after a single dash. 49 | func (f *FlagSet) Uint32VarP(p *uint32, name, shorthand string, value uint32, usage string) { 50 | f.VarP(newUint32Value(value, p), name, shorthand, usage) 51 | } 52 | 53 | // Uint32Var defines a uint32 flag with specified name, default value, and usage string. 54 | // The argument p points to a uint32 variable in which to store the value of the flag. 55 | func Uint32Var(p *uint32, name string, value uint32, usage string) { 56 | CommandLine.VarP(newUint32Value(value, p), name, "", usage) 57 | } 58 | 59 | // Uint32VarP is like Uint32Var, but accepts a shorthand letter that can be used after a single dash. 60 | func Uint32VarP(p *uint32, name, shorthand string, value uint32, usage string) { 61 | CommandLine.VarP(newUint32Value(value, p), name, shorthand, usage) 62 | } 63 | 64 | // Uint32 defines a uint32 flag with specified name, default value, and usage string. 65 | // The return value is the address of a uint32 variable that stores the value of the flag. 66 | func (f *FlagSet) Uint32(name string, value uint32, usage string) *uint32 { 67 | p := new(uint32) 68 | f.Uint32VarP(p, name, "", value, usage) 69 | return p 70 | } 71 | 72 | // Uint32P is like Uint32, but accepts a shorthand letter that can be used after a single dash. 73 | func (f *FlagSet) Uint32P(name, shorthand string, value uint32, usage string) *uint32 { 74 | p := new(uint32) 75 | f.Uint32VarP(p, name, shorthand, value, usage) 76 | return p 77 | } 78 | 79 | // Uint32 defines a uint32 flag with specified name, default value, and usage string. 80 | // The return value is the address of a uint32 variable that stores the value of the flag. 81 | func Uint32(name string, value uint32, usage string) *uint32 { 82 | return CommandLine.Uint32P(name, "", value, usage) 83 | } 84 | 85 | // Uint32P is like Uint32, but accepts a shorthand letter that can be used after a single dash. 86 | func Uint32P(name, shorthand string, value uint32, usage string) *uint32 { 87 | return CommandLine.Uint32P(name, shorthand, value, usage) 88 | } 89 | -------------------------------------------------------------------------------- /vendor/github.com/spf13/pflag/uint64.go: -------------------------------------------------------------------------------- 1 | package pflag 2 | 3 | import "strconv" 4 | 5 | // -- uint64 Value 6 | type uint64Value uint64 7 | 8 | func newUint64Value(val uint64, p *uint64) *uint64Value { 9 | *p = val 10 | return (*uint64Value)(p) 11 | } 12 | 13 | func (i *uint64Value) Set(s string) error { 14 | v, err := strconv.ParseUint(s, 0, 64) 15 | *i = uint64Value(v) 16 | return err 17 | } 18 | 19 | func (i *uint64Value) Type() string { 20 | return "uint64" 21 | } 22 | 23 | func (i *uint64Value) String() string { return strconv.FormatUint(uint64(*i), 10) } 24 | 25 | func uint64Conv(sval string) (interface{}, error) { 26 | v, err := strconv.ParseUint(sval, 0, 64) 27 | if err != nil { 28 | return 0, err 29 | } 30 | return uint64(v), nil 31 | } 32 | 33 | // GetUint64 return the uint64 value of a flag with the given name 34 | func (f *FlagSet) GetUint64(name string) (uint64, error) { 35 | val, err := f.getFlagType(name, "uint64", uint64Conv) 36 | if err != nil { 37 | return 0, err 38 | } 39 | return val.(uint64), nil 40 | } 41 | 42 | // Uint64Var defines a uint64 flag with specified name, default value, and usage string. 43 | // The argument p points to a uint64 variable in which to store the value of the flag. 44 | func (f *FlagSet) Uint64Var(p *uint64, name string, value uint64, usage string) { 45 | f.VarP(newUint64Value(value, p), name, "", usage) 46 | } 47 | 48 | // Uint64VarP is like Uint64Var, but accepts a shorthand letter that can be used after a single dash. 49 | func (f *FlagSet) Uint64VarP(p *uint64, name, shorthand string, value uint64, usage string) { 50 | f.VarP(newUint64Value(value, p), name, shorthand, usage) 51 | } 52 | 53 | // Uint64Var defines a uint64 flag with specified name, default value, and usage string. 54 | // The argument p points to a uint64 variable in which to store the value of the flag. 55 | func Uint64Var(p *uint64, name string, value uint64, usage string) { 56 | CommandLine.VarP(newUint64Value(value, p), name, "", usage) 57 | } 58 | 59 | // Uint64VarP is like Uint64Var, but accepts a shorthand letter that can be used after a single dash. 60 | func Uint64VarP(p *uint64, name, shorthand string, value uint64, usage string) { 61 | CommandLine.VarP(newUint64Value(value, p), name, shorthand, usage) 62 | } 63 | 64 | // Uint64 defines a uint64 flag with specified name, default value, and usage string. 65 | // The return value is the address of a uint64 variable that stores the value of the flag. 66 | func (f *FlagSet) Uint64(name string, value uint64, usage string) *uint64 { 67 | p := new(uint64) 68 | f.Uint64VarP(p, name, "", value, usage) 69 | return p 70 | } 71 | 72 | // Uint64P is like Uint64, but accepts a shorthand letter that can be used after a single dash. 73 | func (f *FlagSet) Uint64P(name, shorthand string, value uint64, usage string) *uint64 { 74 | p := new(uint64) 75 | f.Uint64VarP(p, name, shorthand, value, usage) 76 | return p 77 | } 78 | 79 | // Uint64 defines a uint64 flag with specified name, default value, and usage string. 80 | // The return value is the address of a uint64 variable that stores the value of the flag. 81 | func Uint64(name string, value uint64, usage string) *uint64 { 82 | return CommandLine.Uint64P(name, "", value, usage) 83 | } 84 | 85 | // Uint64P is like Uint64, but accepts a shorthand letter that can be used after a single dash. 86 | func Uint64P(name, shorthand string, value uint64, usage string) *uint64 { 87 | return CommandLine.Uint64P(name, shorthand, value, usage) 88 | } 89 | -------------------------------------------------------------------------------- /vendor/github.com/spf13/pflag/uint8.go: -------------------------------------------------------------------------------- 1 | package pflag 2 | 3 | import "strconv" 4 | 5 | // -- uint8 Value 6 | type uint8Value uint8 7 | 8 | func newUint8Value(val uint8, p *uint8) *uint8Value { 9 | *p = val 10 | return (*uint8Value)(p) 11 | } 12 | 13 | func (i *uint8Value) Set(s string) error { 14 | v, err := strconv.ParseUint(s, 0, 8) 15 | *i = uint8Value(v) 16 | return err 17 | } 18 | 19 | func (i *uint8Value) Type() string { 20 | return "uint8" 21 | } 22 | 23 | func (i *uint8Value) String() string { return strconv.FormatUint(uint64(*i), 10) } 24 | 25 | func uint8Conv(sval string) (interface{}, error) { 26 | v, err := strconv.ParseUint(sval, 0, 8) 27 | if err != nil { 28 | return 0, err 29 | } 30 | return uint8(v), nil 31 | } 32 | 33 | // GetUint8 return the uint8 value of a flag with the given name 34 | func (f *FlagSet) GetUint8(name string) (uint8, error) { 35 | val, err := f.getFlagType(name, "uint8", uint8Conv) 36 | if err != nil { 37 | return 0, err 38 | } 39 | return val.(uint8), nil 40 | } 41 | 42 | // Uint8Var defines a uint8 flag with specified name, default value, and usage string. 43 | // The argument p points to a uint8 variable in which to store the value of the flag. 44 | func (f *FlagSet) Uint8Var(p *uint8, name string, value uint8, usage string) { 45 | f.VarP(newUint8Value(value, p), name, "", usage) 46 | } 47 | 48 | // Uint8VarP is like Uint8Var, but accepts a shorthand letter that can be used after a single dash. 49 | func (f *FlagSet) Uint8VarP(p *uint8, name, shorthand string, value uint8, usage string) { 50 | f.VarP(newUint8Value(value, p), name, shorthand, usage) 51 | } 52 | 53 | // Uint8Var defines a uint8 flag with specified name, default value, and usage string. 54 | // The argument p points to a uint8 variable in which to store the value of the flag. 55 | func Uint8Var(p *uint8, name string, value uint8, usage string) { 56 | CommandLine.VarP(newUint8Value(value, p), name, "", usage) 57 | } 58 | 59 | // Uint8VarP is like Uint8Var, but accepts a shorthand letter that can be used after a single dash. 60 | func Uint8VarP(p *uint8, name, shorthand string, value uint8, usage string) { 61 | CommandLine.VarP(newUint8Value(value, p), name, shorthand, usage) 62 | } 63 | 64 | // Uint8 defines a uint8 flag with specified name, default value, and usage string. 65 | // The return value is the address of a uint8 variable that stores the value of the flag. 66 | func (f *FlagSet) Uint8(name string, value uint8, usage string) *uint8 { 67 | p := new(uint8) 68 | f.Uint8VarP(p, name, "", value, usage) 69 | return p 70 | } 71 | 72 | // Uint8P is like Uint8, but accepts a shorthand letter that can be used after a single dash. 73 | func (f *FlagSet) Uint8P(name, shorthand string, value uint8, usage string) *uint8 { 74 | p := new(uint8) 75 | f.Uint8VarP(p, name, shorthand, value, usage) 76 | return p 77 | } 78 | 79 | // Uint8 defines a uint8 flag with specified name, default value, and usage string. 80 | // The return value is the address of a uint8 variable that stores the value of the flag. 81 | func Uint8(name string, value uint8, usage string) *uint8 { 82 | return CommandLine.Uint8P(name, "", value, usage) 83 | } 84 | 85 | // Uint8P is like Uint8, but accepts a shorthand letter that can be used after a single dash. 86 | func Uint8P(name, shorthand string, value uint8, usage string) *uint8 { 87 | return CommandLine.Uint8P(name, shorthand, value, usage) 88 | } 89 | -------------------------------------------------------------------------------- /vendor/github.com/spf13/pflag/uint_slice.go: -------------------------------------------------------------------------------- 1 | package pflag 2 | 3 | import ( 4 | "fmt" 5 | "strconv" 6 | "strings" 7 | ) 8 | 9 | // -- uintSlice Value 10 | type uintSliceValue struct { 11 | value *[]uint 12 | changed bool 13 | } 14 | 15 | func newUintSliceValue(val []uint, p *[]uint) *uintSliceValue { 16 | uisv := new(uintSliceValue) 17 | uisv.value = p 18 | *uisv.value = val 19 | return uisv 20 | } 21 | 22 | func (s *uintSliceValue) Set(val string) error { 23 | ss := strings.Split(val, ",") 24 | out := make([]uint, len(ss)) 25 | for i, d := range ss { 26 | u, err := strconv.ParseUint(d, 10, 0) 27 | if err != nil { 28 | return err 29 | } 30 | out[i] = uint(u) 31 | } 32 | if !s.changed { 33 | *s.value = out 34 | } else { 35 | *s.value = append(*s.value, out...) 36 | } 37 | s.changed = true 38 | return nil 39 | } 40 | 41 | func (s *uintSliceValue) Type() string { 42 | return "uintSlice" 43 | } 44 | 45 | func (s *uintSliceValue) String() string { 46 | out := make([]string, len(*s.value)) 47 | for i, d := range *s.value { 48 | out[i] = fmt.Sprintf("%d", d) 49 | } 50 | return "[" + strings.Join(out, ",") + "]" 51 | } 52 | 53 | func uintSliceConv(val string) (interface{}, error) { 54 | val = strings.Trim(val, "[]") 55 | // Empty string would cause a slice with one (empty) entry 56 | if len(val) == 0 { 57 | return []uint{}, nil 58 | } 59 | ss := strings.Split(val, ",") 60 | out := make([]uint, len(ss)) 61 | for i, d := range ss { 62 | u, err := strconv.ParseUint(d, 10, 0) 63 | if err != nil { 64 | return nil, err 65 | } 66 | out[i] = uint(u) 67 | } 68 | return out, nil 69 | } 70 | 71 | // GetUintSlice returns the []uint value of a flag with the given name. 72 | func (f *FlagSet) GetUintSlice(name string) ([]uint, error) { 73 | val, err := f.getFlagType(name, "uintSlice", uintSliceConv) 74 | if err != nil { 75 | return []uint{}, err 76 | } 77 | return val.([]uint), nil 78 | } 79 | 80 | // UintSliceVar defines a uintSlice flag with specified name, default value, and usage string. 81 | // The argument p points to a []uint variable in which to store the value of the flag. 82 | func (f *FlagSet) UintSliceVar(p *[]uint, name string, value []uint, usage string) { 83 | f.VarP(newUintSliceValue(value, p), name, "", usage) 84 | } 85 | 86 | // UintSliceVarP is like UintSliceVar, but accepts a shorthand letter that can be used after a single dash. 87 | func (f *FlagSet) UintSliceVarP(p *[]uint, name, shorthand string, value []uint, usage string) { 88 | f.VarP(newUintSliceValue(value, p), name, shorthand, usage) 89 | } 90 | 91 | // UintSliceVar defines a uint[] flag with specified name, default value, and usage string. 92 | // The argument p points to a uint[] variable in which to store the value of the flag. 93 | func UintSliceVar(p *[]uint, name string, value []uint, usage string) { 94 | CommandLine.VarP(newUintSliceValue(value, p), name, "", usage) 95 | } 96 | 97 | // UintSliceVarP is like the UintSliceVar, but accepts a shorthand letter that can be used after a single dash. 98 | func UintSliceVarP(p *[]uint, name, shorthand string, value []uint, usage string) { 99 | CommandLine.VarP(newUintSliceValue(value, p), name, shorthand, usage) 100 | } 101 | 102 | // UintSlice defines a []uint flag with specified name, default value, and usage string. 103 | // The return value is the address of a []uint variable that stores the value of the flag. 104 | func (f *FlagSet) UintSlice(name string, value []uint, usage string) *[]uint { 105 | p := []uint{} 106 | f.UintSliceVarP(&p, name, "", value, usage) 107 | return &p 108 | } 109 | 110 | // UintSliceP is like UintSlice, but accepts a shorthand letter that can be used after a single dash. 111 | func (f *FlagSet) UintSliceP(name, shorthand string, value []uint, usage string) *[]uint { 112 | p := []uint{} 113 | f.UintSliceVarP(&p, name, shorthand, value, usage) 114 | return &p 115 | } 116 | 117 | // UintSlice defines a []uint flag with specified name, default value, and usage string. 118 | // The return value is the address of a []uint variable that stores the value of the flag. 119 | func UintSlice(name string, value []uint, usage string) *[]uint { 120 | return CommandLine.UintSliceP(name, "", value, usage) 121 | } 122 | 123 | // UintSliceP is like UintSlice, but accepts a shorthand letter that can be used after a single dash. 124 | func UintSliceP(name, shorthand string, value []uint, usage string) *[]uint { 125 | return CommandLine.UintSliceP(name, shorthand, value, usage) 126 | } 127 | -------------------------------------------------------------------------------- /vendor/github.com/willf/bitset/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 Will Fitzgerald. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above 10 | copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the 12 | distribution. 13 | * Neither the name of Google Inc. nor the names of its 14 | contributors may be used to endorse or promote products derived from 15 | this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /vendor/github.com/willf/bitset/popcnt.go: -------------------------------------------------------------------------------- 1 | package bitset 2 | 3 | // bit population count, take from 4 | // https://code.google.com/p/go/issues/detail?id=4988#c11 5 | // credit: https://code.google.com/u/arnehormann/ 6 | func popcount(x uint64) (n uint64) { 7 | x -= (x >> 1) & 0x5555555555555555 8 | x = (x>>2)&0x3333333333333333 + x&0x3333333333333333 9 | x += x >> 4 10 | x &= 0x0f0f0f0f0f0f0f0f 11 | x *= 0x0101010101010101 12 | return x >> 56 13 | } 14 | 15 | func popcntSliceGo(s []uint64) uint64 { 16 | cnt := uint64(0) 17 | for _, x := range s { 18 | cnt += popcount(x) 19 | } 20 | return cnt 21 | } 22 | 23 | func popcntMaskSliceGo(s, m []uint64) uint64 { 24 | cnt := uint64(0) 25 | for i := range s { 26 | cnt += popcount(s[i] &^ m[i]) 27 | } 28 | return cnt 29 | } 30 | 31 | func popcntAndSliceGo(s, m []uint64) uint64 { 32 | cnt := uint64(0) 33 | for i := range s { 34 | cnt += popcount(s[i] & m[i]) 35 | } 36 | return cnt 37 | } 38 | 39 | func popcntOrSliceGo(s, m []uint64) uint64 { 40 | cnt := uint64(0) 41 | for i := range s { 42 | cnt += popcount(s[i] | m[i]) 43 | } 44 | return cnt 45 | } 46 | 47 | func popcntXorSliceGo(s, m []uint64) uint64 { 48 | cnt := uint64(0) 49 | for i := range s { 50 | cnt += popcount(s[i] ^ m[i]) 51 | } 52 | return cnt 53 | } 54 | -------------------------------------------------------------------------------- /vendor/github.com/willf/bitset/popcnt_amd64.go: -------------------------------------------------------------------------------- 1 | // +build amd64,!appengine 2 | 3 | package bitset 4 | 5 | // *** the following functions are defined in popcnt_amd64.s 6 | 7 | //go:noescape 8 | 9 | func hasAsm() bool 10 | 11 | // useAsm is a flag used to select the GO or ASM implementation of the popcnt function 12 | var useAsm = hasAsm() 13 | 14 | //go:noescape 15 | 16 | func popcntSliceAsm(s []uint64) uint64 17 | 18 | //go:noescape 19 | 20 | func popcntMaskSliceAsm(s, m []uint64) uint64 21 | 22 | //go:noescape 23 | 24 | func popcntAndSliceAsm(s, m []uint64) uint64 25 | 26 | //go:noescape 27 | 28 | func popcntOrSliceAsm(s, m []uint64) uint64 29 | 30 | //go:noescape 31 | 32 | func popcntXorSliceAsm(s, m []uint64) uint64 33 | 34 | func popcntSlice(s []uint64) uint64 { 35 | if useAsm { 36 | return popcntSliceAsm(s) 37 | } 38 | return popcntSliceGo(s) 39 | } 40 | 41 | func popcntMaskSlice(s, m []uint64) uint64 { 42 | if useAsm { 43 | return popcntMaskSliceAsm(s, m) 44 | } 45 | return popcntMaskSliceGo(s, m) 46 | } 47 | 48 | func popcntAndSlice(s, m []uint64) uint64 { 49 | if useAsm { 50 | return popcntAndSliceAsm(s, m) 51 | } 52 | return popcntAndSliceGo(s, m) 53 | } 54 | 55 | func popcntOrSlice(s, m []uint64) uint64 { 56 | if useAsm { 57 | return popcntOrSliceAsm(s, m) 58 | } 59 | return popcntOrSliceGo(s, m) 60 | } 61 | 62 | func popcntXorSlice(s, m []uint64) uint64 { 63 | if useAsm { 64 | return popcntXorSliceAsm(s, m) 65 | } 66 | return popcntXorSliceGo(s, m) 67 | } 68 | -------------------------------------------------------------------------------- /vendor/github.com/willf/bitset/popcnt_amd64.s: -------------------------------------------------------------------------------- 1 | // +build amd64,!appengine 2 | 3 | TEXT ·hasAsm(SB),4,$0-1 4 | MOVQ $1, AX 5 | CPUID 6 | SHRQ $23, CX 7 | ANDQ $1, CX 8 | MOVB CX, ret+0(FP) 9 | RET 10 | 11 | #define POPCNTQ_DX_DX BYTE $0xf3; BYTE $0x48; BYTE $0x0f; BYTE $0xb8; BYTE $0xd2 12 | 13 | TEXT ·popcntSliceAsm(SB),4,$0-32 14 | XORQ AX, AX 15 | MOVQ s+0(FP), SI 16 | MOVQ s_len+8(FP), CX 17 | TESTQ CX, CX 18 | JZ popcntSliceEnd 19 | popcntSliceLoop: 20 | BYTE $0xf3; BYTE $0x48; BYTE $0x0f; BYTE $0xb8; BYTE $0x16 // POPCNTQ (SI), DX 21 | ADDQ DX, AX 22 | ADDQ $8, SI 23 | LOOP popcntSliceLoop 24 | popcntSliceEnd: 25 | MOVQ AX, ret+24(FP) 26 | RET 27 | 28 | TEXT ·popcntMaskSliceAsm(SB),4,$0-56 29 | XORQ AX, AX 30 | MOVQ s+0(FP), SI 31 | MOVQ s_len+8(FP), CX 32 | TESTQ CX, CX 33 | JZ popcntMaskSliceEnd 34 | MOVQ m+24(FP), DI 35 | popcntMaskSliceLoop: 36 | MOVQ (DI), DX 37 | NOTQ DX 38 | ANDQ (SI), DX 39 | POPCNTQ_DX_DX 40 | ADDQ DX, AX 41 | ADDQ $8, SI 42 | ADDQ $8, DI 43 | LOOP popcntMaskSliceLoop 44 | popcntMaskSliceEnd: 45 | MOVQ AX, ret+48(FP) 46 | RET 47 | 48 | TEXT ·popcntAndSliceAsm(SB),4,$0-56 49 | XORQ AX, AX 50 | MOVQ s+0(FP), SI 51 | MOVQ s_len+8(FP), CX 52 | TESTQ CX, CX 53 | JZ popcntAndSliceEnd 54 | MOVQ m+24(FP), DI 55 | popcntAndSliceLoop: 56 | MOVQ (DI), DX 57 | ANDQ (SI), DX 58 | POPCNTQ_DX_DX 59 | ADDQ DX, AX 60 | ADDQ $8, SI 61 | ADDQ $8, DI 62 | LOOP popcntAndSliceLoop 63 | popcntAndSliceEnd: 64 | MOVQ AX, ret+48(FP) 65 | RET 66 | 67 | TEXT ·popcntOrSliceAsm(SB),4,$0-56 68 | XORQ AX, AX 69 | MOVQ s+0(FP), SI 70 | MOVQ s_len+8(FP), CX 71 | TESTQ CX, CX 72 | JZ popcntOrSliceEnd 73 | MOVQ m+24(FP), DI 74 | popcntOrSliceLoop: 75 | MOVQ (DI), DX 76 | ORQ (SI), DX 77 | POPCNTQ_DX_DX 78 | ADDQ DX, AX 79 | ADDQ $8, SI 80 | ADDQ $8, DI 81 | LOOP popcntOrSliceLoop 82 | popcntOrSliceEnd: 83 | MOVQ AX, ret+48(FP) 84 | RET 85 | 86 | TEXT ·popcntXorSliceAsm(SB),4,$0-56 87 | XORQ AX, AX 88 | MOVQ s+0(FP), SI 89 | MOVQ s_len+8(FP), CX 90 | TESTQ CX, CX 91 | JZ popcntXorSliceEnd 92 | MOVQ m+24(FP), DI 93 | popcntXorSliceLoop: 94 | MOVQ (DI), DX 95 | XORQ (SI), DX 96 | POPCNTQ_DX_DX 97 | ADDQ DX, AX 98 | ADDQ $8, SI 99 | ADDQ $8, DI 100 | LOOP popcntXorSliceLoop 101 | popcntXorSliceEnd: 102 | MOVQ AX, ret+48(FP) 103 | RET 104 | -------------------------------------------------------------------------------- /vendor/github.com/willf/bitset/popcnt_generic.go: -------------------------------------------------------------------------------- 1 | // +build !amd64 appengine 2 | 3 | package bitset 4 | 5 | func popcntSlice(s []uint64) uint64 { 6 | return popcntSliceGo(s) 7 | } 8 | 9 | func popcntMaskSlice(s, m []uint64) uint64 { 10 | return popcntMaskSliceGo(s, m) 11 | } 12 | 13 | func popcntAndSlice(s, m []uint64) uint64 { 14 | return popcntAndSliceGo(s, m) 15 | } 16 | 17 | func popcntOrSlice(s, m []uint64) uint64 { 18 | return popcntOrSliceGo(s, m) 19 | } 20 | 21 | func popcntXorSlice(s, m []uint64) uint64 { 22 | return popcntXorSliceGo(s, m) 23 | } 24 | -------------------------------------------------------------------------------- /vendor/manifest: -------------------------------------------------------------------------------- 1 | { 2 | "version": 0, 3 | "dependencies": [ 4 | { 5 | "importpath": "github.com/edsrzf/mmap-go", 6 | "repository": "https://github.com/edsrzf/mmap-go", 7 | "vcs": "git", 8 | "revision": "935e0e8a636ca4ba70b713f3e38a19e1b77739e8", 9 | "branch": "master", 10 | "notests": true 11 | }, 12 | { 13 | "importpath": "github.com/inconshreveable/mousetrap", 14 | "repository": "https://github.com/inconshreveable/mousetrap", 15 | "vcs": "git", 16 | "revision": "76626ae9c91c4f2a10f34cad8ce83ea42c93bb75", 17 | "branch": "master", 18 | "notests": true 19 | }, 20 | { 21 | "importpath": "github.com/spf13/cobra", 22 | "repository": "https://github.com/spf13/cobra", 23 | "vcs": "git", 24 | "revision": "16c014f1a19d865b765b420e74508f80eb831ada", 25 | "branch": "master", 26 | "notests": true 27 | }, 28 | { 29 | "importpath": "github.com/spf13/pflag", 30 | "repository": "https://github.com/spf13/pflag", 31 | "vcs": "git", 32 | "revision": "9ff6c6923cfffbcd502984b8e0c80539a94968b7", 33 | "branch": "master", 34 | "notests": true 35 | }, 36 | { 37 | "importpath": "github.com/willf/bitset", 38 | "repository": "https://github.com/willf/bitset", 39 | "vcs": "git", 40 | "revision": "5c3c0fce48842b2c0bbaa99b4e61b0175d84b47c", 41 | "branch": "master", 42 | "notests": true 43 | } 44 | ] 45 | } -------------------------------------------------------------------------------- /writer.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Couchbase, 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 | package vellum 16 | 17 | import ( 18 | "bufio" 19 | "io" 20 | ) 21 | 22 | // A writer is a buffered writer used by vellum. It counts how many bytes have 23 | // been written and has some convenience methods used for encoding the data. 24 | type writer struct { 25 | w *bufio.Writer 26 | counter int 27 | } 28 | 29 | func newWriter(w io.Writer) *writer { 30 | return &writer{ 31 | w: bufio.NewWriter(w), 32 | } 33 | } 34 | 35 | func (w *writer) Reset(newWriter io.Writer) { 36 | w.w.Reset(newWriter) 37 | w.counter = 0 38 | } 39 | 40 | func (w *writer) WriteByte(c byte) error { 41 | err := w.w.WriteByte(c) 42 | if err != nil { 43 | return err 44 | } 45 | w.counter++ 46 | return nil 47 | } 48 | 49 | func (w *writer) Write(p []byte) (int, error) { 50 | n, err := w.w.Write(p) 51 | w.counter += n 52 | return n, err 53 | } 54 | 55 | func (w *writer) Flush() error { 56 | return w.w.Flush() 57 | } 58 | 59 | func (w *writer) WritePackedUintIn(v uint64, n int) error { 60 | for shift := uint(0); shift < uint(n*8); shift += 8 { 61 | err := w.WriteByte(byte(v >> shift)) 62 | if err != nil { 63 | return err 64 | } 65 | } 66 | 67 | return nil 68 | } 69 | 70 | func (w *writer) WritePackedUint(v uint64) error { 71 | n := packedSize(v) 72 | return w.WritePackedUintIn(v, n) 73 | } 74 | 75 | func packedSize(n uint64) int { 76 | if n < 1<<8 { 77 | return 1 78 | } else if n < 1<<16 { 79 | return 2 80 | } else if n < 1<<24 { 81 | return 3 82 | } else if n < 1<<32 { 83 | return 4 84 | } else if n < 1<<40 { 85 | return 5 86 | } else if n < 1<<48 { 87 | return 6 88 | } else if n < 1<<56 { 89 | return 7 90 | } 91 | return 8 92 | } 93 | -------------------------------------------------------------------------------- /writer_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Couchbase, 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 | package vellum 16 | 17 | import ( 18 | "bufio" 19 | "errors" 20 | "fmt" 21 | "testing" 22 | ) 23 | 24 | func TestPackedSize(t *testing.T) { 25 | tests := []struct { 26 | input uint64 27 | want int 28 | }{ 29 | {0, 1}, 30 | {1<<8 - 1, 1}, 31 | {1 << 8, 2}, 32 | {1<<16 - 1, 2}, 33 | {1 << 16, 3}, 34 | {1<<24 - 1, 3}, 35 | {1 << 24, 4}, 36 | {1<<32 - 1, 4}, 37 | {1 << 32, 5}, 38 | {1<<40 - 1, 5}, 39 | {1 << 40, 6}, 40 | {1<<48 - 1, 6}, 41 | {1 << 48, 7}, 42 | {1<<56 - 1, 7}, 43 | {1 << 56, 8}, 44 | {1<<64 - 1, 8}, 45 | } 46 | 47 | for _, test := range tests { 48 | t.Run(fmt.Sprintf("input %d", test.input), func(t *testing.T) { 49 | got := packedSize(test.input) 50 | if got != test.want { 51 | t.Errorf("wanted: %d, got: %d", test.want, got) 52 | } 53 | }) 54 | } 55 | } 56 | 57 | var errStub = errors.New("stub error") 58 | 59 | type stubWriter struct { 60 | err error 61 | } 62 | 63 | func (s *stubWriter) Write(p []byte) (n int, err error) { 64 | err = s.err 65 | return 66 | } 67 | 68 | func TestWriteByteErr(t *testing.T) { 69 | // create writer, force underlying buffered writer to size 1 70 | w := &writer{ 71 | w: bufio.NewWriterSize(&stubWriter{errStub}, 1), 72 | } 73 | 74 | // then write 2 bytes, which should force error 75 | _ = w.WriteByte('a') 76 | err := w.WriteByte('a') 77 | if err != errStub { 78 | t.Errorf("expected %v, got %v", errStub, err) 79 | } 80 | } 81 | 82 | func TestWritePackedUintErr(t *testing.T) { 83 | // create writer, force underlying buffered writer to size 1 84 | w := &writer{ 85 | w: bufio.NewWriterSize(&stubWriter{errStub}, 1), 86 | } 87 | 88 | err := w.WritePackedUint(36592) 89 | if err != errStub { 90 | t.Errorf("expected %v, got %v", errStub, err) 91 | } 92 | } 93 | --------------------------------------------------------------------------------