chore: sync dependencies and format code

This commit is contained in:
Zach Kelling
2026-02-04 15:43:42 -08:00
parent a2c22dbba7
commit f80474aedf
7 changed files with 128 additions and 131 deletions
+21 -24
View File
@@ -4,62 +4,59 @@
package math
import (
"github.com/luxfi/ids"
"github.com/luxfi/math/heap"
)
var _ AveragerHeap = (*averagerHeap)(nil)
// TODO replace this interface with utils/heap
// AveragerHeap maintains a heap of the averagers.
type AveragerHeap interface {
// Add the average to the heap. If [nodeID] is already in the heap, the
// AveragerHeap maintains a heap of the averagers keyed by a comparable type.
// K is the key type (e.g., ids.NodeID).
type AveragerHeap[K comparable] interface {
// Add the average to the heap. If key is already in the heap, the
// average will be replaced and the old average will be returned. If there
// was not an old average, false will be returned.
Add(nodeID ids.NodeID, averager Averager) (Averager, bool)
Add(key K, averager Averager) (Averager, bool)
// Remove attempts to remove the average that was added with the provided
// [nodeID], if none is contained in the heap, [false] will be returned.
Remove(nodeID ids.NodeID) (Averager, bool)
// key, if none is contained in the heap, [false] will be returned.
Remove(key K) (Averager, bool)
// Pop attempts to remove the node with either the largest or smallest
// average, depending on if this is a max heap or a min heap, respectively.
Pop() (ids.NodeID, Averager, bool)
Pop() (K, Averager, bool)
// Peek attempts to return the node with either the largest or smallest
// average, depending on if this is a max heap or a min heap, respectively.
Peek() (ids.NodeID, Averager, bool)
Peek() (K, Averager, bool)
// Len returns the number of nodes that are currently in the heap.
Len() int
}
type averagerHeap struct {
heap heap.Map[ids.NodeID, Averager]
type averagerHeap[K comparable] struct {
heap heap.Map[K, Averager]
}
// NewMaxAveragerHeap returns a new empty max heap. The returned heap is not
// thread safe.
func NewMaxAveragerHeap() AveragerHeap {
return averagerHeap{
heap: heap.NewMap[ids.NodeID, Averager](func(a, b Averager) bool {
func NewMaxAveragerHeap[K comparable]() AveragerHeap[K] {
return averagerHeap[K]{
heap: heap.NewMap[K, Averager](func(a, b Averager) bool {
return a.Read() > b.Read()
}),
}
}
func (h averagerHeap) Add(nodeID ids.NodeID, averager Averager) (Averager, bool) {
return h.heap.Push(nodeID, averager)
func (h averagerHeap[K]) Add(key K, averager Averager) (Averager, bool) {
return h.heap.Push(key, averager)
}
func (h averagerHeap) Remove(nodeID ids.NodeID) (Averager, bool) {
return h.heap.Remove(nodeID)
func (h averagerHeap[K]) Remove(key K) (Averager, bool) {
return h.heap.Remove(key)
}
func (h averagerHeap) Pop() (ids.NodeID, Averager, bool) {
func (h averagerHeap[K]) Pop() (K, Averager, bool) {
return h.heap.Pop()
}
func (h averagerHeap) Peek() (ids.NodeID, Averager, bool) {
func (h averagerHeap[K]) Peek() (K, Averager, bool) {
return h.heap.Peek()
}
func (h averagerHeap) Len() int {
func (h averagerHeap[K]) Len() int {
return h.heap.Len()
}
+2 -2
View File
@@ -19,12 +19,12 @@ func TestAveragerHeap(t *testing.T) {
tests := []struct {
name string
h AveragerHeap
h AveragerHeap[ids.NodeID]
a []Averager
}{
{
name: "max heap",
h: NewMaxAveragerHeap(),
h: NewMaxAveragerHeap[ids.NodeID](),
a: []Averager{
NewAverager(0, time.Second, time.Now()),
NewAverager(-1, time.Second, time.Now()),
+2 -2
View File
@@ -7,7 +7,7 @@ require (
github.com/luxfi/math/big v0.1.0
github.com/luxfi/sampler v1.0.0
github.com/stretchr/testify v1.11.1
golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93
golang.org/x/exp v0.0.0-20260112195511-716be5621a96
)
require (
@@ -16,7 +16,7 @@ require (
github.com/luxfi/crypto v1.17.36 // indirect
github.com/mr-tron/base58 v1.2.0 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
golang.org/x/crypto v0.46.0 // indirect
golang.org/x/crypto v0.47.0 // indirect
gonum.org/v1/gonum v0.16.0 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
+4 -4
View File
@@ -26,10 +26,10 @@ github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0t
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU=
golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0=
golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93 h1:fQsdNF2N+/YewlRZiricy4P1iimyPKZ/xwniHj8Q2a0=
golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93/go.mod h1:EPRbTFwzwjXj9NpYyyrvenVh9Y+GFeEvMNh7Xuz7xgU=
golang.org/x/crypto v0.47.0 h1:V6e3FRj+n4dbpw86FJ8Fv7XVOql7TEwpHapKoMJ/GO8=
golang.org/x/crypto v0.47.0/go.mod h1:ff3Y9VzzKbwSSEzWqJsJVBnWmRwRSHt/6Op5n9bQc4A=
golang.org/x/exp v0.0.0-20260112195511-716be5621a96 h1:Z/6YuSHTLOHfNFdb8zVZomZr7cqNgTJvA8+Qz75D8gU=
golang.org/x/exp v0.0.0-20260112195511-716be5621a96/go.mod h1:nzimsREAkjBCIEFtHiYkrJyT+2uy9YZJB7H1k68CXZU=
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+1 -1
View File
@@ -2,4 +2,4 @@ module github.com/luxfi/math/safe
go 1.24.9
require golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93
require golang.org/x/exp v0.0.0-20260112195511-716be5621a96
+1 -1
View File
@@ -1 +1 @@
golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93 h1:fQsdNF2N+/YewlRZiricy4P1iimyPKZ/xwniHj8Q2a0=
golang.org/x/exp v0.0.0-20260112195511-716be5621a96 h1:Z/6YuSHTLOHfNFdb8zVZomZr7cqNgTJvA8+Qz75D8gU=
+97 -97
View File
@@ -1,8 +1,8 @@
package set
import (
"encoding/json"
"sort"
"encoding/json"
"sort"
)
// Set represents a set of unique elements
@@ -10,170 +10,170 @@ type Set[T comparable] map[T]struct{}
// Of creates a new set with the given elements
func Of[T comparable](elements ...T) Set[T] {
s := make(Set[T], len(elements))
for _, e := range elements {
s[e] = struct{}{}
}
return s
s := make(Set[T], len(elements))
for _, e := range elements {
s[e] = struct{}{}
}
return s
}
// Add adds one or more elements to the set
// If the set is nil, this method will panic. Use NewSet() or Of() to create an initialized set.
func (s Set[T]) Add(elements ...T) {
if s == nil {
panic("set: Add called on nil Set - use NewSet() or Of() to create an initialized set")
}
for _, element := range elements {
s[element] = struct{}{}
}
if s == nil {
panic("set: Add called on nil Set - use NewSet() or Of() to create an initialized set")
}
for _, element := range elements {
s[element] = struct{}{}
}
}
// Contains checks if an element is in the set
func (s Set[T]) Contains(element T) bool {
_, exists := s[element]
return exists
_, exists := s[element]
return exists
}
// Remove removes an element from the set
func (s Set[T]) Remove(element T) {
delete(s, element)
delete(s, element)
}
// Len returns the number of elements in the set
func (s Set[T]) Len() int {
return len(s)
return len(s)
}
// List returns a slice of all elements in the set
func (s Set[T]) List() []T {
result := make([]T, 0, len(s))
for element := range s {
result = append(result, element)
}
return result
result := make([]T, 0, len(s))
for element := range s {
result = append(result, element)
}
return result
}
// Clear removes all elements from the set
func (s Set[T]) Clear() {
for k := range s {
delete(s, k)
}
for k := range s {
delete(s, k)
}
}
// Union returns a new set containing all elements from both sets
func (s Set[T]) Union(other Set[T]) Set[T] {
result := make(Set[T])
for k := range s {
result[k] = struct{}{}
}
for k := range other {
result[k] = struct{}{}
}
return result
result := make(Set[T])
for k := range s {
result[k] = struct{}{}
}
for k := range other {
result[k] = struct{}{}
}
return result
}
// Intersection returns a new set containing only elements in both sets
func (s Set[T]) Intersection(other Set[T]) Set[T] {
result := make(Set[T])
for k := range s {
if other.Contains(k) {
result[k] = struct{}{}
}
}
return result
result := make(Set[T])
for k := range s {
if other.Contains(k) {
result[k] = struct{}{}
}
}
return result
}
// Difference returns a new set containing elements in s but not in other
func (s Set[T]) Difference(other Set[T]) Set[T] {
result := make(Set[T])
for k := range s {
if !other.Contains(k) {
result[k] = struct{}{}
}
}
return result
result := make(Set[T])
for k := range s {
if !other.Contains(k) {
result[k] = struct{}{}
}
}
return result
}
// Equals checks if two sets contain the same elements
func (s Set[T]) Equals(other Set[T]) bool {
if len(s) != len(other) {
return false
}
for k := range s {
if !other.Contains(k) {
return false
}
}
return true
if len(s) != len(other) {
return false
}
for k := range s {
if !other.Contains(k) {
return false
}
}
return true
}
// Overlaps checks if two sets have any common elements
func (s Set[T]) Overlaps(other Set[T]) bool {
for k := range s {
if other.Contains(k) {
return true
}
}
return false
for k := range s {
if other.Contains(k) {
return true
}
}
return false
}
// Pop removes and returns an arbitrary element from the set
// Returns the element and true if the set was non-empty, otherwise returns zero value and false
func (s Set[T]) Pop() (T, bool) {
for k := range s {
delete(s, k)
return k, true
}
var zero T
return zero, false
for k := range s {
delete(s, k)
return k, true
}
var zero T
return zero, false
}
// NewSet creates a new empty set with optional initial capacity
func NewSet[T comparable](capacity ...int) Set[T] {
if len(capacity) > 0 && capacity[0] > 0 {
return make(Set[T], capacity[0])
}
return make(Set[T])
if len(capacity) > 0 && capacity[0] > 0 {
return make(Set[T], capacity[0])
}
return make(Set[T])
}
// MarshalJSON implements json.Marshaler interface
// Marshals the set as a JSON array of elements in sorted order
func (s Set[T]) MarshalJSON() ([]byte, error) {
// Convert set to slice for marshaling
list := s.List()
// Convert set to slice for marshaling
list := s.List()
// Sort for consistent output (best effort for common types)
if len(list) > 1 {
switch any(list).(type) {
case []int:
sort.Ints(any(list).([]int))
case []string:
sort.Strings(any(list).([]string))
case []float64:
sort.Float64s(any(list).([]float64))
}
}
// Sort for consistent output (best effort for common types)
if len(list) > 1 {
switch any(list).(type) {
case []int:
sort.Ints(any(list).([]int))
case []string:
sort.Strings(any(list).([]string))
case []float64:
sort.Float64s(any(list).([]float64))
}
}
return json.Marshal(list)
return json.Marshal(list)
}
// UnmarshalJSON implements json.Unmarshaler interface
// Unmarshals a JSON array into a set, replacing existing contents
func (s *Set[T]) UnmarshalJSON(data []byte) error {
var list []T
if err := json.Unmarshal(data, &list); err != nil {
return err
}
var list []T
if err := json.Unmarshal(data, &list); err != nil {
return err
}
// Create a new set to replace existing contents
*s = make(Set[T], len(list))
// Create a new set to replace existing contents
*s = make(Set[T], len(list))
// Add all elements from the list
for _, element := range list {
(*s)[element] = struct{}{}
}
// Add all elements from the list
for _, element := range list {
(*s)[element] = struct{}{}
}
return nil
return nil
}
// Peek returns a random element from the set.