mirror of
https://github.com/go-sylixos/elvish.git
synced 2024-12-12 17:27:50 +08:00
Add Hash to Value interface.
This commit is contained in:
parent
508b41b914
commit
4f884b6dbf
|
@ -8,9 +8,11 @@ import (
|
|||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
"unsafe"
|
||||
|
||||
"github.com/elves/elvish/edit/ui"
|
||||
"github.com/elves/elvish/eval"
|
||||
"github.com/xiaq/persistent/hash"
|
||||
)
|
||||
|
||||
// This file implements types and functions for interactions with the
|
||||
|
@ -41,6 +43,10 @@ func (bf *BuiltinFn) Equal(a interface{}) bool {
|
|||
return bf == a
|
||||
}
|
||||
|
||||
func (bf *BuiltinFn) Hash() uint32 {
|
||||
return hash.Pointer(unsafe.Pointer(bf))
|
||||
}
|
||||
|
||||
// Repr returns the representation of a builtin function as a variable name.
|
||||
func (bf *BuiltinFn) Repr(int) string {
|
||||
return "$" + bf.name
|
||||
|
|
|
@ -2,8 +2,10 @@ package edit
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"unsafe"
|
||||
|
||||
"github.com/elves/elvish/eval"
|
||||
"github.com/xiaq/persistent/hash"
|
||||
)
|
||||
|
||||
// For an overview of completion, see the comment in completers.go.
|
||||
|
@ -123,6 +125,10 @@ func (bac *builtinArgCompleter) Equal(a interface{}) bool {
|
|||
return bac == a
|
||||
}
|
||||
|
||||
func (bac *builtinArgCompleter) Hash() uint32 {
|
||||
return hash.Pointer(unsafe.Pointer(bac))
|
||||
}
|
||||
|
||||
func (bac *builtinArgCompleter) Repr(int) string {
|
||||
return "$edit:&" + bac.name
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"github.com/elves/elvish/edit/ui"
|
||||
"github.com/elves/elvish/eval"
|
||||
"github.com/elves/elvish/parse"
|
||||
"github.com/xiaq/persistent/hash"
|
||||
)
|
||||
|
||||
func getBinding(mode string, k ui.Key) eval.CallableValue {
|
||||
|
@ -45,6 +46,17 @@ func (bt BindingTable) Equal(a interface{}) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
func (bt BindingTable) Hash() uint32 {
|
||||
h := hash.DJBInit
|
||||
for k, v := range bt.inner {
|
||||
// TODO(xiaq): Use a more efficient implementation to derive a hash from
|
||||
// ui.Key.
|
||||
h = hash.DJBCombine(h, hash.String(k.String()))
|
||||
h = hash.DJBCombine(h, v.Hash())
|
||||
}
|
||||
return h
|
||||
}
|
||||
|
||||
// Repr returns the representation of the binding table as if it were an
|
||||
// ordinary map.
|
||||
func (bt BindingTable) Repr(indent int) string {
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"github.com/elves/elvish/edit/ui"
|
||||
"github.com/elves/elvish/eval"
|
||||
"github.com/elves/elvish/parse"
|
||||
"github.com/xiaq/persistent/hash"
|
||||
)
|
||||
|
||||
type candidate struct {
|
||||
|
@ -29,10 +30,11 @@ func (cs rawCandidates) Swap(i, j int) { cs[i], cs[j] = cs[j], cs[i] }
|
|||
func (cs rawCandidates) Less(i, j int) bool { return cs[i].text() < cs[j].text() }
|
||||
|
||||
// plainCandidate is a minimal implementation of rawCandidate.
|
||||
type plainCandidate string
|
||||
type plainCandidate eval.String
|
||||
|
||||
func (plainCandidate) Kind() string { return "string" }
|
||||
func (p plainCandidate) Equal(a interface{}) bool { return p == a }
|
||||
func (p plainCandidate) Hash() uint32 { return hash.String(string(p)) }
|
||||
func (p plainCandidate) Repr(l int) string { return eval.String(p).Repr(l) }
|
||||
func (p plainCandidate) text() string { return string(p) }
|
||||
|
||||
|
@ -47,6 +49,7 @@ type noQuoteCandidate string
|
|||
|
||||
func (noQuoteCandidate) Kind() string { return "string" }
|
||||
func (nq noQuoteCandidate) Equal(a interface{}) bool { return nq == a }
|
||||
func (nq noQuoteCandidate) Hash() uint32 { return hash.String(string(nq)) }
|
||||
func (nq noQuoteCandidate) Repr(l int) string { return eval.String(nq).Repr(l) }
|
||||
func (nq noQuoteCandidate) text() string { return string(nq) }
|
||||
|
||||
|
@ -71,6 +74,15 @@ func (c *complexCandidate) Equal(a interface{}) bool {
|
|||
return ok && c.stem == rhs.stem && c.codeSuffix == rhs.codeSuffix && c.displaySuffix == rhs.displaySuffix && c.style.Eq(rhs.style)
|
||||
}
|
||||
|
||||
func (c *complexCandidate) Hash() uint32 {
|
||||
h := hash.DJBInit
|
||||
h = hash.DJBCombine(h, hash.String(c.stem))
|
||||
h = hash.DJBCombine(h, hash.String(c.codeSuffix))
|
||||
h = hash.DJBCombine(h, hash.String(c.displaySuffix))
|
||||
h = hash.DJBCombine(h, c.style.Hash())
|
||||
return h
|
||||
}
|
||||
|
||||
func (c *complexCandidate) Repr(indent int) string {
|
||||
// TODO(xiaq): Pretty-print when indent >= 0
|
||||
return fmt.Sprintf("(edit:complex-candidate %s &code-suffix=%s &display-suffix=%s style=%s)",
|
||||
|
|
|
@ -25,6 +25,12 @@ func (hv History) Equal(a interface{}) bool {
|
|||
return ok
|
||||
}
|
||||
|
||||
func (hv History) Hash() uint32 {
|
||||
// TODO(xiaq): Make a global registry of singleton hashes to avoid
|
||||
// collision.
|
||||
return 100
|
||||
}
|
||||
|
||||
func (hv History) Repr(int) string {
|
||||
return "$le:history"
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/elves/elvish/parse"
|
||||
"github.com/xiaq/persistent/hash"
|
||||
)
|
||||
|
||||
// Styled is a piece of text with style.
|
||||
|
@ -72,6 +73,13 @@ func (s *Styled) Equal(a interface{}) bool {
|
|||
return s.Text == rhs.Text && s.Styles.Eq(rhs.Styles)
|
||||
}
|
||||
|
||||
func (s *Styled) Hash() uint32 {
|
||||
h := hash.DJBInit
|
||||
h = hash.DJBCombine(h, hash.String(s.Text))
|
||||
h = hash.DJBCombine(h, s.Styles.Hash())
|
||||
return h
|
||||
}
|
||||
|
||||
func (s *Styled) String() string {
|
||||
return "\033[" + s.Styles.String() + "m" + s.Text + "\033[m"
|
||||
}
|
||||
|
@ -94,6 +102,14 @@ func (ss Styles) Eq(rhs Styles) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
func (ss Styles) Hash() uint32 {
|
||||
h := hash.DJBInit
|
||||
for _, s := range ss {
|
||||
h = hash.DJBCombine(h, hash.String(s))
|
||||
}
|
||||
return h
|
||||
}
|
||||
|
||||
func JoinStyles(so Styles, st ...Styles) Styles {
|
||||
for _, v := range st {
|
||||
so = append(so, v...)
|
||||
|
|
|
@ -11,6 +11,13 @@ func (b Bool) Equal(rhs interface{}) bool {
|
|||
return b == rhs
|
||||
}
|
||||
|
||||
func (b Bool) Hash() uint32 {
|
||||
if b {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (b Bool) Repr(int) string {
|
||||
if b {
|
||||
return "$true"
|
||||
|
|
|
@ -23,11 +23,13 @@ import (
|
|||
"syscall"
|
||||
"time"
|
||||
"unicode/utf8"
|
||||
"unsafe"
|
||||
|
||||
"github.com/elves/elvish/parse"
|
||||
"github.com/elves/elvish/store/storedefs"
|
||||
"github.com/elves/elvish/sys"
|
||||
"github.com/elves/elvish/util"
|
||||
"github.com/xiaq/persistent/hash"
|
||||
)
|
||||
|
||||
var builtinFns []*BuiltinFn
|
||||
|
@ -52,6 +54,10 @@ func (b *BuiltinFn) Equal(rhs interface{}) bool {
|
|||
return b == rhs
|
||||
}
|
||||
|
||||
func (b *BuiltinFn) Hash() uint32 {
|
||||
return hash.Pointer(unsafe.Pointer(b))
|
||||
}
|
||||
|
||||
// Repr returns an opaque representation "<builtin xxx>".
|
||||
func (b *BuiltinFn) Repr(int) string {
|
||||
return "<builtin " + b.Name + ">"
|
||||
|
|
|
@ -3,6 +3,9 @@ package eval
|
|||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"unsafe"
|
||||
|
||||
"github.com/xiaq/persistent/hash"
|
||||
)
|
||||
|
||||
// ErrArityMismatch is thrown by a closure when the number of arguments the user
|
||||
|
@ -36,6 +39,10 @@ func (c *Closure) Equal(rhs interface{}) bool {
|
|||
return c == rhs
|
||||
}
|
||||
|
||||
func (c *Closure) Hash() uint32 {
|
||||
return hash.Pointer(unsafe.Pointer(c))
|
||||
}
|
||||
|
||||
// Repr returns an opaque representation "<closure 0x23333333>".
|
||||
func (c *Closure) Repr(int) string {
|
||||
return fmt.Sprintf("<closure %p>", c)
|
||||
|
|
|
@ -5,6 +5,8 @@ import (
|
|||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/xiaq/persistent/hash"
|
||||
)
|
||||
|
||||
// Errors
|
||||
|
@ -70,6 +72,14 @@ func (epl *EnvPathList) Equal(a interface{}) bool {
|
|||
return epl == a || eqListLike(epl, a)
|
||||
}
|
||||
|
||||
func (epl *EnvPathList) Hash() uint32 {
|
||||
h := hash.DJBInit
|
||||
for _, p := range epl.get() {
|
||||
h = hash.DJBCombine(h, hash.String(p))
|
||||
}
|
||||
return h
|
||||
}
|
||||
|
||||
// Repr returns the representation of an EnvPathList, as if it were an ordinary
|
||||
// list.
|
||||
func (epl *EnvPathList) Repr(indent int) string {
|
||||
|
|
|
@ -6,9 +6,11 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"github.com/elves/elvish/parse"
|
||||
"github.com/elves/elvish/util"
|
||||
"github.com/xiaq/persistent/hash"
|
||||
)
|
||||
|
||||
// Exception represents an elvish exception. It is both a Value accessible to
|
||||
|
@ -76,6 +78,10 @@ func (exc *Exception) Equal(rhs interface{}) bool {
|
|||
return exc == rhs
|
||||
}
|
||||
|
||||
func (exc *Exception) Hash() uint32 {
|
||||
return hash.Pointer(unsafe.Pointer(exc))
|
||||
}
|
||||
|
||||
func (exc *Exception) Bool() bool {
|
||||
return exc.Cause == nil
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
|
||||
"github.com/elves/elvish/parse"
|
||||
"github.com/elves/elvish/util"
|
||||
"github.com/xiaq/persistent/hash"
|
||||
)
|
||||
|
||||
// FdNil is a special impossible fd value used for "close fd" in
|
||||
|
@ -32,6 +33,10 @@ func (e ExternalCmd) Equal(a interface{}) bool {
|
|||
return e == a
|
||||
}
|
||||
|
||||
func (e ExternalCmd) Hash() uint32 {
|
||||
return hash.String(e.Name)
|
||||
}
|
||||
|
||||
func (e ExternalCmd) Repr(int) string {
|
||||
return "<external " + parse.Quote(e.Name) + ">"
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"os"
|
||||
|
||||
"github.com/elves/elvish/parse"
|
||||
"github.com/xiaq/persistent/hash"
|
||||
)
|
||||
|
||||
type File struct {
|
||||
|
@ -21,6 +22,10 @@ func (f File) Equal(rhs interface{}) bool {
|
|||
return f == rhs
|
||||
}
|
||||
|
||||
func (f File) Hash() uint32 {
|
||||
return hash.UIntPtr(f.inner.Fd())
|
||||
}
|
||||
|
||||
func (f File) Repr(int) string {
|
||||
return fmt.Sprintf("<file{%s %p}>", parse.Quote(f.inner.Name()), f.inner)
|
||||
}
|
||||
|
|
|
@ -64,6 +64,11 @@ func (gp GlobPattern) Equal(a interface{}) bool {
|
|||
return reflect.DeepEqual(gp, a)
|
||||
}
|
||||
|
||||
func (gp GlobPattern) Hash() uint32 {
|
||||
// GlobPattern is not a first-class value.
|
||||
return 0
|
||||
}
|
||||
|
||||
func (gp GlobPattern) Repr(int) string {
|
||||
return fmt.Sprintf("<GlobPattern%v>", gp)
|
||||
}
|
||||
|
|
|
@ -50,6 +50,10 @@ func (l List) Equal(rhs interface{}) bool {
|
|||
return eqListLike(l, rhs)
|
||||
}
|
||||
|
||||
func (l List) Hash() uint32 {
|
||||
return hashListLike(l)
|
||||
}
|
||||
|
||||
func (l List) Repr(indent int) string {
|
||||
var b ListReprBuilder
|
||||
b.Indent = indent
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package eval
|
||||
|
||||
import "github.com/xiaq/persistent/hash"
|
||||
|
||||
type ListLike interface {
|
||||
Lener
|
||||
Iterable
|
||||
|
@ -16,3 +18,12 @@ func eqListLike(lhs ListLike, r interface{}) bool {
|
|||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func hashListLike(l ListLike) uint32 {
|
||||
h := hash.DJBInit
|
||||
l.Iterate(func(v Value) bool {
|
||||
// h = hash.DJBCombine(h, v.Hash())
|
||||
return true
|
||||
})
|
||||
return h
|
||||
}
|
||||
|
|
|
@ -30,6 +30,10 @@ func (m Map) Equal(a interface{}) bool {
|
|||
return m == a || eqMapLike(m, a)
|
||||
}
|
||||
|
||||
func (m Map) Hash() uint32 {
|
||||
return hashMapLike(m)
|
||||
}
|
||||
|
||||
func (m Map) MarshalJSON() ([]byte, error) {
|
||||
// XXX Not the most efficient way.
|
||||
mm := map[string]Value{}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package eval
|
||||
|
||||
import "github.com/xiaq/persistent/hash"
|
||||
|
||||
type MapLike interface {
|
||||
Lener
|
||||
IndexOneer
|
||||
|
@ -26,3 +28,13 @@ func eqMapLike(lhs MapLike, a interface{}) bool {
|
|||
})
|
||||
return eq
|
||||
}
|
||||
|
||||
func hashMapLike(m MapLike) uint32 {
|
||||
h := hash.DJBInit
|
||||
m.IteratePair(func(k, v Value) bool {
|
||||
// h = hash.DJBCombine(h, k.Hash())
|
||||
// h = hash.DJBCombine(h, v.Hash())
|
||||
return true
|
||||
})
|
||||
return h
|
||||
}
|
||||
|
|
|
@ -3,6 +3,8 @@ package eval
|
|||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/xiaq/persistent/hash"
|
||||
)
|
||||
|
||||
type Pipe struct {
|
||||
|
@ -19,6 +21,13 @@ func (p Pipe) Equal(rhs interface{}) bool {
|
|||
return p == rhs
|
||||
}
|
||||
|
||||
func (p Pipe) Hash() uint32 {
|
||||
h := hash.DJBInit
|
||||
h = hash.DJBCombine(h, hash.UIntPtr(p.r.Fd()))
|
||||
h = hash.DJBCombine(h, hash.UIntPtr(p.w.Fd()))
|
||||
return h
|
||||
}
|
||||
|
||||
func (p Pipe) Repr(int) string {
|
||||
return fmt.Sprintf("<pipe{%v %v}>", p.r.Fd(), p.w.Fd())
|
||||
}
|
||||
|
|
|
@ -4,6 +4,8 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
||||
"github.com/xiaq/persistent/hash"
|
||||
)
|
||||
|
||||
var ErrOnlyStrOrRat = errors.New("only str or rat may be converted to rat")
|
||||
|
@ -30,6 +32,11 @@ func (r Rat) Equal(a interface{}) bool {
|
|||
return r.b.Cmp(r2.b) == 0
|
||||
}
|
||||
|
||||
func (r Rat) Hash() uint32 {
|
||||
// TODO(xiaq): Use a more efficient implementation.
|
||||
return hash.String(r.String())
|
||||
}
|
||||
|
||||
func (r Rat) Repr(int) string {
|
||||
return "(rat " + r.String() + ")"
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"unicode/utf8"
|
||||
|
||||
"github.com/elves/elvish/parse"
|
||||
"github.com/xiaq/persistent/hash"
|
||||
)
|
||||
|
||||
// String is just a string.
|
||||
|
@ -26,6 +27,10 @@ func (s String) Equal(rhs interface{}) bool {
|
|||
return s == rhs
|
||||
}
|
||||
|
||||
func (s String) Hash() uint32 {
|
||||
return hash.String(string(s))
|
||||
}
|
||||
|
||||
func (s String) String() string {
|
||||
return string(s)
|
||||
}
|
||||
|
|
|
@ -31,6 +31,10 @@ func (s *Struct) Equal(rhs interface{}) bool {
|
|||
return s == rhs || eqMapLike(s, rhs)
|
||||
}
|
||||
|
||||
func (s *Struct) Hash() uint32 {
|
||||
return hashMapLike(s)
|
||||
}
|
||||
|
||||
func (s *Struct) Repr(indent int) string {
|
||||
var builder MapReprBuilder
|
||||
builder.Indent = indent
|
||||
|
|
|
@ -17,6 +17,7 @@ const (
|
|||
type Value interface {
|
||||
Kinder
|
||||
Equaler
|
||||
Hasher
|
||||
Reprer
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user