cmd/geth: add --config file flag (#13875)
* p2p/discover, p2p/discv5: add marshaling methods to Node * p2p/netutil: make Netlist decodable from TOML * common/math: encode nil HexOrDecimal256 as 0x0 * cmd/geth: add --config file flag * cmd/geth: add missing license header * eth: prettify Config again, fix tests * eth: use gasprice.Config instead of duplicating its fields * eth/gasprice: hide nil default from dumpconfig output * cmd/geth: hide genesis block in dumpconfig output * node: make tests compile * console: fix tests * cmd/geth: make TOML keys look exactly like Go struct fields * p2p: use discovery by default This makes the zero Config slightly more useful. It also fixes package node tests because Node detects reuse of the datadir through the NodeDatabase. * cmd/geth: make ethstats URL settable through config file * cmd/faucet: fix configuration * cmd/geth: dedup attach tests * eth: add comment for DefaultConfig * eth: pass downloader.SyncMode in Config This removes the FastSync, LightSync flags in favour of a more general SyncMode flag. * cmd/utils: remove jitvm flags * cmd/utils: make mutually exclusive flag error prettier It now reads: Fatal: flags --dev, --testnet can't be used at the same time * p2p: fix typo * node: add DefaultConfig, use it for geth * mobile: add missing NoDiscovery option * cmd/utils: drop MakeNode This exposed a couple of places that needed to be updated to use node.DefaultConfig. * node: fix typo * eth: make fast sync the default mode * cmd/utils: remove IPCApiFlag (unused) * node: remove default IPC path Set it in the frontends instead. * cmd/geth: add --syncmode * cmd/utils: make --ipcdisable and --ipcpath mutually exclusive * cmd/utils: don't enable WS, HTTP when setting addr * cmd/utils: fix --identity
This commit is contained in:
committed by
Péter Szilágyi
parent
b57680b0b2
commit
30d706c35e
19
vendor/github.com/naoina/go-stringutil/LICENSE
generated
vendored
Normal file
19
vendor/github.com/naoina/go-stringutil/LICENSE
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
Copyright (c) 2015 Naoya Inada <naoina@kuune.org>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
13
vendor/github.com/naoina/go-stringutil/README.md
generated
vendored
Normal file
13
vendor/github.com/naoina/go-stringutil/README.md
generated
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
# stringutil [](https://travis-ci.org/naoina/go-stringutil)
|
||||
|
||||
## Installation
|
||||
|
||||
go get -u github.com/naoina/go-stringutil
|
||||
|
||||
## Documentation
|
||||
|
||||
See https://godoc.org/github.com/naoina/go-stringutil
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
253
vendor/github.com/naoina/go-stringutil/da.go
generated
vendored
Normal file
253
vendor/github.com/naoina/go-stringutil/da.go
generated
vendored
Normal file
@ -0,0 +1,253 @@
|
||||
package stringutil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
const (
|
||||
terminationCharacter = '#'
|
||||
)
|
||||
|
||||
func mustDoubleArray(da *doubleArray, err error) *doubleArray {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return da
|
||||
}
|
||||
|
||||
func (da *doubleArray) Build(keys []string) error {
|
||||
records := makeRecords(keys)
|
||||
if err := da.build(records, 1, 0, make(map[int]struct{})); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type doubleArray struct {
|
||||
bc []baseCheck
|
||||
node []int
|
||||
}
|
||||
|
||||
func newDoubleArray(keys []string) (*doubleArray, error) {
|
||||
da := &doubleArray{
|
||||
bc: []baseCheck{0},
|
||||
node: []int{-1}, // A start index is adjusting to 1 because 0 will be used as a mark of non-existent node.
|
||||
}
|
||||
if err := da.Build(keys); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return da, nil
|
||||
}
|
||||
|
||||
// baseCheck contains BASE, CHECK and Extra flags.
|
||||
// From the top, 22bits of BASE, 2bits of Extra flags and 8bits of CHECK.
|
||||
//
|
||||
// BASE (22bit) | Extra flags (2bit) | CHECK (8bit)
|
||||
// |----------------------|--|--------|
|
||||
// 32 10 8 0
|
||||
type baseCheck uint32
|
||||
|
||||
func (bc baseCheck) Base() int {
|
||||
return int(bc >> 10)
|
||||
}
|
||||
|
||||
func (bc *baseCheck) SetBase(base int) {
|
||||
*bc |= baseCheck(base) << 10
|
||||
}
|
||||
|
||||
func (bc baseCheck) Check() byte {
|
||||
return byte(bc)
|
||||
}
|
||||
|
||||
func (bc *baseCheck) SetCheck(check byte) {
|
||||
*bc |= baseCheck(check)
|
||||
}
|
||||
|
||||
func (bc baseCheck) IsEmpty() bool {
|
||||
return bc&0xfffffcff == 0
|
||||
}
|
||||
|
||||
func (da *doubleArray) Lookup(path string) (length int) {
|
||||
idx := 1
|
||||
tmpIdx := idx
|
||||
for i := 0; i < len(path); i++ {
|
||||
c := path[i]
|
||||
tmpIdx = da.nextIndex(da.bc[tmpIdx].Base(), c)
|
||||
if tmpIdx >= len(da.bc) || da.bc[tmpIdx].Check() != c {
|
||||
break
|
||||
}
|
||||
idx = tmpIdx
|
||||
}
|
||||
if next := da.nextIndex(da.bc[idx].Base(), terminationCharacter); next < len(da.bc) && da.bc[next].Check() == terminationCharacter {
|
||||
return da.node[da.bc[next].Base()]
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
func (da *doubleArray) LookupByBytes(path []byte) (length int) {
|
||||
idx := 1
|
||||
tmpIdx := idx
|
||||
for i := 0; i < len(path); i++ {
|
||||
c := path[i]
|
||||
tmpIdx = da.nextIndex(da.bc[tmpIdx].Base(), c)
|
||||
if tmpIdx >= len(da.bc) || da.bc[tmpIdx].Check() != c {
|
||||
break
|
||||
}
|
||||
idx = tmpIdx
|
||||
}
|
||||
if next := da.nextIndex(da.bc[idx].Base(), terminationCharacter); next < len(da.bc) && da.bc[next].Check() == terminationCharacter {
|
||||
return da.node[da.bc[next].Base()]
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
func (da *doubleArray) build(srcs []record, idx, depth int, usedBase map[int]struct{}) error {
|
||||
sort.Stable(recordSlice(srcs))
|
||||
base, siblings, leaf, err := da.arrange(srcs, idx, depth, usedBase)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if leaf != nil {
|
||||
da.bc[idx].SetBase(len(da.node))
|
||||
da.node = append(da.node, leaf.value)
|
||||
}
|
||||
for _, sib := range siblings {
|
||||
da.setCheck(da.nextIndex(base, sib.c), sib.c)
|
||||
}
|
||||
for _, sib := range siblings {
|
||||
if err := da.build(srcs[sib.start:sib.end], da.nextIndex(base, sib.c), depth+1, usedBase); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (da *doubleArray) setBase(i, base int) {
|
||||
da.bc[i].SetBase(base)
|
||||
}
|
||||
|
||||
func (da *doubleArray) setCheck(i int, check byte) {
|
||||
da.bc[i].SetCheck(check)
|
||||
}
|
||||
|
||||
func (da *doubleArray) findEmptyIndex(start int) int {
|
||||
i := start
|
||||
for ; i < len(da.bc); i++ {
|
||||
if da.bc[i].IsEmpty() {
|
||||
break
|
||||
}
|
||||
}
|
||||
return i
|
||||
}
|
||||
|
||||
// findBase returns good BASE.
|
||||
func (da *doubleArray) findBase(siblings []sibling, start int, usedBase map[int]struct{}) (base int) {
|
||||
for idx, firstChar := start+1, siblings[0].c; ; idx = da.findEmptyIndex(idx + 1) {
|
||||
base = da.nextIndex(idx, firstChar)
|
||||
if _, used := usedBase[base]; used {
|
||||
continue
|
||||
}
|
||||
i := 0
|
||||
for ; i < len(siblings); i++ {
|
||||
next := da.nextIndex(base, siblings[i].c)
|
||||
if len(da.bc) <= next {
|
||||
da.bc = append(da.bc, make([]baseCheck, next-len(da.bc)+1)...)
|
||||
}
|
||||
if !da.bc[next].IsEmpty() {
|
||||
break
|
||||
}
|
||||
}
|
||||
if i == len(siblings) {
|
||||
break
|
||||
}
|
||||
}
|
||||
usedBase[base] = struct{}{}
|
||||
return base
|
||||
}
|
||||
|
||||
func (da *doubleArray) arrange(records []record, idx, depth int, usedBase map[int]struct{}) (base int, siblings []sibling, leaf *record, err error) {
|
||||
siblings, leaf, err = makeSiblings(records, depth)
|
||||
if err != nil {
|
||||
return -1, nil, nil, err
|
||||
}
|
||||
if len(siblings) < 1 {
|
||||
return -1, nil, leaf, nil
|
||||
}
|
||||
base = da.findBase(siblings, idx, usedBase)
|
||||
da.setBase(idx, base)
|
||||
return base, siblings, leaf, err
|
||||
}
|
||||
|
||||
type sibling struct {
|
||||
start int
|
||||
end int
|
||||
c byte
|
||||
}
|
||||
|
||||
func (da *doubleArray) nextIndex(base int, c byte) int {
|
||||
return base ^ int(c)
|
||||
}
|
||||
|
||||
func makeSiblings(records []record, depth int) (sib []sibling, leaf *record, err error) {
|
||||
var (
|
||||
pc byte
|
||||
n int
|
||||
)
|
||||
for i, r := range records {
|
||||
if len(r.key) <= depth {
|
||||
leaf = &r
|
||||
continue
|
||||
}
|
||||
c := r.key[depth]
|
||||
switch {
|
||||
case pc < c:
|
||||
sib = append(sib, sibling{start: i, c: c})
|
||||
case pc == c:
|
||||
continue
|
||||
default:
|
||||
return nil, nil, fmt.Errorf("stringutil: BUG: records hasn't been sorted")
|
||||
}
|
||||
if n > 0 {
|
||||
sib[n-1].end = i
|
||||
}
|
||||
pc = c
|
||||
n++
|
||||
}
|
||||
if n == 0 {
|
||||
return nil, leaf, nil
|
||||
}
|
||||
sib[n-1].end = len(records)
|
||||
return sib, leaf, nil
|
||||
}
|
||||
|
||||
type record struct {
|
||||
key string
|
||||
value int
|
||||
}
|
||||
|
||||
func makeRecords(srcs []string) (records []record) {
|
||||
termChar := string(terminationCharacter)
|
||||
for _, s := range srcs {
|
||||
records = append(records, record{
|
||||
key: string(s + termChar),
|
||||
value: utf8.RuneCountInString(s),
|
||||
})
|
||||
}
|
||||
return records
|
||||
}
|
||||
|
||||
type recordSlice []record
|
||||
|
||||
func (rs recordSlice) Len() int {
|
||||
return len(rs)
|
||||
}
|
||||
|
||||
func (rs recordSlice) Less(i, j int) bool {
|
||||
return rs[i].key < rs[j].key
|
||||
}
|
||||
|
||||
func (rs recordSlice) Swap(i, j int) {
|
||||
rs[i], rs[j] = rs[j], rs[i]
|
||||
}
|
320
vendor/github.com/naoina/go-stringutil/strings.go
generated
vendored
Normal file
320
vendor/github.com/naoina/go-stringutil/strings.go
generated
vendored
Normal file
@ -0,0 +1,320 @@
|
||||
package stringutil
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
var (
|
||||
mu sync.Mutex
|
||||
|
||||
// Based on https://github.com/golang/lint/blob/32a87160691b3c96046c0c678fe57c5bef761456/lint.go#L702
|
||||
commonInitialismMap = map[string]struct{}{
|
||||
"API": struct{}{},
|
||||
"ASCII": struct{}{},
|
||||
"CPU": struct{}{},
|
||||
"CSRF": struct{}{},
|
||||
"CSS": struct{}{},
|
||||
"DNS": struct{}{},
|
||||
"EOF": struct{}{},
|
||||
"GUID": struct{}{},
|
||||
"HTML": struct{}{},
|
||||
"HTTP": struct{}{},
|
||||
"HTTPS": struct{}{},
|
||||
"ID": struct{}{},
|
||||
"IP": struct{}{},
|
||||
"JSON": struct{}{},
|
||||
"LHS": struct{}{},
|
||||
"QPS": struct{}{},
|
||||
"RAM": struct{}{},
|
||||
"RHS": struct{}{},
|
||||
"RPC": struct{}{},
|
||||
"SLA": struct{}{},
|
||||
"SMTP": struct{}{},
|
||||
"SQL": struct{}{},
|
||||
"SSH": struct{}{},
|
||||
"TCP": struct{}{},
|
||||
"TLS": struct{}{},
|
||||
"TTL": struct{}{},
|
||||
"UDP": struct{}{},
|
||||
"UI": struct{}{},
|
||||
"UID": struct{}{},
|
||||
"UUID": struct{}{},
|
||||
"URI": struct{}{},
|
||||
"URL": struct{}{},
|
||||
"UTF8": struct{}{},
|
||||
"VM": struct{}{},
|
||||
"XML": struct{}{},
|
||||
"XSRF": struct{}{},
|
||||
"XSS": struct{}{},
|
||||
}
|
||||
commonInitialisms = keys(commonInitialismMap)
|
||||
commonInitialism = mustDoubleArray(newDoubleArray(commonInitialisms))
|
||||
longestLen = longestLength(commonInitialisms)
|
||||
shortestLen = shortestLength(commonInitialisms, longestLen)
|
||||
)
|
||||
|
||||
// ToUpperCamelCase returns a copy of the string s with all Unicode letters mapped to their camel case.
|
||||
// It will convert to upper case previous letter of '_' and first letter, and remove letter of '_'.
|
||||
func ToUpperCamelCase(s string) string {
|
||||
if s == "" {
|
||||
return ""
|
||||
}
|
||||
upper := true
|
||||
start := 0
|
||||
result := make([]byte, 0, len(s))
|
||||
var runeBuf [utf8.UTFMax]byte
|
||||
var initialism []byte
|
||||
for _, c := range s {
|
||||
if c == '_' {
|
||||
upper = true
|
||||
candidate := string(result[start:])
|
||||
initialism = initialism[:0]
|
||||
for _, r := range candidate {
|
||||
if r < utf8.RuneSelf {
|
||||
initialism = append(initialism, toUpperASCII(byte(r)))
|
||||
} else {
|
||||
n := utf8.EncodeRune(runeBuf[:], unicode.ToUpper(r))
|
||||
initialism = append(initialism, runeBuf[:n]...)
|
||||
}
|
||||
}
|
||||
if length := commonInitialism.LookupByBytes(initialism); length > 0 {
|
||||
result = append(result[:start], initialism...)
|
||||
}
|
||||
start = len(result)
|
||||
continue
|
||||
}
|
||||
if upper {
|
||||
if c < utf8.RuneSelf {
|
||||
result = append(result, toUpperASCII(byte(c)))
|
||||
} else {
|
||||
n := utf8.EncodeRune(runeBuf[:], unicode.ToUpper(c))
|
||||
result = append(result, runeBuf[:n]...)
|
||||
}
|
||||
upper = false
|
||||
continue
|
||||
}
|
||||
if c < utf8.RuneSelf {
|
||||
result = append(result, byte(c))
|
||||
} else {
|
||||
n := utf8.EncodeRune(runeBuf[:], c)
|
||||
result = append(result, runeBuf[:n]...)
|
||||
}
|
||||
}
|
||||
candidate := string(result[start:])
|
||||
initialism = initialism[:0]
|
||||
for _, r := range candidate {
|
||||
if r < utf8.RuneSelf {
|
||||
initialism = append(initialism, toUpperASCII(byte(r)))
|
||||
} else {
|
||||
n := utf8.EncodeRune(runeBuf[:], unicode.ToUpper(r))
|
||||
initialism = append(initialism, runeBuf[:n]...)
|
||||
}
|
||||
}
|
||||
if length := commonInitialism.LookupByBytes(initialism); length > 0 {
|
||||
result = append(result[:start], initialism...)
|
||||
}
|
||||
return string(result)
|
||||
}
|
||||
|
||||
// ToUpperCamelCaseASCII is similar to ToUpperCamelCase, but optimized for
|
||||
// only the ASCII characters.
|
||||
// ToUpperCamelCaseASCII is faster than ToUpperCamelCase, but doesn't work if
|
||||
// contains non-ASCII characters.
|
||||
func ToUpperCamelCaseASCII(s string) string {
|
||||
if s == "" {
|
||||
return ""
|
||||
}
|
||||
upper := true
|
||||
start := 0
|
||||
result := make([]byte, 0, len(s))
|
||||
var initialism []byte
|
||||
for i := 0; i < len(s); i++ {
|
||||
c := s[i]
|
||||
if c == '_' {
|
||||
upper = true
|
||||
candidate := result[start:]
|
||||
initialism = initialism[:0]
|
||||
for _, b := range candidate {
|
||||
initialism = append(initialism, toUpperASCII(b))
|
||||
}
|
||||
if length := commonInitialism.LookupByBytes(initialism); length > 0 {
|
||||
result = append(result[:start], initialism...)
|
||||
}
|
||||
start = len(result)
|
||||
continue
|
||||
}
|
||||
if upper {
|
||||
result = append(result, toUpperASCII(c))
|
||||
upper = false
|
||||
continue
|
||||
}
|
||||
result = append(result, c)
|
||||
}
|
||||
candidate := result[start:]
|
||||
initialism = initialism[:0]
|
||||
for _, b := range candidate {
|
||||
initialism = append(initialism, toUpperASCII(b))
|
||||
}
|
||||
if length := commonInitialism.LookupByBytes(initialism); length > 0 {
|
||||
result = append(result[:start], initialism...)
|
||||
}
|
||||
return string(result)
|
||||
}
|
||||
|
||||
// ToSnakeCase returns a copy of the string s with all Unicode letters mapped to their snake case.
|
||||
// It will insert letter of '_' at position of previous letter of uppercase and all
|
||||
// letters convert to lower case.
|
||||
// ToSnakeCase does not insert '_' letter into a common initialism word like ID, URL and so on.
|
||||
func ToSnakeCase(s string) string {
|
||||
if s == "" {
|
||||
return ""
|
||||
}
|
||||
result := make([]byte, 0, len(s))
|
||||
var runeBuf [utf8.UTFMax]byte
|
||||
var j, skipCount int
|
||||
for i, c := range s {
|
||||
if i < skipCount {
|
||||
continue
|
||||
}
|
||||
if unicode.IsUpper(c) {
|
||||
if i != 0 {
|
||||
result = append(result, '_')
|
||||
}
|
||||
next := nextIndex(j, len(s))
|
||||
if length := commonInitialism.Lookup(s[j:next]); length > 0 {
|
||||
for _, r := range s[j : j+length] {
|
||||
if r < utf8.RuneSelf {
|
||||
result = append(result, toLowerASCII(byte(r)))
|
||||
} else {
|
||||
n := utf8.EncodeRune(runeBuf[:], unicode.ToLower(r))
|
||||
result = append(result, runeBuf[:n]...)
|
||||
}
|
||||
}
|
||||
j += length - 1
|
||||
skipCount = i + length
|
||||
continue
|
||||
}
|
||||
}
|
||||
if c < utf8.RuneSelf {
|
||||
result = append(result, toLowerASCII(byte(c)))
|
||||
} else {
|
||||
n := utf8.EncodeRune(runeBuf[:], unicode.ToLower(c))
|
||||
result = append(result, runeBuf[:n]...)
|
||||
}
|
||||
j++
|
||||
}
|
||||
return string(result)
|
||||
}
|
||||
|
||||
// ToSnakeCaseASCII is similar to ToSnakeCase, but optimized for only the ASCII
|
||||
// characters.
|
||||
// ToSnakeCaseASCII is faster than ToSnakeCase, but doesn't work correctly if
|
||||
// contains non-ASCII characters.
|
||||
func ToSnakeCaseASCII(s string) string {
|
||||
if s == "" {
|
||||
return ""
|
||||
}
|
||||
result := make([]byte, 0, len(s))
|
||||
for i := 0; i < len(s); i++ {
|
||||
c := s[i]
|
||||
if isUpperASCII(c) {
|
||||
if i != 0 {
|
||||
result = append(result, '_')
|
||||
}
|
||||
if k := i + shortestLen - 1; k < len(s) && isUpperASCII(s[k]) {
|
||||
if length := commonInitialism.Lookup(s[i:nextIndex(i, len(s))]); length > 0 {
|
||||
for j, buf := 0, s[i:i+length]; j < len(buf); j++ {
|
||||
result = append(result, toLowerASCII(buf[j]))
|
||||
}
|
||||
i += length - 1
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
result = append(result, toLowerASCII(c))
|
||||
}
|
||||
return string(result)
|
||||
}
|
||||
|
||||
// AddCommonInitialism adds ss to list of common initialisms.
|
||||
func AddCommonInitialism(ss ...string) {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
for _, s := range ss {
|
||||
commonInitialismMap[s] = struct{}{}
|
||||
}
|
||||
commonInitialisms = keys(commonInitialismMap)
|
||||
commonInitialism = mustDoubleArray(newDoubleArray(commonInitialisms))
|
||||
longestLen = longestLength(commonInitialisms)
|
||||
shortestLen = shortestLength(commonInitialisms, longestLen)
|
||||
}
|
||||
|
||||
// DelCommonInitialism deletes ss from list of common initialisms.
|
||||
func DelCommonInitialism(ss ...string) {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
for _, s := range ss {
|
||||
delete(commonInitialismMap, s)
|
||||
}
|
||||
commonInitialisms = keys(commonInitialismMap)
|
||||
commonInitialism = mustDoubleArray(newDoubleArray(commonInitialisms))
|
||||
longestLen = longestLength(commonInitialisms)
|
||||
shortestLen = shortestLength(commonInitialisms, longestLen)
|
||||
}
|
||||
|
||||
func isUpperASCII(c byte) bool {
|
||||
return 'A' <= c && c <= 'Z'
|
||||
}
|
||||
|
||||
func isLowerASCII(c byte) bool {
|
||||
return 'a' <= c && c <= 'z'
|
||||
}
|
||||
|
||||
func toUpperASCII(c byte) byte {
|
||||
if isLowerASCII(c) {
|
||||
return c - ('a' - 'A')
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
func toLowerASCII(c byte) byte {
|
||||
if isUpperASCII(c) {
|
||||
return c + 'a' - 'A'
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
func nextIndex(i, maxlen int) int {
|
||||
if n := i + longestLen; n < maxlen {
|
||||
return n
|
||||
}
|
||||
return maxlen
|
||||
}
|
||||
|
||||
func keys(m map[string]struct{}) []string {
|
||||
result := make([]string, 0, len(m))
|
||||
for k := range m {
|
||||
result = append(result, k)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func shortestLength(strs []string, shortest int) int {
|
||||
for _, s := range strs {
|
||||
if candidate := utf8.RuneCountInString(s); candidate < shortest {
|
||||
shortest = candidate
|
||||
}
|
||||
}
|
||||
return shortest
|
||||
}
|
||||
|
||||
func longestLength(strs []string) (longest int) {
|
||||
for _, s := range strs {
|
||||
if candidate := utf8.RuneCountInString(s); candidate > longest {
|
||||
longest = candidate
|
||||
}
|
||||
}
|
||||
return longest
|
||||
}
|
Reference in New Issue
Block a user