Encode a slice of f64 values using ALP compression. Finds the optimal decimal exponent, converts to integers, stores exceptions for values that don't round-trip, and bit-packs the integers via FastLanes.
(values: &[f64])
| 88 | /// exceptions for values that don't round-trip, and bit-packs the integers |
| 89 | /// via FastLanes. |
| 90 | pub fn encode(values: &[f64]) -> Vec<u8> { |
| 91 | let count = values.len() as u32; |
| 92 | |
| 93 | if values.is_empty() { |
| 94 | let mut out = Vec::with_capacity(11); |
| 95 | out.extend_from_slice(&0u32.to_le_bytes()); // count |
| 96 | out.push(0); // encode exponent |
| 97 | out.push(0); // decode exponent |
| 98 | out.push(0); // mode |
| 99 | out.extend_from_slice(&0u32.to_le_bytes()); // exception count |
| 100 | return out; |
| 101 | } |
| 102 | |
| 103 | // Step 1: Find optimal parameters by sampling. |
| 104 | let params = find_best_params(values); |
| 105 | let factor = POW10[params.encode_exp as usize]; |
| 106 | |
| 107 | // Step 2: Encode values to integers, collect exceptions. |
| 108 | let mut encoded_ints = Vec::with_capacity(values.len()); |
| 109 | let mut exceptions: Vec<(u32, u64)> = Vec::new(); |
| 110 | |
| 111 | for (i, &val) in values.iter().enumerate() { |
| 112 | let encoded = try_alp_encode(val, factor, params.decode_exp, params.mode); |
| 113 | match encoded { |
| 114 | Some(int_val) => { |
| 115 | encoded_ints.push(int_val); |
| 116 | } |
| 117 | None => { |
| 118 | // Exception: store original bits, use 0 as placeholder in int array. |
| 119 | exceptions.push((i as u32, val.to_bits())); |
| 120 | encoded_ints.push(0); |
| 121 | } |
| 122 | } |
| 123 | } |
| 124 | |
| 125 | // Step 3: Build output. |
| 126 | let exception_count = exceptions.len() as u32; |
| 127 | let packed_ints = fastlanes::encode(&encoded_ints); |
| 128 | |
| 129 | let mut out = Vec::with_capacity(10 + exceptions.len() * 12 + packed_ints.len()); |
| 130 | |
| 131 | // Header. |
| 132 | out.extend_from_slice(&count.to_le_bytes()); |
| 133 | out.push(params.encode_exp); |
| 134 | out.push(params.decode_exp); |
| 135 | out.push(match params.mode { |
| 136 | DecodeMode::MultiplyInverse => 0, |
| 137 | DecodeMode::DivideByFactor => 1, |
| 138 | }); |
| 139 | out.extend_from_slice(&exception_count.to_le_bytes()); |
| 140 | |
| 141 | // Exceptions. |
| 142 | for &(idx, bits) in &exceptions { |
| 143 | out.extend_from_slice(&idx.to_le_bytes()); |
| 144 | out.extend_from_slice(&bits.to_le_bytes()); |
| 145 | } |
| 146 | |
| 147 | // Packed integers. |