mirror of
https://github.com/documize/community.git
synced 2025-07-24 23:59:47 +02:00
[WIP] Admin level Jira creds and vendored jira libs
This commit is contained in:
parent
0c5ec43c80
commit
7878a244d3
83 changed files with 10569 additions and 28 deletions
113
vendor/github.com/trivago/tgo/tcontainer/arrays.go
generated
vendored
Normal file
113
vendor/github.com/trivago/tgo/tcontainer/arrays.go
generated
vendored
Normal file
|
@ -0,0 +1,113 @@
|
|||
// Copyright 2015-2016 trivago GmbH
|
||||
//
|
||||
// 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 tcontainer
|
||||
|
||||
import "sort"
|
||||
|
||||
// Int64Slice is a typedef to allow sortable int64 slices
|
||||
type Int64Slice []int64
|
||||
|
||||
func (s Int64Slice) Len() int {
|
||||
return len(s)
|
||||
}
|
||||
|
||||
func (s Int64Slice) Less(i, j int) bool {
|
||||
return s[i] < s[j]
|
||||
}
|
||||
|
||||
func (s Int64Slice) Swap(i, j int) {
|
||||
s[i], s[j] = s[j], s[i]
|
||||
}
|
||||
|
||||
// Sort is a shortcut for sort.Sort(s)
|
||||
func (s Int64Slice) Sort() {
|
||||
sort.Sort(s)
|
||||
}
|
||||
|
||||
// IsSorted is a shortcut for sort.IsSorted(s)
|
||||
func (s Int64Slice) IsSorted() bool {
|
||||
return sort.IsSorted(s)
|
||||
}
|
||||
|
||||
// Set sets all values in this slice to the given value
|
||||
func (s Int64Slice) Set(v int64) {
|
||||
for i := range s {
|
||||
s[i] = v
|
||||
}
|
||||
}
|
||||
|
||||
// Uint64Slice is a typedef to allow sortable uint64 slices
|
||||
type Uint64Slice []uint64
|
||||
|
||||
func (s Uint64Slice) Len() int {
|
||||
return len(s)
|
||||
}
|
||||
|
||||
func (s Uint64Slice) Less(i, j int) bool {
|
||||
return s[i] < s[j]
|
||||
}
|
||||
|
||||
func (s Uint64Slice) Swap(i, j int) {
|
||||
s[i], s[j] = s[j], s[i]
|
||||
}
|
||||
|
||||
// Sort is a shortcut for sort.Sort(s)
|
||||
func (s Uint64Slice) Sort() {
|
||||
sort.Sort(s)
|
||||
}
|
||||
|
||||
// IsSorted is a shortcut for sort.IsSorted(s)
|
||||
func (s Uint64Slice) IsSorted() bool {
|
||||
return sort.IsSorted(s)
|
||||
}
|
||||
|
||||
// Set sets all values in this slice to the given value
|
||||
func (s Uint64Slice) Set(v uint64) {
|
||||
for i := range s {
|
||||
s[i] = v
|
||||
}
|
||||
}
|
||||
|
||||
// Float32Slice is a typedef to allow sortable float32 slices
|
||||
type Float32Slice []float32
|
||||
|
||||
func (s Float32Slice) Len() int {
|
||||
return len(s)
|
||||
}
|
||||
|
||||
func (s Float32Slice) Less(i, j int) bool {
|
||||
return s[i] < s[j]
|
||||
}
|
||||
|
||||
func (s Float32Slice) Swap(i, j int) {
|
||||
s[i], s[j] = s[j], s[i]
|
||||
}
|
||||
|
||||
// Sort is a shortcut for sort.Sort(s)
|
||||
func (s Float32Slice) Sort() {
|
||||
sort.Sort(s)
|
||||
}
|
||||
|
||||
// IsSorted is a shortcut for sort.IsSorted(s)
|
||||
func (s Float32Slice) IsSorted() bool {
|
||||
return sort.IsSorted(s)
|
||||
}
|
||||
|
||||
// Set sets all values in this slice to the given value
|
||||
func (s Float32Slice) Set(v float32) {
|
||||
for i := range s {
|
||||
s[i] = v
|
||||
}
|
||||
}
|
157
vendor/github.com/trivago/tgo/tcontainer/bytepool.go
generated
vendored
Normal file
157
vendor/github.com/trivago/tgo/tcontainer/bytepool.go
generated
vendored
Normal file
|
@ -0,0 +1,157 @@
|
|||
// Copyright 2015-2016 trivago GmbH
|
||||
//
|
||||
// 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 tcontainer
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"runtime"
|
||||
"sync/atomic"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
tiny = 64
|
||||
small = 512
|
||||
medium = 1024
|
||||
large = 1024 * 10
|
||||
huge = 1024 * 100
|
||||
|
||||
tinyCount = 16384 // 1 MB
|
||||
smallCount = 2048 // 1 MB
|
||||
mediumCount = 1024 // 1 MB
|
||||
largeCount = 102 // ~1 MB
|
||||
hugeCount = 10 // ~1 MB
|
||||
)
|
||||
|
||||
type byteSlab struct {
|
||||
buffer []byte
|
||||
bufferSize uintptr
|
||||
stride uintptr
|
||||
basePtr *uintptr
|
||||
nextPtr *uintptr
|
||||
}
|
||||
|
||||
// BytePool is a fragmentation friendly way to allocated byte slices.
|
||||
type BytePool struct {
|
||||
tinySlab byteSlab
|
||||
smallSlab byteSlab
|
||||
mediumSlab byteSlab
|
||||
largeSlab byteSlab
|
||||
hugeSlab byteSlab
|
||||
}
|
||||
|
||||
func newByteSlab(size, count int) byteSlab {
|
||||
bufferSize := count * size
|
||||
buffer := make([]byte, bufferSize)
|
||||
basePtr := (*reflect.SliceHeader)(unsafe.Pointer(&buffer)).Data
|
||||
nextPtr := basePtr + uintptr(bufferSize)
|
||||
|
||||
return byteSlab{
|
||||
buffer: buffer,
|
||||
bufferSize: uintptr(bufferSize),
|
||||
stride: uintptr(size),
|
||||
basePtr: &basePtr,
|
||||
nextPtr: &nextPtr,
|
||||
}
|
||||
}
|
||||
|
||||
func (slab *byteSlab) getSlice(size int) (chunk []byte) {
|
||||
chunkHeader := (*reflect.SliceHeader)(unsafe.Pointer(&chunk))
|
||||
chunkHeader.Len = size
|
||||
chunkHeader.Cap = int(slab.stride)
|
||||
|
||||
for {
|
||||
// WARNING: The following two lines are order sensitive
|
||||
basePtr := atomic.LoadUintptr(slab.basePtr)
|
||||
nextPtr := atomic.AddUintptr(slab.nextPtr, -slab.stride)
|
||||
lastPtr := basePtr + slab.bufferSize
|
||||
|
||||
switch {
|
||||
case nextPtr < basePtr || nextPtr >= lastPtr:
|
||||
// out of range either means alloc while realloc or race between
|
||||
// base and next during realloc. In the latter case we lose a chunk.
|
||||
runtime.Gosched()
|
||||
|
||||
case nextPtr == basePtr:
|
||||
// Last item: realloc
|
||||
slab.buffer = make([]byte, slab.bufferSize)
|
||||
dataPtr := (*reflect.SliceHeader)(unsafe.Pointer(&slab.buffer)).Data
|
||||
|
||||
// WARNING: The following two lines are order sensitive
|
||||
atomic.StoreUintptr(slab.nextPtr, dataPtr+slab.bufferSize)
|
||||
atomic.StoreUintptr(slab.basePtr, dataPtr)
|
||||
fallthrough
|
||||
|
||||
default:
|
||||
chunkHeader.Data = nextPtr
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NewBytePool creates a new BytePool with each slab using 1 MB of storage.
|
||||
// The pool contains 5 slabs of different sizes: 64B, 512B, 1KB, 10KB and 100KB.
|
||||
// Allocations above 100KB will be allocated directly.
|
||||
func NewBytePool() BytePool {
|
||||
return BytePool{
|
||||
tinySlab: newByteSlab(tiny, tinyCount),
|
||||
smallSlab: newByteSlab(small, smallCount),
|
||||
mediumSlab: newByteSlab(medium, mediumCount),
|
||||
largeSlab: newByteSlab(large, largeCount),
|
||||
hugeSlab: newByteSlab(huge, hugeCount),
|
||||
}
|
||||
}
|
||||
|
||||
// NewBytePoolWithSize creates a new BytePool with each slab size using n MB of
|
||||
// storage. See NewBytePool() for slab size details.
|
||||
func NewBytePoolWithSize(n int) BytePool {
|
||||
if n <= 0 {
|
||||
n = 1
|
||||
}
|
||||
return BytePool{
|
||||
tinySlab: newByteSlab(tiny, tinyCount*n),
|
||||
smallSlab: newByteSlab(small, smallCount*n),
|
||||
mediumSlab: newByteSlab(medium, mediumCount*n),
|
||||
largeSlab: newByteSlab(large, largeCount*n),
|
||||
hugeSlab: newByteSlab(huge, hugeCount*n),
|
||||
}
|
||||
}
|
||||
|
||||
// Get returns a slice allocated to a normalized size.
|
||||
// Sizes are organized in evenly sized buckets so that fragmentation is kept low.
|
||||
func (b *BytePool) Get(size int) []byte {
|
||||
switch {
|
||||
case size == 0:
|
||||
return []byte{}
|
||||
|
||||
case size <= tiny:
|
||||
return b.tinySlab.getSlice(size)
|
||||
|
||||
case size <= small:
|
||||
return b.smallSlab.getSlice(size)
|
||||
|
||||
case size <= medium:
|
||||
return b.mediumSlab.getSlice(size)
|
||||
|
||||
case size <= large:
|
||||
return b.largeSlab.getSlice(size)
|
||||
|
||||
case size <= huge:
|
||||
return b.hugeSlab.getSlice(size)
|
||||
|
||||
default:
|
||||
return make([]byte, size)
|
||||
}
|
||||
}
|
464
vendor/github.com/trivago/tgo/tcontainer/marshalmap.go
generated
vendored
Normal file
464
vendor/github.com/trivago/tgo/tcontainer/marshalmap.go
generated
vendored
Normal file
|
@ -0,0 +1,464 @@
|
|||
// Copyright 2015-2016 trivago GmbH
|
||||
//
|
||||
// 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 tcontainer
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/trivago/tgo/treflect"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// MarshalMap is a wrapper type to attach converter methods to maps normally
|
||||
// returned by marshalling methods, i.e. key/value parsers.
|
||||
// All methods that do a conversion will return an error if the value stored
|
||||
// behind key is not of the expected type or if the key is not existing in the
|
||||
// map.
|
||||
type MarshalMap map[string]interface{}
|
||||
|
||||
const (
|
||||
// MarshalMapSeparator defines the rune used for path separation
|
||||
MarshalMapSeparator = '/'
|
||||
// MarshalMapArrayBegin defines the rune starting array index notation
|
||||
MarshalMapArrayBegin = '['
|
||||
// MarshalMapArrayEnd defines the rune ending array index notation
|
||||
MarshalMapArrayEnd = ']'
|
||||
)
|
||||
|
||||
// NewMarshalMap creates a new marshal map (string -> interface{})
|
||||
func NewMarshalMap() MarshalMap {
|
||||
return make(map[string]interface{})
|
||||
}
|
||||
|
||||
// TryConvertToMarshalMap converts collections to MarshalMap if possible.
|
||||
// This is a deep conversion, i.e. each element in the collection will be
|
||||
// traversed. You can pass a formatKey function that will be applied to all
|
||||
// string keys that are detected.
|
||||
func TryConvertToMarshalMap(value interface{}, formatKey func(string) string) interface{} {
|
||||
valueMeta := reflect.ValueOf(value)
|
||||
switch valueMeta.Kind() {
|
||||
default:
|
||||
return value
|
||||
|
||||
case reflect.Array, reflect.Slice:
|
||||
arrayLen := valueMeta.Len()
|
||||
converted := make([]interface{}, arrayLen)
|
||||
for i := 0; i < arrayLen; i++ {
|
||||
converted[i] = TryConvertToMarshalMap(valueMeta.Index(i).Interface(), formatKey)
|
||||
}
|
||||
return converted
|
||||
|
||||
case reflect.Map:
|
||||
converted := NewMarshalMap()
|
||||
keys := valueMeta.MapKeys()
|
||||
|
||||
for _, keyMeta := range keys {
|
||||
strKey, isString := keyMeta.Interface().(string)
|
||||
if !isString {
|
||||
continue
|
||||
}
|
||||
if formatKey != nil {
|
||||
strKey = formatKey(strKey)
|
||||
}
|
||||
val := valueMeta.MapIndex(keyMeta).Interface()
|
||||
converted[strKey] = TryConvertToMarshalMap(val, formatKey)
|
||||
}
|
||||
return converted // ### return, converted MarshalMap ###
|
||||
}
|
||||
}
|
||||
|
||||
// ConvertToMarshalMap tries to convert a compatible map type to a marshal map.
|
||||
// Compatible types are map[interface{}]interface{}, map[string]interface{} and of
|
||||
// course MarshalMap. The same rules as for ConvertValueToMarshalMap apply.
|
||||
func ConvertToMarshalMap(value interface{}, formatKey func(string) string) (MarshalMap, error) {
|
||||
converted := TryConvertToMarshalMap(value, formatKey)
|
||||
if result, isMap := converted.(MarshalMap); isMap {
|
||||
return result, nil
|
||||
}
|
||||
return nil, fmt.Errorf("Root value cannot be converted to MarshalMap")
|
||||
}
|
||||
|
||||
// Bool returns a value at key that is expected to be a boolean
|
||||
func (mmap MarshalMap) Bool(key string) (bool, error) {
|
||||
val, exists := mmap.Value(key)
|
||||
if !exists {
|
||||
return false, fmt.Errorf(`"%s" is not set`, key)
|
||||
}
|
||||
|
||||
boolValue, isBool := val.(bool)
|
||||
if !isBool {
|
||||
return false, fmt.Errorf(`"%s" is expected to be a boolean`, key)
|
||||
}
|
||||
return boolValue, nil
|
||||
}
|
||||
|
||||
// Uint returns a value at key that is expected to be an uint64 or compatible
|
||||
// integer value.
|
||||
func (mmap MarshalMap) Uint(key string) (uint64, error) {
|
||||
val, exists := mmap.Value(key)
|
||||
if !exists {
|
||||
return 0, fmt.Errorf(`"%s" is not set`, key)
|
||||
}
|
||||
|
||||
if intVal, isNumber := treflect.Uint64(val); isNumber {
|
||||
return intVal, nil
|
||||
}
|
||||
|
||||
return 0, fmt.Errorf(`"%s" is expected to be an unsigned number type`, key)
|
||||
}
|
||||
|
||||
// Int returns a value at key that is expected to be an int64 or compatible
|
||||
// integer value.
|
||||
func (mmap MarshalMap) Int(key string) (int64, error) {
|
||||
val, exists := mmap.Value(key)
|
||||
if !exists {
|
||||
return 0, fmt.Errorf(`"%s" is not set`, key)
|
||||
}
|
||||
|
||||
if intVal, isNumber := treflect.Int64(val); isNumber {
|
||||
return intVal, nil
|
||||
}
|
||||
|
||||
return 0, fmt.Errorf(`"%s" is expected to be a signed number type`, key)
|
||||
}
|
||||
|
||||
// Float returns a value at key that is expected to be a float64 or compatible
|
||||
// float value.
|
||||
func (mmap MarshalMap) Float(key string) (float64, error) {
|
||||
val, exists := mmap.Value(key)
|
||||
if !exists {
|
||||
return 0, fmt.Errorf(`"%s" is not set`, key)
|
||||
}
|
||||
|
||||
if floatVal, isNumber := treflect.Float64(val); isNumber {
|
||||
return floatVal, nil
|
||||
}
|
||||
|
||||
return 0, fmt.Errorf(`"%s" is expected to be a signed number type`, key)
|
||||
}
|
||||
|
||||
// Duration returns a value at key that is expected to be a string
|
||||
func (mmap MarshalMap) Duration(key string) (time.Duration, error) {
|
||||
val, exists := mmap.Value(key)
|
||||
if !exists {
|
||||
return time.Duration(0), fmt.Errorf(`"%s" is not set`, key)
|
||||
}
|
||||
|
||||
switch val.(type) {
|
||||
case time.Duration:
|
||||
return val.(time.Duration), nil
|
||||
case string:
|
||||
return time.ParseDuration(val.(string))
|
||||
}
|
||||
|
||||
return time.Duration(0), fmt.Errorf(`"%s" is expected to be a duration or string`, key)
|
||||
}
|
||||
|
||||
// String returns a value at key that is expected to be a string
|
||||
func (mmap MarshalMap) String(key string) (string, error) {
|
||||
val, exists := mmap.Value(key)
|
||||
if !exists {
|
||||
return "", fmt.Errorf(`"%s" is not set`, key)
|
||||
}
|
||||
|
||||
strValue, isString := val.(string)
|
||||
if !isString {
|
||||
return "", fmt.Errorf(`"%s" is expected to be a string`, key)
|
||||
}
|
||||
return strValue, nil
|
||||
}
|
||||
|
||||
// Array returns a value at key that is expected to be a []interface{}
|
||||
func (mmap MarshalMap) Array(key string) ([]interface{}, error) {
|
||||
val, exists := mmap.Value(key)
|
||||
if !exists {
|
||||
return nil, fmt.Errorf(`"%s" is not set`, key)
|
||||
}
|
||||
|
||||
arrayValue, isArray := val.([]interface{})
|
||||
if !isArray {
|
||||
return nil, fmt.Errorf(`"%s" is expected to be an array`, key)
|
||||
}
|
||||
return arrayValue, nil
|
||||
}
|
||||
|
||||
// Map returns a value at key that is expected to be a
|
||||
// map[interface{}]interface{}.
|
||||
func (mmap MarshalMap) Map(key string) (map[interface{}]interface{}, error) {
|
||||
val, exists := mmap.Value(key)
|
||||
if !exists {
|
||||
return nil, fmt.Errorf(`"%s" is not set`, key)
|
||||
}
|
||||
|
||||
mapValue, isMap := val.(map[interface{}]interface{})
|
||||
if !isMap {
|
||||
return nil, fmt.Errorf(`"%s" is expected to be a map`, key)
|
||||
}
|
||||
return mapValue, nil
|
||||
}
|
||||
|
||||
func castToStringArray(key string, value interface{}) ([]string, error) {
|
||||
switch value.(type) {
|
||||
case string:
|
||||
return []string{value.(string)}, nil
|
||||
|
||||
case []interface{}:
|
||||
arrayVal := value.([]interface{})
|
||||
stringArray := make([]string, 0, len(arrayVal))
|
||||
|
||||
for _, val := range arrayVal {
|
||||
strValue, isString := val.(string)
|
||||
if !isString {
|
||||
return nil, fmt.Errorf(`"%s" does not contain string keys`, key)
|
||||
}
|
||||
stringArray = append(stringArray, strValue)
|
||||
}
|
||||
return stringArray, nil
|
||||
|
||||
case []string:
|
||||
return value.([]string), nil
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf(`"%s" is not a valid string array type`, key)
|
||||
}
|
||||
}
|
||||
|
||||
// StringArray returns a value at key that is expected to be a []string
|
||||
// This function supports conversion (by copy) from
|
||||
// * []interface{}
|
||||
func (mmap MarshalMap) StringArray(key string) ([]string, error) {
|
||||
val, exists := mmap.Value(key)
|
||||
if !exists {
|
||||
return nil, fmt.Errorf(`"%s" is not set`, key)
|
||||
}
|
||||
|
||||
return castToStringArray(key, val)
|
||||
}
|
||||
|
||||
func castToInt64Array(key string, value interface{}) ([]int64, error) {
|
||||
switch value.(type) {
|
||||
case int:
|
||||
return []int64{value.(int64)}, nil
|
||||
|
||||
case []interface{}:
|
||||
arrayVal := value.([]interface{})
|
||||
intArray := make([]int64, 0, len(arrayVal))
|
||||
|
||||
for _, val := range arrayVal {
|
||||
intValue, isInt := val.(int64)
|
||||
if !isInt {
|
||||
return nil, fmt.Errorf(`"%s" does not contain int keys`, key)
|
||||
}
|
||||
intArray = append(intArray, intValue)
|
||||
}
|
||||
return intArray, nil
|
||||
|
||||
case []int64:
|
||||
return value.([]int64), nil
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf(`"%s" is not a valid string array type`, key)
|
||||
}
|
||||
}
|
||||
|
||||
// IntArray returns a value at key that is expected to be a []int64
|
||||
// This function supports conversion (by copy) from
|
||||
// * []interface{}
|
||||
func (mmap MarshalMap) Int64Array(key string) ([]int64, error) {
|
||||
val, exists := mmap.Value(key)
|
||||
if !exists {
|
||||
return nil, fmt.Errorf(`"%s" is not set`, key)
|
||||
}
|
||||
|
||||
return castToInt64Array(key, val)
|
||||
}
|
||||
|
||||
// StringMap returns a value at key that is expected to be a map[string]string.
|
||||
// This function supports conversion (by copy) from
|
||||
// * map[interface{}]interface{}
|
||||
// * map[string]interface{}
|
||||
func (mmap MarshalMap) StringMap(key string) (map[string]string, error) {
|
||||
val, exists := mmap.Value(key)
|
||||
if !exists {
|
||||
return nil, fmt.Errorf(`"%s" is not set`, key)
|
||||
}
|
||||
|
||||
switch val.(type) {
|
||||
case map[string]string:
|
||||
return val.(map[string]string), nil
|
||||
|
||||
default:
|
||||
valueMeta := reflect.ValueOf(val)
|
||||
if valueMeta.Kind() != reflect.Map {
|
||||
return nil, fmt.Errorf(`"%s" is expected to be a map[string]string but is %T`, key, val)
|
||||
}
|
||||
|
||||
result := make(map[string]string)
|
||||
for _, keyMeta := range valueMeta.MapKeys() {
|
||||
strKey, isString := keyMeta.Interface().(string)
|
||||
if !isString {
|
||||
return nil, fmt.Errorf(`"%s" is expected to be a map[string]string. Key is not a string`, key)
|
||||
}
|
||||
|
||||
value := valueMeta.MapIndex(keyMeta)
|
||||
strValue, isString := value.Interface().(string)
|
||||
if !isString {
|
||||
return nil, fmt.Errorf(`"%s" is expected to be a map[string]string. Value is not a string`, key)
|
||||
}
|
||||
|
||||
result[strKey] = strValue
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
}
|
||||
|
||||
// StringArrayMap returns a value at key that is expected to be a
|
||||
// map[string][]string. This function supports conversion (by copy) from
|
||||
// * map[interface{}][]interface{}
|
||||
// * map[interface{}]interface{}
|
||||
// * map[string]interface{}
|
||||
func (mmap MarshalMap) StringArrayMap(key string) (map[string][]string, error) {
|
||||
val, exists := mmap.Value(key)
|
||||
if !exists {
|
||||
return nil, fmt.Errorf(`"%s" is not set`, key)
|
||||
}
|
||||
|
||||
switch val.(type) {
|
||||
case map[string][]string:
|
||||
return val.(map[string][]string), nil
|
||||
|
||||
default:
|
||||
valueMeta := reflect.ValueOf(val)
|
||||
if valueMeta.Kind() != reflect.Map {
|
||||
return nil, fmt.Errorf(`"%s" is expected to be a map[string][]string but is %T`, key, val)
|
||||
}
|
||||
|
||||
result := make(map[string][]string)
|
||||
for _, keyMeta := range valueMeta.MapKeys() {
|
||||
strKey, isString := keyMeta.Interface().(string)
|
||||
if !isString {
|
||||
return nil, fmt.Errorf(`"%s" is expected to be a map[string][]string. Key is not a string`, key)
|
||||
}
|
||||
|
||||
value := valueMeta.MapIndex(keyMeta)
|
||||
arrayValue, err := castToStringArray(strKey, value.Interface())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(`"%s" is expected to be a map[string][]string. Value is not a []string`, key)
|
||||
}
|
||||
|
||||
result[strKey] = arrayValue
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
}
|
||||
|
||||
// MarshalMap returns a value at key that is expected to be another MarshalMap
|
||||
// This function supports conversion (by copy) from
|
||||
// * map[interface{}]interface{}
|
||||
func (mmap MarshalMap) MarshalMap(key string) (MarshalMap, error) {
|
||||
val, exists := mmap.Value(key)
|
||||
if !exists {
|
||||
return nil, fmt.Errorf(`"%s" is not set`, key)
|
||||
}
|
||||
|
||||
return ConvertToMarshalMap(val, nil)
|
||||
}
|
||||
|
||||
// Value returns a value from a given value path.
|
||||
// Fields can be accessed by their name. Nested fields can be accessed by using
|
||||
// "/" as a separator. Arrays can be addressed using the standard array
|
||||
// notation "[<index>]".
|
||||
// Examples:
|
||||
// "key" -> mmap["key"] single value
|
||||
// "key1/key2" -> mmap["key1"]["key2"] nested map
|
||||
// "key1[0]" -> mmap["key1"][0] nested array
|
||||
// "key1[0]key2" -> mmap["key1"][0]["key2"] nested array, nested map
|
||||
func (mmap MarshalMap) Value(key string) (interface{}, bool) {
|
||||
return mmap.resolvePath(key, mmap)
|
||||
}
|
||||
|
||||
func (mmap MarshalMap) resolvePathKey(key string) (int, int) {
|
||||
keyEnd := len(key)
|
||||
nextKeyStart := keyEnd
|
||||
pathIdx := strings.IndexRune(key, MarshalMapSeparator)
|
||||
arrayIdx := strings.IndexRune(key, MarshalMapArrayBegin)
|
||||
|
||||
if pathIdx > -1 && pathIdx < keyEnd {
|
||||
keyEnd = pathIdx
|
||||
nextKeyStart = pathIdx + 1 // don't include slash
|
||||
}
|
||||
if arrayIdx > -1 && arrayIdx < keyEnd {
|
||||
keyEnd = arrayIdx
|
||||
nextKeyStart = arrayIdx // include bracket because of multidimensional arrays
|
||||
}
|
||||
|
||||
// a -> key: "a", remain: "" -- value
|
||||
// a/b/c -> key: "a", remain: "b/c" -- nested map
|
||||
// a[1]b/c -> key: "a", remain: "[1]b/c" -- nested array
|
||||
|
||||
return keyEnd, nextKeyStart
|
||||
}
|
||||
|
||||
func (mmap MarshalMap) resolvePath(key string, value interface{}) (interface{}, bool) {
|
||||
if len(key) == 0 {
|
||||
return value, true // ### return, found requested value ###
|
||||
}
|
||||
|
||||
valueMeta := reflect.ValueOf(value)
|
||||
switch valueMeta.Kind() {
|
||||
case reflect.Array, reflect.Slice:
|
||||
startIdx := strings.IndexRune(key, MarshalMapArrayBegin) // Must be first char, otherwise malformed
|
||||
endIdx := strings.IndexRune(key, MarshalMapArrayEnd) // Must be > startIdx, otherwise malformed
|
||||
|
||||
if startIdx == -1 || endIdx == -1 {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
if startIdx == 0 && endIdx > startIdx {
|
||||
index, err := strconv.Atoi(key[startIdx+1 : endIdx])
|
||||
|
||||
// [1] -> index: "1", remain: "" -- value
|
||||
// [1]a/b -> index: "1", remain: "a/b" -- nested map
|
||||
// [1][2] -> index: "1", remain: "[2]" -- nested array
|
||||
|
||||
if err == nil && index < valueMeta.Len() {
|
||||
item := valueMeta.Index(index).Interface()
|
||||
key := key[endIdx+1:]
|
||||
return mmap.resolvePath(key, item) // ### return, nested array ###
|
||||
}
|
||||
}
|
||||
|
||||
case reflect.Map:
|
||||
keyMeta := reflect.ValueOf(key)
|
||||
if storedValue := valueMeta.MapIndex(keyMeta); storedValue.IsValid() {
|
||||
return storedValue.Interface(), true
|
||||
}
|
||||
|
||||
keyEnd, nextKeyStart := mmap.resolvePathKey(key)
|
||||
pathKey := key[:keyEnd]
|
||||
keyMeta = reflect.ValueOf(pathKey)
|
||||
|
||||
if storedValue := valueMeta.MapIndex(keyMeta); storedValue.IsValid() {
|
||||
remain := key[nextKeyStart:]
|
||||
return mmap.resolvePath(remain, storedValue.Interface()) // ### return, nested map ###
|
||||
}
|
||||
}
|
||||
|
||||
return nil, false
|
||||
}
|
227
vendor/github.com/trivago/tgo/tcontainer/trie.go
generated
vendored
Normal file
227
vendor/github.com/trivago/tgo/tcontainer/trie.go
generated
vendored
Normal file
|
@ -0,0 +1,227 @@
|
|||
// Copyright 2015-2016 trivago GmbH
|
||||
//
|
||||
// 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 tcontainer
|
||||
|
||||
// TrieNode represents a single node inside a trie.
|
||||
// Each node can contain a payload which can be retrieved after a successfull
|
||||
// match. In addition to that PathLen will contain the length of the match.
|
||||
type TrieNode struct {
|
||||
suffix []byte
|
||||
children []*TrieNode
|
||||
longestPath int
|
||||
PathLen int
|
||||
Payload interface{}
|
||||
}
|
||||
|
||||
// NewTrie creates a new root TrieNode
|
||||
func NewTrie(data []byte, payload interface{}) *TrieNode {
|
||||
return &TrieNode{
|
||||
suffix: data,
|
||||
children: []*TrieNode{},
|
||||
longestPath: len(data),
|
||||
PathLen: len(data),
|
||||
Payload: payload,
|
||||
}
|
||||
}
|
||||
|
||||
func (node *TrieNode) addNewChild(data []byte, payload interface{}, pathLen int) {
|
||||
if node.longestPath < pathLen {
|
||||
node.longestPath = pathLen
|
||||
}
|
||||
|
||||
idx := len(node.children)
|
||||
node.children = append(node.children, nil)
|
||||
|
||||
for idx > 0 {
|
||||
nextIdx := idx - 1
|
||||
if node.children[nextIdx].longestPath > pathLen {
|
||||
break
|
||||
}
|
||||
node.children[idx] = node.children[nextIdx]
|
||||
idx = nextIdx
|
||||
}
|
||||
|
||||
node.children[idx] = &TrieNode{
|
||||
suffix: data,
|
||||
children: []*TrieNode{},
|
||||
longestPath: pathLen,
|
||||
PathLen: pathLen,
|
||||
Payload: payload,
|
||||
}
|
||||
}
|
||||
|
||||
func (node *TrieNode) replace(oldChild *TrieNode, newChild *TrieNode) {
|
||||
for i, child := range node.children {
|
||||
if child == oldChild {
|
||||
node.children[i] = newChild
|
||||
return // ### return, replaced ###
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ForEach applies a function to each node in the tree including and below the
|
||||
// passed node.
|
||||
func (node *TrieNode) ForEach(callback func(*TrieNode)) {
|
||||
callback(node)
|
||||
for _, child := range node.children {
|
||||
child.ForEach(callback)
|
||||
}
|
||||
}
|
||||
|
||||
// Add adds a new data path to the trie.
|
||||
// The TrieNode returned is the (new) root node so you should always reassign
|
||||
// the root with the return value of Add.
|
||||
func (node *TrieNode) Add(data []byte, payload interface{}) *TrieNode {
|
||||
return node.addPath(data, payload, len(data), nil)
|
||||
}
|
||||
|
||||
func (node *TrieNode) addPath(data []byte, payload interface{}, pathLen int, parent *TrieNode) *TrieNode {
|
||||
dataLen := len(data)
|
||||
suffixLen := len(node.suffix)
|
||||
testLen := suffixLen
|
||||
if dataLen < suffixLen {
|
||||
testLen = dataLen
|
||||
}
|
||||
|
||||
var splitIdx int
|
||||
for splitIdx = 0; splitIdx < testLen; splitIdx++ {
|
||||
if data[splitIdx] != node.suffix[splitIdx] {
|
||||
break // ### break, split found ###
|
||||
}
|
||||
}
|
||||
|
||||
if splitIdx == suffixLen {
|
||||
// Continue down or stop here (full suffix match)
|
||||
|
||||
if splitIdx == dataLen {
|
||||
node.Payload = payload // may overwrite
|
||||
return node // ### return, path already stored ###
|
||||
}
|
||||
|
||||
data = data[splitIdx:]
|
||||
if suffixLen > 0 {
|
||||
for _, child := range node.children {
|
||||
if child.suffix[0] == data[0] {
|
||||
child.addPath(data, payload, pathLen, node)
|
||||
return node // ### return, continue on path ###
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
node.addNewChild(data, payload, pathLen)
|
||||
return node // ### return, new leaf ###
|
||||
}
|
||||
|
||||
if splitIdx == dataLen {
|
||||
// Make current node a subpath of new data node (full data match)
|
||||
// This case implies that dataLen < suffixLen as splitIdx == suffixLen
|
||||
// did not match.
|
||||
|
||||
node.suffix = node.suffix[splitIdx:]
|
||||
|
||||
newParent := NewTrie(data, payload)
|
||||
newParent.PathLen = pathLen
|
||||
newParent.longestPath = node.longestPath
|
||||
newParent.children = []*TrieNode{node}
|
||||
|
||||
if parent != nil {
|
||||
parent.replace(node, newParent)
|
||||
}
|
||||
return newParent // ### return, rotation ###
|
||||
}
|
||||
|
||||
// New parent required with both nodes as children (partial match)
|
||||
|
||||
node.suffix = node.suffix[splitIdx:]
|
||||
|
||||
newParent := NewTrie(data[:splitIdx], nil)
|
||||
newParent.PathLen = 0
|
||||
newParent.longestPath = node.longestPath
|
||||
newParent.children = []*TrieNode{node}
|
||||
newParent.addNewChild(data[splitIdx:], payload, pathLen)
|
||||
|
||||
if parent != nil {
|
||||
parent.replace(node, newParent)
|
||||
}
|
||||
return newParent // ### return, new parent ###
|
||||
}
|
||||
|
||||
// Match compares the trie to the given data stream.
|
||||
// Match returns true if data can be completely matched to the trie.
|
||||
func (node *TrieNode) Match(data []byte) *TrieNode {
|
||||
dataLen := len(data)
|
||||
suffixLen := len(node.suffix)
|
||||
if dataLen < suffixLen {
|
||||
return nil // ### return, cannot be fully matched ###
|
||||
}
|
||||
|
||||
for i := 0; i < suffixLen; i++ {
|
||||
if data[i] != node.suffix[i] {
|
||||
return nil // ### return, no match ###
|
||||
}
|
||||
}
|
||||
|
||||
if dataLen == suffixLen {
|
||||
if node.PathLen > 0 {
|
||||
return node // ### return, full match ###
|
||||
}
|
||||
return nil // ### return, invalid match ###
|
||||
}
|
||||
|
||||
data = data[suffixLen:]
|
||||
numChildren := len(node.children)
|
||||
for i := 0; i < numChildren; i++ {
|
||||
matchedNode := node.children[i].Match(data)
|
||||
if matchedNode != nil {
|
||||
return matchedNode // ### return, match found ###
|
||||
}
|
||||
}
|
||||
|
||||
return nil // ### return, no valid path ###
|
||||
}
|
||||
|
||||
// MatchStart compares the trie to the beginning of the given data stream.
|
||||
// MatchStart returns true if the beginning of data can be matched to the trie.
|
||||
func (node *TrieNode) MatchStart(data []byte) *TrieNode {
|
||||
dataLen := len(data)
|
||||
suffixLen := len(node.suffix)
|
||||
if dataLen < suffixLen {
|
||||
return nil // ### return, cannot be fully matched ###
|
||||
}
|
||||
|
||||
for i := 0; i < suffixLen; i++ {
|
||||
if data[i] != node.suffix[i] {
|
||||
return nil // ### return, no match ###
|
||||
}
|
||||
}
|
||||
|
||||
// Match longest path first
|
||||
|
||||
data = data[suffixLen:]
|
||||
numChildren := len(node.children)
|
||||
for i := 0; i < numChildren; i++ {
|
||||
matchedNode := node.children[i].MatchStart(data)
|
||||
if matchedNode != nil {
|
||||
return matchedNode // ### return, match found ###
|
||||
}
|
||||
}
|
||||
|
||||
// May be only a part of data but we have a valid match
|
||||
|
||||
if node.PathLen > 0 {
|
||||
return node // ### return, full match ###
|
||||
}
|
||||
return nil // ### return, no valid path ###
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue