xref: /aosp_15_r20/bootable/libbootloader/gbl/libgbl/src/overlap.rs (revision 5225e6b173e52d2efc6bcf950c27374fd72adabc)
1*5225e6b1SAndroid Build Coastguard Worker // Copyright 2024, The Android Open Source Project
2*5225e6b1SAndroid Build Coastguard Worker //
3*5225e6b1SAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*5225e6b1SAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*5225e6b1SAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*5225e6b1SAndroid Build Coastguard Worker //
7*5225e6b1SAndroid Build Coastguard Worker //     http://www.apache.org/licenses/LICENSE-2.0
8*5225e6b1SAndroid Build Coastguard Worker //
9*5225e6b1SAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*5225e6b1SAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*5225e6b1SAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*5225e6b1SAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*5225e6b1SAndroid Build Coastguard Worker // limitations under the License.
14*5225e6b1SAndroid Build Coastguard Worker 
15*5225e6b1SAndroid Build Coastguard Worker //! Helper functions to verify image buffers
16*5225e6b1SAndroid Build Coastguard Worker use core::cmp::{max, min};
17*5225e6b1SAndroid Build Coastguard Worker extern crate itertools_noalloc;
18*5225e6b1SAndroid Build Coastguard Worker use itertools_noalloc::Itertools;
19*5225e6b1SAndroid Build Coastguard Worker 
20*5225e6b1SAndroid Build Coastguard Worker /// Check if provided buffers overlap in any way.
21*5225e6b1SAndroid Build Coastguard Worker ///
22*5225e6b1SAndroid Build Coastguard Worker /// Note that zero length buffer is considered to contain no elements.
23*5225e6b1SAndroid Build Coastguard Worker /// And would not overlap with any other buffer.
24*5225e6b1SAndroid Build Coastguard Worker ///
25*5225e6b1SAndroid Build Coastguard Worker /// # Args
26*5225e6b1SAndroid Build Coastguard Worker ///
27*5225e6b1SAndroid Build Coastguard Worker /// * `buffers`: slice of buffers to verify
28*5225e6b1SAndroid Build Coastguard Worker ///
29*5225e6b1SAndroid Build Coastguard Worker /// # Returns
30*5225e6b1SAndroid Build Coastguard Worker ///
31*5225e6b1SAndroid Build Coastguard Worker /// * true: if any of the buffers have common elements
32*5225e6b1SAndroid Build Coastguard Worker /// * false: if there are no common elements in buffers
is_overlap(buffers: &[&[u8]]) -> bool33*5225e6b1SAndroid Build Coastguard Worker pub fn is_overlap(buffers: &[&[u8]]) -> bool {
34*5225e6b1SAndroid Build Coastguard Worker     // Compare each with each since we can't use alloc and sort buffers.
35*5225e6b1SAndroid Build Coastguard Worker     // Since the number of buffers we expect is not big, O(n^2) complexity will do.
36*5225e6b1SAndroid Build Coastguard Worker     //
37*5225e6b1SAndroid Build Coastguard Worker     // Note: this is nice way to find out if 2 ranges overlap:
38*5225e6b1SAndroid Build Coastguard Worker     // max(a_start, b_start) > min(a_end, b_end)) -> no overlap
39*5225e6b1SAndroid Build Coastguard Worker     buffers
40*5225e6b1SAndroid Build Coastguard Worker         .iter()
41*5225e6b1SAndroid Build Coastguard Worker         .filter(|buffer| !buffer.is_empty())
42*5225e6b1SAndroid Build Coastguard Worker         .map(|slice: &&[u8]| (slice.as_ptr(), slice.last_chunk::<1>().unwrap().as_ptr()))
43*5225e6b1SAndroid Build Coastguard Worker         .tuple_combinations()
44*5225e6b1SAndroid Build Coastguard Worker         .any(|((a_start, a_end), (b_start, b_end))| !(max(a_start, b_start) > min(a_end, b_end)))
45*5225e6b1SAndroid Build Coastguard Worker }
46*5225e6b1SAndroid Build Coastguard Worker 
47*5225e6b1SAndroid Build Coastguard Worker #[cfg(test)]
48*5225e6b1SAndroid Build Coastguard Worker mod tests {
49*5225e6b1SAndroid Build Coastguard Worker     use super::*;
50*5225e6b1SAndroid Build Coastguard Worker     use itertools::Itertools;
51*5225e6b1SAndroid Build Coastguard Worker 
52*5225e6b1SAndroid Build Coastguard Worker     // Creates slice of specified range: [first; last)
53*5225e6b1SAndroid Build Coastguard Worker     // Max range value is SIZE = 64;
get_range(first: usize, last: usize) -> &'static [u8]54*5225e6b1SAndroid Build Coastguard Worker     fn get_range(first: usize, last: usize) -> &'static [u8] {
55*5225e6b1SAndroid Build Coastguard Worker         const SIZE: usize = 64;
56*5225e6b1SAndroid Build Coastguard Worker         assert!(first < SIZE);
57*5225e6b1SAndroid Build Coastguard Worker         assert!(last <= SIZE);
58*5225e6b1SAndroid Build Coastguard Worker         static BUFFER: &'static [u8; SIZE] = &[0; SIZE];
59*5225e6b1SAndroid Build Coastguard Worker         &BUFFER[first..last]
60*5225e6b1SAndroid Build Coastguard Worker     }
61*5225e6b1SAndroid Build Coastguard Worker 
62*5225e6b1SAndroid Build Coastguard Worker     // Check if ranges overlap, testing all permutations
check_overlap(ranges_set: &[(usize, usize)]) -> bool63*5225e6b1SAndroid Build Coastguard Worker     fn check_overlap(ranges_set: &[(usize, usize)]) -> bool {
64*5225e6b1SAndroid Build Coastguard Worker         ranges_set.iter().permutations(ranges_set.len()).all(|ranges| {
65*5225e6b1SAndroid Build Coastguard Worker             let ranges_slices: Vec<&[u8]> =
66*5225e6b1SAndroid Build Coastguard Worker                 ranges.iter().map(|&(start, end)| get_range(*start, *end)).collect();
67*5225e6b1SAndroid Build Coastguard Worker             is_overlap(&ranges_slices)
68*5225e6b1SAndroid Build Coastguard Worker         })
69*5225e6b1SAndroid Build Coastguard Worker     }
70*5225e6b1SAndroid Build Coastguard Worker 
71*5225e6b1SAndroid Build Coastguard Worker     // Check if ranges don't overlap, testing all permutations
check_not_overlap(ranges_set: &[(usize, usize)]) -> bool72*5225e6b1SAndroid Build Coastguard Worker     fn check_not_overlap(ranges_set: &[(usize, usize)]) -> bool {
73*5225e6b1SAndroid Build Coastguard Worker         ranges_set.iter().permutations(ranges_set.len()).all(|ranges| {
74*5225e6b1SAndroid Build Coastguard Worker             let ranges_slices: Vec<&[u8]> =
75*5225e6b1SAndroid Build Coastguard Worker                 ranges.iter().map(|&(start, end)| get_range(*start, *end)).collect();
76*5225e6b1SAndroid Build Coastguard Worker             !is_overlap(&ranges_slices)
77*5225e6b1SAndroid Build Coastguard Worker         })
78*5225e6b1SAndroid Build Coastguard Worker     }
79*5225e6b1SAndroid Build Coastguard Worker 
80*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_is_overlap_false()81*5225e6b1SAndroid Build Coastguard Worker     fn test_is_overlap_false() {
82*5225e6b1SAndroid Build Coastguard Worker         assert!(check_not_overlap(&[(10, 15), (20, 25), (30, 35)]));
83*5225e6b1SAndroid Build Coastguard Worker     }
84*5225e6b1SAndroid Build Coastguard Worker 
85*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_is_overlap_true()86*5225e6b1SAndroid Build Coastguard Worker     fn test_is_overlap_true() {
87*5225e6b1SAndroid Build Coastguard Worker         assert!(check_overlap(&[(10, 19), (15, 25)]));
88*5225e6b1SAndroid Build Coastguard Worker     }
89*5225e6b1SAndroid Build Coastguard Worker 
90*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_is_overlap_included()91*5225e6b1SAndroid Build Coastguard Worker     fn test_is_overlap_included() {
92*5225e6b1SAndroid Build Coastguard Worker         assert!(check_overlap(&[(10, 11), (10, 11)]));
93*5225e6b1SAndroid Build Coastguard Worker         assert!(check_overlap(&[(10, 12), (10, 12)]));
94*5225e6b1SAndroid Build Coastguard Worker         assert!(check_overlap(&[(10, 13), (11, 12)]));
95*5225e6b1SAndroid Build Coastguard Worker         assert!(check_overlap(&[(10, 14), (11, 13)]));
96*5225e6b1SAndroid Build Coastguard Worker         assert!(check_overlap(&[(10, 20), (15, 18)]));
97*5225e6b1SAndroid Build Coastguard Worker         assert!(check_overlap(&[(10, 20), (11, 19), (12, 18), (13, 17)]));
98*5225e6b1SAndroid Build Coastguard Worker     }
99*5225e6b1SAndroid Build Coastguard Worker 
100*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_is_overlap_touching()101*5225e6b1SAndroid Build Coastguard Worker     fn test_is_overlap_touching() {
102*5225e6b1SAndroid Build Coastguard Worker         assert!(check_not_overlap(&[(10, 20), (20, 30), (30, 31)]));
103*5225e6b1SAndroid Build Coastguard Worker     }
104*5225e6b1SAndroid Build Coastguard Worker 
105*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_is_overlap_last_element()106*5225e6b1SAndroid Build Coastguard Worker     fn test_is_overlap_last_element() {
107*5225e6b1SAndroid Build Coastguard Worker         assert!(check_overlap(&[(10, 20), (19, 21)]));
108*5225e6b1SAndroid Build Coastguard Worker     }
109*5225e6b1SAndroid Build Coastguard Worker 
110*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_is_overlap_short()111*5225e6b1SAndroid Build Coastguard Worker     fn test_is_overlap_short() {
112*5225e6b1SAndroid Build Coastguard Worker         assert!(check_not_overlap(&[(10, 11), (11, 12), (12, 13)]));
113*5225e6b1SAndroid Build Coastguard Worker     }
114*5225e6b1SAndroid Build Coastguard Worker 
115*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_is_overlap_empty_slice()116*5225e6b1SAndroid Build Coastguard Worker     fn test_is_overlap_empty_slice() {
117*5225e6b1SAndroid Build Coastguard Worker         assert!(check_not_overlap(&[]));
118*5225e6b1SAndroid Build Coastguard Worker         assert!(check_not_overlap(&[(10, 10)]));
119*5225e6b1SAndroid Build Coastguard Worker         assert!(check_not_overlap(&[(10, 20), (10, 10), (20, 30), (11, 11), (23, 23)]));
120*5225e6b1SAndroid Build Coastguard Worker     }
121*5225e6b1SAndroid Build Coastguard Worker }
122