├── .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 |
53 |
--------------------------------------------------------------------------------
/docs/demo2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/couchbase/vellum/abd0418dd6c7952bc327f5f2ec44072fa787bba5/docs/demo2.png
--------------------------------------------------------------------------------
/docs/demo2.svg:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
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 |
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 |
--------------------------------------------------------------------------------