{-| 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