1 /*
2 * Copyright (C) 2021 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 /// Common block and page size in Linux.
18 pub const CHUNK_SIZE: u64 = 4096;
19
divide_roundup(dividend: u64, divisor: u64) -> u6420 pub fn divide_roundup(dividend: u64, divisor: u64) -> u64 {
21 (dividend + divisor - 1) / divisor
22 }
23
24 /// Given `offset` and `length`, generates (offset, size) tuples that together form the same length,
25 /// and aligned to `alignment`.
26 pub struct ChunkedSizeIter {
27 remaining: usize,
28 offset: u64,
29 alignment: usize,
30 }
31
32 impl ChunkedSizeIter {
new(remaining: usize, offset: u64, alignment: usize) -> Self33 pub fn new(remaining: usize, offset: u64, alignment: usize) -> Self {
34 ChunkedSizeIter { remaining, offset, alignment }
35 }
36 }
37
38 impl Iterator for ChunkedSizeIter {
39 type Item = (u64, usize);
40
next(&mut self) -> Option<Self::Item>41 fn next(&mut self) -> Option<Self::Item> {
42 if self.remaining == 0 {
43 return None;
44 }
45 let chunk_data_size = std::cmp::min(
46 self.remaining,
47 self.alignment - (self.offset % self.alignment as u64) as usize,
48 );
49 let retval = (self.offset, chunk_data_size);
50 self.offset += chunk_data_size as u64;
51 self.remaining = self.remaining.saturating_sub(chunk_data_size);
52 Some(retval)
53 }
54 }
55
56 #[cfg(test)]
57 mod tests {
58 use super::*;
59
collect_chunk_read_iter(remaining: usize, offset: u64) -> Vec<(u64, usize)>60 fn collect_chunk_read_iter(remaining: usize, offset: u64) -> Vec<(u64, usize)> {
61 ChunkedSizeIter::new(remaining, offset, 4096).collect::<Vec<_>>()
62 }
63
64 #[test]
test_chunk_read_iter()65 fn test_chunk_read_iter() {
66 assert_eq!(collect_chunk_read_iter(4096, 0), [(0, 4096)]);
67 assert_eq!(collect_chunk_read_iter(8192, 0), [(0, 4096), (4096, 4096)]);
68 assert_eq!(collect_chunk_read_iter(8192, 4096), [(4096, 4096), (8192, 4096)]);
69
70 assert_eq!(
71 collect_chunk_read_iter(16384, 1),
72 [(1, 4095), (4096, 4096), (8192, 4096), (12288, 4096), (16384, 1)]
73 );
74
75 assert_eq!(collect_chunk_read_iter(0, 0), []);
76 assert_eq!(collect_chunk_read_iter(0, 100), []);
77 }
78 }
79