mirror of
https://github.com/go-sylixos/elvish.git
synced 2024-12-13 18:07:51 +08:00
Update github.com/xiaq/persistent.
This commit is contained in:
parent
99921ea222
commit
1cbef84551
2
Gopkg.lock
generated
2
Gopkg.lock
generated
|
@ -23,7 +23,7 @@
|
|||
branch = "master"
|
||||
name = "github.com/xiaq/persistent"
|
||||
packages = ["hash","hashmap","vector"]
|
||||
revision = "3621ae09791316ac331a0cc984c6a1cbf9d4eabf"
|
||||
revision = "8f8f5eb31fdd1340ad5abdf018d07448c6a768d7"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
|
|
80
vendor/github.com/xiaq/persistent/hashmap/hashmap.go
generated
vendored
80
vendor/github.com/xiaq/persistent/hashmap/hashmap.go
generated
vendored
|
@ -1,6 +1,15 @@
|
|||
// Package hashmap implements persistent hashmap.
|
||||
package hashmap
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
const (
|
||||
chunkBits = 5
|
||||
nodeCap = 1 << chunkBits
|
||||
|
@ -13,11 +22,12 @@ type Equal func(k1, k2 interface{}) bool
|
|||
// Hash is the type of a function that returns the hash code of a key.
|
||||
type Hash func(k interface{}) uint32
|
||||
|
||||
// HashMap is a persistent associative data structure mapping keys to values. It
|
||||
// Map is a persistent associative data structure mapping keys to values. It
|
||||
// is immutable, and supports near-O(1) operations to create modified version of
|
||||
// the hashmap that shares the underlying data structure, making it suitable for
|
||||
// concurrent access.
|
||||
type HashMap interface {
|
||||
type Map interface {
|
||||
json.Marshaler
|
||||
// Len returns the length of the hashmap.
|
||||
Len() int
|
||||
// Get returns whether there is a value associated with the given key, and
|
||||
|
@ -25,10 +35,10 @@ type HashMap interface {
|
|||
Get(k interface{}) (interface{}, bool)
|
||||
// Assoc returns an almost identical hashmap, with the given key associated
|
||||
// with the given value.
|
||||
Assoc(k, v interface{}) HashMap
|
||||
Assoc(k, v interface{}) Map
|
||||
// Without returns an almost identical hashmap, with the given key
|
||||
// associated with no value.
|
||||
Without(k interface{}) HashMap
|
||||
Without(k interface{}) Map
|
||||
// Iterator returns an iterator over the map.
|
||||
Iterator() Iterator
|
||||
}
|
||||
|
@ -49,8 +59,8 @@ type Iterator interface {
|
|||
}
|
||||
|
||||
// New takes an equality function and a hash function, and returns an empty
|
||||
// HashMap.
|
||||
func New(e Equal, h Hash) HashMap {
|
||||
// Map.
|
||||
func New(e Equal, h Hash) Map {
|
||||
return &hashMap{0, emptyBitmapNode, e, h}
|
||||
}
|
||||
|
||||
|
@ -69,7 +79,7 @@ func (m *hashMap) Get(k interface{}) (interface{}, bool) {
|
|||
return m.root.find(0, m.hash(k), k, m.equal)
|
||||
}
|
||||
|
||||
func (m *hashMap) Assoc(k, v interface{}) HashMap {
|
||||
func (m *hashMap) Assoc(k, v interface{}) Map {
|
||||
newRoot, added := m.root.assoc(0, m.hash(k), k, v, m.hash, m.equal)
|
||||
newCount := m.count
|
||||
if added {
|
||||
|
@ -78,7 +88,7 @@ func (m *hashMap) Assoc(k, v interface{}) HashMap {
|
|||
return &hashMap{newCount, newRoot, m.equal, m.hash}
|
||||
}
|
||||
|
||||
func (m *hashMap) Without(k interface{}) HashMap {
|
||||
func (m *hashMap) Without(k interface{}) Map {
|
||||
newRoot, deleted := m.root.without(0, m.hash(k), k, m.equal)
|
||||
newCount := m.count
|
||||
if deleted {
|
||||
|
@ -91,6 +101,60 @@ func (m *hashMap) Iterator() Iterator {
|
|||
return m.root.iterator()
|
||||
}
|
||||
|
||||
func (m *hashMap) MarshalJSON() ([]byte, error) {
|
||||
var buf bytes.Buffer
|
||||
buf.WriteByte('{')
|
||||
first := true
|
||||
for it := m.Iterator(); it.HasElem(); it.Next() {
|
||||
if first {
|
||||
first = false
|
||||
} else {
|
||||
buf.WriteByte(',')
|
||||
}
|
||||
k, v := it.Elem()
|
||||
kString, err := convertKey(k)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
kBytes, err := json.Marshal(kString)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
vBytes, err := json.Marshal(v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
buf.Write(kBytes)
|
||||
buf.WriteByte(':')
|
||||
buf.Write(vBytes)
|
||||
}
|
||||
buf.WriteByte('}')
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
// convertKey converts a map key to a string. The implementation matches the
|
||||
// behavior of how json.Marshal encodes keys of the builtin map type.
|
||||
func convertKey(k interface{}) (string, error) {
|
||||
kref := reflect.ValueOf(k)
|
||||
if kref.Kind() == reflect.String {
|
||||
return kref.String(), nil
|
||||
}
|
||||
if t, ok := k.(encoding.TextMarshaler); ok {
|
||||
b2, err := t.MarshalText()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(b2), nil
|
||||
}
|
||||
switch kref.Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
return strconv.FormatInt(kref.Int(), 10), nil
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||
return strconv.FormatUint(kref.Uint(), 10), nil
|
||||
}
|
||||
return "", fmt.Errorf("unsupported key type %T", k)
|
||||
}
|
||||
|
||||
// node is an interface for all nodes in the hash map tree.
|
||||
type node interface {
|
||||
// assoc adds a new pair of key and value. It returns the new node, and
|
||||
|
|
58
vendor/github.com/xiaq/persistent/hashmap/hashmap_test.go
generated
vendored
58
vendor/github.com/xiaq/persistent/hashmap/hashmap_test.go
generated
vendored
|
@ -1,7 +1,6 @@
|
|||
package hashmap
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
@ -35,18 +34,13 @@ type anotherTestKey uint32
|
|||
|
||||
func equalFunc(k1, k2 interface{}) bool {
|
||||
switch k1 := k1.(type) {
|
||||
case uint32:
|
||||
return k1 == k2
|
||||
case string:
|
||||
s2, ok := k2.(string)
|
||||
return ok && k1 == s2
|
||||
case testKey:
|
||||
t2, ok := k2.(testKey)
|
||||
return ok && k1 == t2
|
||||
case anotherTestKey:
|
||||
return false
|
||||
default:
|
||||
panic(fmt.Errorf("unknown key type %T", k1))
|
||||
return k1 == k2
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -63,7 +57,7 @@ func hashFunc(k interface{}) uint32 {
|
|||
case anotherTestKey:
|
||||
return uint32(k)
|
||||
default:
|
||||
panic(fmt.Errorf("unknown key type %T", k))
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -152,9 +146,45 @@ func TestHashMapSmallRandom(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
// testHashMapWithRefEntries tests the operations of a HashMap. It uses the
|
||||
// supplied list of entries to build the hash map, and then test all its
|
||||
// operations.
|
||||
var marshalJSONTests = []struct {
|
||||
in Map
|
||||
wantOut string
|
||||
wantErr bool
|
||||
}{
|
||||
{makeHashMap(uint32(1), "a", "2", "b"), `{"1":"a","2":"b"}`, false},
|
||||
// Invalid key type
|
||||
{makeHashMap([]interface{}{}, "x"), "", true},
|
||||
}
|
||||
|
||||
func TestMarshalJSON(t *testing.T) {
|
||||
for i, test := range marshalJSONTests {
|
||||
out, err := test.in.MarshalJSON()
|
||||
if string(out) != test.wantOut {
|
||||
t.Errorf("m%d.MarshalJSON -> out %s, want %s", i, out, test.wantOut)
|
||||
}
|
||||
if (err != nil) != test.wantErr {
|
||||
var wantErr string
|
||||
if test.wantErr {
|
||||
wantErr = "non-nil"
|
||||
} else {
|
||||
wantErr = "nil"
|
||||
}
|
||||
t.Errorf("m%d.MarshalJSON -> err %v, want %s", i, err, wantErr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func makeHashMap(data ...interface{}) Map {
|
||||
m := empty
|
||||
for i := 0; i+1 < len(data); i += 2 {
|
||||
k, v := data[i], data[i+1]
|
||||
m = m.Assoc(k, v)
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// testHashMapWithRefEntries tests the operations of a Map. It uses the supplied
|
||||
// list of entries to build the map, and then test all its operations.
|
||||
func testHashMapWithRefEntries(t *testing.T, refEntries []refEntry) {
|
||||
m := empty
|
||||
// Len of Empty should be 0.
|
||||
|
@ -210,7 +240,7 @@ func testHashMapWithRefEntries(t *testing.T, refEntries []refEntry) {
|
|||
}
|
||||
}
|
||||
|
||||
func testMapContent(t *testing.T, m HashMap, ref map[testKey]string) {
|
||||
func testMapContent(t *testing.T, m Map, ref map[testKey]string) {
|
||||
for k, v := range ref {
|
||||
got, in := m.Get(k)
|
||||
if !in {
|
||||
|
@ -222,7 +252,7 @@ func testMapContent(t *testing.T, m HashMap, ref map[testKey]string) {
|
|||
}
|
||||
}
|
||||
|
||||
func testIterator(t *testing.T, m HashMap, ref map[testKey]string) {
|
||||
func testIterator(t *testing.T, m Map, ref map[testKey]string) {
|
||||
ref2 := map[interface{}]interface{}{}
|
||||
for k, v := range ref {
|
||||
ref2[k] = v
|
||||
|
@ -258,7 +288,7 @@ func BenchmarkSequentialConsPersistent1(b *testing.B) { sequentialCons(b.N, N1)
|
|||
func BenchmarkSequentialConsPersistent2(b *testing.B) { sequentialCons(b.N, N2) }
|
||||
func BenchmarkSequentialConsPersistent3(b *testing.B) { sequentialCons(b.N, N3) }
|
||||
|
||||
// sequentialCons starts with an empty HashMap and adds elements 0...n-1 to the
|
||||
// sequentialCons starts with an empty hash map and adds elements 0...n-1 to the
|
||||
// map, using the same value as the key, repeating for N times.
|
||||
func sequentialCons(N int, n uint32) {
|
||||
for r := 0; r < N; r++ {
|
||||
|
|
47
vendor/github.com/xiaq/persistent/vector/vector.go
generated
vendored
47
vendor/github.com/xiaq/persistent/vector/vector.go
generated
vendored
|
@ -1,6 +1,12 @@
|
|||
// Package vector implements persistent vector.
|
||||
package vector
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
const (
|
||||
chunkBits = 5
|
||||
nodeSize = 1 << chunkBits
|
||||
|
@ -15,6 +21,7 @@ const (
|
|||
// vector that shares the underlying data structure, making it suitable for
|
||||
// concurrent access. The empty value is a valid empty vector.
|
||||
type Vector interface {
|
||||
json.Marshaler
|
||||
// Len returns the length of the vector.
|
||||
Len() int
|
||||
// Nth returns the i-th element of the vector. It returns nil if the index
|
||||
|
@ -244,6 +251,14 @@ func (v *vector) SubVector(begin, end int) Vector {
|
|||
return &subVector{v, begin, end}
|
||||
}
|
||||
|
||||
func (v *vector) Iterator() Iterator {
|
||||
return newIterator(v)
|
||||
}
|
||||
|
||||
func (v *vector) MarshalJSON() ([]byte, error) {
|
||||
return marshalJSON(v.Iterator())
|
||||
}
|
||||
|
||||
type subVector struct {
|
||||
v *vector
|
||||
begin int
|
||||
|
@ -293,8 +308,8 @@ func (s *subVector) Iterator() Iterator {
|
|||
return newIteratorWithRange(s.v, s.begin, s.end)
|
||||
}
|
||||
|
||||
func (v *vector) Iterator() Iterator {
|
||||
return newIterator(v)
|
||||
func (s *subVector) MarshalJSON() ([]byte, error) {
|
||||
return marshalJSON(s.Iterator())
|
||||
}
|
||||
|
||||
type iterator struct {
|
||||
|
@ -366,3 +381,31 @@ func (it *iterator) Next() {
|
|||
}
|
||||
it.index++
|
||||
}
|
||||
|
||||
type marshalError struct {
|
||||
index int
|
||||
cause error
|
||||
}
|
||||
|
||||
func (err *marshalError) Error() string {
|
||||
return fmt.Sprintf("element %d: %s", err.index, err.cause)
|
||||
}
|
||||
|
||||
func marshalJSON(it Iterator) ([]byte, error) {
|
||||
var buf bytes.Buffer
|
||||
buf.WriteByte('[')
|
||||
index := 0
|
||||
for ; it.HasElem(); it.Next() {
|
||||
if index > 0 {
|
||||
buf.WriteByte(',')
|
||||
}
|
||||
elemBytes, err := json.Marshal(it.Elem())
|
||||
if err != nil {
|
||||
return nil, &marshalError{index, err}
|
||||
}
|
||||
buf.Write(elemBytes)
|
||||
index++
|
||||
}
|
||||
buf.WriteByte(']')
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
|
38
vendor/github.com/xiaq/persistent/vector/vector_test.go
generated
vendored
38
vendor/github.com/xiaq/persistent/vector/vector_test.go
generated
vendored
|
@ -1,6 +1,7 @@
|
|||
package vector
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"math/rand"
|
||||
"testing"
|
||||
"time"
|
||||
|
@ -223,6 +224,43 @@ func eqVector(v1, v2 Vector) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
var marshalJSONTests = []struct {
|
||||
in Vector
|
||||
wantOut string
|
||||
wantErr error
|
||||
}{
|
||||
{makeVector("1", 2, nil), `["1",2,null]`, nil},
|
||||
{makeVector("1", makeVector(2)), `["1",[2]]`, nil},
|
||||
{makeVector(0, 1, 2, 3, 4, 5).SubVector(1, 5), `[1,2,3,4]`, nil},
|
||||
{makeVector(0, func() {}), "", errors.New("element 1: json: unsupported type: func()")},
|
||||
}
|
||||
|
||||
func TestMarshalJSON(t *testing.T) {
|
||||
for i, test := range marshalJSONTests {
|
||||
out, err := test.in.MarshalJSON()
|
||||
if string(out) != test.wantOut {
|
||||
t.Errorf("v%d.MarshalJSON -> out %q, want %q", i, out, test.wantOut)
|
||||
}
|
||||
if err == nil || test.wantErr == nil {
|
||||
if err != test.wantErr {
|
||||
t.Errorf("v%d.MarshalJSON -> err %v, want %v", i, err, test.wantErr)
|
||||
}
|
||||
} else {
|
||||
if err.Error() != test.wantErr.Error() {
|
||||
t.Errorf("v%d.MarshalJSON -> err %v, want %v", i, err, test.wantErr)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func makeVector(elements ...interface{}) Vector {
|
||||
v := Empty
|
||||
for _, element := range elements {
|
||||
v = v.Cons(element)
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
func BenchmarkConsNative1(b *testing.B) { benchmarkNativeAppend(b, N1) }
|
||||
func BenchmarkConsNative2(b *testing.B) { benchmarkNativeAppend(b, N2) }
|
||||
func BenchmarkConsNative3(b *testing.B) { benchmarkNativeAppend(b, N3) }
|
||||
|
|
Loading…
Reference in New Issue
Block a user