func (s *Selector) SetAttribute(a string) {
	(*netmap.Selector)(s).
		SetAttribute(a)
}
SetAttribute sets attribute bucket to select from.
package netmap
import (
	"fmt"
	"sort"
	"github.com/nspcc-dev/hrw"
	"github.com/nspcc-dev/neofs-api-go/v2/netmap"
)
type Selector netmap.Selector
func (c *Context) processSelectors(p *PlacementPolicy) error {
	for _, s := range p.Selectors() {
		if s == nil {
			return fmt.Errorf("%w: SELECT", ErrMissingField)
		} else if s.Filter() != MainFilterName {
			_, ok := c.Filters[s.Filter()]
			if !ok {
				return fmt.Errorf("%w: SELECT FROM '%s'", ErrFilterNotFound, s.Filter())
			}
		}
		c.Selectors[s.Name()] = s
		result, err := c.getSelection(p, s)
		if err != nil {
			return err
		}
		c.Selections[s.Name()] = result
	}
	return nil
}
func GetNodesCount(_ *PlacementPolicy, s *Selector) (int, int) {
	switch s.Clause() {
	case ClauseSame:
		return 1, int(s.Count())
	default:
		return int(s.Count()), 1
	}
}
func (c *Context) getSelection(p *PlacementPolicy, s *Selector) ([]Nodes, error) {
	bucketCount, nodesInBucket := GetNodesCount(p, s)
	buckets := c.getSelectionBase(s)
	if len(buckets) < bucketCount {
		return nil, fmt.Errorf("%w: '%s'", ErrNotEnoughNodes, s.Name())
	}
	if len(c.pivot) == 0 {
		if s.Attribute() == "" {
			sort.Slice(buckets, func(i, j int) bool {
				return buckets[i].nodes[0].ID < buckets[j].nodes[0].ID
			})
		} else {
			sort.Slice(buckets, func(i, j int) bool {
				return buckets[i].attr < buckets[j].attr
			})
		}
	}
	maxNodesInBucket := nodesInBucket * int(c.cbf)
	nodes := make([]Nodes, 0, len(buckets))
	fallback := make([]Nodes, 0, len(buckets))
	for i := range buckets {
		ns := buckets[i].nodes
		if len(ns) >= maxNodesInBucket {
			nodes = append(nodes, ns[:maxNodesInBucket])
		} else if len(ns) >= nodesInBucket {
			fallback = append(fallback, ns)
		}
	}
	if len(nodes) < bucketCount {
		nodes = append(nodes, fallback...)
		if len(nodes) < bucketCount {
			return nil, fmt.Errorf("%w: '%s'", ErrNotEnoughNodes, s.Name())
		}
	}
	if len(c.pivot) != 0 {
		weights := make([]float64, len(nodes))
		for i := range nodes {
			weights[i] = GetBucketWeight(nodes[i], c.aggregator(), c.weightFunc)
		}
		hrw.SortSliceByWeightIndex(nodes, weights, c.pivotHash)
	}
	if s.Attribute() == "" {
		nodes, fallback = nodes[:bucketCount], nodes[bucketCount:]
		for i := range fallback {
			index := i % bucketCount
			if len(nodes[index]) >= maxNodesInBucket {
				break
			}
			nodes[index] = append(nodes[index], fallback[i]...)
		}
	}
	return nodes[:bucketCount], nil
}
type nodeAttrPair struct {
	attr  string
	nodes Nodes
}
func (c *Context) getSelectionBase(s *Selector) []nodeAttrPair {
	f := c.Filters[s.Filter()]
	isMain := s.Filter() == MainFilterName
	result := []nodeAttrPair{}
	nodeMap := map[string]Nodes{}
	attr := s.Attribute()
	for i := range c.Netmap.Nodes {
		if isMain || c.match(f, c.Netmap.Nodes[i]) {
			if attr == "" {
				result = append(result, nodeAttrPair{attr: "", nodes: Nodes{c.Netmap.Nodes[i]}})
			} else {
				v := c.Netmap.Nodes[i].Attribute(attr)
				nodeMap[v] = append(nodeMap[v], c.Netmap.Nodes[i])
			}
		}
	}
	if attr != "" {
		for k, ns := range nodeMap {
			result = append(result, nodeAttrPair{attr: k, nodes: ns})
		}
	}
	if len(c.pivot) != 0 {
		for i := range result {
			hrw.SortSliceByWeightValue(result[i].nodes, result[i].nodes.Weights(c.weightFunc), c.pivotHash)
		}
	}
	return result
}
func NewSelector() *Selector {
	return NewSelectorFromV2(new(netmap.Selector))
}
func NewSelectorFromV2(f *netmap.Selector) *Selector {
	return (*Selector)(f)
}
func (s *Selector) ToV2() *netmap.Selector {
	return (*netmap.Selector)(s)
}
func (s *Selector) Name() string {
	return (*netmap.Selector)(s).
		GetName()
}
func (s *Selector) SetName(name string) {
	(*netmap.Selector)(s).
		SetName(name)
}
func (s *Selector) Count() uint32 {
	return (*netmap.Selector)(s).
		GetCount()
}
func (s *Selector) SetCount(c uint32) {
	(*netmap.Selector)(s).
		SetCount(c)
}
func (s *Selector) Clause() Clause {
	return ClauseFromV2(
		(*netmap.Selector)(s).
			GetClause(),
	)
}
func (s *Selector) SetClause(c Clause) {
	(*netmap.Selector)(s).
		SetClause(c.ToV2())
}
func (s *Selector) Attribute() string {
	return (*netmap.Selector)(s).
		GetAttribute()
}