Skip to main content

sshash_lib/
constants.rs

1//! Constants and configuration for SSHash
2//!
3//! This module defines compile-time and runtime constants used throughout
4//! the library, including valid k-mer sizes and algorithm parameters.
5
6/// Invalid value sentinel (matching C++ behavior)
7pub const INVALID_UINT64: u64 = u64::MAX;
8
9/// Default seed for hash functions
10pub const DEFAULT_SEED: u64 = 1;
11
12/// Default RAM limit in GiB for construction
13pub const DEFAULT_RAM_LIMIT_GIB: usize = 8;
14
15/// For PTHash/PHast MPHF construction
16pub const DEFAULT_LAMBDA: f64 = 5.0;
17/// Average partition size for MPHF construction
18pub const AVG_PARTITION_SIZE: usize = 3_000_000;
19
20/// Bucket size range parameters (for sparse and skew index)
21pub const MIN_L: usize = 6;
22/// Maximum bucket size parameter
23pub const MAX_L: usize = 13;
24
25/// Orientation constants
26pub const FORWARD_ORIENTATION: i8 = 1;
27/// Backward (reverse complement) orientation
28pub const BACKWARD_ORIENTATION: i8 = -1;
29
30/// Version number
31pub const VERSION: (u8, u8, u8) = (0, 1, 0);
32
33/// All valid k-mer sizes (odd numbers from 3 to 63)
34/// This is the single source of truth for supported K values
35pub const VALID_K_VALUES: &[usize] = &[
36    3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 43, 45, 47, 49,
37    51, 53, 55, 57, 59, 61, 63,
38];
39
40/// Check if a k-mer size is valid
41#[inline]
42pub const fn is_valid_k(k: usize) -> bool {
43    k >= 3 && k <= 63 && k % 2 == 1
44}
45
46/// Maximum k-mer size supported
47pub const MAX_K: usize = 63;
48
49/// Minimum k-mer size supported
50pub const MIN_K: usize = 3;
51
52/// Compute ceil(log2(x)), matching C++ std::ceil(std::log2(x)).
53///
54/// Returns 0 for x <= 1, and the minimum number of bits needed to
55/// represent values in [0, x) for x >= 2.
56#[inline]
57pub const fn ceil_log2(x: u64) -> usize {
58    if x <= 1 {
59        0
60    } else {
61        64 - (x - 1).leading_zeros() as usize
62    }
63}
64
65#[cfg(test)]
66mod tests {
67    use super::*;
68
69    #[test]
70    fn test_valid_k_values() {
71        // Verify all values in VALID_K_VALUES are actually valid
72        for &k in VALID_K_VALUES {
73            assert!(is_valid_k(k), "k={} should be valid", k);
74        }
75
76        // Verify count (31 odd numbers from 3 to 63)
77        assert_eq!(VALID_K_VALUES.len(), 31);
78
79        // Verify no duplicates
80        let mut sorted = VALID_K_VALUES.to_vec();
81        sorted.sort_unstable();
82        sorted.dedup();
83        assert_eq!(sorted.len(), VALID_K_VALUES.len());
84    }
85
86    #[test]
87    fn test_is_valid_k() {
88        // Valid cases
89        assert!(is_valid_k(3));
90        assert!(is_valid_k(31));
91        assert!(is_valid_k(63));
92        assert!(is_valid_k(21));
93
94        // Invalid cases (even)
95        assert!(!is_valid_k(2));
96        assert!(!is_valid_k(4));
97        assert!(!is_valid_k(30));
98        assert!(!is_valid_k(32));
99
100        // Invalid cases (out of range)
101        assert!(!is_valid_k(1));
102        assert!(!is_valid_k(65));
103        assert!(!is_valid_k(100));
104    }
105}