symphonia_core/
util.rs

1// Symphonia
2// Copyright (c) 2019-2022 The Project Symphonia Developers.
3//
4// This Source Code Form is subject to the terms of the Mozilla Public
5// License, v. 2.0. If a copy of the MPL was not distributed with this
6// file, You can obtain one at https://mozilla.org/MPL/2.0/.
7
8//! The `util` module provides a repository of commonly used utility functions sorted into distinct
9//! categories.
10//!
11//! If a function is used all-over the codebase, and does not belong to specific top-level module,
12//! it should be placed here.
13
14pub mod bits {
15    //! Utilities for bit manipulation.
16
17    /// Sign extends an arbitrary, 8-bit or less, signed two's complement integer stored within an
18    /// u8 to a full width i8.
19    #[inline(always)]
20    pub fn sign_extend_leq8_to_i8(value: u8, width: u32) -> i8 {
21        // Rust uses an arithmetic shift right (the original sign bit is repeatedly shifted on) for
22        // signed integer types. Therefore, shift the value to the right-hand side of the integer,
23        // then shift it back to extend the sign bit.
24        (value.wrapping_shl(8 - width) as i8).wrapping_shr(8 - width)
25    }
26
27    /// Sign extends an arbitrary, 16-bit or less, signed two's complement integer stored within an
28    /// u16 to a full width i16.
29    #[inline(always)]
30    pub fn sign_extend_leq16_to_i16(value: u16, width: u32) -> i16 {
31        (value.wrapping_shl(16 - width) as i16).wrapping_shr(16 - width)
32    }
33
34    /// Sign extends an arbitrary, 32-bit or less, signed two's complement integer stored within an
35    /// u32 to a full width i32.
36    #[inline(always)]
37    pub fn sign_extend_leq32_to_i32(value: u32, width: u32) -> i32 {
38        (value.wrapping_shl(32 - width) as i32).wrapping_shr(32 - width)
39    }
40
41    /// Sign extends an arbitrary, 64-bit or less, signed two's complement integer stored within an
42    /// u64 to a full width i64.
43    #[inline(always)]
44    pub fn sign_extend_leq64_to_i64(value: u64, width: u32) -> i64 {
45        (value.wrapping_shl(64 - width) as i64).wrapping_shr(64 - width)
46    }
47
48    /// Masks the bit at the specified bit index.
49    #[inline(always)]
50    pub fn mask_at(idx: u32) -> u8 {
51        debug_assert!(idx <= 7);
52        1 << idx
53    }
54
55    /// Masks all bits with an index greater than or equal to idx.
56    #[inline(always)]
57    pub fn mask_upper_eq(idx: u32) -> u8 {
58        debug_assert!(idx <= 7);
59        !((1 << idx) - 1)
60    }
61
62    /// Masks all bits with an index greater than idx.
63    #[inline(always)]
64    pub fn mask_upper(idx: u32) -> u8 {
65        debug_assert!(idx <= 7);
66        !((1 << idx) - 1) ^ (1 << idx)
67    }
68
69    /// Masks all bits with an index less than or equal to idx.
70    #[inline(always)]
71    pub fn mask_lower_eq(idx: u32) -> u8 {
72        debug_assert!(idx <= 7);
73        ((1 << idx) - 1) ^ (1 << idx)
74    }
75
76    /// Masks all bits with an index less than idx.
77    #[inline(always)]
78    pub fn mask_lower(idx: u32) -> u8 {
79        debug_assert!(idx <= 7);
80        (1 << idx) - 1
81    }
82
83    /// Masks out all bits in positions less than upper, but greater than or equal to lower
84    /// (upper < bit <= lower)
85    #[inline(always)]
86    pub fn mask_range(upper: u32, lower: u32) -> u8 {
87        debug_assert!(upper <= 8);
88        debug_assert!(lower <= 8);
89        ((0xff_u32 << upper) ^ (0xff_u32 << lower)) as u8
90    }
91
92    /// Returns the number of trailing ones in an unsigned 8-bit integer.
93    #[inline(always)]
94    pub fn trailing_ones_u8(value: u8) -> u32 {
95        (!value & value.wrapping_add(1)).trailing_zeros()
96    }
97
98    /// Returns the number of trailing ones in an unsigned 16-bit integer.
99    #[inline(always)]
100    pub fn trailing_ones_u16(value: u16) -> u32 {
101        (!value & value.wrapping_add(1)).trailing_zeros()
102    }
103
104    /// Returns the number of trailing ones in an unsigned 32-bit integer.
105    #[inline(always)]
106    pub fn trailing_ones_u32(value: u32) -> u32 {
107        (!value & value.wrapping_add(1)).trailing_zeros()
108    }
109
110    /// Returns the number of trailing ones in an unsigned 64-bit integer.
111    #[inline(always)]
112    pub fn trailing_ones_u64(value: u64) -> u32 {
113        (!value & value.wrapping_add(1)).trailing_zeros()
114    }
115
116    /// Returns true if the unsigned 16-bit integer contains one or more bytes which have all bits
117    /// set.
118    #[inline(always)]
119    pub fn contains_ones_byte_u16(value: u16) -> bool {
120        ((value & !value.wrapping_add(0x0101)) & 0x8080) != 0
121    }
122
123    /// Returns true if the unsigned 32-bit integer contains one or more bytes which have all bits
124    /// set.
125    #[inline(always)]
126    pub fn contains_ones_byte_u32(value: u32) -> bool {
127        ((value & !value.wrapping_add(0x0101_0101)) & 0x8080_8080) != 0
128    }
129
130    /// Returns true if the unsigned 64-bit integer contains one or more bytes which have all bits
131    /// set.
132    #[inline(always)]
133    pub fn contains_ones_byte_u64(value: u64) -> bool {
134        ((value & !value.wrapping_add(0x0101_0101_0101_0101)) & 0x8080_8080_8080_8080) != 0
135    }
136
137    #[test]
138    fn verify_trailing_ones() {
139        assert_eq!(trailing_ones_u32(0), 0);
140        assert_eq!(trailing_ones_u32(1), 1);
141        assert_eq!(trailing_ones_u32(2), 0);
142        assert_eq!(trailing_ones_u32(3), 2);
143        assert_eq!(trailing_ones_u32(0xf00f_7fff), 15);
144        assert_eq!(trailing_ones_u32(0xffff_ffff), 32);
145    }
146
147    #[test]
148    fn verify_masks() {
149        assert_eq!(mask_at(0), 0b0000_0001);
150        assert_eq!(mask_at(1), 0b0000_0010);
151        assert_eq!(mask_at(2), 0b0000_0100);
152        assert_eq!(mask_at(3), 0b0000_1000);
153        assert_eq!(mask_at(4), 0b0001_0000);
154        assert_eq!(mask_at(5), 0b0010_0000);
155        assert_eq!(mask_at(6), 0b0100_0000);
156        assert_eq!(mask_at(7), 0b1000_0000);
157
158        assert_eq!(mask_upper(0), 0b1111_1110);
159        assert_eq!(mask_upper(1), 0b1111_1100);
160        assert_eq!(mask_upper(2), 0b1111_1000);
161        assert_eq!(mask_upper(3), 0b1111_0000);
162        assert_eq!(mask_upper(4), 0b1110_0000);
163        assert_eq!(mask_upper(5), 0b1100_0000);
164        assert_eq!(mask_upper(6), 0b1000_0000);
165        assert_eq!(mask_upper(7), 0b0000_0000);
166
167        assert_eq!(mask_upper_eq(0), 0b1111_1111);
168        assert_eq!(mask_upper_eq(1), 0b1111_1110);
169        assert_eq!(mask_upper_eq(2), 0b1111_1100);
170        assert_eq!(mask_upper_eq(3), 0b1111_1000);
171        assert_eq!(mask_upper_eq(4), 0b1111_0000);
172        assert_eq!(mask_upper_eq(5), 0b1110_0000);
173        assert_eq!(mask_upper_eq(6), 0b1100_0000);
174        assert_eq!(mask_upper_eq(7), 0b1000_0000);
175
176        assert_eq!(mask_lower(0), 0b0000_0000);
177        assert_eq!(mask_lower(1), 0b0000_0001);
178        assert_eq!(mask_lower(2), 0b0000_0011);
179        assert_eq!(mask_lower(3), 0b0000_0111);
180        assert_eq!(mask_lower(4), 0b0000_1111);
181        assert_eq!(mask_lower(5), 0b0001_1111);
182        assert_eq!(mask_lower(6), 0b0011_1111);
183        assert_eq!(mask_lower(7), 0b0111_1111);
184
185        assert_eq!(mask_lower_eq(0), 0b0000_0001);
186        assert_eq!(mask_lower_eq(1), 0b0000_0011);
187        assert_eq!(mask_lower_eq(2), 0b0000_0111);
188        assert_eq!(mask_lower_eq(3), 0b0000_1111);
189        assert_eq!(mask_lower_eq(4), 0b0001_1111);
190        assert_eq!(mask_lower_eq(5), 0b0011_1111);
191        assert_eq!(mask_lower_eq(6), 0b0111_1111);
192        assert_eq!(mask_lower_eq(7), 0b1111_1111);
193
194        assert_eq!(mask_range(0, 0), 0b0000_0000);
195        assert_eq!(mask_range(1, 1), 0b0000_0000);
196        assert_eq!(mask_range(7, 7), 0b0000_0000);
197        assert_eq!(mask_range(1, 0), 0b0000_0001);
198        assert_eq!(mask_range(2, 0), 0b0000_0011);
199        assert_eq!(mask_range(7, 0), 0b0111_1111);
200        assert_eq!(mask_range(5, 2), 0b0001_1100);
201        assert_eq!(mask_range(7, 2), 0b0111_1100);
202        assert_eq!(mask_range(8, 2), 0b1111_1100);
203    }
204}
205
206pub mod clamp {
207    //! Utilities for clamping numeric values to a defined range.
208
209    /// Clamps the given value to the [0, 255] range.
210    #[inline]
211    pub fn clamp_u8(val: u16) -> u8 {
212        if val & !0xff == 0 {
213            val as u8
214        }
215        else {
216            0xff
217        }
218    }
219
220    /// Clamps the given value to the [-128, 127] range.
221    #[inline]
222    pub fn clamp_i8(val: i16) -> i8 {
223        // Add 128 (0x80) to the given value, val, to make the i8 range of [-128,127] map to
224        // [0,255]. Valid negative numbers are now positive so all bits above the 8th bit should be
225        // 0. Check this by ANDing with 0xffffff00 (!0xff). If val wraps, the test is still valid as
226        // it'll wrap around to the other numerical limit +/- 128, which is still well outside the
227        // limits of an i8.
228        if val.wrapping_add(0x80) & !0xff == 0 {
229            val as i8
230        }
231        else {
232            // The given value was determined to be outside the valid numerical range of i8.
233            //
234            // Shift right all the magnitude bits of val, leaving val to be either 0xff if val was
235            // negative (sign bit was 1), or 0x00 if val was positive (sign bit was 0). Xor the
236            // shift value with 0x7f (the positive limit) to obtain the appropriate numerical limit.
237            //
238            //  E.g., 0x7f ^ 0x00 = 0x7f (127)
239            //  E.g., 0x7f ^ 0xff = 0x10 (-128)
240            0x7f ^ val.wrapping_shr(15) as i8
241        }
242    }
243
244    /// Clamps the given value to the [0, 65_535] range.
245    #[inline]
246    pub fn clamp_u16(val: u32) -> u16 {
247        if val & !0xffff == 0 {
248            val as u16
249        }
250        else {
251            0xffff
252        }
253    }
254
255    /// Clamps the given value to the [-32_767, 32_768] range.
256    #[inline]
257    pub fn clamp_i16(val: i32) -> i16 {
258        if val.wrapping_add(0x8000) & !0xffff == 0 {
259            val as i16
260        }
261        else {
262            0x7fff ^ val.wrapping_shr(31) as i16
263        }
264    }
265
266    /// Clamps the given value to the [0, 16_777_215] range.
267    #[inline]
268    pub fn clamp_u24(val: u32) -> u32 {
269        if val & !0x00ff_ffff == 0 {
270            val
271        }
272        else {
273            0x00ff_ffff
274        }
275    }
276
277    /// Clamps the given value to the [-8_388_608, 8_388_607] range.
278    #[inline]
279    pub fn clamp_i24(val: i32) -> i32 {
280        if val.wrapping_add(0x0080_0000) & !0x00ff_ffff == 0 {
281            val
282        }
283        else {
284            0x007f_ffff ^ val.wrapping_shr(31)
285        }
286    }
287
288    /// Clamps the given value to the [0, 4_294_967_295] range.
289    #[inline]
290    pub fn clamp_u32(val: u64) -> u32 {
291        if val & !0xffff_ffff == 0 {
292            val as u32
293        }
294        else {
295            0xffff_ffff
296        }
297    }
298
299    /// Clamps the given value to the [-2_147_483_648, 2_147_483_647] range.
300    #[inline]
301    pub fn clamp_i32(val: i64) -> i32 {
302        if val.wrapping_add(0x8000_0000) & !0xffff_ffff == 0 {
303            val as i32
304        }
305        else {
306            0x7fff_ffff ^ val.wrapping_shr(63) as i32
307        }
308    }
309
310    /// Clamps the given value to the [-1.0, 1.0] range.
311    #[inline]
312    pub fn clamp_f32(val: f32) -> f32 {
313        // This slightly inelegant code simply returns min(max(1.0, val), -1.0). In release mode on
314        // platforms with SSE2 support, it will compile down to 4 SSE instructions with no branches,
315        // thereby making it the most performant clamping implementation for floating-point samples.
316        let mut clamped = val;
317        clamped = if clamped > 1.0 { 1.0 } else { clamped };
318        clamped = if clamped < -1.0 { -1.0 } else { clamped };
319        clamped
320    }
321
322    /// Clamps the given value to the [-1.0, 1.0] range.
323    #[inline]
324    pub fn clamp_f64(val: f64) -> f64 {
325        let mut clamped = val;
326        clamped = if clamped > 1.0 { 1.0 } else { clamped };
327        clamped = if clamped < -1.0 { -1.0 } else { clamped };
328        clamped
329    }
330
331    #[cfg(test)]
332    mod tests {
333        use super::*;
334        use std::{i16, i32, i64, i8, u16, u32, u64, u8};
335
336        #[test]
337        fn verify_clamp() {
338            assert_eq!(clamp_u8(256u16), u8::MAX);
339            assert_eq!(clamp_u8(u16::MAX), u8::MAX);
340
341            assert_eq!(clamp_i8(128i16), i8::MAX);
342            assert_eq!(clamp_i8(-129i16), i8::MIN);
343            assert_eq!(clamp_i8(i16::MAX), i8::MAX);
344            assert_eq!(clamp_i8(i16::MIN), i8::MIN);
345
346            assert_eq!(clamp_u16(65536u32), u16::MAX);
347            assert_eq!(clamp_u16(u32::MAX), u16::MAX);
348
349            assert_eq!(clamp_i16(32_768i32), i16::MAX);
350            assert_eq!(clamp_i16(-32_769i32), i16::MIN);
351            assert_eq!(clamp_i16(i32::MAX), i16::MAX);
352            assert_eq!(clamp_i16(i32::MIN), i16::MIN);
353
354            assert_eq!(clamp_u32(4_294_967_296u64), u32::MAX);
355            assert_eq!(clamp_u32(u64::MAX), u32::MAX);
356
357            assert_eq!(clamp_i32(2_147_483_648i64), i32::MAX);
358            assert_eq!(clamp_i32(-2_147_483_649i64), i32::MIN);
359            assert_eq!(clamp_i32(i64::MAX), i32::MAX);
360            assert_eq!(clamp_i32(i64::MIN), i32::MIN);
361
362            assert_eq!(clamp_f32(1.1), 1.0);
363            assert_eq!(clamp_f32(5.6), 1.0);
364            assert_eq!(clamp_f32(0.5), 0.5);
365            assert_eq!(clamp_f32(-1.1), -1.0);
366            assert_eq!(clamp_f32(-5.6), -1.0);
367            assert_eq!(clamp_f32(-0.5), -0.5);
368
369            assert_eq!(clamp_f64(1.1), 1.0);
370            assert_eq!(clamp_f64(5.6), 1.0);
371            assert_eq!(clamp_f64(0.5), 0.5);
372            assert_eq!(clamp_f64(-1.1), -1.0);
373            assert_eq!(clamp_f64(-5.6), -1.0);
374            assert_eq!(clamp_f64(-0.5), -0.5);
375        }
376    }
377}