2 releases
0.1.1 | Sep 6, 2023 |
---|---|
0.1.0 | Apr 27, 2020 |
#1275 in Algorithms
17KB
191 lines
Represents a non-negative power of 2, by storing its exponent.
The Pow2
type is limited in range to 1 .. 2^255
(inclusive). It is simply a wrapper around
u8
, which stores the exponent.
Pow2
is typically used for aligning integer values, such as I/O buffer sizes, page sizes,
etc.
Negative powers of 2 are not supported because they have little or no application in managing memory, quick multiplication, etc.
Pow2
can represent values outside of the range of specific integer types. For example,
Pow2::from_exponent(40)
cannot be converted to u32
. The conversion implementations treat
this in a way similar to arithmetic overflow for operations such as x * y
; the operation is
defined, but may fail at runtime.
It would be possible to define a family of Pow2
variants, one for each primitive integer type.
However, the ergonomics of that design might be undesireable; it is left for future study.
The operators defined for Pow2
are defined in terms of the value of the power of 2, not the
exponent. For example, Pow2 * Pow2
results in adding the exponents, not in multiplying the
exponents.
Examples
const PAGE_SIZE: Pow2 = Pow2::from_exponent(12);
assert_eq!(u32::from(PAGE_SIZE), 0x1000);
let x: u32 = 0x1eee;
assert_eq!(PAGE_SIZE.align_down(x), 0x1000);
assert_eq!(PAGE_SIZE.align_up(x), Some(0x2000));
assert_eq!(PAGE_SIZE.align_up_unchecked(x), 0x2000);
The pow2_const!
macro can be used for writing constant powers of 2, using a value rather than
an exponent. Due to current limitations of const fns, the pow2_const!
macro does not check
whether the input is a valid power of 2. If it is not a power of 2, then its behavior is
undefined.
use pow2::{Pow2, pow2_const};
const PAGE_SIZE: Pow2 = pow2_const!(0x1000);
assert_eq!(PAGE_SIZE.exponent(), 12);
Signed examples
Pow2
works with signed types as well as unsigned.
use pow2::Pow2;
const ALIGN4: Pow2 = Pow2::from_exponent(2);
assert_eq!(ALIGN4.align_up(4i32), Some(4i32));
assert_eq!(ALIGN4.align_up(3i32), Some(4i32));
assert_eq!(ALIGN4.align_up(2i32), Some(4i32));
assert_eq!(ALIGN4.align_up(1i32), Some(4i32));
assert_eq!(ALIGN4.align_up(-0i32), Some(0i32));
assert_eq!(ALIGN4.align_up(-1i32), Some(0i32));
assert_eq!(ALIGN4.align_up(-2i32), Some(0i32));
assert_eq!(ALIGN4.align_up(-3i32), Some(0i32));
assert_eq!(ALIGN4.align_up(-4i32), Some(-4i32));
assert_eq!(ALIGN4.align_up(-5i32), Some(-4i32));
assert_eq!(ALIGN4.align_up(-6i32), Some(-4i32));
assert_eq!(ALIGN4.align_up(-7i32), Some(-4i32));
assert_eq!(ALIGN4.align_up(-8i32), Some(-8i32));
Unsafe code examples
This library does not contain unsafe code, but it can be used by unsafe code to operate on pointers. This is because Rust allows safe code to operate on the values of unsafe pointers, but not to dereference them.
use pow2::{Pow2, pow2_const};
const U32_ALIGN: Pow2 = Pow2::align_of::<u32>();
let array: [u32; 4] = [ 111, 222, 333, 444 ];
let item_0_address: *const u8 = &array[0] as *const u32 as *const u8;
let item_1_address: *const u8 = &array[1] as *const u32 as *const u8;
assert_eq!(
U32_ALIGN.align_up((item_0_address as usize + 1) as *const u8).unwrap(),
item_1_address
);
Dependencies
~0.9–1.5MB
~27K SLoC