-- | Signed integer version of dynamic word vectors. -- -- See "Data.Vector.Compact.WordVec" for more details. {-# LANGUAGE BangPatterns #-} module Data.Vector.Compact.IntVec where -------------------------------------------------------------------------------- import Data.Bits import Data.List import Data.Vector.Compact.WordVec ( Shape(..) ) import qualified Data.Vector.Compact.WordVec as Dyn -------------------------------------------------------------------------------- -- * The dynamic Int vector type -- | A dynamic int vector is a (small) vector of small signed integers stored compactly newtype IntVec = IntVec Dyn.WordVec deriving (Eq,Ord) vecShape :: IntVec -> Shape vecShape (IntVec dyn) = Dyn.vecShape dyn vecLen :: IntVec -> Int vecLen (IntVec dyn) = Dyn.vecLen dyn vecBits :: IntVec -> Int vecBits (IntVec dyn) = Dyn.vecBits dyn -------------------------------------------------------------------------------- instance Show IntVec where showsPrec = showsPrecIntVec showIntVec :: IntVec -> String showIntVec vec = showsPrecIntVec 0 vec [] showsPrecIntVec :: Int -> IntVec -> ShowS showsPrecIntVec prec intvec = showParen (prec > 10) $ showString "fromList " -- . showsPrec 11 (lenMinMax intvec) . showChar ' ' . shows (toList intvec) -------------------------------------------------------------------------------- -- * Empty empty :: IntVec empty = fromList [] null :: IntVec -> Bool null v = vecLen v == 0 -------------------------------------------------------------------------------- -- * Conversion from\/to lists toList :: IntVec -> [Int] toList (IntVec dynvec) = map (word2int bits) $ Dyn.toList dynvec where !bits = Dyn.vecBits dynvec fromList :: [Int] -> IntVec fromList xs = IntVec $ Dyn.fromList' (Dyn.Shape len bits) $ map (int2word bits) xs where (!len,!minMax) = lenMinMax xs !bits = roundBits (bitsNeededForMinMax minMax) fromList' :: (Int,(Int,Int)) -> [Int] -> IntVec fromList' (!len,!minMax) xs = IntVec $ Dyn.fromList' (Dyn.Shape len bits) $ map (int2word bits) xs where !bits = roundBits (bitsNeededForMinMax minMax) lenMinMax :: [Int] -> (Int,(Int,Int)) lenMinMax = go 0 0 0 where go !cnt !p !q (x:xs) = go (cnt+1) (min x p) (max x q) xs go !cnt !p !q [] = (cnt,(p,q)) int2word :: Int -> (Int -> Word) int2word !bits = i2w where !mask = shiftL 1 bits - 1 :: Word i2w :: Int -> Word i2w x = (fromIntegral x :: Word) .&. mask word2int :: Int -> (Word -> Int) word2int !bits = w2i where !mask = shiftL 1 bits - 1 :: Word !ffff = complement mask :: Word !bitsMinus1 = bits - 1 w2i :: Word -> Int w2i x = case testBit x bitsMinus1 of False -> fromIntegral x -- non-negative True -> fromIntegral (ffff .|. x) -- negative -------------------------------------------------------------------------------- -- * Indexing unsafeIndex :: Int -> IntVec -> Int unsafeIndex idx (IntVec dynvec) = word2int bits (Dyn.unsafeIndex idx dynvec) where !bits = Dyn.vecBits dynvec safeIndex :: Int -> IntVec -> Maybe Int safeIndex idx (IntVec dynvec) = (word2int bits) <$> (Dyn.safeIndex idx dynvec) where !bits = Dyn.vecBits dynvec head :: IntVec -> Int head (IntVec dynvec) = word2int bits (Dyn.head dynvec) where !bits = Dyn.vecBits dynvec -------------------------------------------------------------------------------- {- concat :: IntVec -> IntVec -> IntVec concat u v = fromList' (Shape (lu+lv) (max bu bv)) (toList u ++ toList v) where Shape lu bu = vecShape u Shape lv bv = vecShape v -} -------------------------------------------------------------------------------- -- * helpers for counting the necessary number of bits bitsNeededForMinMax :: (Int,Int) -> Int bitsNeededForMinMax (p,q) = max (bitsNeededFor p) (bitsNeededFor q) bitsNeededFor :: Int -> Int bitsNeededFor bound | bound >= 0 = ceilingLog2 ( bound + 1) + 1 -- +8 needs 5 bits (-16..+15) | bound < 0 = ceilingLog2 (abs bound ) + 1 -- -8 needs 4 bits (-8 ..+7 ) where -- | Smallest integer @k@ such that @2^k@ is larger or equal to @n@ ceilingLog2 :: Int -> Int ceilingLog2 0 = 0 ceilingLog2 n = 1 + go (n-1) where go 0 = -1 go k = 1 + go (shiftR k 1) -- | We only allow multiples of 4. roundBits :: Int -> Int roundBits 0 = 4 roundBits k = shiftL (shiftR (k+3) 2) 2 --------------------------------------------------------------------------------