42
vendor/github.com/open-policy-agent/opa/util/backoff.go
generated
vendored
Normal file
42
vendor/github.com/open-policy-agent/opa/util/backoff.go
generated
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
// Copyright 2018 The OPA Authors. All rights reserved.
|
||||
// Use of this source code is governed by an Apache2
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package util
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"time"
|
||||
)
|
||||
|
||||
// DefaultBackoff returns a delay with an exponential backoff based on the
|
||||
// number of retries.
|
||||
func DefaultBackoff(base, max float64, retries int) time.Duration {
|
||||
return Backoff(base, max, .2, 1.6, retries)
|
||||
}
|
||||
|
||||
// Backoff returns a delay with an exponential backoff based on the number of
|
||||
// retries. Same algorithm used in gRPC.
|
||||
func Backoff(base, max, jitter, factor float64, retries int) time.Duration {
|
||||
if retries == 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
backoff, max := float64(base), float64(max)
|
||||
for backoff < max && retries > 0 {
|
||||
backoff *= factor
|
||||
retries--
|
||||
}
|
||||
if backoff > max {
|
||||
backoff = max
|
||||
}
|
||||
|
||||
// Randomize backoff delays so that if a cluster of requests start at
|
||||
// the same time, they won't operate in lockstep.
|
||||
backoff *= 1 + jitter*(rand.Float64()*2-1)
|
||||
if backoff < 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
return time.Duration(backoff)
|
||||
}
|
||||
23
vendor/github.com/open-policy-agent/opa/util/close.go
generated
vendored
Normal file
23
vendor/github.com/open-policy-agent/opa/util/close.go
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
// Copyright 2018 The OPA Authors. All rights reserved.
|
||||
// Use of this source code is governed by an Apache2
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package util
|
||||
|
||||
import (
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// Close reads the remaining bytes from the response and then closes it to
|
||||
// ensure that the connection is freed. If the body is not read and closed, a
|
||||
// leak can occur.
|
||||
func Close(resp *http.Response) {
|
||||
if resp != nil && resp.Body != nil {
|
||||
if _, err := io.Copy(ioutil.Discard, resp.Body); err != nil {
|
||||
return
|
||||
}
|
||||
resp.Body.Close()
|
||||
}
|
||||
}
|
||||
161
vendor/github.com/open-policy-agent/opa/util/compare.go
generated
vendored
Normal file
161
vendor/github.com/open-policy-agent/opa/util/compare.go
generated
vendored
Normal file
@@ -0,0 +1,161 @@
|
||||
// Copyright 2016 The OPA Authors. All rights reserved.
|
||||
// Use of this source code is governed by an Apache2
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package util
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"sort"
|
||||
)
|
||||
|
||||
// Compare returns 0 if a equals b, -1 if a is less than b, and 1 if b is than a.
|
||||
//
|
||||
// For comparison between values of different types, the following ordering is used:
|
||||
// nil < bool < float64 < string < []interface{} < map[string]interface{}. Slices and maps
|
||||
// are compared recursively. If one slice or map is a subset of the other slice or map
|
||||
// it is considered "less than". Nil is always equal to nil.
|
||||
//
|
||||
func Compare(a, b interface{}) int {
|
||||
aSortOrder := sortOrder(a)
|
||||
bSortOrder := sortOrder(b)
|
||||
if aSortOrder < bSortOrder {
|
||||
return -1
|
||||
} else if bSortOrder < aSortOrder {
|
||||
return 1
|
||||
}
|
||||
switch a := a.(type) {
|
||||
case nil:
|
||||
return 0
|
||||
case bool:
|
||||
switch b := b.(type) {
|
||||
case bool:
|
||||
if a == b {
|
||||
return 0
|
||||
}
|
||||
if !a {
|
||||
return -1
|
||||
}
|
||||
return 1
|
||||
}
|
||||
case json.Number:
|
||||
switch b := b.(type) {
|
||||
case json.Number:
|
||||
return compareJSONNumber(a, b)
|
||||
}
|
||||
case string:
|
||||
switch b := b.(type) {
|
||||
case string:
|
||||
if a == b {
|
||||
return 0
|
||||
} else if a < b {
|
||||
return -1
|
||||
}
|
||||
return 1
|
||||
}
|
||||
case []interface{}:
|
||||
switch b := b.(type) {
|
||||
case []interface{}:
|
||||
bLen := len(b)
|
||||
aLen := len(a)
|
||||
minLen := aLen
|
||||
if bLen < minLen {
|
||||
minLen = bLen
|
||||
}
|
||||
for i := 0; i < minLen; i++ {
|
||||
cmp := Compare(a[i], b[i])
|
||||
if cmp != 0 {
|
||||
return cmp
|
||||
}
|
||||
}
|
||||
if aLen == bLen {
|
||||
return 0
|
||||
} else if aLen < bLen {
|
||||
return -1
|
||||
}
|
||||
return 1
|
||||
}
|
||||
case map[string]interface{}:
|
||||
switch b := b.(type) {
|
||||
case map[string]interface{}:
|
||||
var aKeys []string
|
||||
for k := range a {
|
||||
aKeys = append(aKeys, k)
|
||||
}
|
||||
var bKeys []string
|
||||
for k := range b {
|
||||
bKeys = append(bKeys, k)
|
||||
}
|
||||
sort.Strings(aKeys)
|
||||
sort.Strings(bKeys)
|
||||
aLen := len(aKeys)
|
||||
bLen := len(bKeys)
|
||||
minLen := aLen
|
||||
if bLen < minLen {
|
||||
minLen = bLen
|
||||
}
|
||||
for i := 0; i < minLen; i++ {
|
||||
if aKeys[i] < bKeys[i] {
|
||||
return -1
|
||||
} else if bKeys[i] < aKeys[i] {
|
||||
return 1
|
||||
}
|
||||
aVal := a[aKeys[i]]
|
||||
bVal := b[bKeys[i]]
|
||||
cmp := Compare(aVal, bVal)
|
||||
if cmp != 0 {
|
||||
return cmp
|
||||
}
|
||||
}
|
||||
if aLen == bLen {
|
||||
return 0
|
||||
} else if aLen < bLen {
|
||||
return -1
|
||||
}
|
||||
return 1
|
||||
}
|
||||
}
|
||||
|
||||
panic(fmt.Sprintf("illegal arguments of type %T and type %T", a, b))
|
||||
}
|
||||
|
||||
const (
|
||||
nilSort = iota
|
||||
boolSort = iota
|
||||
numberSort = iota
|
||||
stringSort = iota
|
||||
arraySort = iota
|
||||
objectSort = iota
|
||||
)
|
||||
|
||||
func compareJSONNumber(a, b json.Number) int {
|
||||
bigA, ok := new(big.Float).SetString(string(a))
|
||||
if !ok {
|
||||
panic("illegal value")
|
||||
}
|
||||
bigB, ok := new(big.Float).SetString(string(b))
|
||||
if !ok {
|
||||
panic("illegal value")
|
||||
}
|
||||
return bigA.Cmp(bigB)
|
||||
}
|
||||
|
||||
func sortOrder(v interface{}) int {
|
||||
switch v.(type) {
|
||||
case nil:
|
||||
return nilSort
|
||||
case bool:
|
||||
return boolSort
|
||||
case json.Number:
|
||||
return numberSort
|
||||
case string:
|
||||
return stringSort
|
||||
case []interface{}:
|
||||
return arraySort
|
||||
case map[string]interface{}:
|
||||
return objectSort
|
||||
}
|
||||
panic(fmt.Sprintf("illegal argument of type %T", v))
|
||||
}
|
||||
6
vendor/github.com/open-policy-agent/opa/util/doc.go
generated
vendored
Normal file
6
vendor/github.com/open-policy-agent/opa/util/doc.go
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
// Copyright 2016 The OPA Authors. All rights reserved.
|
||||
// Use of this source code is governed by an Apache2
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package util provides generic utilities used throughout the policy engine.
|
||||
package util
|
||||
54
vendor/github.com/open-policy-agent/opa/util/enumflag.go
generated
vendored
Normal file
54
vendor/github.com/open-policy-agent/opa/util/enumflag.go
generated
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
// Copyright 2017 The OPA Authors. All rights reserved.
|
||||
// Use of this source code is governed by an Apache2
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package util
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// EnumFlag implements the pflag.Value interface to provide enumerated command
|
||||
// line parameter values.
|
||||
type EnumFlag struct {
|
||||
defaultValue string
|
||||
vs []string
|
||||
i int
|
||||
}
|
||||
|
||||
// NewEnumFlag returns a new EnumFlag that has a defaultValue and vs enumerated
|
||||
// values.
|
||||
func NewEnumFlag(defaultValue string, vs []string) *EnumFlag {
|
||||
f := &EnumFlag{
|
||||
i: -1,
|
||||
vs: vs,
|
||||
defaultValue: defaultValue,
|
||||
}
|
||||
return f
|
||||
}
|
||||
|
||||
// Type returns the valid enumeration values.
|
||||
func (f *EnumFlag) Type() string {
|
||||
return "{" + strings.Join(f.vs, ",") + "}"
|
||||
}
|
||||
|
||||
// String returns the EnumValue's value as string.
|
||||
func (f *EnumFlag) String() string {
|
||||
if f.i == -1 {
|
||||
return f.defaultValue
|
||||
}
|
||||
return f.vs[f.i]
|
||||
}
|
||||
|
||||
// Set sets the enum value. If s is not a valid enum value, an error is
|
||||
// returned.
|
||||
func (f *EnumFlag) Set(s string) error {
|
||||
for i := range f.vs {
|
||||
if f.vs[i] == s {
|
||||
f.i = i
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return fmt.Errorf("must be one of %v", f.Type())
|
||||
}
|
||||
90
vendor/github.com/open-policy-agent/opa/util/graph.go
generated
vendored
Normal file
90
vendor/github.com/open-policy-agent/opa/util/graph.go
generated
vendored
Normal file
@@ -0,0 +1,90 @@
|
||||
// Copyright 2016 The OPA Authors. All rights reserved.
|
||||
// Use of this source code is governed by an Apache2
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package util
|
||||
|
||||
// Traversal defines a basic interface to perform traversals.
|
||||
type Traversal interface {
|
||||
|
||||
// Edges should return the neighbours of node "u".
|
||||
Edges(u T) []T
|
||||
|
||||
// Visited should return true if node "u" has already been visited in this
|
||||
// traversal. If the same traversal is used multiple times, the state that
|
||||
// tracks visited nodes should be reset.
|
||||
Visited(u T) bool
|
||||
}
|
||||
|
||||
// Equals should return true if node "u" equals node "v".
|
||||
type Equals func(u T, v T) bool
|
||||
|
||||
// Iter should return true to indicate stop.
|
||||
type Iter func(u T) bool
|
||||
|
||||
// DFS performs a depth first traversal calling f for each node starting from u.
|
||||
// If f returns true, traversal stops and DFS returns true.
|
||||
func DFS(t Traversal, f Iter, u T) bool {
|
||||
lifo := NewLIFO(u)
|
||||
for lifo.Size() > 0 {
|
||||
next, _ := lifo.Pop()
|
||||
if t.Visited(next) {
|
||||
continue
|
||||
}
|
||||
if f(next) {
|
||||
return true
|
||||
}
|
||||
for _, v := range t.Edges(next) {
|
||||
lifo.Push(v)
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// BFS performs a breadth first traversal calling f for each node starting from
|
||||
// u. If f returns true, traversal stops and BFS returns true.
|
||||
func BFS(t Traversal, f Iter, u T) bool {
|
||||
fifo := NewFIFO(u)
|
||||
for fifo.Size() > 0 {
|
||||
next, _ := fifo.Pop()
|
||||
if t.Visited(next) {
|
||||
continue
|
||||
}
|
||||
if f(next) {
|
||||
return true
|
||||
}
|
||||
for _, v := range t.Edges(next) {
|
||||
fifo.Push(v)
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// DFSPath returns a path from node a to node z found by performing
|
||||
// a depth first traversal. If no path is found, an empty slice is returned.
|
||||
func DFSPath(t Traversal, eq Equals, a, z T) []T {
|
||||
p := dfsRecursive(t, eq, a, z, []T{})
|
||||
for i := len(p)/2 - 1; i >= 0; i-- {
|
||||
o := len(p) - i - 1
|
||||
p[i], p[o] = p[o], p[i]
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
func dfsRecursive(t Traversal, eq Equals, u, z T, path []T) []T {
|
||||
if t.Visited(u) {
|
||||
return path
|
||||
}
|
||||
for _, v := range t.Edges(u) {
|
||||
if eq(v, z) {
|
||||
path = append(path, z)
|
||||
path = append(path, u)
|
||||
return path
|
||||
}
|
||||
if p := dfsRecursive(t, eq, v, z, path); len(p) > 0 {
|
||||
path = append(p, u)
|
||||
return path
|
||||
}
|
||||
}
|
||||
return path
|
||||
}
|
||||
157
vendor/github.com/open-policy-agent/opa/util/hashmap.go
generated
vendored
Normal file
157
vendor/github.com/open-policy-agent/opa/util/hashmap.go
generated
vendored
Normal file
@@ -0,0 +1,157 @@
|
||||
// Copyright 2016 The OPA Authors. All rights reserved.
|
||||
// Use of this source code is governed by an Apache2
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package util
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// T is a concise way to refer to T.
|
||||
type T interface{}
|
||||
|
||||
type hashEntry struct {
|
||||
k T
|
||||
v T
|
||||
next *hashEntry
|
||||
}
|
||||
|
||||
// HashMap represents a key/value map.
|
||||
type HashMap struct {
|
||||
eq func(T, T) bool
|
||||
hash func(T) int
|
||||
table map[int]*hashEntry
|
||||
size int
|
||||
}
|
||||
|
||||
// NewHashMap returns a new empty HashMap.
|
||||
func NewHashMap(eq func(T, T) bool, hash func(T) int) *HashMap {
|
||||
return &HashMap{
|
||||
eq: eq,
|
||||
hash: hash,
|
||||
table: make(map[int]*hashEntry),
|
||||
size: 0,
|
||||
}
|
||||
}
|
||||
|
||||
// Copy returns a shallow copy of this HashMap.
|
||||
func (h *HashMap) Copy() *HashMap {
|
||||
cpy := NewHashMap(h.eq, h.hash)
|
||||
h.Iter(func(k, v T) bool {
|
||||
cpy.Put(k, v)
|
||||
return false
|
||||
})
|
||||
return cpy
|
||||
}
|
||||
|
||||
// Equal returns true if this HashMap equals the other HashMap.
|
||||
// Two hash maps are equal if they contain the same key/value pairs.
|
||||
func (h *HashMap) Equal(other *HashMap) bool {
|
||||
if h.Len() != other.Len() {
|
||||
return false
|
||||
}
|
||||
return !h.Iter(func(k, v T) bool {
|
||||
ov, ok := other.Get(k)
|
||||
if !ok {
|
||||
return true
|
||||
}
|
||||
return !h.eq(v, ov)
|
||||
})
|
||||
}
|
||||
|
||||
// Get returns the value for k.
|
||||
func (h *HashMap) Get(k T) (T, bool) {
|
||||
hash := h.hash(k)
|
||||
for entry := h.table[hash]; entry != nil; entry = entry.next {
|
||||
if h.eq(entry.k, k) {
|
||||
return entry.v, true
|
||||
}
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// Delete removes the the key k.
|
||||
func (h *HashMap) Delete(k T) {
|
||||
hash := h.hash(k)
|
||||
var prev *hashEntry
|
||||
for entry := h.table[hash]; entry != nil; entry = entry.next {
|
||||
if h.eq(entry.k, k) {
|
||||
if prev != nil {
|
||||
prev.next = entry.next
|
||||
} else {
|
||||
h.table[hash] = entry.next
|
||||
}
|
||||
h.size--
|
||||
return
|
||||
}
|
||||
prev = entry
|
||||
}
|
||||
}
|
||||
|
||||
// Hash returns the hash code for this hash map.
|
||||
func (h *HashMap) Hash() int {
|
||||
var hash int
|
||||
h.Iter(func(k, v T) bool {
|
||||
hash += h.hash(k) + h.hash(v)
|
||||
return false
|
||||
})
|
||||
return hash
|
||||
}
|
||||
|
||||
// Iter invokes the iter function for each element in the HashMap.
|
||||
// If the iter function returns true, iteration stops and the return value is true.
|
||||
// If the iter function never returns true, iteration proceeds through all elements
|
||||
// and the return value is false.
|
||||
func (h *HashMap) Iter(iter func(T, T) bool) bool {
|
||||
for _, entry := range h.table {
|
||||
for ; entry != nil; entry = entry.next {
|
||||
if iter(entry.k, entry.v) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Len returns the current size of this HashMap.
|
||||
func (h *HashMap) Len() int {
|
||||
return h.size
|
||||
}
|
||||
|
||||
// Put inserts a key/value pair into this HashMap. If the key is already present, the existing
|
||||
// value is overwritten.
|
||||
func (h *HashMap) Put(k T, v T) {
|
||||
hash := h.hash(k)
|
||||
head := h.table[hash]
|
||||
for entry := head; entry != nil; entry = entry.next {
|
||||
if h.eq(entry.k, k) {
|
||||
entry.v = v
|
||||
return
|
||||
}
|
||||
}
|
||||
h.table[hash] = &hashEntry{k: k, v: v, next: head}
|
||||
h.size++
|
||||
}
|
||||
|
||||
func (h *HashMap) String() string {
|
||||
var buf []string
|
||||
h.Iter(func(k T, v T) bool {
|
||||
buf = append(buf, fmt.Sprintf("%v: %v", k, v))
|
||||
return false
|
||||
})
|
||||
return "{" + strings.Join(buf, ", ") + "}"
|
||||
}
|
||||
|
||||
// Update returns a new HashMap with elements from the other HashMap put into this HashMap.
|
||||
// If the other HashMap contains elements with the same key as this HashMap, the value
|
||||
// from the other HashMap overwrites the value from this HashMap.
|
||||
func (h *HashMap) Update(other *HashMap) *HashMap {
|
||||
updated := h.Copy()
|
||||
other.Iter(func(k, v T) bool {
|
||||
updated.Put(k, v)
|
||||
return false
|
||||
})
|
||||
return updated
|
||||
}
|
||||
99
vendor/github.com/open-policy-agent/opa/util/json.go
generated
vendored
Normal file
99
vendor/github.com/open-policy-agent/opa/util/json.go
generated
vendored
Normal file
@@ -0,0 +1,99 @@
|
||||
// Copyright 2016 The OPA Authors. All rights reserved.
|
||||
// Use of this source code is governed by an Apache2
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package util
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"reflect"
|
||||
|
||||
"github.com/ghodss/yaml"
|
||||
)
|
||||
|
||||
// UnmarshalJSON parses the JSON encoded data and stores the result in the value
|
||||
// pointed to by x.
|
||||
//
|
||||
// This function is intended to be used in place of the standard json.Marshal
|
||||
// function when json.Number is required.
|
||||
func UnmarshalJSON(bs []byte, x interface{}) (err error) {
|
||||
buf := bytes.NewBuffer(bs)
|
||||
decoder := NewJSONDecoder(buf)
|
||||
return decoder.Decode(x)
|
||||
}
|
||||
|
||||
// NewJSONDecoder returns a new decoder that reads from r.
|
||||
//
|
||||
// This function is intended to be used in place of the standard json.NewDecoder
|
||||
// when json.Number is required.
|
||||
func NewJSONDecoder(r io.Reader) *json.Decoder {
|
||||
decoder := json.NewDecoder(r)
|
||||
decoder.UseNumber()
|
||||
return decoder
|
||||
}
|
||||
|
||||
// MustUnmarshalJSON parse the JSON encoded data and returns the result.
|
||||
//
|
||||
// If the data cannot be decoded, this function will panic. This function is for
|
||||
// test purposes.
|
||||
func MustUnmarshalJSON(bs []byte) interface{} {
|
||||
var x interface{}
|
||||
if err := UnmarshalJSON(bs, &x); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
||||
// MustMarshalJSON returns the JSON encoding of x
|
||||
//
|
||||
// If the data cannot be encoded, this function will panic. This function is for
|
||||
// test purposes.
|
||||
func MustMarshalJSON(x interface{}) []byte {
|
||||
bs, err := json.Marshal(x)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return bs
|
||||
}
|
||||
|
||||
// RoundTrip encodes to JSON, and decodes the result again.
|
||||
//
|
||||
// Thereby, it is converting its argument to the representation expected by
|
||||
// rego.Input and inmem's Write operations. Works with both references and
|
||||
// values.
|
||||
func RoundTrip(x *interface{}) error {
|
||||
bs, err := json.Marshal(x)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return UnmarshalJSON(bs, x)
|
||||
}
|
||||
|
||||
// Reference returns a pointer to its argument unless the argument already is
|
||||
// a pointer. If the argument is **t, or ***t, etc, it will return *t.
|
||||
//
|
||||
// Used for preparing Go types (including pointers to structs) into values to be
|
||||
// put through util.RoundTrip().
|
||||
func Reference(x interface{}) *interface{} {
|
||||
var y interface{}
|
||||
rv := reflect.ValueOf(x)
|
||||
if rv.Kind() == reflect.Ptr {
|
||||
return Reference(rv.Elem().Interface())
|
||||
}
|
||||
if rv.Kind() != reflect.Invalid {
|
||||
y = rv.Interface()
|
||||
return &y
|
||||
}
|
||||
return &x
|
||||
}
|
||||
|
||||
// Unmarshal decodes a YAML or JSON value into the specified type.
|
||||
func Unmarshal(bs []byte, v interface{}) error {
|
||||
bs, err := yaml.YAMLToJSON(bs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return UnmarshalJSON(bs, v)
|
||||
}
|
||||
113
vendor/github.com/open-policy-agent/opa/util/queue.go
generated
vendored
Normal file
113
vendor/github.com/open-policy-agent/opa/util/queue.go
generated
vendored
Normal file
@@ -0,0 +1,113 @@
|
||||
// Copyright 2017 The OPA Authors. All rights reserved.
|
||||
// Use of this source code is governed by an Apache2
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package util
|
||||
|
||||
// LIFO represents a simple LIFO queue.
|
||||
type LIFO struct {
|
||||
top *queueNode
|
||||
size int
|
||||
}
|
||||
|
||||
type queueNode struct {
|
||||
v T
|
||||
next *queueNode
|
||||
}
|
||||
|
||||
// NewLIFO returns a new LIFO queue containing elements ts starting with the
|
||||
// left-most argument at the bottom.
|
||||
func NewLIFO(ts ...T) *LIFO {
|
||||
s := &LIFO{}
|
||||
for i := range ts {
|
||||
s.Push(ts[i])
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// Push adds a new element onto the LIFO.
|
||||
func (s *LIFO) Push(t T) {
|
||||
node := &queueNode{v: t, next: s.top}
|
||||
s.top = node
|
||||
s.size++
|
||||
}
|
||||
|
||||
// Peek returns the top of the LIFO. If LIFO is empty, returns nil, false.
|
||||
func (s *LIFO) Peek() (T, bool) {
|
||||
if s.top == nil {
|
||||
return nil, false
|
||||
}
|
||||
return s.top.v, true
|
||||
}
|
||||
|
||||
// Pop returns the top of the LIFO and removes it. If LIFO is empty returns
|
||||
// nil, false.
|
||||
func (s *LIFO) Pop() (T, bool) {
|
||||
if s.top == nil {
|
||||
return nil, false
|
||||
}
|
||||
node := s.top
|
||||
s.top = node.next
|
||||
s.size--
|
||||
return node.v, true
|
||||
}
|
||||
|
||||
// Size returns the size of the LIFO.
|
||||
func (s *LIFO) Size() int {
|
||||
return s.size
|
||||
}
|
||||
|
||||
// FIFO represents a simple FIFO queue.
|
||||
type FIFO struct {
|
||||
front *queueNode
|
||||
back *queueNode
|
||||
size int
|
||||
}
|
||||
|
||||
// NewFIFO returns a new FIFO queue containing elements ts starting with the
|
||||
// left-most argument at the front.
|
||||
func NewFIFO(ts ...T) *FIFO {
|
||||
s := &FIFO{}
|
||||
for i := range ts {
|
||||
s.Push(ts[i])
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// Push adds a new element onto the LIFO.
|
||||
func (s *FIFO) Push(t T) {
|
||||
node := &queueNode{v: t, next: nil}
|
||||
if s.front == nil {
|
||||
s.front = node
|
||||
s.back = node
|
||||
} else {
|
||||
s.back.next = node
|
||||
s.back = node
|
||||
}
|
||||
s.size++
|
||||
}
|
||||
|
||||
// Peek returns the top of the LIFO. If LIFO is empty, returns nil, false.
|
||||
func (s *FIFO) Peek() (T, bool) {
|
||||
if s.front == nil {
|
||||
return nil, false
|
||||
}
|
||||
return s.front.v, true
|
||||
}
|
||||
|
||||
// Pop returns the top of the LIFO and removes it. If LIFO is empty returns
|
||||
// nil, false.
|
||||
func (s *FIFO) Pop() (T, bool) {
|
||||
if s.front == nil {
|
||||
return nil, false
|
||||
}
|
||||
node := s.front
|
||||
s.front = node.next
|
||||
s.size--
|
||||
return node.v, true
|
||||
}
|
||||
|
||||
// Size returns the size of the LIFO.
|
||||
func (s *FIFO) Size() int {
|
||||
return s.size
|
||||
}
|
||||
Reference in New Issue
Block a user