1use crate::consts::{Range, RG_LOG};
4
5fn log(value: i32) -> i64 {
8 log_positive(value as u64)
9}
10
11fn log_positive(value: u64) -> i64 {
12 let exponent = 63 - value.leading_zeros();
13 let mut x = (value as u128) << (63 - exponent);
14 let mut result = i64::from(exponent) << 40;
15 for bit in (0..40).rev() {
16 x = (x * x) >> 63;
17 if x >= 1 << 64 {
18 x >>= 1;
19 result |= 1 << bit;
20 }
21 }
22 result
23}
24
25impl Range {
26 pub fn position(&self, value: i32, travel: i32) -> i32 {
30 if travel <= 0 || self.max <= self.min { return 0; }
31 let value = value.clamp(self.min, self.max);
32 let (offset, span) = if self.flags & RG_LOG != 0 && self.min > 0 {
33 (log(value) - log(self.min), log(self.max) - log(self.min))
34 } else { (i64::from(value) - i64::from(self.min), i64::from(self.max) - i64::from(self.min)) };
35 (i128::from(offset) * i128::from(travel) / i128::from(span)) as i32
36 }
37
38 pub fn value_at(&self, position: i32, travel: i32) -> i32 {
42 if travel <= 0 || self.max <= self.min { return self.min; }
43 let position = position.clamp(0, travel);
44 if position == 0 { return self.min; }
45 if position == travel { return self.max; }
46 if self.flags & RG_LOG == 0 || self.min <= 0 {
47 let span = i64::from(self.max) - i64::from(self.min);
48 return (i64::from(self.min) + (i64::from(position) * span + i64::from(travel / 2)) / i64::from(travel)) as i32;
49 }
50 let target = log(self.min) + (i128::from(log(self.max) - log(self.min)) * i128::from(position) / i128::from(travel)) as i64;
51 let (mut low, mut high) = (self.min, self.max);
52 while high - low > 1 {
53 let mid = low + (high - low) / 2;
54 if log(mid) <= target { low = mid; } else { high = mid; }
55 }
56 let midpoint = log_positive(low as u64 * 2 + 1) - (1_i64 << 40);
59 if target < midpoint { low } else { high }
60 }
61}