func (rt *table) Less(i, j int) bool {
	return rt.buckets[i].Before(rt.buckets[j])
}
Less returns whether bucket i's ID lower bound is less than bucket j's.
package routing
import (
	"container/heap"
	"errors"
	"fmt"
	"math/big"
	"math/rand"
	"sort"
	"sync"
	"github.com/drausin/libri/libri/common/ecid"
	errors2 "github.com/drausin/libri/libri/common/errors"
	"github.com/drausin/libri/libri/common/id"
	"github.com/drausin/libri/libri/common/storage"
	"github.com/drausin/libri/libri/librarian/server/comm"
	"github.com/drausin/libri/libri/librarian/server/peer"
)
const (
	Existed PushStatus = iota
	Added
	Dropped
	Replaced
)
const (
	DefaultMaxActivePeers = uint(16)
)
type PushStatus int
func (p PushStatus) String() string {
	switch p {
	case Existed:
		return "Existed"
	case Added:
		return "Added"
	case Dropped:
		return "Dropped"
	case Replaced:
		return "Replaced"
	}
	panic(fmt.Errorf("unknown PushStatus value %d", p))
}
type Table interface {
	SelfID() id.ID
	Push(new peer.Peer) PushStatus
	Find(target id.ID, k uint) []peer.Peer
	Get(peerID id.ID) (peer.Peer, bool)
	Sample(k uint, rng *rand.Rand) []peer.Peer
	NumPeers() int
	NumBuckets() int
	Save(ns storage.Storer) error
}
type Parameters struct {
	MaxBucketPeers uint
}
func NewDefaultParameters() *Parameters {
	return &Parameters{
		MaxBucketPeers: DefaultMaxActivePeers,
	}
}
type table struct {
	selfID id.ID
	peers map[string]peer.Peer
	buckets []*bucket
	params *Parameters
	mu sync.Mutex
}
func NewEmpty(selfID id.ID, preferer comm.Preferer, doctor comm.Doctor, params *Parameters) Table {
	firstBucket := newFirstBucket(params.MaxBucketPeers, preferer, doctor)
	return &table{
		selfID:  selfID,
		peers:   make(map[string]peer.Peer),
		buckets: []*bucket{firstBucket},
		params:  params,
	}
}
func NewWithPeers(
	selfID id.ID,
	preferer comm.Preferer,
	doctor comm.Doctor,
	params *Parameters,
	peers []peer.Peer,
) (Table, int) {
	rt := NewEmpty(selfID, preferer, doctor, params)
	nAdded := 0
	for _, p := range peers {
		if rt.Push(p) == Added {
			nAdded++
		}
	}
	return rt, nAdded
}
func NewTestWithPeers(rng *rand.Rand, n int) (Table, ecid.ID, int, comm.Preferer) {
	peerID := ecid.NewPseudoRandom(rng)
	params := NewDefaultParameters()
	ps := peer.NewTestPeers(rng, n)
	k := comm.NewAlwaysKnower()
	rec := comm.NewQueryRecorderGetter(k)
	preferer := comm.NewRpPreferer(rec)
	doctor := comm.NewNaiveDoctor()
	rt, nAdded := NewWithPeers(peerID.ID(), preferer, doctor, params, ps)
	return rt, peerID, nAdded, preferer
}
func (rt *table) SelfID() id.ID {
	return rt.selfID
}
func (rt *table) NumPeers() int {
	return len(rt.peers)
}
func (rt *table) NumBuckets() int {
	return rt.Len()
}
func (rt *table) Push(new peer.Peer) PushStatus {
	if rt.selfID.Cmp(new.ID()) == 0 {
		return Dropped
	}
	rt.mu.Lock()
	bucketIdx := rt.bucketIndex(new.ID())
	insertBucket := rt.buckets[bucketIdx]
	if insertBucket.unhealthyRoot() {
		popped := heap.Pop(insertBucket).(peer.Peer)
		delete(rt.peers, popped.ID().String())
	}
	if pHeapIdx, in := insertBucket.positions[new.ID().String()]; in {
		err := insertBucket.activePeers[pHeapIdx].Merge(new)
		errors2.MaybePanic(err)  
		heap.Fix(insertBucket, pHeapIdx)
		rt.mu.Unlock()
		return Existed
	}
	if _, exists := rt.peers[new.ID().String()]; exists {
		panic(errors.New("peer should be found in its insert bucket if in peers map"))
	}
	if new.Address() == nil {
		rt.mu.Unlock()
		return Dropped
	}
	if !insertBucket.Vacancy() && insertBucket.containsSelf {
		rt.splitBucket(bucketIdx)
		rt.mu.Unlock()
		return rt.Push(new)
	}
	heap.Push(insertBucket, new)
	rt.peers[new.ID().String()] = new
	if len(insertBucket.activePeers) > int(insertBucket.maxActivePeers) {
		popped := heap.Pop(insertBucket).(peer.Peer)
		delete(rt.peers, popped.ID().String())
		rt.mu.Unlock()
		if popped == new {
			return Dropped
		}
		return Replaced
	}
	rt.mu.Unlock()
	return Added
}
func (rt *table) Find(target id.ID, k uint) []peer.Peer {
	rt.mu.Lock()
	defer rt.mu.Unlock()
	if int(k) > rt.NumPeers() {
		k = uint(rt.NumPeers())
	}
	fwdIdx := rt.bucketIndex(target)
	bkwdIdx := fwdIdx - 1
	next := make([]peer.Peer, 0, k)
	for len(next) < int(k) && (fwdIdx < len(rt.buckets) || bkwdIdx >= 0) {
		bucketIdx := rt.chooseBucketIndex(target, fwdIdx, bkwdIdx)
		found := rt.buckets[bucketIdx].Find(target, k-uint(len(next)))
		next = append(next, found...)
		if bucketIdx == fwdIdx {
			fwdIdx++
		} else {
			bkwdIdx--
		}
	}
	return next
}
func (rt *table) Get(peerID id.ID) (peer.Peer, bool) {
	rt.mu.Lock()
	defer rt.mu.Unlock()
	if p, exists := rt.peers[peerID.String()]; exists {
		return p, true
	}
	return nil, false
}
func (rt *table) Sample(k uint, rng *rand.Rand) []peer.Peer {
	rt.mu.Lock()
	defer rt.mu.Unlock()
	bucketCounts := make([]uint, len(rt.buckets))
	for c := 0; c < int(k) && c < len(rt.peers); {
		density := rng.Float64()
		idx := rt.densityBucketIndex(density)
		if int(bucketCounts[idx]) < rt.buckets[idx].Len() {
			bucketCounts[idx]++
			c++
		}
	}
	sample := make([]peer.Peer, 0, k)
	for i := 0; i < len(bucketCounts); i++ {
		if bucketCounts[i] > 0 {
			sample = append(sample, rt.buckets[i].Peak(bucketCounts[i])...)
		}
	}
	return sample
}
func (rt *table) Len() int {
	return len(rt.buckets)
}