Skip to content

Commit d8e473c

Browse files
bonzinijiangliu
authored andcommitted
address: add alignment methods
Add methods to round addresses up to the next power of two. This in turn requires adding the zero() and one() method; Rust does not have a standard trait, so I am using From<u8> instead. Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
1 parent c6ff340 commit d8e473c

File tree

1 file changed

+65
-2
lines changed

1 file changed

+65
-2
lines changed

src/address.rs

Lines changed: 65 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@
1919
//! object and defines methods to access and manipulate it.
2020
2121
use std::cmp::{Eq, Ord, PartialEq, PartialOrd};
22-
use std::ops::{Add, BitAnd, BitOr, Sub};
22+
use std::fmt::Debug;
23+
use std::ops::{Add, BitAnd, BitOr, Not, Sub};
2324

2425
/// Simple helper trait used to store a raw address value.
2526
pub trait AddressValue {
@@ -29,10 +30,23 @@ pub trait AddressValue {
2930
+ Eq
3031
+ PartialOrd
3132
+ Ord
33+
+ Not<Output = Self::V>
3234
+ Add<Output = Self::V>
3335
+ Sub<Output = Self::V>
3436
+ BitAnd<Output = Self::V>
35-
+ BitOr<Output = Self::V>;
37+
+ BitOr<Output = Self::V>
38+
+ Debug
39+
+ From<u8>;
40+
41+
/// Return the value zero, coerced into the value type `Self::V`
42+
fn zero() -> Self::V {
43+
0u8.into()
44+
}
45+
46+
/// Return the value zero, coerced into the value type `Self::V`
47+
fn one() -> Self::V {
48+
1u8.into()
49+
}
3650
}
3751

3852
/// Trait to represent an address within an address space.
@@ -89,6 +103,21 @@ pub trait Address:
89103
self.raw_value() - base.raw_value()
90104
}
91105

106+
/// Returns self, aligned to the given power of two.
107+
fn checked_align_up(&self, power_of_two: Self::V) -> Option<Self> {
108+
let mask = power_of_two - Self::one();
109+
assert_ne!(power_of_two, Self::zero());
110+
assert_eq!(power_of_two & mask, Self::zero());
111+
self.checked_add(mask).map(|x| x & !mask)
112+
}
113+
114+
/// Returns self, aligned to the given power of two.
115+
/// Only use this when the result is guaranteed not to overflow.
116+
fn unchecked_align_up(&self, power_of_two: Self::V) -> Self {
117+
let mask = power_of_two - Self::one();
118+
self.unchecked_add(mask) & !mask
119+
}
120+
92121
/// Computes `self + other`, returning `None` if overflow occurred.
93122
fn checked_add(&self, other: Self::V) -> Option<Self>;
94123

@@ -232,6 +261,40 @@ mod tests {
232261
assert!(a < b);
233262
}
234263

264+
#[test]
265+
fn test_checked_align_up() {
266+
assert_eq!(
267+
MockAddress::new(0x128).checked_align_up(8),
268+
Some(MockAddress(0x128))
269+
);
270+
assert_eq!(
271+
MockAddress::new(0x128).checked_align_up(16),
272+
Some(MockAddress(0x130))
273+
);
274+
assert_eq!(
275+
MockAddress::new(std::u64::MAX - 0x3fff).checked_align_up(0x10000),
276+
None
277+
);
278+
}
279+
280+
#[test]
281+
#[should_panic]
282+
fn test_checked_align_up_invalid() {
283+
let _ = MockAddress::new(0x128).checked_align_up(12);
284+
}
285+
286+
#[test]
287+
fn test_unchecked_align_up() {
288+
assert_eq!(
289+
MockAddress::new(0x128).unchecked_align_up(8),
290+
MockAddress(0x128)
291+
);
292+
assert_eq!(
293+
MockAddress::new(0x128).unchecked_align_up(16),
294+
MockAddress(0x130)
295+
);
296+
}
297+
235298
#[test]
236299
fn test_mask() {
237300
let a = MockAddress(0x5050);

0 commit comments

Comments
 (0)