mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-01-24 22:08:58 -05:00
158 lines
3.4 KiB
Go
158 lines
3.4 KiB
Go
// 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
|
|
}
|