summaryrefslogtreecommitdiff
path: root/vendor/github.com/jzelinskie/stringz/stringz.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/jzelinskie/stringz/stringz.go')
-rw-r--r--vendor/github.com/jzelinskie/stringz/stringz.go406
1 files changed, 406 insertions, 0 deletions
diff --git a/vendor/github.com/jzelinskie/stringz/stringz.go b/vendor/github.com/jzelinskie/stringz/stringz.go
new file mode 100644
index 00000000..be3cffd7
--- /dev/null
+++ b/vendor/github.com/jzelinskie/stringz/stringz.go
@@ -0,0 +1,406 @@
+// Copyright 2019 Jimmy Zelinskie
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Package stringz implements a collection of utility functions for
+// manipulating strings and lists of strings.
+package stringz
+
+import (
+ "errors"
+ "strings"
+)
+
+// ErrInconsistentUnpackLen is returned when Unpack is provided two slices
+// without the same length.
+var ErrInconsistentUnpackLen = errors.New("the length of the unpacked is not equal to the provided input")
+
+// SliceContains returns true if the provided string is in the provided string
+// slice.
+func SliceContains(ys []string, x string) bool {
+ for _, y := range ys {
+ if x == y {
+ return true
+ }
+ }
+ return false
+}
+
+// SliceIndex returns the index of the first instance of x in ys, or -1 if it
+// is not present.
+func SliceIndex(ys []string, x string) int {
+ for i, y := range ys {
+ if x == y {
+ return i
+ }
+ }
+ return -1
+}
+
+// Dedup returns a new slice with any duplicates removed.
+func Dedup(xs []string) []string {
+ set := make(map[string]struct{}, 0)
+ ys := make([]string, 0, len(xs))
+ for _, x := range xs {
+ if _, alreadyExists := set[x]; alreadyExists {
+ continue
+ }
+ ys = append(ys, x)
+ set[x] = struct{}{}
+ }
+
+ return ys
+}
+
+// DefaultEmpty returns the fallback when val is empty string.
+//
+// This function is inspired by Python's `dict.get()`.
+func DefaultEmpty(val, fallback string) string {
+ return Default(val, fallback, "")
+}
+
+// Default returns a fallback value when the provided value is equal to any
+// of the zero values.
+func Default(val, fallback string, zeroValues ...string) string {
+ for _, zeroValue := range zeroValues {
+ if val == zeroValue {
+ return fallback
+ }
+ }
+
+ return val
+}
+
+// SliceEqual returns true if two string slices are the same.
+// This function is sensitive to order.
+func SliceEqual(xs, ys []string) bool {
+ if len(xs) != len(ys) {
+ return false
+ }
+
+ for i, x := range xs {
+ if x != ys[i] {
+ return false
+ }
+ }
+
+ return true
+}
+
+// MatrixEqual returns true if two [][]string are equal.
+// This function is sensitive to order.
+func MatrixEqual(xs, ys [][]string) bool {
+ if len(xs) != len(ys) {
+ return false
+ }
+
+ for i, x := range xs {
+ if !SliceEqual(x, ys[i]) {
+ return false
+ }
+ }
+
+ return true
+}
+
+// TrimPrefixIndex trims everything before the provided index.
+func TrimPrefixIndex(s, index string) string {
+ i := strings.Index(s, index)
+ if i <= 0 {
+ return s
+ }
+ return s[i+len(index):]
+}
+
+// TrimSurrounding returns a string with both a prefix and suffix trimmed from
+// it.
+//
+// Do not confuse this with strings.Trim() which removes characters in a cutset
+// rather than working on prefixes and suffixes.
+func TrimSurrounding(s, surrounding string) string {
+ s = strings.TrimPrefix(s, surrounding)
+ return strings.TrimSuffix(s, surrounding)
+}
+
+// SliceMap is a functional-style mapping function for slices of strings.
+//
+// This is particularly useful when you would normally use a for-loop, but want
+// `defer` to execute for each iteration.
+func SliceMap(xs []string, fn func(string) error) error {
+ for _, x := range xs {
+ err := fn(x)
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// Join is strings.Join, but variadic.
+func Join(prefix string, xs ...string) string { return strings.Join(xs, prefix) }
+
+// CopyStringMap returns a new copy of a map of strings.
+func CopyStringMap(xs map[string]string) map[string]string {
+ // Zero allocation path.
+ if xs == nil {
+ return nil
+ }
+
+ ys := make(map[string]string, len(xs))
+ for k, v := range xs {
+ ys[k] = v
+ }
+ return ys
+}
+
+// Unpack assigns a slice into local variables.
+func Unpack(xs []string, vars ...*string) error {
+ if len(xs) != len(vars) {
+ return ErrInconsistentUnpackLen
+ }
+ for i, x := range xs {
+ *vars[i] = x
+ }
+ return nil
+}
+
+// SplitExact splits the string `s` into `len(vars)` number of strings and
+// unpacks them into those vars.
+//
+// Returns ErrInconsistentUnpackLen if len(vars) doesn't match the number of
+// split segments.
+func SplitExact(s, sep string, vars ...*string) error {
+ exploded := strings.Split(s, sep)
+ return Unpack(exploded, vars...)
+}
+
+// SplitInto splits the string `s` into `len(vars)` number of strings and
+// unpacks them into those vars. If there are more substrings that would be
+// split after len(vars), they will be all be put into the final variable.
+//
+// Returns ErrInconsistentUnpackLen if len(vars) is greater than the number
+// of split substrings.
+func SplitInto(s, sep string, vars ...*string) error {
+ exploded := strings.SplitN(s, sep, len(vars))
+ return Unpack(exploded, vars...)
+}
+
+// SlicePermutations returns all permutations of a string slice.
+//
+// It is equivalent to `SliceCombinationsR(xs, len(xs))`.
+func SlicePermutations(xs []string) [][]string {
+ return SlicePermutationsR(xs, len(xs))
+}
+
+// SlicePermutationsR returns successive r-length permutations of elements in
+// the provided string slice.
+//
+// If r is less than 0 or larger than the length of the pool, nil is returned.
+//
+// The permutation tuples are emitted in lexicographic ordering according to
+// the order of the input iterable. So, if the input iterable is sorted, the
+// combination tuples will be produced in sorted order.
+//
+// Elements are treated as unique based on their position, not on their value.
+// So if the input elements are unique, there will be no repeat values in each
+// permutation.
+//
+// This is the algorithm used in Python's itertools library:
+// itertools.permutations(iterable, r=None)
+func SlicePermutationsR(pool []string, r int) [][]string {
+ if r <= 0 || pool == nil || r > len(pool) {
+ return nil
+ }
+ n := len(pool)
+
+ indices := make([]int, n)
+ for i := range pool {
+ indices[i] = i
+ }
+
+ var ys [][]string
+
+ {
+ var y []string
+ for _, i := range indices[:r] {
+ y = append(y, pool[i])
+ }
+ ys = append(ys, y)
+ }
+
+ cycles := make([]int, n-(n-r))
+ for i := range cycles {
+ cycles[i] = n - i
+ }
+
+ for {
+ broke := false
+
+ for i := r - 1; i >= 0; i-- {
+ cycles[i] = cycles[i] - 1
+ if cycles[i] == 0 {
+ indices = append(indices[:i], append(indices[i+1:], indices[i:i+1]...)...)
+ cycles[i] = n - i
+ } else {
+ j := cycles[i]
+ indices[i], indices[len(indices)-j] = indices[len(indices)-j], indices[i]
+
+ var y []string
+ for _, i := range indices[:r] {
+ y = append(y, pool[i])
+ }
+ ys = append(ys, y)
+
+ broke = true
+ break
+ }
+ }
+ if !broke {
+ return ys
+ }
+ }
+}
+
+// SliceCombinationsR returns r-length subsequences of elements from the
+// provided string slice.
+//
+// If r is less than 0 or larger than the length of the pool, nil is returned.
+//
+// The combinations are emitted in lexicographic ordering according to the
+// order of the input iterable. So, if the input iterable is sorted, the
+// combination tuples will be produced in sorted order.
+//
+// Elements are treated as unique based on their position, not on their value.
+// So if the input elements are unique, there will be no repeat values in each
+// combination.
+//
+// This is the algorithm used in Python's itertools library:
+// itertools.combinations(iterable, r)
+func SliceCombinationsR(pool []string, r int) [][]string {
+ if r <= 0 || pool == nil || r > len(pool) {
+ return nil
+ }
+ n := len(pool)
+
+ indices := make([]int, r)
+ for i := range indices {
+ indices[i] = i
+ }
+
+ var ys [][]string
+
+ {
+ var y []string
+ for _, j := range indices {
+ y = append(y, pool[j])
+ }
+ ys = append(ys, y)
+ }
+
+ for {
+ var i int
+ broke := false
+ for i = r - 1; i >= 0; i-- {
+ if indices[i] != i+n-r {
+ broke = true
+ break
+ }
+ }
+ if !broke {
+ return ys
+ }
+
+ indices[i] = indices[i] + 1
+ for j := i + 1; j < r; j++ {
+ indices[j] = indices[j-1] + 1
+ }
+
+ var y []string
+ for _, j := range indices {
+ y = append(y, pool[j])
+ }
+ ys = append(ys, y)
+ }
+}
+
+// SliceCombinationsWithReplacement returns r-length subsequences of elements
+// from the provided string slice allowing individual elements to be repeated
+// more than once.
+//
+// If r is less than 0 or larger than the length of the pool, nil is returned.
+//
+// The combination tuples are emitted in lexicographic ordering according to
+// the order of the input iterable. So, if the input iterable is sorted, the
+// combination tuples will be produced in sorted order.
+//
+// Elements are treated as unique based on their position, not on their value.
+// So if the input elements are unique, the generated combinations will also be
+// unique.
+//
+// This is the algorithm used in Python's itertools library:
+// itertools.combinations_with_replacement(iterable, r)
+func SliceCombinationsWithReplacement(pool []string, r int) [][]string {
+ if r <= 0 || pool == nil || r > len(pool) {
+ return nil
+ }
+ n := len(pool)
+
+ indices := make([]int, r)
+ var ys [][]string
+
+ {
+ var y []string
+ for _, j := range indices {
+ y = append(y, pool[j])
+ }
+ ys = append(ys, y)
+ }
+
+ for {
+ var i int
+ broke := false
+ for i = r - 1; i >= 0; i-- {
+ if indices[i] != n-1 {
+ broke = true
+ break
+ }
+ }
+ if !broke {
+ return ys
+ }
+
+ newIndices := make([]int, r-i)
+ for j := range newIndices {
+ newIndices[j] = indices[i] + 1
+ }
+ indices = append(indices[:i], newIndices...)
+
+ var y []string
+ for _, j := range indices {
+ y = append(y, pool[j])
+ }
+ ys = append(ys, y)
+ }
+}
+
+// LastCut slices s around the last instance of sep,
+// returning the text before and after sep.
+//
+// The found result reports whether sep appears in s.
+// If sep does not appear in s, LastCut returns s, "", false.
+func LastCut(s, sep string) (before, after string, found bool) {
+ if i := strings.LastIndex(s, sep); i >= 0 {
+ return s[:i], s[i+len(sep):], true
+ }
+ return s, "", false
+}