Movatterモバイル変換


[0]ホーム

URL:


deephash

package
v1.92.3Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 16, 2025 License:BSD-3-ClauseImports:11Imported by:12

Details

Repository

github.com/tailscale/tailscale

Links

Documentation

Overview

Package deephash hashes a Go value recursively, in a predictable order,without looping. The hash is only valid within the lifetime of a program.Users should not store the hash on disk or send it over the network.The hash is sufficiently strong and unique such thatHash(&x) == Hash(&y) is an appropriate replacement for x == y.

The definition of equality is identical to reflect.DeepEqual except:

  • Floating-point values are compared based on the raw bits,which means that NaNs (with the same bit pattern) are treated as equal.
  • time.Time are compared based on whether they are the same instant in timeand also in the same zone offset. Monotonic measurements and zone namesare ignored as part of the hash.
  • netip.Addr are compared based on a shallow comparison of the struct.

WARNING: This package, like most of the tailscale.com Go module,should be considered Tailscale-internal; we make no API promises.

Cycle detection

This package correctly handles cycles in the value graph,but in a way that is potentially pathological in some situations.

The algorithm for cycle detection operates bypushing a pointer onto a stack whenever deephash is visiting a pointer andpopping the pointer from the stack after deephash is leaving the pointer.Before visiting a new pointer, deephash checks whether it has already beenvisited on the pointer stack. If so, it hashes the index of the pointeron the stack and avoids visiting the pointer.

This algorithm is guaranteed to detect cycles, but may expand pointersmore often than a potential alternate algorithm that remembers all pointersever visited in a map. The current algorithm uses O(D) memory, where Dis the maximum depth of the recursion, while the alternate algorithmwould use O(P) memory where P is all pointers ever seen, which can be a lot,and most of which may have nothing to do with cycles.Also, the alternate algorithm has to deal with challenges of producingdeterministic results when pointers are visited in non-deterministic wayssuch as when iterating through a Go map. The stack-based algorithm avoidsthis challenge since the stack is always deterministic regardless ofnon-deterministic iteration order of Go maps.

To concretely see how this algorithm can be pathological,consider the following data structure:

var big *Item = ... // some large data structure that is slow to hashvar manyBig []*Itemfor i := range 1000 {manyBig = append(manyBig, &big)}deephash.Hash(manyBig)

Here, the manyBig data structure is not even cyclic.We have the same big *Item being stored multiple times in a []*Item.When deephash hashes []*Item, it hashes each individual *Itemnot realizing that it had just done the computation earlier.To avoid the pathological situation, Item should implementSelfHasher andmemoize attempts to hash itself.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

funcHasherForTypeadded inv1.30.0

func HasherForType[Tany](opts ...Option) func(*T)Sum

HasherForType returns a hash that is specialized for the provided type.

HasherForType panics if the opts are invalid for the provided type.

Currently, at most one option can be provided (IncludeFields orExcludeFields) and its type must match the type of T. Those restrictions maybe removed in the future, along with documentation about their precedencewhen combined.

funcUpdate

func Update[Tany](last *Sum, v *T) (changedbool)

Update sets last to the hash of v and reports whether its value changed.

Types

typeHasheradded inv1.60.0

type Hasher struct {// contains filtered or unexported fields}

Hasher is a value passed to [SelfHasher.Hash] that allow implementationsto hash themselves in a structured manner.

func (Hasher)HashBytesadded inv1.60.0

func (hHasher) HashBytes(b []byte)

HashBytes hashes a sequence of bytes b.The length of b is not explicitly hashed.

func (Hasher)HashStringadded inv1.60.0

func (hHasher) HashString(sstring)

HashString hashes the string data of sThe length of s is not explicitly hashed.

func (Hasher)HashSumadded inv1.60.0

func (hHasher) HashSum(sSum)

HashSum hashes aSum.

func (Hasher)HashUint16added inv1.60.0

func (hHasher) HashUint16(nuint16)

HashUint16 hashes a uint16.

func (Hasher)HashUint32added inv1.60.0

func (hHasher) HashUint32(nuint32)

HashUint32 hashes a uint32.

func (Hasher)HashUint64added inv1.60.0

func (hHasher) HashUint64(nuint64)

HashUint64 hashes a uint64.

func (Hasher)HashUint8added inv1.60.0

func (hHasher) HashUint8(nuint8)

HashUint8 hashes a uint8.

typeOptionadded inv1.50.0

type Option interface {// contains filtered or unexported methods}

Option is an optional argument to HasherForType.

funcExcludeFieldsadded inv1.50.0

func ExcludeFields[Tany](fields ...string)Option

ExcludeFields returns an option that modifies the hashing for T to includeall struct fields of T except those provided in fields.

T must be a struct type, and must match the type of the value passed toHasherForType.

funcIncludeFieldsadded inv1.50.0

func IncludeFields[Tany](fields ...string)Option

IncludeFields returns an option that modifies the hashing for T to onlyinclude the named struct fields.

T must be a struct type, and must match the type of the value passed toHasherForType.

typeSelfHasheradded inv1.60.0

type SelfHasher interface {Hash(Hasher)}

SelfHasher is implemented by types that can compute their own hashby writing values through the providedHasher parameter.Implementations must not leak the providedHasher.

If the implementation of SelfHasher recursively callsdeephash.Hash,then infinite recursion is quite likely to occur.To avoid this, use a type definition to drop methods before callingdeephash.Hash:

func (v *MyType) Hash(h deephash.Hasher) {v.hashMu.Lock()defer v.hashMu.Unlock()if v.dirtyHash {type MyTypeWithoutMethods MyType // type define MyType to drop Hash methodv.dirtyHash = false              // clear out dirty bit to avoid hashing over itv.hashSum = deephash.Sum{}       // clear out hashSum to avoid hashing over itv.hashSum = deephash.Hash((*MyTypeWithoutMethods)(v))}h.HashSum(v.hashSum)}

In the above example, we acquire a lock since it is possible that deephashis called in a concurrent manner, which implies that MyType.Hash may alsobe called in a concurrent manner. Whether this lock is necessary isapplication-dependent and left as an exercise to the reader.Also, the example assumes that dirtyHash is set elsewhere by applicationlogic whenever a mutation is made to MyType that would alter the hash.

typeSum

type Sum struct {// contains filtered or unexported fields}

Sum is an opaque checksum type that is comparable.

funcHash

func Hash[Tany](v *T)Sum

Hash returns the hash of v.

func (Sum)AppendToadded inv1.32.0

func (sSum) AppendTo(b []byte) []byte

AppendTo appends the string encoding of this sum (as returned by the Stringmethod) to the provided byte slice and returns the extended buffer.

func (Sum)String

func (sSum) String()string

Source Files

View all Source files

Directories

PathSynopsis
Package testtype contains types for testing deephash.
Package testtype contains types for testing deephash.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f orF : Jump to
y orY : Canonical URL
go.dev uses cookies from Google to deliver and enhance the quality of its services and to analyze traffic.Learn more.

[8]ページ先頭

©2009-2025 Movatter.jp