Skip to main content

pi_wrr/
lib.rs

1
2
3///
4/// 交替加权轮询选择器
5///
6#[derive(Debug, Clone)]
7pub struct IWRRSelector<const LEN: usize> {
8    pos:        usize,      //当前选择的位置
9    round:      u8,         //选择的当前轮数
10    max_weight: u8,         //最大的权重
11    weights:    [u8; LEN],  //待选择的权重数组
12}
13
14impl<const LEN: usize> Default for IWRRSelector<LEN> {
15    /// 默认构建指定长度且权重相同的交替加权轮询选择器
16    fn default() -> Self {
17        Self::new([1; LEN])
18    }
19}
20
21impl<const LEN: usize> IWRRSelector<LEN> {
22    /// 构建指定待选择的权重数组的交替加权轮询选择器
23    pub fn new(weights: [u8; LEN]) -> Self {
24        let mut max_weight = 0;
25        for weight in weights {
26            if weight >= u8::MAX {
27                panic!("Create IWRRSelector failed, weight: {}, reason: invalid weight",
28                       weight);
29            }
30
31            if max_weight < weight {
32                //替换最大的权重
33                max_weight = weight;
34            }
35        }
36
37        IWRRSelector {
38            round: 0,
39            max_weight,
40            pos: 0,
41            weights,
42        }
43    }
44
45    /// 获取待选择的权重数组的长度
46    pub const fn len(&self) -> usize {
47        LEN
48    }
49
50    /// 获取选择的当前轮数
51    pub fn round(&self) -> u8 {
52        self.round
53    }
54
55    /// 获取最大的权重
56    pub fn max_weight(&self) -> u8 {
57        self.max_weight
58    }
59
60    /// 尝试获取指定位置的权重
61    pub fn try_weight(&self, index: usize) -> Option<u8> {
62        if index >= self.len() {
63            None
64        } else {
65            Some(self.weights[index])
66        }
67    }
68
69    /// 改变指定位置的权重,改变成功则返回指定位置的上个权重
70    pub fn change_weight(&mut self,
71                         index: usize,
72                         weight: u8) -> Option<u8> {
73        if weight >= u8::MAX {
74            return None;
75        }
76
77        if let Some(old) = self.try_weight(index) {
78            self.weights[index] = weight;
79            Some(old)
80        } else {
81            None
82        }
83    }
84
85    /// 获取当前选择的位置
86    pub fn pos(&self) -> usize {
87        self.pos
88    }
89
90    /// 根据权重选择,并返回被选择的位置
91    pub fn select(&mut self) -> usize {
92        loop {
93            for pos in self.pos..self.len() {
94                let weight = self.weights[pos];
95                if weight == 0 || weight < self.round {
96                    //被忽略,则继续下一个位置的选择
97                    self.pos += 1;
98                    continue;
99                }
100
101                //返回被选择的位置
102                self.pos += 1;
103                return pos;
104            }
105
106            if self.round > self.max_weight {
107                //完成当前周期的选择,则重置选择器
108                self.reset();
109            } else {
110                //完成当前轮的选择,则重置位置,并继续下一轮的选择
111                self.pos = 0;
112                self.round += 1;
113            }
114        }
115    }
116
117    /// 重置选择器
118    pub fn reset(&mut self) {
119        self.round = 0;
120        self.pos = 0;
121    }
122}
123
124///
125/// 交替加权轮询选择器
126///
127#[derive(Debug, Clone)]
128pub struct IWRRSelectorByWider<const LEN: usize> {
129    pos:        usize,          //当前选择的位置
130    round:      usize,          //选择的当前轮数
131    max_weight: usize,          //最大的权重
132    weights:    [usize; LEN],   //待选择的权重数组
133}
134
135impl<const LEN: usize> Default for IWRRSelectorByWider<LEN> {
136    /// 默认构建指定长度且权重相同的交替加权轮询选择器
137    fn default() -> Self {
138        Self::new([1; LEN])
139    }
140}
141
142impl<const LEN: usize> IWRRSelectorByWider<LEN> {
143    /// 构建指定待选择的权重数组的交替加权轮询选择器
144    pub fn new(weights: [usize; LEN]) -> Self {
145        let mut max_weight = 0;
146        for weight in weights {
147            if weight >= usize::MAX {
148                panic!("Create IWRRSelector failed, weight: {}, reason: invalid weight",
149                       weight);
150            }
151
152            if max_weight < weight {
153                //替换最大的权重
154                max_weight = weight;
155            }
156        }
157
158        IWRRSelectorByWider {
159            round: 0,
160            max_weight,
161            pos: 0,
162            weights,
163        }
164    }
165
166    /// 获取待选择的权重数组的长度
167    pub const fn len(&self) -> usize {
168        LEN
169    }
170
171    /// 获取选择的当前轮数
172    pub fn round(&self) -> usize {
173        self.round
174    }
175
176    /// 获取最大的权重
177    pub fn max_weight(&self) -> usize {
178        self.max_weight
179    }
180
181    /// 尝试获取指定位置的权重
182    pub fn try_weight(&self, index: usize) -> Option<usize> {
183        if index >= self.len() {
184            None
185        } else {
186            Some(self.weights[index])
187        }
188    }
189
190    /// 改变指定位置的权重,改变成功则返回指定位置的上个权重
191    pub fn change_weight(&mut self,
192                         index: usize,
193                         weight: usize) -> Option<usize> {
194        if weight >= usize::MAX {
195            return None;
196        }
197
198        if let Some(old) = self.try_weight(index) {
199            self.weights[index] = weight;
200            Some(old)
201        } else {
202            None
203        }
204    }
205
206    /// 获取当前选择的位置
207    pub fn pos(&self) -> usize {
208        self.pos
209    }
210
211    /// 根据权重选择,并返回被选择的位置
212    pub fn select(&mut self) -> usize {
213        loop {
214            for pos in self.pos..self.len() {
215                let weight = self.weights[pos];
216                if weight == 0 || weight < self.round {
217                    //被忽略,则继续下一个位置的选择
218                    self.pos += 1;
219                    continue;
220                }
221
222                //返回被选择的位置
223                self.pos += 1;
224                return pos;
225            }
226
227            if self.round > self.max_weight {
228                //完成当前周期的选择,则重置选择器
229                self.reset();
230            } else {
231                //完成当前轮的选择,则重置位置,并继续下一轮的选择
232                self.pos = 0;
233                self.round += 1;
234            }
235        }
236    }
237
238    /// 重置选择器
239    pub fn reset(&mut self) {
240        self.round = 0;
241        self.pos = 0;
242    }
243}