summaryrefslogtreecommitdiff
path: root/lib/containers
diff options
context:
space:
mode:
authorLuke Shumaker <lukeshu@lukeshu.com>2022-12-07 22:08:51 -0700
committerLuke Shumaker <lukeshu@lukeshu.com>2022-12-20 19:58:11 -0700
commit85169c799b4a0d4ba7d39347c07690dc0b49a1d1 (patch)
treee64e11ada70b17cc7c196c31ea04b5b5ad153a67 /lib/containers
parent87b11decd105d620b3ad6f56c45b9bf1cf86a1b3 (diff)
containers.Set: Don't use constraints.Ordered
Diffstat (limited to 'lib/containers')
-rw-r--r--lib/containers/ordered.go4
-rw-r--r--lib/containers/set.go57
2 files changed, 53 insertions, 8 deletions
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)