blob: 913a2f50e9c5cea33889301dacb4943839458097 [file] [log] [blame]
// Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause
//! Contains a generic implementation of `BitmapSlice`.
use std::fmt::{self, Debug};
use std::ops::Deref;
use std::sync::Arc;
use crate::bitmap::{Bitmap, BitmapSlice, WithBitmapSlice};
/// Represents a slice into a `Bitmap` object, starting at `base_offset`.
#[derive(Clone, Copy)]
pub struct BaseSlice<B> {
inner: B,
base_offset: usize,
}
impl<B> BaseSlice<B> {
/// Create a new `BitmapSlice`, starting at the specified `offset`.
pub fn new(inner: B, offset: usize) -> Self {
BaseSlice {
inner,
base_offset: offset,
}
}
}
impl<'a, B> WithBitmapSlice<'a> for BaseSlice<B>
where
B: Clone + Deref,
B::Target: Bitmap,
{
type S = Self;
}
impl<B> BitmapSlice for BaseSlice<B>
where
B: Clone + Deref,
B::Target: Bitmap,
{
}
impl<B> Bitmap for BaseSlice<B>
where
B: Clone + Deref,
B::Target: Bitmap,
{
/// Mark the memory range specified by the given `offset` (relative to the base offset of
/// the slice) and `len` as dirtied.
fn mark_dirty(&self, offset: usize, len: usize) {
// The `Bitmap` operations are supposed to accompany guest memory accesses defined by the
// same parameters (i.e. offset & length), so we use simple wrapping arithmetic instead of
// performing additional checks. If an overflow would occur, we simply end up marking some
// other region as dirty (which is just a false positive) instead of a region that could
// not have been accessed to begin with.
self.inner
.mark_dirty(self.base_offset.wrapping_add(offset), len)
}
fn dirty_at(&self, offset: usize) -> bool {
self.inner.dirty_at(self.base_offset.wrapping_add(offset))
}
/// Create a new `BitmapSlice` starting from the specified `offset` into the current slice.
fn slice_at(&self, offset: usize) -> Self {
BaseSlice {
inner: self.inner.clone(),
base_offset: self.base_offset.wrapping_add(offset),
}
}
}
impl<B> Debug for BaseSlice<B> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
// Dummy impl for now.
write!(f, "(bitmap slice)")
}
}
impl<B: Default> Default for BaseSlice<B> {
fn default() -> Self {
BaseSlice {
inner: B::default(),
base_offset: 0,
}
}
}
/// A `BitmapSlice` implementation that wraps a reference to a `Bitmap` object.
pub type RefSlice<'a, B> = BaseSlice<&'a B>;
/// A `BitmapSlice` implementation that uses an `Arc` handle to a `Bitmap` object.
pub type ArcSlice<B> = BaseSlice<Arc<B>>;
#[cfg(test)]
mod tests {
use super::*;
use crate::bitmap::tests::{range_is_clean, range_is_dirty, test_bitmap};
use crate::bitmap::AtomicBitmap;
#[test]
fn test_slice() {
let bitmap_size = 0x1_0000;
let dirty_offset = 0x1000;
let dirty_len = 0x100;
{
let bitmap = AtomicBitmap::new(bitmap_size, 1);
let slice1 = bitmap.slice_at(0);
let slice2 = bitmap.slice_at(dirty_offset);
assert!(range_is_clean(&slice1, 0, bitmap_size));
assert!(range_is_clean(&slice2, 0, dirty_len));
bitmap.mark_dirty(dirty_offset, dirty_len);
assert!(range_is_dirty(&slice1, dirty_offset, dirty_len));
assert!(range_is_dirty(&slice2, 0, dirty_len));
}
{
let bitmap = AtomicBitmap::new(bitmap_size, 1);
let slice = bitmap.slice_at(0);
test_bitmap(&slice);
}
}
}