forest/utils/misc/
adaptive_value_provider.rs1use parking_lot::RwLock;
5
6pub trait AdaptiveValueProvider<T: num::PrimInt> {
7 fn get(&self) -> T;
8
9 fn adapt_on_success(&self, record: T) -> bool;
10
11 fn adapt_on_failure(&self);
12}
13
14pub struct ExponentialAdaptiveValueProvider<T: num::PrimInt> {
15 value: RwLock<T>,
16 min: T,
17 max: T,
18 increase_on_success: bool,
19}
20
21impl<T: num::PrimInt> ExponentialAdaptiveValueProvider<T> {
22 pub fn new(value: T, min: T, max: T, increase_on_success: bool) -> Self {
23 Self {
24 value: RwLock::new(value),
25 min,
26 max,
27 increase_on_success,
28 }
29 }
30
31 fn increase(&self, record: Option<T>) -> bool {
32 let current = self.get();
33 if current == self.max {
34 return false;
35 }
36 let new_value = current.shl(1).min(self.max);
37 if let Some(record) = record
38 && record < new_value
39 {
40 return false;
41 }
42 *self.value.write() = new_value;
43 true
44 }
45
46 fn decrease(&self, record: Option<T>) -> bool {
47 let current = self.get();
48 if current == self.min {
49 return false;
50 }
51 let new_value = current.shr(1).max(self.min);
52 if let Some(record) = record
53 && record > new_value
54 {
55 return false;
56 }
57 *self.value.write() = new_value;
58 true
59 }
60}
61
62impl<T: num::PrimInt> AdaptiveValueProvider<T> for ExponentialAdaptiveValueProvider<T> {
63 fn get(&self) -> T {
64 *self.value.read()
65 }
66
67 fn adapt_on_success(&self, record: T) -> bool {
68 if self.increase_on_success {
69 self.increase(Some(record))
70 } else {
71 self.decrease(Some(record))
72 }
73 }
74
75 fn adapt_on_failure(&self) {
76 if !self.increase_on_success {
77 self.increase(None);
78 } else {
79 self.decrease(None);
80 }
81 }
82}
83
84#[cfg(test)]
85mod tests {
86 use super::*;
87
88 #[test]
89 fn test_exponential_adaptive_value_provider_behaviour() {
90 let p = ExponentialAdaptiveValueProvider::new(8, 2, 60, false);
91 assert_eq!(p.get(), 8);
92 assert!(!p.adapt_on_success(5));
93 assert_eq!(p.get(), 8);
94 assert!(p.adapt_on_success(4));
95 assert_eq!(p.get(), 4);
96 assert!(!p.adapt_on_success(3));
97 assert_eq!(p.get(), 4);
98 assert!(p.adapt_on_success(2));
99 assert_eq!(p.get(), 2);
100 assert!(!p.adapt_on_success(1));
101 assert_eq!(p.get(), 2);
102 assert!(!p.adapt_on_success(1));
103 assert_eq!(p.get(), 2);
104 p.adapt_on_failure();
105 assert_eq!(p.get(), 4);
106 p.adapt_on_failure();
107 assert_eq!(p.get(), 8);
108 p.adapt_on_failure();
109 assert_eq!(p.get(), 16);
110 p.adapt_on_failure();
111 assert_eq!(p.get(), 32);
112 p.adapt_on_failure();
113 assert_eq!(p.get(), 60);
114 p.adapt_on_failure();
115 assert_eq!(p.get(), 60);
116 }
117}