Skip to content

Commit

Permalink
moved Storage out of BitWidth into its own module. refactored dependi…
Browse files Browse the repository at this point in the history
…ng code. decoupled Width trait verifications and assertions into an own trait.
  • Loading branch information
Robbepop committed Oct 23, 2017
1 parent 2ff4574 commit cdf7d0a
Show file tree
Hide file tree
Showing 9 changed files with 113 additions and 15 deletions.
3 changes: 2 additions & 1 deletion src/apint/casting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
use apint::{APInt, APIntData};
use errors::{Error, Result};

use bitwidth::{BitWidth, Storage};
use bitwidth::{BitWidth};
use storage::{Storage};
use digit::{Bit, Digit};

impl Clone for APInt {
Expand Down
3 changes: 2 additions & 1 deletion src/apint/constructors.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@

use apint::{APInt, APIntData};
use bitwidth::{BitWidth, Storage};
use bitwidth::{BitWidth};
use storage::{Storage};
use digit::{Digit};
use digit;

Expand Down
2 changes: 1 addition & 1 deletion src/apint/utils.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

use bitwidth::{Storage};
use storage::{Storage};
use digit::{Digit};
use apint::{APInt};
use small_apint::{SmallAPInt, SmallAPIntMut};
Expand Down
12 changes: 8 additions & 4 deletions src/bitwidth.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use digit;
use storage::Storage;
use errors::{Result, Error};

/// The `BitWidth` represents the length of an `APInt`.
Expand All @@ -8,9 +9,6 @@ use errors::{Result, Error};
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct BitWidth(usize);

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub(crate) enum Storage { Inl, Ext }

// ===========================================================================
/// Constructors
/// ===========================================================================
Expand Down Expand Up @@ -70,21 +68,27 @@ impl BitWidth {
self.0
}

// TODO: Move this method out of this context. (Does not fit here!)
// ----------------------------------------------------------------
pub(crate) fn excess_bits(self) -> Option<usize> {
match self.to_usize() % digit::BITS {
0 => None,
n => Some(n)
}
}

// TODO: Move this method out of this context. (Fits better as constructor of Storage.)
// ------------------------------------------------------------------------------------
/// Returns a storage specifier that tells the caller if `APInt`'s
/// associated with this bitwidth require an external memory (`Ext`) to store
/// their digits or may use inplace memory (`Inl`).
#[inline]
pub(crate) fn storage(self) -> Storage {
if self.to_usize() < digit::BITS { Storage::Inl } else { Storage::Ext }
Storage::from(self)
}

// TODO: Move this method out of this context. (Does not fit here!)
// ----------------------------------------------------------------
/// Returns the number of digit-blocks that are required to represent any
/// value with a bit-width equal to `self`.
#[inline]
Expand Down
19 changes: 14 additions & 5 deletions src/errors.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use bitwidth::BitWidth;

use std::result;
use std::error;
use std::fmt;
Expand All @@ -8,9 +10,12 @@ pub enum ErrorKind {
InvalidDecimalStr(String),
InvalidHexStr(String),

BitAccessOutOfBounds{bit_idx: usize, upper_bound: usize},
BitAccessOutOfBounds{
bit_idx: usize,
upper_bound: usize
},

UnmatchingBitwidth(usize, usize),
UnmatchingBitwidth(BitWidth, BitWidth),
InvalidZeroBitWidth,
BitWidthOutOfBounds{bitwidth: usize, lo: usize, hi: usize},
BitWidthTooLarge{bitwidth: usize, upper_bound: usize},
Expand Down Expand Up @@ -88,10 +93,14 @@ impl Error {
}

#[inline]
pub(crate) fn unmatching_bitwidths(left: usize, right: usize) -> Error {
pub(crate) fn unmatching_bitwidths<W>(lhs: W, rhs: W) -> Error
where W: Into<BitWidth>
{
let lhs = lhs.into();
let rhs = rhs.into();
Error{
kind: ErrorKind::UnmatchingBitwidth(left, right),
message: format!("Encountered invalid operation on entities with non-matching bit-widths of {:?} and {:?}.", left, right),
kind: ErrorKind::UnmatchingBitwidth(lhs, rhs),
message: format!("Encountered invalid operation on entities with non-matching bit-widths of {:?} and {:?}.", lhs, rhs),
annotation: None
}
}
Expand Down
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ mod errors;
mod traits;
mod digit;
mod bitwidth;
mod storage;
mod small_apint;
mod large_apint;
mod apint;
Expand Down
5 changes: 3 additions & 2 deletions src/small_apint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use bitwidth::BitWidth;
use errors::{Result};
use traits::{
Width,
WidthAssertions,
APIntImpl,
APIntMutImpl,
};
Expand Down Expand Up @@ -114,7 +115,7 @@ impl<'a> DigitMutWrapper for &'a mut SmallAPIntMut<'a> {
// ============================================================================

impl<T> APIntImpl<SmallAPInt> for T
where T: Width + DigitWrapper
where T: Width + WidthAssertions + DigitWrapper
{
#[inline]
fn get(&self, n: usize) -> Result<Bit> {
Expand Down Expand Up @@ -144,7 +145,7 @@ impl<T> APIntImpl<SmallAPInt> for T
}

impl<T> APIntMutImpl<SmallAPInt> for T
where T: Width + DigitMutWrapper
where T: Width + WidthAssertions + DigitMutWrapper
{

#[inline]
Expand Down
40 changes: 40 additions & 0 deletions src/storage.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
use digit;
use bitwidth::BitWidth;

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub(crate) enum Storage { Inl, Ext }

impl<W> From<W> for Storage
where W: Into<BitWidth>
{
#[inline]
fn from(width: W) -> Storage {
let width = width.into();
if Storage::is_inline(width) {
Storage::Inl
}
else {
Storage::Ext
}
}
}

impl Storage {
/// Returns `true` if the given `BitWidth` is small enough to be stored inline.
///
/// Note: Inline storage in the context of `APInt` means that it is space-optimized
/// similar to the well-known small-string optimization.
#[inline]
fn is_inline(width: BitWidth) -> bool {
width.to_usize() < digit::BITS
}

/// Returns `true` if the given `BitWidth` is large enough to require it to be stored externally.
///
/// Note: External storage in the context of `APInt` means that it is **not** space-optimized
/// and thus stored on the heap with indirect access via pointer-to-data.
#[inline]
fn is_extern(width: BitWidth) -> bool {
!Storage::is_inline(width)
}
}
43 changes: 42 additions & 1 deletion src/traits.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,30 @@
use errors::{Error, Result};
use bitwidth::{BitWidth, Storage};
use bitwidth::{BitWidth};
use storage::{Storage};
use digit::{Bit};
use digit;

pub(crate) trait Width {
fn width(&self) -> BitWidth;
}

pub(crate) trait WidthAssertions: Width {
fn verify_bit_access(&self, n: usize) -> Result<()>;
fn assert_bit_access(&self, n: usize);

fn verify_small_bitwidth(&self) -> Result<()>;
fn assert_small_bitwidth(&self);

fn verify_large_bitwidth(&self) -> Result<()>;
fn assert_large_bitwidth(&self);

fn verify_common_bitwidth<W>(&self, other: &W) -> Result<()>
where W: Width;
fn assert_common_bitwidth<W>(&self, other: &W)
where W: Width;
}

impl<T> WidthAssertions for T where T: Width {
#[inline]
fn verify_bit_access(&self, n: usize) -> Result<()> {
if n < self.width().to_usize() {
Expand All @@ -15,6 +34,11 @@ pub(crate) trait Width {
}
}

#[inline]
fn assert_bit_access(&self, n: usize) {
Self::verify_bit_access(self, n).unwrap()
}

#[inline]
fn verify_small_bitwidth(&self) -> Result<()> {
match self.width().storage() {
Expand All @@ -23,6 +47,11 @@ pub(crate) trait Width {
}
}

#[inline]
fn assert_small_bitwidth(&self) {
Self::verify_small_bitwidth(self).unwrap()
}

#[inline]
fn verify_large_bitwidth(&self) -> Result<()> {
match self.width().storage() {
Expand All @@ -31,6 +60,11 @@ pub(crate) trait Width {
}
}

#[inline]
fn assert_large_bitwidth(&self) {
Self::verify_large_bitwidth(self).unwrap()
}

#[inline]
fn verify_common_bitwidth<W>(&self, other: &W) -> Result<()>
where W: Width
Expand All @@ -41,6 +75,13 @@ pub(crate) trait Width {
Error::unmatching_bitwidths(self.width().to_usize(), digit::BITS + 1).into()
}
}

#[inline]
fn assert_common_bitwidth<W>(&self, other: &W)
where W: Width
{
Self::verify_common_bitwidth(self, other).unwrap()
}
}

pub(crate) trait APIntImpl<I>
Expand Down

0 comments on commit cdf7d0a

Please sign in to comment.