{-# LANGUAGE BangPatterns #-}
module Data.Vector.Compact.IntVec
(
IntVec(..)
, Shape(..)
, vecShape
, vecLen , vecBits
, showIntVec , showsPrecIntVec
, null , empty
, singleton , isSingleton
, fromList , fromList' , fromList''
, lenMinMax
, toList , toRevList
, unsafeIndex , safeIndex
, head , tail , cons , uncons
, last , snoc
, concat
, fold
, naiveMap , boundedMap
, naiveZipWith , boundedZipWith , listZipWith
, bitsNeededForMinMax
, bitsNeededFor
, roundBits
)
where
import Prelude hiding ( head , tail , init , last , null , concat )
import qualified Data.List as L
import Data.Bits
import Data.Vector.Compact.WordVec ( Shape(..) )
import qualified Data.Vector.Compact.WordVec as Dyn
newtype IntVec
= IntVec Dyn.WordVec
instance Eq IntVec where
(==) x y = (vecLen x == vecLen y) && (toList x == toList y)
instance Ord IntVec where
compare x y = case compare (vecLen x) (vecLen y) of
LT -> LT
GT -> GT
EQ -> compare (toList x) (toList y)
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 "
. showChar ' '
. shows (toList intvec)
empty :: IntVec
empty = fromList []
null :: IntVec -> Bool
null v = vecLen v == 0
singleton :: Int -> IntVec
singleton i = fromList [i]
isSingleton :: IntVec -> Maybe Int
isSingleton (IntVec dynvec) = case Dyn.isSingleton dynvec of
Nothing -> Nothing
Just w -> Just $ word2int (Dyn.vecBits dynvec) w
toList :: IntVec -> [Int]
toList (IntVec dynvec) = map (word2int bits) $ Dyn.toList dynvec where
!bits = Dyn.vecBits dynvec
toRevList :: IntVec -> [Int]
toRevList (IntVec dynvec) = map (word2int bits) $ Dyn.toRevList 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)
fromList'' :: Shape -> [Int] -> IntVec
fromList'' shape@(Shape len !bits) xs = IntVec $ Dyn.fromList' shape $ map (int2word bits) xs
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
True -> fromIntegral (ffff .|. x)
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
last :: IntVec -> Int
last (IntVec dynvec) = word2int bits (Dyn.last dynvec) where
!bits = Dyn.vecBits dynvec
tail :: IntVec -> IntVec
tail (IntVec dynvec) = IntVec (Dyn.tail dynvec)
uncons :: IntVec -> Maybe (Int,IntVec)
uncons (IntVec dynvec) = case Dyn.uncons dynvec of
Nothing -> Nothing
Just (w,tl) -> Just (word2int bits w , IntVec tl)
where
bits = Dyn.vecBits dynvec
cons :: Int -> IntVec -> IntVec
cons k ivec@(IntVec vec) = IntVec $ Dyn.fromList' shape' $ map (int2word bits') (k : toList ivec) where
(Shape len bits) = Dyn.vecShape vec
bits' = roundBits $ max bits (bitsNeededFor k)
shape' = Shape (len+1) bits'
snoc :: IntVec -> Int -> IntVec
snoc ivec@(IntVec vec) k = IntVec $ Dyn.fromList' shape' $ map (int2word bits') (toList ivec ++ [k]) where
(Shape len bits) = Dyn.vecShape vec
bits' = roundBits $ max bits (bitsNeededFor k)
shape' = Shape (len+1) bits'
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
fold :: (a -> Int -> a) -> a -> IntVec -> a
fold f x v = L.foldl' f x (toList v)
naiveMap :: (Int -> Int) -> IntVec -> IntVec
naiveMap f u = fromList (map f $ toList u)
boundedMap :: (Int,Int) -> (Int -> Int) -> IntVec -> IntVec
boundedMap minMax f vec = fromList'' (Shape l bits) (toList vec) where
l = vecLen vec
bits = roundBits $ bitsNeededForMinMax minMax
naiveZipWith :: (Int -> Int -> Int) -> IntVec -> IntVec -> IntVec
naiveZipWith f u v = fromList $ L.zipWith f (toList u) (toList v)
boundedZipWith :: (Int,Int) -> (Int -> Int -> Int) -> IntVec -> IntVec -> IntVec
boundedZipWith minMax f vec1 vec2 = fromList'' (Shape l bits) $ L.zipWith f (toList vec1) (toList vec2) where
l = min (vecLen vec1) (vecLen vec2)
bits = roundBits $ bitsNeededForMinMax minMax
listZipWith :: (Int -> Int -> a) -> IntVec -> IntVec -> [a]
listZipWith f u v = L.zipWith f (toList u) (toList v)
bitsNeededForMinMax :: (Int,Int) -> Int
bitsNeededForMinMax (p,q) = max (bitsNeededFor p) (bitsNeededFor q)
bitsNeededFor :: Int -> Int
bitsNeededFor = roundBits . bitsNeededFor'
bitsNeededFor' :: Int -> Int
bitsNeededFor' bound
| bound >= 0 = ceilingLog2 ( bound + 1) + 1
| bound < 0 = ceilingLog2 (abs bound ) + 1
where
ceilingLog2 :: Int -> Int
ceilingLog2 0 = 0
ceilingLog2 n = 1 + go (n-1) where
go 0 = -1
go k = 1 + go (shiftR k 1)
roundBits :: Int -> Int
roundBits 0 = 4
roundBits k = shiftL (shiftR (k+3) 2) 2