strict-data-0.2.0.2: src/Data/StrictVector.hs
{-# OPTIONS_GHC -fno-warn-name-shadowing #-}
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TypeFamilies #-}
module Data.StrictVector
( module Data.Vector.Generic
, Vector
, null, length, (!), (!?), head, last
, fromList, fromListN, toList, empty, singleton
, generate, generateM
, catMaybes, mapMaybe, lastMay, toHashSet
, lookAround
, dropWhileEnd
, dropWhileLookingAround
, fromSL
, imapM, binarySearchL, binarySearchR
, sort
, sortBy
, sortOn
, groupBy
, groupOn
, toSL
, uncons
, updateVector, updateVectorWith
, unfoldrM, unfoldrNM
, theOnlyOne
) where
import Data.Option
import Data.StrictList (SL, toLazyList, fromLazyList)
-- import qualified Cpm.Util.List as L
import qualified Data.StrictVector.Mutable as VM
import Control.DeepSeq (NFData)
import Control.Monad
import Data.Aeson (ToJSON, FromJSON(..))
import Data.Bits (shiftR)
import Data.Data
import Data.HashSet (HashSet)
import Data.Hashable (Hashable(..))
import Data.Vector.Generic hiding
( Vector, fromList, fromListN, toList, empty, singleton, null, length ,(!), (!?), head, last
, imapM, generate, generateM, unfoldrNM, unfoldrM, mapMaybe)
import Prelude hiding
( map, drop, dropWhile, concatMap, length, zip3, mapM, null, (++), replicate, head, last)
import Safe.Plus
import Test.QuickCheck (Arbitrary(..))
import Text.Read
import qualified Control.Applicative as A
import qualified Control.Monad.Fail
import qualified Data.HashSet as HashSet
import qualified Data.Vector as V
import qualified Data.Vector.Algorithms.Intro as VA (sortBy, sort)
import qualified Data.Vector.Fusion.Bundle.Monadic as VFM
import qualified Data.Vector.Generic as VG
import qualified GHC.Exts as Exts
newtype Vector a = Vector (V.Vector a)
deriving (Eq, Ord, NFData, ToJSON, Monoid, Foldable, Data, Typeable)
type instance VG.Mutable Vector = VM.MVector
instance VG.Vector Vector a where
basicUnsafeFreeze (VM.MVector v) = fmap Vector (basicUnsafeFreeze v)
basicUnsafeThaw (Vector v) = fmap VM.MVector (basicUnsafeThaw v)
basicLength (Vector v) = basicLength v
basicUnsafeSlice n m (Vector v) = Vector (basicUnsafeSlice n m v)
basicUnsafeIndexM (Vector v) = basicUnsafeIndexM v
basicUnsafeCopy (VM.MVector v1) (Vector v2) = basicUnsafeCopy v1 v2
elemseq _ = seq
instance Show a => Show (Vector a) where
showsPrec = VG.showsPrec
instance Read a => Read (Vector a) where
readPrec = VG.readPrec
readListPrec = readListPrecDefault
instance (Hashable a) => Hashable (Vector a) where
hashWithSalt = hashVectorWithSalt
instance Arbitrary a => Arbitrary (Vector a) where
arbitrary = VG.fromList <$> arbitrary
instance Functor Vector where
{-# INLINE fmap #-}
fmap = VG.map
instance Control.Monad.Fail.MonadFail Vector where
{-# INLINE fail #-}
fail _ = VG.empty
instance Monad Vector where
{-# INLINE return #-}
return = VG.singleton
{-# INLINE (>>=) #-}
(>>=) = flip VG.concatMap
{-# INLINE fail #-}
fail = safeFail
instance MonadPlus Vector where
{-# INLINE mzero #-}
mzero = VG.empty
{-# INLINE mplus #-}
mplus = (VG.++)
instance Applicative Vector where
{-# INLINE pure #-}
pure = VG.singleton
{-# INLINE (<*>) #-}
(<*>) = ap
instance A.Alternative Vector where
{-# INLINE empty #-}
empty = VG.empty
{-# INLINE (<|>) #-}
(<|>) = (VG.++)
instance Traversable Vector where
{-# INLINE traverse #-}
traverse f xs = fromList <$> traverse f (toList xs)
{-# INLINE mapM #-}
mapM = VG.mapM
{-# INLINE sequence #-}
sequence = VG.sequence
instance Exts.IsList (Vector a) where
type Item (Vector a) = a
fromList = fromList
fromListN = fromListN
toList = toList
instance FromJSON a => FromJSON (Vector a) where
parseJSON x = (convert :: V.Vector a -> Vector a) <$> parseJSON x
-- | /O(1)/ Yield the length of the vector.
length :: Vector a -> Int
{-# INLINE length #-}
length = VG.length
-- | /O(1)/ Test whether a vector if empty
null :: Vector a -> Bool
{-# INLINE null #-}
null = VG.null
-- | O(1) Indexing
(!) :: Vector a -> Int -> a
{-# INLINE (!) #-}
(!) = (VG.!)
-- | O(1) Safe indexing
(!?) :: Vector a -> Int -> Maybe a
{-# INLINE (!?) #-}
(!?) = (VG.!?)
-- | /O(1)/ First element
head :: Vector a -> a
{-# INLINE head #-}
head = VG.head
-- | /O(1)/ Last element
last :: Vector a -> a
{-# INLINE last #-}
last = VG.last
fromList :: [a] -> Vector a
{-# INLINE fromList #-}
fromList = VG.fromList
fromListN :: Int -> [a] -> Vector a
{-# INLINE fromListN #-}
fromListN = VG.fromListN
toList :: Vector a -> [a]
{-# INLINE toList #-}
toList = VG.toList
singleton :: a -> Vector a
{-# INLINE singleton #-}
singleton = VG.singleton
empty :: Vector a
{-# INLINE empty #-}
empty = VG.empty
generate :: Int -> (Int -> a) -> Vector a
{-# INLINE generate #-}
generate = VG.generate
generateM :: Monad m => Int -> (Int -> m a) -> m (Vector a)
{-# INLINE generateM #-}
generateM = VG.generateM
fromSL :: SL a -> Vector a
{-# INLINE fromSL #-}
fromSL = VG.fromList . toLazyList
toSL :: Vector a -> SL a
{-# INLINE toSL #-}
toSL = fromLazyList . toList
{-# INLINABLE hashVectorWithSalt #-}
hashVectorWithSalt :: Hashable a => Int -> Vector a -> Int
hashVectorWithSalt salt v = foldl' hashWithSalt salt v
{-# INLINABLE mapMaybe #-}
mapMaybe :: (a -> Maybe b) -> Vector a -> Vector b
mapMaybe f = catMaybes . map f
{-# INLINABLE catMaybes #-}
catMaybes :: Vector (Maybe a) -> Vector a
catMaybes = concatMap maybeToVector
{-# INLINABLE maybeToVector #-}
maybeToVector :: Maybe a -> Vector a
maybeToVector Nothing = VG.empty
maybeToVector (Just x) = VG.singleton x
{-# INLINABLE lastMay #-}
lastMay :: Vector a -> Maybe a
lastMay vec =
vec !? ((length vec) - 1)
uncons :: Vector a -> Option (a, Vector a)
uncons v | null v = None
| otherwise = Some (unsafeHead v, drop 1 v)
-- | Returns `Just` the only element of the vector if there is exactly
-- one element or `Nothing` otherwise.
theOnlyOne :: Vector a -> Maybe a
theOnlyOne xs
| length xs /= 1 = Nothing
| otherwise = xs !? 0
{-# INLINABLE lookAround #-}
lookAround :: Vector a -> Vector (Maybe a, a, Maybe a)
lookAround v = zip3 lookBehind v lookAhead
where
lookBehind = Nothing `cons` map Just v
lookAhead = drop 1 (map Just v) `snoc` Nothing
{-# INLINABLE toHashSet #-}
toHashSet :: (Eq a, Hashable a) => Vector a -> HashSet a
toHashSet = foldl' (\set elem -> HashSet.insert elem set) HashSet.empty
dropWhileLookingAround :: (Maybe a -> a -> Maybe a -> Bool) -> Vector a -> Vector a
dropWhileLookingAround f = map (\(_, v, _) -> v) . dropWhile (\(x,y,z) -> f x y z) . lookAround
dropWhileEnd :: (a -> Bool) -> Vector a -> Vector a
dropWhileEnd pred v =
case pred `fmap` (v !? (length v - 1)) of
Nothing -> v
Just False -> v
Just True ->
let toDelete count =
case pred `fmap` (v !? (length v - count - 1)) of
Nothing -> count
Just False -> count
Just True -> toDelete (count + 1)
in VG.take (length v - toDelete 1) v
imapM :: Monad m => (Int -> a -> m b) -> Vector a -> m (Vector b)
{-# INLINE imapM #-}
imapM = VG.imapM
binarySearchL :: (e -> Ordering) -> Vector e -> Int
binarySearchL cmp vec = loop 0 (length vec)
where
loop !l !u
| u <= l = l
| otherwise =
let k = (u + l) `shiftR` 1
in case cmp (vec ! k) of
LT -> loop (k+1) u
_ -> loop l k
binarySearchR :: (e -> Ordering) -> Vector e -> Int
binarySearchR cmp vec = loop 0 (length vec)
where
loop !l !u
| u <= l = l
| otherwise =
let k = (u + l) `shiftR` 1
in case cmp (vec ! k) of
GT -> loop l k
_ -> loop (k+1) u
sortOn :: Ord b => (a -> b) -> Vector a -> Vector a
sortOn f = sortBy (\x y -> compare (f x) (f y))
sortBy :: (a -> a -> Ordering) -> Vector a -> Vector a
sortBy comp v =
modify (VA.sortBy comp) v
sort :: Ord a => Vector a -> Vector a
sort v = modify VA.sort v
groupBy :: (a -> a -> Bool) -> Vector a -> Vector (Vector a)
groupBy eq xs = unfoldrN (VG.length xs) next xs
where
next ys
| VG.null ys = Nothing
| otherwise =
let y = VG.unsafeHead ys
ys' = VG.unsafeTail ys
(l1,l2) = VG.span (eq y) ys'
in Just (y `VG.cons` l1, l2)
groupOn :: Eq b => (a -> b) -> Vector a -> Vector (b, (Vector a))
groupOn proj xs = unfoldrN (VG.length xs) next xs
where
next ys
| VG.null ys = Nothing
| otherwise =
let y = VG.unsafeHead ys
z = proj y
ys' = VG.unsafeTail ys
(l1,l2) = VG.span (\x -> proj x == z) ys'
in Just ((z , y `VG.cons` l1), l2)
unfoldrM :: Monad m => (s -> m (Maybe (a, s))) -> s -> m (Vector a)
unfoldrM f s = unstreamM (VFM.unfoldrM f s)
unfoldrNM :: Monad m => Int -> (s -> m (Maybe (a, s))) -> s -> m (Vector a)
unfoldrNM n f s = unstreamM (VFM.unfoldrNM n f s)
-- | Copied from Data.Vector.Generic as it isn't exported there
unstreamM :: (Monad m) => VFM.Bundle m u a -> m (Vector a)
{-# INLINE unstreamM #-}
unstreamM s =
do xs <- VFM.toList s
return $ unstream $ VFM.unsafeFromList (VFM.size s) xs
updateVector :: Int -> a -> a -> Vector a -> Vector a
updateVector comp def val vect = updateVectorWith comp def (const val) vect
updateVectorWith :: Int -> a -> (a -> a) -> Vector a -> Vector a
updateVectorWith comp def val vect =
let vect' =
if comp >= length vect
then vect ++ replicate (comp - (length vect) + 1) def
else vect
in vect' // [(comp, val (vect' ! comp))]