bv-embed-0.1.0: src/Data/BitVector/Embed.hs
{-|
Module : Data.BitVector.Embed
Copyright : (c) Galois Inc. 2018
License : BSD-3
Maintainer : benselfridge@galois.com
Stability : experimental
Portability : portable
This module exports types and functions for defining how a small bit vector is
embedded into a larger one.
-}
module Data.BitVector.Embed
( BitEmbedding
, fromList
, bitEmbed
, bitExtract
) where
import qualified Data.Bits as B
-- | Defines a mapping from each bit of a small bit vector into a larger one.
newtype BitEmbedding = BitEmbedding [Int]
deriving (Eq, Ord, Show)
-- | Construct a `BitEmbedding` from a list, where the length of the list is the same
-- as the width of the "small" bit vector we are embedding into the larger one. The
-- nth element of the list tells us at which bit index in the target to embed bit n
-- of the source.
fromList :: [Int] -> BitEmbedding
fromList = BitEmbedding
-- | Embed a smaller bit vector into a larger one using a `BitEmbedding`.
--
-- >>> bitEmbed (fromList [4,5,7] 7 0)
-- 176
bitEmbed :: (B.Bits src, B.Bits tgt) => BitEmbedding -> src -> tgt -> tgt
bitEmbed (BitEmbedding []) _ tgt = tgt
bitEmbed (BitEmbedding (bit:rst)) src tgt =
bitEmbed (BitEmbedding rst) (src `B.shiftR` 1) (tgt B..|. bitMask)
where bitMask = if B.testBit src 0
then B.bit bit
else B.zeroBits
-- | Extract a smaller bit vector from a larger one using a `BitEmbedding`.
--
-- >>> bitExtract (fromList [4,5,7] 7 0) 176
-- 7
bitExtract :: (B.Bits src, B.Bits tgt) => BitEmbedding -> tgt -> src
bitExtract (BitEmbedding []) _ = B.zeroBits
bitExtract (BitEmbedding (bit:rst)) tgt =
(bitExtract (BitEmbedding rst) tgt `B.shiftL` 1) B..|. bitMask
where bitMask = if B.testBit tgt bit
then B.bit 0
else B.zeroBits