permutation-0.3: lib/Data/Choose/Base.hs
-----------------------------------------------------------------------------
-- |
-- Module : Data.Choose.Base
-- Copyright : Copyright (c) , Patrick Perry <patperry@stanford.edu>
-- License : BSD3
-- Maintainer : Patrick Perry <patperry@stanford.edu>
-- Stability : experimental
--
module Data.Choose.Base
where
import Control.Monad
import Control.Monad.ST
import Foreign
import Data.IntArray ( IntArray, STIntArray )
import qualified Data.IntArray as Arr
import qualified Data.IntArray as ArrST
--------------------------------- Choose ---------------------------------
-- | The immutable combination data type. A way of representing @k@
-- unordered outcomes from @n@ possiblities. The possibilites are
-- represented as the indices @0, ..., n-1@, and the outcomes are
-- given as a subset of size @k@. The subset is stored with the indices
-- in ascending order.
data Choose = Choose {-# UNPACK #-} !Int -- n
{-# UNPACK #-} !IntArray -- the subset of size k
unsafeAt :: Choose -> Int -> Int
unsafeAt (Choose _ arr) i = Arr.unsafeAt arr i
{-# INLINE unsafeAt #-}
-- | Get the number of outcomes, @k@.
size :: Choose -> Int
size (Choose _ arr) = Arr.numElements arr
{-# INLINE size #-}
-- | Get the number of possibilities, @n@.
possible :: Choose -> Int
possible (Choose n _) = n
{-# INLINE possible #-}
-- | Get a list of the @k@ outcomes.
elems :: Choose -> [Int]
elems (Choose _ arr) = Arr.elems arr
{-# INLINE elems #-}
instance Show Choose where
show c = "listChoose " ++ show n ++ " " ++ show k ++ " " ++ show es
where
n = possible c
k = size c
es = elems c
instance Eq Choose where
(==) c1 c2 = ( (possible c1 == possible c2)
&& (size c1 == size c2)
&& (elems c1 == elems c2)
)
--------------------------------- STChoose --------------------------------
-- | A mutable combination that can be manipulated in the 'ST' monad. The
-- type argument @s@ is the state variable argument for the 'ST' type.
data STChoose s = STChoose {-# UNPACK #-} !Int -- n
{-# UNPACK #-} !(STIntArray s) -- the subset
getSizeSTChoose :: STChoose s -> ST s Int
getSizeSTChoose (STChoose _ marr) = ArrST.getNumElements marr
{-# INLINE getSizeSTChoose #-}
sizeSTChoose :: STChoose s -> Int
sizeSTChoose (STChoose _ marr) = ArrST.numElementsSTIntArray marr
{-# INLINE sizeSTChoose #-}
getPossibleSTChoose :: STChoose s -> ST s Int
getPossibleSTChoose (STChoose n _) = return n
{-# INLINE getPossibleSTChoose #-}
possibleSTChoose :: STChoose s -> Int
possibleSTChoose (STChoose n _) = n
{-# INLINE possibleSTChoose #-}
newSTChoose :: Int -> Int -> ST s (STChoose s)
newSTChoose n k = do
c@(STChoose _ marr) <- newSTChoose_ n k
ArrST.writeElems marr [0 .. k-1]
return c
{-# INLINE newSTChoose #-}
newSTChoose_ :: Int -> Int -> ST s (STChoose s)
newSTChoose_ n k = do
when (n < 0) $ fail "invalid number of possibilities"
when (k < 0 || k > n) $ fail "invalid outcome size"
liftM (STChoose n) $ ArrST.newArray_ k
{-# INLINE newSTChoose_ #-}
unsafeGetElemSTChoose :: STChoose s -> Int -> ST s Int
unsafeGetElemSTChoose (STChoose _ marr) i = ArrST.unsafeRead marr i
{-# INLINE unsafeGetElemSTChoose #-}
unsafeSetElemSTChoose :: STChoose s -> Int -> Int -> ST s ()
unsafeSetElemSTChoose (STChoose _ marr) i x = ArrST.unsafeWrite marr i x
{-# INLINE unsafeSetElemSTChoose #-}
getElemsSTChoose :: STChoose s -> ST s [Int]
getElemsSTChoose (STChoose _ marr) = ArrST.readElems marr
{-# INLINE getElemsSTChoose #-}
setElemsSTChoose :: STChoose s -> [Int] -> ST s ()
setElemsSTChoose (STChoose _ marr) is = ArrST.writeElems marr is
{-# INLINE setElemsSTChoose #-}
unsafeFreezeSTChoose :: STChoose s -> ST s Choose
unsafeFreezeSTChoose (STChoose n marr) =
(liftM (Choose n) . ArrST.unsafeFreeze) marr
{-# INLINE unsafeFreezeSTChoose #-}
unsafeThawSTChoose :: Choose -> ST s (STChoose s)
unsafeThawSTChoose (Choose n arr) =
(liftM (STChoose n) . ArrST.unsafeThaw) arr
{-# INLINE unsafeThawSTChoose #-}
instance Eq (STChoose s) where
(==) (STChoose _ marr1) (STChoose _ marr2) =
ArrST.sameSTIntArray marr1 marr2