maniac_runtime/utils/
bits.rs1use std::sync::atomic::{AtomicU64, Ordering};
2
3#[inline(always)]
4pub fn size(value: &AtomicU64) -> u64 {
5 value.load(Ordering::Relaxed).count_ones() as u64
6}
7
8#[inline(always)]
9pub fn is_empty(value: &AtomicU64) -> bool {
10 value.load(Ordering::Relaxed).count_ones() == 0
11}
12
13#[inline(always)]
14pub fn set(value: &AtomicU64, index: u64) -> (bool, bool) {
15 let bit = 1u64 << index;
17 let prev = value.fetch_or(bit, Ordering::AcqRel);
18 (prev == 0, (prev & bit) == 0)
20}
21
22#[inline(always)]
23pub fn set_with_bit(value: &AtomicU64, bit: u64) -> u64 {
24 value.fetch_or(bit, Ordering::AcqRel)
25}
26
27#[inline(always)]
28pub fn acquire(value: &AtomicU64, index: u64) -> bool {
29 if !is_set(value, index) {
31 return false;
32 }
33 let bit = 1u64 << index;
34 let previous = value.fetch_and(!bit, Ordering::AcqRel);
35 (previous & bit) == bit
36}
37
38#[inline(always)]
39pub fn try_acquire(value: &AtomicU64, index: u64) -> (u64, u64, bool) {
40 if !is_set(value, index) {
41 return (0, 0, false);
42 }
43 let bit = 1u64 << index;
44 let previous = value.fetch_and(!bit, Ordering::AcqRel);
45 (bit, previous, (previous & bit) == bit)
46}
47
48#[inline(always)]
49pub fn is_set(value: &AtomicU64, index: u64) -> bool {
50 let bit = 1u64 << index;
52 (value.load(Ordering::Relaxed) & bit) != 0
53}
54
55pub fn find_nearest_set_bit(value: u64, start_index: u64) -> u64 {
56 if start_index >= 64 {
57 return 64;
58 }
59
60 let mask_forward = !((1u64 << start_index) - 1); let forward_bits = value & mask_forward;
63
64 if forward_bits != 0 {
65 return forward_bits.trailing_zeros() as u64;
67 }
68
69 let mask_backward = (1u64 << start_index) - 1; let backward_bits = value & mask_backward;
72
73 if backward_bits != 0 {
74 return 63 - backward_bits.leading_zeros() as u64;
76 }
77
78 64
80}
81
82pub fn find_nearest_by_distance0(value: u64, start_index: u64) -> u64 {
83 let out_of_bounds = start_index >= 64;
84 let idx = start_index & 63;
85
86 let forward_bits = value & !((1u64 << idx) - 1);
87 let backward_bits = value & ((1u64 << idx) - 1);
88
89 let f_idx = forward_bits.trailing_zeros() as u64;
90 let b_idx = 63 - backward_bits.leading_zeros() as u64;
91
92 let f_valid = forward_bits != 0;
93 let b_valid = backward_bits != 0;
94
95 let f_dist = f_idx - idx;
96 let b_dist = idx - b_idx;
97
98 let use_forward = f_valid && (!b_valid || f_dist <= b_dist);
100 let use_backward = b_valid && !use_forward;
101
102 let result = if use_forward {
103 f_idx
104 } else if use_backward {
105 b_idx
106 } else {
107 64
108 };
109
110 if out_of_bounds { 64 } else { result }
111}
112
113pub fn find_nearest_by_distance_branchless(value: u64, start_index: u64) -> u64 {
114 let valid = (start_index < 64) as u64;
116 let clamped_index = start_index & 63; let mask_forward = !((1u64 << clamped_index) - 1);
120 let forward_bits = value & mask_forward;
121 let mask_backward = (1u64 << clamped_index) - 1;
122 let backward_bits = value & mask_backward;
123
124 let forward_tz = forward_bits.trailing_zeros() as u64;
126 let forward_valid = (forward_bits != 0) as u64;
127 let forward_index = forward_tz | (64 * (1 - forward_valid));
128
129 let backward_lz = backward_bits.leading_zeros() as u64;
130 let backward_valid = (backward_bits != 0) as u64;
131 let backward_index = (63 - backward_lz) | (64 * (1 - backward_valid));
132
133 let forward_dist = forward_index - clamped_index;
135 let backward_dist = clamped_index - backward_index;
136
137 let choose_forward = ((forward_dist <= backward_dist) & (forward_valid != 0)) as u64;
139 let choose_backward = ((backward_dist < forward_dist) & (backward_valid != 0)) as u64;
140
141 let result = forward_index * choose_forward
142 + backward_index * choose_backward
143 + 64 * (1 - choose_forward) * (1 - choose_backward);
144
145 result | (64 * (1 - valid))
147}
148
149pub fn find_nearest_by_distance(value: u64, start_index: u64) -> u64 {
150 if start_index >= 64 {
151 return 64;
152 }
153
154 let mask_forward = !((1u64 << start_index) - 1);
156 let forward_bits = value & mask_forward;
157 let mask_backward = (1u64 << start_index) - 1;
158 let backward_bits = value & mask_backward;
159
160 if forward_bits != 0 {
161 let forward_index = forward_bits.trailing_zeros() as u64;
162
163 if backward_bits == 0 {
164 return forward_index;
165 }
166
167 let forward_dist = forward_index - start_index;
168 let backward_index = 63 - backward_bits.leading_zeros() as u64;
169 let backward_dist = start_index - backward_index;
170
171 if forward_dist < backward_dist {
172 forward_index
173 } else {
174 backward_index
175 }
176 } else if backward_bits != 0 {
177 63 - backward_bits.leading_zeros() as u64
178 } else {
179 64
180 }
181}
182
183pub fn find_nearest(value: u64, signal_index: u64) -> u64 {
257 find_nearest_by_distance(value, signal_index)
258 }
260
261#[cfg(test)]
262mod tests {
263 use super::*;
264
265 #[test]
266 fn nearest_test() {
267 let signal = AtomicU64::new(0);
268 let _ = set(&signal, 33u64);
269 println!("33: {}", is_set(&signal, 33));
270 println!("32: {}", is_set(&signal, 32));
271 set(&signal, 63);
272 println!(
273 "nearest by dist 35: {}",
274 find_nearest_by_distance(signal.load(Ordering::Relaxed), 35)
275 );
276 println!(
277 "nearest by dist branchless 35: {}",
278 find_nearest_by_distance_branchless(signal.load(Ordering::Relaxed), 35)
279 );
280 println!(
281 "nearest 35: {}",
282 find_nearest_set_bit(signal.load(Ordering::Relaxed), 35)
283 );
284 println!(
285 "nearest 31: {}",
286 find_nearest_set_bit(signal.load(Ordering::Relaxed), 31)
287 );
288 println!(
289 "nearest 1: {}",
290 find_nearest_set_bit(signal.load(Ordering::Relaxed), 1)
291 );
292 }
293}