func (sl *NeighborList) Remove(remoteNode *node.RemoteNode) bool {
	if sl.Exists(remoteNode.Id) {
		sl.nodes.Delete(string(remoteNode.Id))
		return true
	}
	return false
}
Remove remove a node from NeighborList, returns if node is in NeighborList
package chord
import (
	"errors"
	"fmt"
	"math/big"
	"math/rand"
	"sort"
	"sync"
	"github.com/nknorg/nnet/log"
	"github.com/nknorg/nnet/node"
	"github.com/nknorg/nnet/protobuf"
)
const (
	randomQueryProbability = 0.5
)
type NeighborList struct {
	startID         []byte
	endID           []byte
	reversed        bool
	nodeIDBits      uint32
	maxNumNodes     uint32
	maxNumNodesLock sync.RWMutex
	nodes           sync.Map
}
func NewNeighborList(startID, endID []byte, nodeIDBits, maxNumNodes uint32, reversed bool) (*NeighborList, error) {
	if uint32(len(startID)) > nodeIDBits || uint32(len(endID)) > nodeIDBits {
		return nil, fmt.Errorf("key has more than %d bits", nodeIDBits)
	}
	sl := &NeighborList{
		startID:     startID,
		endID:       endID,
		nodeIDBits:  nodeIDBits,
		maxNumNodes: maxNumNodes,
		reversed:    reversed,
	}
	return sl, nil
}
func (sl *NeighborList) cmp(node1, node2 *protobuf.Node) int {
	res := Distance(sl.startID, node1.Id, sl.nodeIDBits).Cmp(Distance(sl.startID, node2.Id, sl.nodeIDBits))
	if sl.reversed {
		return -res
	}
	return res
}
func (sl *NeighborList) IsIDInRange(id []byte) bool {
	if sl.reversed {
		return BetweenIncl(sl.endID, sl.startID, id)
	}
	return BetweenIncl(sl.startID, sl.endID, id)
}
func (sl *NeighborList) IsEmpty() bool {
	isEmpty := true
	sl.nodes.Range(func(key, value interface{}) bool {
		isEmpty = false
		return false
	})
	return isEmpty
}
func (sl *NeighborList) Len() uint32 {
	var length uint32
	sl.nodes.Range(func(key, value interface{}) bool {
		length++
		return true
	})
	return length
}
func (sl *NeighborList) Cap() uint32 {
	sl.maxNumNodesLock.RLock()
	defer sl.maxNumNodesLock.RUnlock()
	return sl.maxNumNodes
}
func (sl *NeighborList) SetMaxNumNodes(maxNumNodes uint32) {
	sl.maxNumNodesLock.Lock()
	sl.maxNumNodes = maxNumNodes
	sl.maxNumNodesLock.Unlock()
}
func (sl *NeighborList) GetByID(id []byte) *node.RemoteNode {
	value, ok := sl.nodes.Load(string(id))
	if ok {
		rn, ok := value.(*node.RemoteNode)
		if ok {
			return rn
		}
	}
	return nil
}
func (sl *NeighborList) Exists(id []byte) bool {
	rn := sl.GetByID(id)
	return rn != nil
}
func (sl *NeighborList) GetIndex(id []byte) int {
	for i, n := range sl.ToRemoteNodeList(true) {
		if CompareID(n.Id, id) == 0 {
			return i
		}
	}
	return -1
}
func (sl *NeighborList) GetFirst() *node.RemoteNode {
	var first *node.RemoteNode
	var dist, minDist *big.Int
	sl.nodes.Range(func(key, value interface{}) bool {
		remoteNode, ok := value.(*node.RemoteNode)
		if ok {
			if sl.reversed {
				dist = Distance(remoteNode.Id, sl.startID, sl.nodeIDBits)
			} else {
				dist = Distance(sl.startID, remoteNode.Id, sl.nodeIDBits)
			}
			if minDist == nil || dist.Cmp(minDist) < 0 {
				first = remoteNode
				minDist = dist
			}
		}
		return true
	})
	return first
}
func (sl *NeighborList) GetLast() *node.RemoteNode {
	var last *node.RemoteNode
	var dist, maxDist *big.Int
	sl.nodes.Range(func(key, value interface{}) bool {
		remoteNode, ok := value.(*node.RemoteNode)
		if ok {
			if sl.reversed {
				dist = Distance(remoteNode.Id, sl.startID, sl.nodeIDBits)
			} else {
				dist = Distance(sl.startID, remoteNode.Id, sl.nodeIDBits)
			}
			if maxDist == nil || dist.Cmp(maxDist) > 0 {
				last = remoteNode
				maxDist = dist
			}
		}
		return true
	})
	return last
}
func (sl *NeighborList) AddOrReplace(remoteNode *node.RemoteNode) (bool, *node.RemoteNode, error) {
	if remoteNode.IsStopped() || !sl.IsIDInRange(remoteNode.Id) {
		return false, nil, nil
	}
	var replaced *node.RemoteNode
	if sl.Cap() > 0 && sl.Len() >= sl.Cap() {
		replaced = sl.GetLast()
		if replaced != nil && sl.cmp(remoteNode.Node.Node, replaced.Node.Node) >= 0 {
			return false, nil, nil
		}
	}
	_, loaded := sl.nodes.LoadOrStore(string(remoteNode.Id), remoteNode)
	if loaded {
		log.Info("Node already in neighbor list")
		return false, nil, nil
	}
	if replaced != nil {
		sl.Remove(replaced)
	}
	return true, replaced, nil
}