module Bio.SeqLoc.ShiftedVector
where
import Prelude hiding (length)
import Control.Arrow
import Data.Maybe
import Data.Monoid
import qualified Data.Vector as V
data ShiftedVector a = ShiftedVector { zerois :: !Int, nullis :: !a, vector :: !(V.Vector a) } deriving (Show)
empty :: (Monoid a) => ShiftedVector a
empty = ShiftedVector { zerois = 0, nullis = mempty, vector = V.empty }
emptyZ :: a -> ShiftedVector a
emptyZ z = ShiftedVector { zerois = 0, nullis = z, vector = V.empty }
singleton :: (Monoid a) => Int -> a -> ShiftedVector a
singleton i x = ShiftedVector { zerois = i, nullis = mempty, vector = V.singleton x }
replicate :: (Monoid a) => Int -> Int -> a -> ShiftedVector a
replicate i0 n x = ShiftedVector { zerois = i0, nullis = mempty, vector = V.replicate n x }
length :: ShiftedVector a -> Int
length = V.length . vector
null :: ShiftedVector a -> Bool
null = V.null . vector
start :: ShiftedVector a -> Int
start = zerois
end :: ShiftedVector a -> Int
end sv = zerois sv + length sv 1
(!?) :: ShiftedVector a -> Int -> a
(!?) sv i = fromMaybe (nullis sv) $ (vector sv) V.!? (i zerois sv)
(//) :: ShiftedVector a -> [(Int, a)] -> ShiftedVector a
(//) sv0 ixs | Prelude.null ixs = sv0
| otherwise = updateUnsafe sv'
where ilow = minimum . map fst $ ixs
ihigh = maximum . map fst $ ixs
sv' = ensureLow ilow . ensureHigh ihigh $ sv0
updateUnsafe sv = sv { vector = vector sv V.// jxs }
where jxs = map (first $ subtract (zerois sv)) ixs
modifySome :: ShiftedVector a -> [Int] -> (a -> a) -> ShiftedVector a
modifySome sv0 is f | Prelude.null is = sv0
| otherwise = modifyUnsafe sv'
where ilow = minimum is
ihigh = maximum is
sv' = ensureLow ilow . ensureHigh ihigh $ sv0
modifyUnsafe sv = let js = map (subtract (zerois sv)) is
ys = [ f (sv !? i) | i <- is ]
in sv { vector = vector sv V.// (zip js ys) }
ensureLow :: Int -> ShiftedVector a -> ShiftedVector a
ensureLow lb sv0 = case zerois sv0 lb of
down | down <= 0 -> sv0
| otherwise -> let !d = max down ((V.length . vector $ sv0) `div` 2)
in sv0 { zerois = zerois sv0 d, vector = (V.replicate d $ nullis sv0) V.++ vector sv0 }
ensureHigh :: Int -> ShiftedVector a -> ShiftedVector a
ensureHigh ub sv0 = case ub end sv0 of
up | up <= 0 -> sv0
| otherwise -> let !u = max up ((V.length . vector $ sv0) `div` 2)
in sv0 { vector = vector sv0 V.++ (V.replicate u $ nullis sv0) }