use core::sync::atomic::{AtomicU32, Ordering};
pub const NULL_INDEX: i32 = -1;
pub const SECRET_COOKIE: i32 = 1152023;
pub const HASH_INIT: u32 = 5381;
static LENGTH_UNITS_PER_METER_BITS: AtomicU32 = AtomicU32::new(0x3F80_0000);
pub fn set_length_units_per_meter(length_units: f32) {
debug_assert!(crate::math_functions::is_valid_float(length_units) && length_units > 0.0);
LENGTH_UNITS_PER_METER_BITS.store(length_units.to_bits(), Ordering::Relaxed);
}
pub fn get_length_units_per_meter() -> f32 {
f32::from_bits(LENGTH_UNITS_PER_METER_BITS.load(Ordering::Relaxed))
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Version {
pub major: i32,
pub minor: i32,
pub revision: i32,
}
pub fn get_version() -> Version {
Version {
major: 3,
minor: 2,
revision: 0,
}
}
pub fn is_double_precision() -> bool {
cfg!(feature = "double-precision")
}
pub fn hash(hash: u32, data: &[u8]) -> u32 {
let mut result = hash;
for &byte in data {
result = (result << 5).wrapping_add(result).wrapping_add(byte as u32);
}
result
}
pub fn ctz32(block: u32) -> u32 {
block.trailing_zeros()
}
pub fn clz32(value: u32) -> u32 {
value.leading_zeros()
}
pub fn ctz64(block: u64) -> u32 {
block.trailing_zeros()
}
pub fn pop_count64(block: u64) -> i32 {
block.count_ones() as i32
}
pub fn is_power_of2(x: i32) -> bool {
(x & (x - 1)) == 0
}
pub fn bounding_power_of2(x: i32) -> i32 {
if x <= 1 {
return 1;
}
32 - clz32((x as u32) - 1) as i32
}
pub fn round_up_power_of2(x: i32) -> i32 {
if x <= 1 {
return 1;
}
1 << (32 - clz32((x as u32) - 1))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn djb2_hash_matches_reference() {
let mut expected: u32 = HASH_INIT;
for &b in b"box2d" {
expected = (expected << 5)
.wrapping_add(expected)
.wrapping_add(b as u32);
}
assert_eq!(hash(HASH_INIT, b"box2d"), expected);
assert_eq!(hash(HASH_INIT, b""), HASH_INIT);
}
#[test]
fn bit_helpers() {
assert_eq!(ctz32(0b1000), 3);
assert_eq!(clz32(1), 31);
assert_eq!(ctz64(1u64 << 40), 40);
assert_eq!(pop_count64(0xFFFF_FFFF_FFFF_FFFF), 64);
assert!(is_power_of2(8));
assert!(!is_power_of2(6));
assert_eq!(round_up_power_of2(5), 8);
assert_eq!(round_up_power_of2(1), 1);
assert_eq!(bounding_power_of2(5), 3);
}
#[test]
fn version_and_precision() {
let v = get_version();
assert_eq!((v.major, v.minor, v.revision), (3, 2, 0));
assert_eq!(is_double_precision(), cfg!(feature = "double-precision"));
}
#[test]
fn length_units_scale_constants() {
use crate::constants;
assert_eq!(get_length_units_per_meter(), 1.0);
assert_eq!(constants::linear_slop(), 0.005);
set_length_units_per_meter(100.0);
assert_eq!(get_length_units_per_meter(), 100.0);
assert_eq!(constants::linear_slop(), 0.5);
assert_eq!(constants::speculative_distance(), 4.0 * 0.5);
assert_eq!(constants::max_aabb_margin(), 0.05 * 100.0);
set_length_units_per_meter(1.0);
assert_eq!(constants::linear_slop(), 0.005);
}
}