{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE MagicHash #-}
{-# LANGUAGE UnboxedTuples #-}
{-# LANGUAGE RoleAnnotations #-}
module Data.Primitive.SmallArray.Maybe
( SmallMaybeArray
, SmallMutableMaybeArray
, indexSmallMaybeArray
, newSmallMaybeArray
, readSmallMaybeArray
, writeSmallMaybeArray
, sequenceSmallMaybeArray
, unsafeFreezeSmallMaybeArray
) where
import Control.Monad.Primitive
import Data.Primitive.SmallArray
import Data.Primitive.Maybe.Internal (nothingSurrogate)
import GHC.Exts (Any,reallyUnsafePtrEquality#)
import Unsafe.Coerce (unsafeCoerce)
newtype SmallMaybeArray a = SmallMaybeArray (SmallArray Any)
newtype SmallMutableMaybeArray s a = SmallMutableMaybeArray (SmallMutableArray s Any)
type role SmallMaybeArray representational
type role SmallMutableMaybeArray nominal representational
unsafeToMaybe :: Any -> Maybe a
unsafeToMaybe a =
case reallyUnsafePtrEquality# a nothingSurrogate of
0# -> Just (unsafeCoerce a)
_ -> Nothing
{-# INLINE unsafeToMaybe #-}
newSmallMaybeArray :: PrimMonad m => Int -> Maybe a -> m (SmallMutableMaybeArray (PrimState m) a)
{-# INLINE newSmallMaybeArray #-}
newSmallMaybeArray i ma = case ma of
Just a -> do
x <- newSmallArray i (unsafeCoerce a)
return (SmallMutableMaybeArray x)
Nothing -> do
x <- newSmallArray i nothingSurrogate
return (SmallMutableMaybeArray x)
indexSmallMaybeArray :: SmallMaybeArray a -> Int -> Maybe a
{-# INLINE indexSmallMaybeArray #-}
indexSmallMaybeArray (SmallMaybeArray a) ix =
let (# v #) = indexSmallArray## a ix
in unsafeToMaybe v
readSmallMaybeArray :: PrimMonad m => SmallMutableMaybeArray (PrimState m) a -> Int -> m (Maybe a)
{-# INLINE readSmallMaybeArray #-}
readSmallMaybeArray (SmallMutableMaybeArray m) ix = do
a <- readSmallArray m ix
return (unsafeToMaybe a)
writeSmallMaybeArray :: PrimMonad m => SmallMutableMaybeArray (PrimState m) a -> Int -> Maybe a -> m ()
{-# INLINE writeSmallMaybeArray #-}
writeSmallMaybeArray (SmallMutableMaybeArray marr) ix ma = case ma of
Just a -> writeSmallArray marr ix (unsafeCoerce a)
Nothing -> writeSmallArray marr ix nothingSurrogate
sequenceSmallMaybeArray :: SmallMaybeArray a -> Maybe (SmallArray a)
sequenceSmallMaybeArray m@(SmallMaybeArray a) =
if hasNothing m then Nothing else Just (unsafeCoerce a)
hasNothing :: SmallMaybeArray a -> Bool
hasNothing (SmallMaybeArray a) = go 0 where
go !ix = if ix < sizeofSmallArray a
then
let (# v #) = indexSmallArray## a ix
in case reallyUnsafePtrEquality# v nothingSurrogate of
0# -> True
_ -> go (ix + 1)
else False
unsafeFreezeSmallMaybeArray :: PrimMonad m => SmallMutableMaybeArray (PrimState m) a -> m (SmallMaybeArray a)
{-# INLINE unsafeFreezeSmallMaybeArray #-}
unsafeFreezeSmallMaybeArray (SmallMutableMaybeArray ma) = do
a <- unsafeFreezeSmallArray ma
return (SmallMaybeArray a)