jsonschema: using hashing for uniqueItems
Determine if a slice contains unique items by hashing them. This should take linear time on average, better than the previous quadratic algorithm. Change-Id: I8dc95bb6f29d802bdbc64bc7f7e698c71eae5ce7 Reviewed-on: https://go-review.googlesource.com/c/tools/+/669455 Reviewed-by: Alan Donovan <adonovan@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
This commit is contained in:
parent
7a76f3502a
commit
3e8ca36823
1 changed files with 162 additions and 8 deletions
|
|
@ -6,6 +6,7 @@ package jsonschema
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"hash/maphash"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
|
@ -71,3 +72,56 @@ func TestJSONType(t *testing.T) {
|
|||
|
||||
}
|
||||
}
|
||||
|
||||
func TestHash(t *testing.T) {
|
||||
x := map[string]any{
|
||||
"s": []any{1, "foo", nil, true},
|
||||
"f": 2.5,
|
||||
"m": map[string]any{
|
||||
"n": json.Number("123.456"),
|
||||
"schema": &Schema{Type: "integer", UniqueItems: true},
|
||||
},
|
||||
"c": 1.2 + 3.4i,
|
||||
"n": nil,
|
||||
}
|
||||
|
||||
seed := maphash.MakeSeed()
|
||||
|
||||
hash := func(x any) uint64 {
|
||||
var h maphash.Hash
|
||||
h.SetSeed(seed)
|
||||
hashValue(&h, reflect.ValueOf(x))
|
||||
return h.Sum64()
|
||||
}
|
||||
|
||||
want := hash(x)
|
||||
// Run several times to verify consistency.
|
||||
for range 10 {
|
||||
if got := hash(x); got != want {
|
||||
t.Errorf("hash values differ: %d vs. %d", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
// Check mathematically equal values.
|
||||
nums := []any{
|
||||
5,
|
||||
uint(5),
|
||||
5.0,
|
||||
json.Number("5"),
|
||||
json.Number("5.00"),
|
||||
}
|
||||
for i, n := range nums {
|
||||
if i == 0 {
|
||||
want = hash(n)
|
||||
} else if got := hash(n); got != want {
|
||||
t.Errorf("hashes differ between %v (%[1]T) and %v (%[2]T)", nums[0], n)
|
||||
}
|
||||
}
|
||||
|
||||
// Check that a bare JSON `null` is OK.
|
||||
var null any
|
||||
if err := json.Unmarshal([]byte(`null`), &null); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_ = hash(null)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue