From 85169c799b4a0d4ba7d39347c07690dc0b49a1d1 Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Wed, 7 Dec 2022 22:08:51 -0700 Subject: containers.Set: Don't use constraints.Ordered --- lib/containers/ordered.go | 4 +++- lib/containers/set.go | 57 +++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 53 insertions(+), 8 deletions(-) (limited to 'lib/containers') diff --git a/lib/containers/ordered.go b/lib/containers/ordered.go index 038edf8..d918149 100644 --- a/lib/containers/ordered.go +++ b/lib/containers/ordered.go @@ -8,10 +8,12 @@ import ( "golang.org/x/exp/constraints" ) -type Ordered[T interface{ Cmp(T) int }] interface { +type _Ordered[T any] interface { Cmp(T) int } +type Ordered[T _Ordered[T]] _Ordered[T] + type NativeOrdered[T constraints.Ordered] struct { Val T } diff --git a/lib/containers/set.go b/lib/containers/set.go index 1c525ca..d3f8ca7 100644 --- a/lib/containers/set.go +++ b/lib/containers/set.go @@ -5,27 +5,70 @@ package containers import ( + "fmt" "io" + "sort" "git.lukeshu.com/go/lowmemjson" - "golang.org/x/exp/constraints" "git.lukeshu.com/btrfs-progs-ng/lib/maps" ) // Set[T] is an unordered set of T. -// -// Despite Set[T] being unordered, T is required to be an ordered type -// in order that a Set[T] have a deterministic JSON representation. -type Set[T constraints.Ordered] map[T]struct{} +type Set[T comparable] map[T]struct{} var ( _ lowmemjson.Encodable = Set[int]{} _ lowmemjson.Decodable = (*Set[int])(nil) ) +func cast[T any](x any) T { return x.(T) } + func (o Set[T]) EncodeJSON(w io.Writer) error { - return lowmemjson.Encode(w, maps.SortedKeys(o)) + var less func(a, b T) bool + var zero T + switch (any(zero)).(type) { + case _Ordered[T]: + less = func(a, b T) bool { return cast[_Ordered[T]](a).Cmp(b) < 0 } + // This is the constraints.Ordered list + case string: + less = func(a, b T) bool { return cast[string](a) < cast[string](b) } + case int: + less = func(a, b T) bool { return cast[int](a) < cast[int](b) } + case int8: + less = func(a, b T) bool { return cast[int8](a) < cast[int8](b) } + case int16: + less = func(a, b T) bool { return cast[int16](a) < cast[int16](b) } + case int32: + less = func(a, b T) bool { return cast[int32](a) < cast[int32](b) } + case int64: + less = func(a, b T) bool { return cast[int64](a) < cast[int64](b) } + case uint: + less = func(a, b T) bool { return cast[uint](a) < cast[uint](b) } + case uint8: + less = func(a, b T) bool { return cast[uint8](a) < cast[uint8](b) } + case uint16: + less = func(a, b T) bool { return cast[uint16](a) < cast[uint16](b) } + case uint32: + less = func(a, b T) bool { return cast[uint32](a) < cast[uint32](b) } + case uint64: + less = func(a, b T) bool { return cast[uint64](a) < cast[uint64](b) } + case uintptr: + less = func(a, b T) bool { return cast[uintptr](a) < cast[uintptr](b) } + case float32: + less = func(a, b T) bool { return cast[float32](a) < cast[float32](b) } + case float64: + less = func(a, b T) bool { return cast[float64](a) < cast[float64](b) } + default: + less = func(a, b T) bool { return fmt.Sprint(a) < fmt.Sprint(b) } + } + + keys := maps.Keys(o) + sort.Slice(keys, func(i, j int) bool { + return less(keys[i], keys[j]) + }) + + return lowmemjson.Encode(w, keys) } func (o *Set[T]) DecodeJSON(r io.RuneScanner) error { @@ -49,7 +92,7 @@ func (o *Set[T]) DecodeJSON(r io.RuneScanner) error { }) } -func NewSet[T constraints.Ordered](values ...T) Set[T] { +func NewSet[T comparable](values ...T) Set[T] { ret := make(Set[T], len(values)) for _, value := range values { ret.Insert(value) -- cgit v1.2.3-54-g00ecf