1 // Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 // SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause
3 
4 //! Contains a generic implementation of `BitmapSlice`.
5 
6 use std::fmt::{self, Debug};
7 use std::ops::Deref;
8 use std::sync::Arc;
9 
10 use crate::bitmap::{Bitmap, BitmapSlice, WithBitmapSlice};
11 
12 /// Represents a slice into a `Bitmap` object, starting at `base_offset`.
13 #[derive(Clone, Copy)]
14 pub struct BaseSlice<B> {
15     inner: B,
16     base_offset: usize,
17 }
18 
19 impl<B> BaseSlice<B> {
20     /// Create a new `BitmapSlice`, starting at the specified `offset`.
new(inner: B, offset: usize) -> Self21     pub fn new(inner: B, offset: usize) -> Self {
22         BaseSlice {
23             inner,
24             base_offset: offset,
25         }
26     }
27 }
28 
29 impl<'a, B> WithBitmapSlice<'a> for BaseSlice<B>
30 where
31     B: Clone + Deref,
32     B::Target: Bitmap,
33 {
34     type S = Self;
35 }
36 
37 impl<B> BitmapSlice for BaseSlice<B>
38 where
39     B: Clone + Deref,
40     B::Target: Bitmap,
41 {
42 }
43 
44 impl<B> Bitmap for BaseSlice<B>
45 where
46     B: Clone + Deref,
47     B::Target: Bitmap,
48 {
49     /// Mark the memory range specified by the given `offset` (relative to the base offset of
50     /// the slice) and `len` as dirtied.
mark_dirty(&self, offset: usize, len: usize)51     fn mark_dirty(&self, offset: usize, len: usize) {
52         // The `Bitmap` operations are supposed to accompany guest memory accesses defined by the
53         // same parameters (i.e. offset & length), so we use simple wrapping arithmetic instead of
54         // performing additional checks. If an overflow would occur, we simply end up marking some
55         // other region as dirty (which is just a false positive) instead of a region that could
56         // not have been accessed to begin with.
57         self.inner
58             .mark_dirty(self.base_offset.wrapping_add(offset), len)
59     }
60 
dirty_at(&self, offset: usize) -> bool61     fn dirty_at(&self, offset: usize) -> bool {
62         self.inner.dirty_at(self.base_offset.wrapping_add(offset))
63     }
64 
65     /// Create a new `BitmapSlice` starting from the specified `offset` into the current slice.
slice_at(&self, offset: usize) -> Self66     fn slice_at(&self, offset: usize) -> Self {
67         BaseSlice {
68             inner: self.inner.clone(),
69             base_offset: self.base_offset.wrapping_add(offset),
70         }
71     }
72 }
73 
74 impl<B> Debug for BaseSlice<B> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result75     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
76         // Dummy impl for now.
77         write!(f, "(bitmap slice)")
78     }
79 }
80 
81 impl<B: Default> Default for BaseSlice<B> {
default() -> Self82     fn default() -> Self {
83         BaseSlice {
84             inner: B::default(),
85             base_offset: 0,
86         }
87     }
88 }
89 
90 /// A `BitmapSlice` implementation that wraps a reference to a `Bitmap` object.
91 pub type RefSlice<'a, B> = BaseSlice<&'a B>;
92 
93 /// A `BitmapSlice` implementation that uses an `Arc` handle to a `Bitmap` object.
94 pub type ArcSlice<B> = BaseSlice<Arc<B>>;
95 
96 #[cfg(test)]
97 mod tests {
98     use super::*;
99 
100     use crate::bitmap::tests::{range_is_clean, range_is_dirty, test_bitmap};
101     use crate::bitmap::AtomicBitmap;
102 
103     #[test]
test_slice()104     fn test_slice() {
105         let bitmap_size = 0x1_0000;
106         let dirty_offset = 0x1000;
107         let dirty_len = 0x100;
108 
109         {
110             let bitmap = AtomicBitmap::new(bitmap_size, 1);
111             let slice1 = bitmap.slice_at(0);
112             let slice2 = bitmap.slice_at(dirty_offset);
113 
114             assert!(range_is_clean(&slice1, 0, bitmap_size));
115             assert!(range_is_clean(&slice2, 0, dirty_len));
116 
117             bitmap.mark_dirty(dirty_offset, dirty_len);
118 
119             assert!(range_is_dirty(&slice1, dirty_offset, dirty_len));
120             assert!(range_is_dirty(&slice2, 0, dirty_len));
121         }
122 
123         {
124             let bitmap = AtomicBitmap::new(bitmap_size, 1);
125             let slice = bitmap.slice_at(0);
126             test_bitmap(&slice);
127         }
128     }
129 }
130