discrimination-0.5: src/Data/Discrimination/Internal.hs
{-# LANGUAGE CPP #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE ParallelListComp #-}
{-# LANGUAGE MagicHash #-}
module Data.Discrimination.Internal
( runs
, groupNum
, bdiscNat
, updateBag
, updateSet
, spanEither
, integerCases
, naturalCases
) where
import Data.Array as Array
import Data.Functor
import Data.Int
import qualified Data.List as List
import Prelude hiding (read, concat)
import GHC.Word
import GHC.Exts
import Data.Primitive.Types (Prim)
import Data.Primitive.PrimArray
#ifdef MIN_VERSION_ghc_bignum
import GHC.Num.Integer
import GHC.Num.Natural
#else
import GHC.Natural
import GHC.Integer.GMP.Internals
#endif
--------------------------------------------------------------------------------
-- * Utilities
--------------------------------------------------------------------------------
bdiscNat :: Int -> ([v] -> v -> [v]) -> [(Int,v)] -> [[v]]
bdiscNat n update xs = reverse <$> Array.elems (Array.accumArray update [] (0,n) xs)
{-# INLINE bdiscNat #-}
runs :: Eq a => [(a,b)] -> [[b]]
runs [] = []
runs ((a,b):xs0) = (b:ys0) : runs zs0
where
(ys0,zs0) = go xs0
go [] = ([],[])
go xs@((a', b'):xs')
| a == a' = case go xs' of
(ys, zs) -> (b':ys,zs)
| otherwise = ([], xs)
groupNum :: [[k]] -> [(k,Int)]
groupNum kss = List.concat [ (,n) <$> ks | n <- [0..] | ks <- kss ]
updateBag :: [Int] -> Int -> [Int]
updateBag vs v = v : vs
updateSet :: [Int] -> Int -> [Int]
updateSet [] w = [w]
updateSet vs@(v:_) w
| v == w = vs
| otherwise = w : vs
-- | Optimized and CPS'd version of 'Data.Either.partitionEithers', where all lefts are known to come before all rights
spanEither :: ([a] -> [b] -> c) -> [Either a b] -> c
spanEither k xs0 = go [] xs0 where
go acc (Left x:xs) = go (x:acc) xs
go acc rights = k (reverse acc) (fromRight <$> rights)
fromRight :: Either a b -> b
fromRight (Right y) = y
fromRight _ = error "unstable discriminator"
-------------------------------------------------------------------------------
-- * Integer and Natural
-------------------------------------------------------------------------------
integerCases :: Integer -> Either (Int,[Word]) (Either Int (Int,[Word]))
#ifdef MIN_VERSION_ghc_bignum
integerCases (IN b) = Left $ decomposeBigNat b
integerCases (IS i) = Right . Left $ I# i
integerCases (IP b) = Right . Right $ decomposeBigNat b
#else
integerCases (Jn# b) = Left $ decomposeBigNat b
integerCases (S# i) = Right . Left $ I# i
integerCases (Jp# b) = Right . Right $ decomposeBigNat b
#endif
{-# INLINE integerCases #-}
naturalCases :: Natural -> Either Word (Int,[Word])
#ifdef MIN_VERSION_ghc_bignum
naturalCases (NS w) = Left $ W# w
naturalCases (NB b) = Right $ decomposeBigNat b
#else
naturalCases (NatS# w) = Left $ W# w
naturalCases (NatJ# b) = Right $ decomposeBigNat b
#endif
{-# INLINE naturalCases #-}
-- We need to reverse the limb array. Its stored least-significant word first
-- but for comparison to work right we need most-significant words first.
#ifdef MIN_VERSION_ghc_bignum
decomposeBigNat :: ByteArray# -> (Int, [Word])
decomposeBigNat ba = let pa = PrimArray ba :: PrimArray Word in (sizeofPrimArray pa, primArrayToReverseList pa)
#else
decomposeBigNat :: BigNat -> (Int, [Word])
decomposeBigNat (BN# ba) = let pa = PrimArray ba :: PrimArray Word in (sizeofPrimArray pa, primArrayToReverseList pa)
#endif
{-# INLINE decomposeBigNat #-}
primArrayToReverseList :: Prim a => PrimArray a -> [a]
primArrayToReverseList xs = build (\c n -> foldlPrimArray (flip c) n xs)
{-# INLINE primArrayToReverseList #-}