packages feed

primitive-maybe 0.1.0 → 0.1.1

raw patch · 5 files changed

+983/−23 lines, 5 filesdep +QuickCheckdep +quickcheck-classesdep +taggeddep ~primitivenew-uploaderPVP ok

version bump matches the API change (PVP)

Dependencies added: QuickCheck, quickcheck-classes, tagged, tasty, tasty-quickcheck

Dependency ranges changed: primitive

API changes (from Hackage documentation)

+ Data.Primitive.Array.Maybe: instance Control.Monad.Fail.MonadFail Data.Primitive.Array.Maybe.MaybeArray
+ Data.Primitive.Array.Maybe: instance Control.Monad.Zip.MonadZip Data.Primitive.Array.Maybe.MaybeArray
+ Data.Primitive.Array.Maybe: instance Data.Data.Data a => Data.Data.Data (Data.Primitive.Array.Maybe.MaybeArray a)
+ Data.Primitive.Array.Maybe: instance Data.Foldable.Foldable Data.Primitive.Array.Maybe.MaybeArray
+ Data.Primitive.Array.Maybe: instance Data.Functor.Classes.Eq1 Data.Primitive.Array.Maybe.MaybeArray
+ Data.Primitive.Array.Maybe: instance Data.Functor.Classes.Ord1 Data.Primitive.Array.Maybe.MaybeArray
+ Data.Primitive.Array.Maybe: instance Data.Functor.Classes.Read1 Data.Primitive.Array.Maybe.MaybeArray
+ Data.Primitive.Array.Maybe: instance Data.Functor.Classes.Show1 Data.Primitive.Array.Maybe.MaybeArray
+ Data.Primitive.Array.Maybe: instance Data.Primitive.UnliftedArray.PrimUnlifted (Data.Primitive.Array.Maybe.MaybeArray a)
+ Data.Primitive.Array.Maybe: instance Data.Primitive.UnliftedArray.PrimUnlifted (Data.Primitive.Array.Maybe.MutableMaybeArray s a)
+ Data.Primitive.Array.Maybe: instance Data.Traversable.Traversable Data.Primitive.Array.Maybe.MaybeArray
+ Data.Primitive.Array.Maybe: instance GHC.Base.Alternative Data.Primitive.Array.Maybe.MaybeArray
+ Data.Primitive.Array.Maybe: instance GHC.Base.Applicative Data.Primitive.Array.Maybe.MaybeArray
+ Data.Primitive.Array.Maybe: instance GHC.Base.Functor Data.Primitive.Array.Maybe.MaybeArray
+ Data.Primitive.Array.Maybe: instance GHC.Base.Monad Data.Primitive.Array.Maybe.MaybeArray
+ Data.Primitive.Array.Maybe: instance GHC.Base.MonadPlus Data.Primitive.Array.Maybe.MaybeArray
+ Data.Primitive.Array.Maybe: instance GHC.Base.Monoid (Data.Primitive.Array.Maybe.MaybeArray a)
+ Data.Primitive.Array.Maybe: instance GHC.Base.Semigroup (Data.Primitive.Array.Maybe.MaybeArray a)
+ Data.Primitive.Array.Maybe: instance GHC.Classes.Eq a => GHC.Classes.Eq (Data.Primitive.Array.Maybe.MaybeArray a)
+ Data.Primitive.Array.Maybe: instance GHC.Classes.Ord a => GHC.Classes.Ord (Data.Primitive.Array.Maybe.MaybeArray a)
+ Data.Primitive.Array.Maybe: instance GHC.Exts.IsList (Data.Primitive.Array.Maybe.MaybeArray a)
+ Data.Primitive.Array.Maybe: instance GHC.Read.Read a => GHC.Read.Read (Data.Primitive.Array.Maybe.MaybeArray a)
+ Data.Primitive.Array.Maybe: instance GHC.Show.Show a => GHC.Show.Show (Data.Primitive.Array.Maybe.MaybeArray a)
+ Data.Primitive.Array.Maybe: maybeArrayFromList :: [a] -> MaybeArray a
+ Data.Primitive.Array.Maybe: maybeArrayFromListN :: Int -> [a] -> MaybeArray a
+ Data.Primitive.Array.Maybe: sizeofMaybeArray :: MaybeArray a -> Int
+ Data.Primitive.Array.Maybe: thawMaybeArray :: PrimMonad m => MaybeArray a -> Int -> Int -> m (MutableMaybeArray (PrimState m) a)
+ Data.Primitive.SmallArray.Maybe: instance Control.Monad.Fail.MonadFail Data.Primitive.SmallArray.Maybe.SmallMaybeArray
+ Data.Primitive.SmallArray.Maybe: instance Control.Monad.Zip.MonadZip Data.Primitive.SmallArray.Maybe.SmallMaybeArray
+ Data.Primitive.SmallArray.Maybe: instance Data.Data.Data a => Data.Data.Data (Data.Primitive.SmallArray.Maybe.SmallMaybeArray a)
+ Data.Primitive.SmallArray.Maybe: instance Data.Foldable.Foldable Data.Primitive.SmallArray.Maybe.SmallMaybeArray
+ Data.Primitive.SmallArray.Maybe: instance Data.Functor.Classes.Eq1 Data.Primitive.SmallArray.Maybe.SmallMaybeArray
+ Data.Primitive.SmallArray.Maybe: instance Data.Functor.Classes.Ord1 Data.Primitive.SmallArray.Maybe.SmallMaybeArray
+ Data.Primitive.SmallArray.Maybe: instance Data.Functor.Classes.Read1 Data.Primitive.SmallArray.Maybe.SmallMaybeArray
+ Data.Primitive.SmallArray.Maybe: instance Data.Functor.Classes.Show1 Data.Primitive.SmallArray.Maybe.SmallMaybeArray
+ Data.Primitive.SmallArray.Maybe: instance Data.Primitive.UnliftedArray.PrimUnlifted (Data.Primitive.SmallArray.Maybe.SmallMaybeArray a)
+ Data.Primitive.SmallArray.Maybe: instance Data.Primitive.UnliftedArray.PrimUnlifted (Data.Primitive.SmallArray.Maybe.SmallMutableMaybeArray s a)
+ Data.Primitive.SmallArray.Maybe: instance Data.Traversable.Traversable Data.Primitive.SmallArray.Maybe.SmallMaybeArray
+ Data.Primitive.SmallArray.Maybe: instance GHC.Base.Alternative Data.Primitive.SmallArray.Maybe.SmallMaybeArray
+ Data.Primitive.SmallArray.Maybe: instance GHC.Base.Applicative Data.Primitive.SmallArray.Maybe.SmallMaybeArray
+ Data.Primitive.SmallArray.Maybe: instance GHC.Base.Functor Data.Primitive.SmallArray.Maybe.SmallMaybeArray
+ Data.Primitive.SmallArray.Maybe: instance GHC.Base.Monad Data.Primitive.SmallArray.Maybe.SmallMaybeArray
+ Data.Primitive.SmallArray.Maybe: instance GHC.Base.MonadPlus Data.Primitive.SmallArray.Maybe.SmallMaybeArray
+ Data.Primitive.SmallArray.Maybe: instance GHC.Base.Monoid (Data.Primitive.SmallArray.Maybe.SmallMaybeArray a)
+ Data.Primitive.SmallArray.Maybe: instance GHC.Base.Semigroup (Data.Primitive.SmallArray.Maybe.SmallMaybeArray a)
+ Data.Primitive.SmallArray.Maybe: instance GHC.Classes.Eq a => GHC.Classes.Eq (Data.Primitive.SmallArray.Maybe.SmallMaybeArray a)
+ Data.Primitive.SmallArray.Maybe: instance GHC.Classes.Ord a => GHC.Classes.Ord (Data.Primitive.SmallArray.Maybe.SmallMaybeArray a)
+ Data.Primitive.SmallArray.Maybe: instance GHC.Exts.IsList (Data.Primitive.SmallArray.Maybe.SmallMaybeArray a)
+ Data.Primitive.SmallArray.Maybe: instance GHC.Read.Read a => GHC.Read.Read (Data.Primitive.SmallArray.Maybe.SmallMaybeArray a)
+ Data.Primitive.SmallArray.Maybe: instance GHC.Show.Show a => GHC.Show.Show (Data.Primitive.SmallArray.Maybe.SmallMaybeArray a)
+ Data.Primitive.SmallArray.Maybe: sizeofSmallMaybeArray :: SmallMaybeArray a -> Int
+ Data.Primitive.SmallArray.Maybe: smallMaybeArrayFromList :: [a] -> SmallMaybeArray a
+ Data.Primitive.SmallArray.Maybe: smallMaybeArrayFromListN :: Int -> [a] -> SmallMaybeArray a
+ Data.Primitive.SmallArray.Maybe: thawSmallMaybeArray :: PrimMonad m => SmallMaybeArray a -> Int -> Int -> m (SmallMutableMaybeArray (PrimState m) a)

Files

primitive-maybe.cabal view
@@ -1,6 +1,6 @@ cabal-version: 2.0 name: primitive-maybe-version: 0.1.0+version: 0.1.1 synopsis: Arrays of Maybes description:   This library provides types for working with arrays of @Maybe@@@ -43,4 +43,10 @@   build-depends:       base >=4.9.1.0 && <5     , primitive-maybe+    , primitive+    , QuickCheck+    , tasty+    , tasty-quickcheck+    , tagged+    , quickcheck-classes >= 0.4.11.1   default-language: Haskell2010
src/Data/Primitive/Array/Maybe.hs view
@@ -1,7 +1,13 @@ {-# LANGUAGE BangPatterns #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE MagicHash #-} {-# LANGUAGE UnboxedTuples #-}+{-# LANGUAGE Rank2Types #-} {-# LANGUAGE RoleAnnotations #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE InstanceSigs #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE UndecidableInstances #-}  -- | This provides an interface to working with boxed arrays -- with elements of type @Maybe a@. That is:@@ -20,28 +26,348 @@   , writeMaybeArray   , sequenceMaybeArray   , unsafeFreezeMaybeArray+  , thawMaybeArray+  , maybeArrayFromList+  , maybeArrayFromListN+  , sizeofMaybeArray   ) where +import Prelude hiding (zipWith)+import Control.Applicative (Alternative(..), liftA2)+import Control.Monad (when, MonadPlus(..))+import Control.Monad.Fail (MonadFail(..))+import Control.Monad.ST (ST, runST)+import Control.Monad.Zip (MonadZip(..)) import Control.Monad.Primitive import Data.Primitive.Array+import Data.Primitive.UnliftedArray (PrimUnlifted)+import Data.Foldable hiding (toList)+import Data.Functor.Classes+import qualified Data.Foldable as Foldable+import Data.Maybe (maybe) -import Data.Primitive.Maybe.Internal (nothingSurrogate)-import GHC.Exts (Any,reallyUnsafePtrEquality#)+import Data.Data+  (Data(..), DataType, mkDataType, Constr, mkConstr, Fixity(..), constrIndex)+import Data.Primitive.Maybe.Internal+import GHC.Exts (Any,reallyUnsafePtrEquality#, Int(..), IsList(..), MutableArray#)+import Text.ParserCombinators.ReadP import Unsafe.Coerce (unsafeCoerce) +-- | An immutable array of boxed values of type @'Maybe' a@. newtype MaybeArray a = MaybeArray (Array Any)+  deriving (PrimUnlifted)+-- | A mutable array of boxed values of type @'Maybe' a@. newtype MutableMaybeArray s a = MutableMaybeArray (MutableArray s Any)+  deriving (PrimUnlifted)  type role MaybeArray representational type role MutableMaybeArray nominal representational -unsafeToMaybe :: Any -> Maybe a-unsafeToMaybe a =-  case reallyUnsafePtrEquality# a nothingSurrogate of-    0# -> Just (unsafeCoerce a)-    _  -> Nothing-{-# INLINE unsafeToMaybe #-}+instance Functor MaybeArray where+  fmap :: forall a b. (a -> b) -> MaybeArray a -> MaybeArray b+  fmap f (MaybeArray arr) = MaybeArray $+    createArray (sizeofArray arr) (error "impossible") $ \mb ->+      let go i+            | i == (sizeofArray arr) = return ()+            | otherwise = do+                x <- indexArrayM arr i+                case unsafeToMaybe x of+                  Nothing -> pure () +                  Just val -> writeArray mb i (toAny (f val))+                go (i + 1)+      in go 0+  e <$ (MaybeArray a) = MaybeArray $ createArray (sizeofArray a) (toAny e) (\ !_ -> pure ()) +instance Applicative MaybeArray where+  pure :: a -> MaybeArray a+  pure a = MaybeArray $ runArray $ newArray 1 (toAny a)+  (<*>) :: MaybeArray (a -> b) -> MaybeArray a -> MaybeArray b+  abm@(MaybeArray ab) <*> am@(MaybeArray a) = MaybeArray $ createArray (szab * sza) nothingSurrogate $ \mb ->+    let go1 i = when (i < szab) $ do+          case indexMaybeArray abm i of+            Nothing -> pure ()+            Just f -> go2 (i * sza) f 0+          go1 (i + 1)+        go2 off f j = when (j < sza) $ do+          case indexMaybeArray am j of+            Nothing -> pure ()+            Just v -> writeArray mb (off + j) (toAny (f v))+          go2 off f (j + 1)+    in go1 0+      where szab = sizeofArray ab; sza = sizeofArray a+  MaybeArray a *> MaybeArray b = MaybeArray $ createArray (sza * szb) nothingSurrogate $ \mb ->+    let go i | i < sza = copyArray mb (i * szb) b 0 szb+             | otherwise = return ()+    in go 0+      where sza = sizeofArray a; szb = sizeofArray b+  MaybeArray a <* MaybeArray b = MaybeArray $ createArray (sza*szb) nothingSurrogate $ \ma ->+    let fill off i e | i < szb   = writeArray ma (off+i) e >> fill off (i+1) e+                     | otherwise = return ()+        go i | i < sza+             = do x <- indexArrayM a i+                  fill (i*szb) 0 x >> go (i+1)+             | otherwise = return ()+     in go 0+   where sza = sizeofArray a ; szb = sizeofArray b++instance Traversable MaybeArray where+  traverse = traverseArray++traverseArray :: Applicative f+  => (a -> f b)+  -> MaybeArray a+  -> f (MaybeArray b)+traverseArray f =  \ !(MaybeArray ary) ->+  let+    !len = sizeofArray ary+    go !ix+      | ix == len = pure $ STA $ \mary -> unsafeFreezeArray (MutableArray mary)+      | otherwise = let x = indexArray ary ix+                    in case unsafeToMaybe x of+                      Nothing -> go (ix + 1)+                      Just v -> liftA2 (\b (STA m) -> STA $ \mary ->+                                          writeArray (MutableArray mary) ix (toAny b) >> m mary)+                                       (f v) (go (ix + 1))+  in if len == 0+       then pure mempty+       else MaybeArray <$> runSTA len <$> go 0++newtype STA a = STA { _runSTA :: forall s. MutableArray# s a -> ST s (Array a) }++runSTA :: Int -> STA a -> Array a+runSTA !sz = \(STA m) -> runST $ newArray_ sz >>= \ar -> m (marray# ar)++newArray_ :: Int -> ST s (MutableArray s a)+newArray_ !n = newArray n badTraverseValue++badTraverseValue :: a+badTraverseValue = error "traverse: bad indexing"++instance Alternative MaybeArray where+  empty = mempty+  (<|>) = (<>)+  some a | sizeofMaybeArray a == 0 = mempty+         | otherwise = error "some: infinite arrays are not well defined"+  many a | sizeofMaybeArray a == 0 = pure []+         | otherwise = error "many: infinite arrays are not well defined"++instance MonadPlus MaybeArray where+  mzero = empty+  mplus = (<|>)++instance MonadFail MaybeArray where+  fail _ = empty++zipWith :: (a -> b -> c) -> MaybeArray a -> MaybeArray b -> MaybeArray c+zipWith f (MaybeArray aa) (MaybeArray ab) = MaybeArray $+  createArray mn nothingSurrogate $ \mc ->+    let go i+          | i < mn = do+              x <- indexArrayM aa i+              y <- indexArrayM ab i+              let x' = unsafeToMaybe x+                  y' = unsafeToMaybe y+              case x' of+                Nothing -> go (i + 1)+                Just va -> case y' of+                  Nothing -> go (i + 1)+                  Just vb -> writeArray mc i (toAny $ f va vb) >> go (i + 1)+          | otherwise = return ()+    in go 0+  where mn = sizeofArray aa `min` sizeofArray ab++instance MonadZip MaybeArray where+  mzip aa ab = zipWith (,) aa ab+  mzipWith f aa ab = zipWith f aa ab+  munzip :: forall a b. MaybeArray (a, b) -> (MaybeArray a, MaybeArray b) +  munzip (MaybeArray aab) = runST $ do+    let sz = sizeofArray aab+    ma_ <- newArray sz nothingSurrogate :: ST s (MutableArray s Any)+    mb_ <- newArray sz nothingSurrogate :: ST s (MutableArray s Any)+    let go :: forall s. Int -> MutableArray s Any -> MutableArray s Any -> ST s ()+        go i ma mb = if i < sz+          then do+            tab <- indexArrayM aab i+            let (a, b) = fromAny tab+                a' = unsafeToMaybe a+                b' = unsafeToMaybe b+            maybe (pure ()) (writeArray ma i) a'+            maybe (pure ()) (writeArray mb i) b'+            go (i + 1) ma mb+          else return ()+    +    go 0 ma_ mb_+    (ma1, ma2) <- (,) <$> unsafeFreezeArray ma_ <*> unsafeFreezeArray mb_+    return (unsafeCoerce ma1, unsafeCoerce ma2) :: ST s (MaybeArray a, MaybeArray b)++data ArrayStack a+  = PushArray !(Array a) !(ArrayStack a)+  | EmptyStack++instance Monad MaybeArray where+  return = pure+  (>>) = (*>)+  (MaybeArray ary) >>= f = MaybeArray $ collect 0 EmptyStack (la - 1)+    where+      la = sizeofArray ary+      collect sz stk i+        | i < 0 = createArray sz nothingSurrogate $ fill 0 stk+        | otherwise = let x = indexArray ary i+                      in case unsafeToMaybe x of+                        Nothing -> collect sz stk (i - 1)+                        Just v -> let (MaybeArray sb) = f v+                                      lsb = sizeofArray sb+                                  in if lsb == 0+                                       then collect sz stk (i - 1)+                                       else collect (sz + lsb) (PushArray sb stk) (i - 1)+      fill _ EmptyStack _ = return ()+      fill off (PushArray sb sbs) smb+        | let lsb = sizeofArray sb+        = copyArray smb off sb 0 lsb+            *> fill (off + lsb) sbs smb++instance Foldable MaybeArray where+  -- Note: we perform the array lookups eagerly so we won't+  -- create thunks to perform lookups even if GHC can't see+  -- that the folding function is strict.+  foldr f = \z !(MaybeArray ary) ->+    let+      !sz = sizeofArray ary+      go i+        | i == sz = z+        | otherwise = let !x = indexArray ary i+                      in case unsafeToMaybe x of+                        Nothing -> z+                        Just val -> f val (go (i + 1))+    in go 0+  {-# INLINE foldr #-}+  foldl f = \z !(MaybeArray ary) ->+    let+      go i+        | i < 0 = z+        | otherwise = let !x = indexArray ary i+                      in case unsafeToMaybe x of+                        Nothing -> z+                        Just val -> f (go (i - 1)) val+    in go (sizeofArray ary - 1)+  {-# INLINE foldl #-}+  null (MaybeArray a) = sizeofArray a == 0+  {-# INLINE null #-}+  length (MaybeArray a) = sizeofArray a+  {-# INLINE length #-}+  sum = foldl' (+) 0+  {-# INLINE sum #-}+  product = foldl' (*) 1+  {-# INLINE product #-}++instance Semigroup (MaybeArray a) where+  (<>) :: MaybeArray a -> MaybeArray a -> MaybeArray a+  MaybeArray a1 <> MaybeArray a2 = MaybeArray $+    createArray (sza1 + sza2) nothingSurrogate $ \ma ->+      copyArray ma 0 a1 0 sza1 >> copyArray ma sza1 a2 0 sza2+    where+      sza1 = sizeofArray a1; sza2 = sizeofArray a2++instance Monoid (MaybeArray a) where+  mempty = MaybeArray emptyArray+  mappend = (<>)++instance IsList (MaybeArray a) where+  type Item (MaybeArray a) = a+  fromListN = maybeArrayFromListN+  fromList  = maybeArrayFromList+  toList    = Foldable.toList++instance Eq a => Eq (MaybeArray a) where+  sma1 == sma2 = maybeArrayLiftEq (==) sma1 sma2++instance Eq1 MaybeArray where+  liftEq = maybeArrayLiftEq++instance Ord1 MaybeArray where+  liftCompare = maybeArrayLiftCompare++maybeArrayLiftEq :: (a -> b -> Bool) -> MaybeArray a -> MaybeArray b -> Bool+maybeArrayLiftEq p (MaybeArray sa1) (MaybeArray sa2) = length sa1 == length sa2 && loop (length sa1 - 1)+  where+    loop i+      | i < 0 = True+      | otherwise = let x = unsafeToMaybe (indexArray sa1 i)+                        y = unsafeToMaybe (indexArray sa2 i)+                    in case x of+                      Nothing -> case y of+                        Nothing -> True && loop (i - 1)+                        _       -> False+                      Just x' -> case y of+                        Nothing -> False+                        Just y' -> p x' y' && loop (i - 1)++maybeArrayLiftCompare :: (a -> b -> Ordering) -> MaybeArray a -> MaybeArray b -> Ordering+maybeArrayLiftCompare elemCompare (MaybeArray a1) (MaybeArray a2) = loop 0+  where+    la1 = length a1+    la2 = length a2+    mn = la1 `min` la2+    loop i+      | i < mn = let x = unsafeToMaybe (indexArray a1 i)+                     y = unsafeToMaybe (indexArray a2 i)+                 in case x of+                   Nothing -> case y of+                     Nothing -> EQ `mappend` loop (i + 1)+                     _       -> LT+                   Just x' -> case y of+                     Nothing -> GT+                     Just y' -> elemCompare x' y' `mappend` loop (i     + 1)+     | otherwise = compare la1 la2++instance Ord a => Ord (MaybeArray a) where+  compare sma1 sma2 = maybeArrayLiftCompare compare sma1 sma2++maybeArrayLiftShowsPrec :: (Int -> a -> ShowS) -> ([a] -> ShowS) -> Int -> MaybeArray a -> ShowS+maybeArrayLiftShowsPrec elemShowsPrec elemListShowsPrec p sa = showParen (p > 10) $+  showString "fromListN " . shows (length sa) . showString " "+  . listLiftShowsPrec elemShowsPrec elemListShowsPrec 11 (toList sa)++listLiftShowsPrec :: (Int -> a -> ShowS) -> ([a] -> ShowS) -> Int -> [a] -> ShowS+listLiftShowsPrec _ sl _ = sl++instance Show1 MaybeArray where+  liftShowsPrec = maybeArrayLiftShowsPrec++instance Show a => Show (MaybeArray a) where+  showsPrec p sa = maybeArrayLiftShowsPrec showsPrec showList p sa++maybeArrayLiftReadsPrec :: (Int -> ReadS a) -> ReadS [a] -> Int -> ReadS (MaybeArray a)+maybeArrayLiftReadsPrec _ listReadsPrec p = readParen (p > 10) . readP_to_S $ do+  () <$ string "fromListN"+  skipSpaces+  n <- readS_to_P reads+  skipSpaces+  l <- readS_to_P listReadsPrec+  return $ maybeArrayFromListN n l++instance Read1 MaybeArray where+  liftReadsPrec = maybeArrayLiftReadsPrec++instance Read a => Read (MaybeArray a) where+  readsPrec = maybeArrayLiftReadsPrec readsPrec readList++maybeArrayDataType :: DataType+maybeArrayDataType = mkDataType "Data.Primitive.Array.Maybe.MaybeArray" [fromListConstr]++fromListConstr :: Constr+fromListConstr = mkConstr maybeArrayDataType "fromList" [] Prefix++instance Data a => Data (MaybeArray a) where+  toConstr _ = fromListConstr+  dataTypeOf _ = maybeArrayDataType+  gunfold k z c = case constrIndex c of+    1 -> k (z fromList)+    _ -> error "gunfold"+  gfoldl f z m = z fromList `f` toList m++-- | Create a new 'MutableMaybeArray' of the given size and initialize all elements+--   with the given 'Maybe' value. newMaybeArray :: PrimMonad m => Int -> Maybe a -> m (MutableMaybeArray (PrimState m) a) {-# INLINE newMaybeArray #-} newMaybeArray i ma = case ma of@@ -52,18 +378,21 @@     x <- newArray i nothingSurrogate     return (MutableMaybeArray x) +-- | Get the 'Maybe' value at the given index out of a 'MaybeArray'. indexMaybeArray :: MaybeArray a -> Int -> Maybe a {-# INLINE indexMaybeArray #-} indexMaybeArray (MaybeArray a) ix =   let (# v #) = indexArray## a ix    in unsafeToMaybe v +-- | Get the 'Maybe' value at the given index out of a 'MutableMaybeArray'. readMaybeArray :: PrimMonad m => MutableMaybeArray (PrimState m) a -> Int -> m (Maybe a) {-# INLINE readMaybeArray #-} readMaybeArray (MutableMaybeArray m) ix = do   a <- readArray m ix   return (unsafeToMaybe a) +-- | Write a 'Maybe' value to the given index of a 'MutableMaybeArray'. writeMaybeArray :: PrimMonad m => MutableMaybeArray (PrimState m) a -> Int -> Maybe a -> m () {-# INLINE writeMaybeArray #-} writeMaybeArray (MutableMaybeArray marr) ix ma = case ma of@@ -78,18 +407,62 @@ sequenceMaybeArray m@(MaybeArray a) =   if hasNothing m then Nothing else Just (unsafeCoerce a) +-- | Returns @True@ if the 'MaybeArray' contains a @Nothing@ value. hasNothing :: MaybeArray a -> Bool hasNothing (MaybeArray a) = go 0 where   go !ix = if ix < sizeofArray a     then       let (# v #) = indexArray## a ix        in case reallyUnsafePtrEquality# v nothingSurrogate of-            0# -> True-            _  -> go (ix + 1)+            0# -> go (ix + 1)+            _ -> True     else False +-- | Convert a 'MutableMaybeArray' to an immutable one without copying.+--   The array should not be modified after the conversion. unsafeFreezeMaybeArray :: PrimMonad m => MutableMaybeArray (PrimState m) a -> m (MaybeArray a) {-# INLINE unsafeFreezeMaybeArray #-} unsafeFreezeMaybeArray (MutableMaybeArray ma) = do   a <- unsafeFreezeArray ma   return (MaybeArray a)++-- | Create a 'MutablePrimArray' from a slice of an immutable array.+--   This operation makes a copy of the specified slice, so it is safe+--   to use the immutable array afterward.+thawMaybeArray+  :: PrimMonad m+  => MaybeArray a -- ^ source+  -> Int -- ^ offset+  -> Int -- ^ length+  -> m (MutableMaybeArray (PrimState m) a)+thawMaybeArray (MaybeArray a) off len =+  fmap MutableMaybeArray (thawArray a off len)++-- | Given the length of a list and a list of @a@,+--   build a 'MaybeArray' from the values in the list.+--   If the given 'Int' does not match the length of+--   the list, this function calls 'error'.+--   You should prefer this to 'maybeArrayFromList' if+--   the length of the list has already been computed.+maybeArrayFromListN :: Int -> [a] -> MaybeArray a+maybeArrayFromListN n l = MaybeArray $+  createArray n (error "uninitialized element") $ \sma ->+    let go !ix [] = if ix == n+          then return ()+          else error "list length less than specified size"+        go !ix (x : xs) = if ix < n+          then do+            writeArray sma ix (toAny x)+            go (ix+1) xs+          else error "list length greater than specified size"+    in go 0 l++-- | Given a list of @a@, build a 'MaybeArray' from+--   the values in the list.+maybeArrayFromList :: [a] -> MaybeArray a+maybeArrayFromList l = maybeArrayFromListN (length l) l++-- | Yield the size of the 'MaybeArray'.+sizeofMaybeArray :: MaybeArray a -> Int+sizeofMaybeArray (MaybeArray a) = sizeofArray a+{-# INLINE sizeofMaybeArray #-}
src/Data/Primitive/Maybe/Internal.hs view
@@ -1,10 +1,107 @@+{-# LANGUAGE MagicHash #-}+{-# LANGUAGE Rank2Types #-}+{-# LANGUAGE UnboxedTuples #-}+ module Data.Primitive.Maybe.Internal   ( nothingSurrogate+  , unsafeToMaybe +  , toAny+  , fromAny+  , toAny1+  , fromAny1+  , anyToFunctor+  , functorToAny++  , createArray+  , createSmallArray+  , emptyArray+  , emptySmallArray   ) where -import GHC.Exts (Any)+import Data.Primitive.Array+import Data.Primitive.SmallArray+import Control.Monad.ST (ST, runST)+import GHC.Exts (Any, reallyUnsafePtrEquality#, Array#, SmallArray#)+import Unsafe.Coerce (unsafeCoerce)  nothingSurrogate :: Any nothingSurrogate = error "nothingSurrogate: This value should not be forced!" {-# NOINLINE nothingSurrogate #-}+-- inlining this = fearful concurrency +unsafeToMaybe :: Any -> Maybe a+unsafeToMaybe a =+  case reallyUnsafePtrEquality# a nothingSurrogate of+    1#  -> Nothing+    _ -> Just (fromAny a)+{-# INLINE unsafeToMaybe #-}++toAny :: a -> Any+toAny = unsafeCoerce+{-# INLINE toAny #-}++toAny1 :: f a -> f Any+toAny1 = unsafeCoerce+{-# INLINE toAny1 #-}++fromAny1 :: f Any -> f a+fromAny1 = unsafeCoerce+{-# INLINE fromAny1 #-}++fromAny :: Any -> a+fromAny = unsafeCoerce+{-# INLINE fromAny #-}++anyToFunctor :: Any -> (a -> b)+anyToFunctor = unsafeCoerce+{-# INLINE anyToFunctor #-}++functorToAny :: (a -> b) -> Any+functorToAny = unsafeCoerce+{-# INLINE functorToAny #-}++-- This low-level business is designed to work with GHC's worker-wrapper+-- transformation. A lot of the time, we don't actually need an Array+-- constructor. By putting it on the outside, and being careful about+-- how we special-case the empty array, we can make GHC smarter about this.+-- The only downside is that separately created 0-length arrays won't share+-- their Array constructors, although they'll share their underlying+-- Array#s.+createArray+  :: Int+  -> a+  -> (forall s. MutableArray s a -> ST s ())+  -> Array a+createArray 0 _ _ = Array (emptyArray# (# #))+createArray n x f = runArray $ do+  mary <- newArray n x+  f mary+  pure mary++emptyArray# :: (# #) -> Array# a+emptyArray# _ = case emptyArray of Array ar -> ar+{-# NOINLINE emptyArray# #-}++emptyArray :: Array a+emptyArray =+  runST $ newArray 0 (error "impossible") >>= unsafeFreezeArray+{-# NOINLINE emptyArray #-}++createSmallArray ::+     Int+  -> a+  -> (forall s. SmallMutableArray s a -> ST s ())+  -> SmallArray a+createSmallArray 0 _ _ = SmallArray (emptySmallArray# (# #))+createSmallArray n x f = runSmallArray $ do+  mary <- newSmallArray n x+  f mary+  pure mary++emptySmallArray# :: (# #) -> SmallArray# a+emptySmallArray# _ = case emptySmallArray of SmallArray ar -> ar+{-# NOINLINE emptySmallArray# #-}++emptySmallArray :: SmallArray a+emptySmallArray = runST $ newSmallArray 0 (error "impossible") >>= unsafeFreezeSmallArray+{-# NOINLINE emptySmallArray #-}
src/Data/Primitive/SmallArray/Maybe.hs view
@@ -1,7 +1,12 @@ {-# LANGUAGE BangPatterns #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE MagicHash #-} {-# LANGUAGE UnboxedTuples #-}+{-# LANGUAGE RankNTypes #-} {-# LANGUAGE RoleAnnotations #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE InstanceSigs #-}+{-# LANGUAGE UndecidableInstances #-}  -- | This provides an interface to working with boxed arrays -- with elements of type @Maybe a@. That is:@@ -20,28 +25,218 @@   , writeSmallMaybeArray   , sequenceSmallMaybeArray   , unsafeFreezeSmallMaybeArray+  , thawSmallMaybeArray+  , smallMaybeArrayFromList+  , smallMaybeArrayFromListN+  , sizeofSmallMaybeArray   ) where +import Prelude hiding (zipWith)+import Control.Applicative (Alternative(..), liftA2)+import Control.Monad (when, MonadPlus(..))+import Control.Monad.Fail (MonadFail(..))+import Control.Monad.ST (ST, runST)+import Control.Monad.Zip (MonadZip(..)) import Control.Monad.Primitive import Data.Primitive.SmallArray+import Data.Primitive.UnliftedArray (PrimUnlifted)+import Data.Data (Data(..), DataType, mkDataType, Constr, mkConstr, Fixity(..), constrIndex)+import Data.Function (fix)+import Data.Functor.Classes+import Data.Foldable hiding (toList)+import Data.Maybe (maybe)+import qualified Data.Foldable as Foldable -import Data.Primitive.Maybe.Internal (nothingSurrogate)-import GHC.Exts (Any,reallyUnsafePtrEquality#)+import Data.Primitive.Maybe.Internal+import GHC.Exts (Any,reallyUnsafePtrEquality#, IsList(..), SmallMutableArray#)+import Text.ParserCombinators.ReadP import Unsafe.Coerce (unsafeCoerce) +-- | An immutable array of boxed values of type @'Maybe' a@. newtype SmallMaybeArray a = SmallMaybeArray (SmallArray Any)+  deriving (PrimUnlifted)+-- | A mutable array of boxed values of type @'Maybe' a@. newtype SmallMutableMaybeArray s a = SmallMutableMaybeArray (SmallMutableArray s Any)+  deriving (PrimUnlifted)  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 #-}+infixl 1 ?+(?) :: (a -> b -> c) -> (b -> a -> c)+(?) = flip+{-# INLINE (?) #-} +instance Functor SmallMaybeArray where+  fmap f (SmallMaybeArray arr) = SmallMaybeArray $+    createSmallArray (sizeofSmallArray arr) nothingSurrogate $ \mb ->+      let go i+            | i == (sizeofSmallArray arr) = return ()+            | otherwise = do+                x <- indexSmallArrayM arr i+                case unsafeToMaybe x of+                  Nothing -> pure () +                  Just val -> writeSmallArray mb i (toAny (f val))+                go (i + 1)+      in go 0+  {-# INLINE fmap #-}+  x <$ SmallMaybeArray sa = SmallMaybeArray $ createSmallArray (length sa) (toAny x) (\ !_ -> pure ())++instance Applicative SmallMaybeArray where+  pure a = SmallMaybeArray $ createSmallArray 1 (toAny a) (\ !_ -> pure ())++  SmallMaybeArray sa *> SmallMaybeArray sb = SmallMaybeArray $ createSmallArray (la*lb) (error "impossible") $ \smb ->+    fix ? 0 $ \go i ->+      when (i < la) $+        copySmallArray smb 0 sb 0 lb *> go (i+1)+   where+   la = length sa ; lb = length sb+  +  SmallMaybeArray a <* SmallMaybeArray b = SmallMaybeArray $ createSmallArray (sza*szb) (error "impossible") $ \ma ->+    let fill off i e = when (i < szb) $+                         writeSmallArray ma (off+i) e >> fill off (i+1) e+        go i = when (i < sza) $ do+                 x <- indexSmallArrayM a i+                 fill (i*szb) 0 x+                 go (i+1)+     in go 0+   where sza = sizeofSmallArray a ; szb = sizeofSmallArray b+  +  abm@(SmallMaybeArray ab) <*> am@(SmallMaybeArray a) = SmallMaybeArray $ createSmallArray (szab * sza) nothingSurrogate $ \mb ->+    let go1 i = when (i < szab) $ do+          case indexSmallMaybeArray abm i of+            Nothing -> pure ()+            Just f -> go2 (i * sza) f 0+          go1 (i + 1)+        go2 off f j = when (j < sza) $ do+          case indexSmallMaybeArray am j of+            Nothing -> pure ()+            Just v -> writeSmallArray mb (off + j) (toAny (f v))+          go2 off f (j + 1)+    in go1 0+      where szab = sizeofSmallArray ab; sza = sizeofSmallArray a++instance Traversable SmallMaybeArray where+  traverse = traverseSmallArray++traverseSmallArray :: Applicative f+  => (a -> f b)+  -> SmallMaybeArray a+  -> f (SmallMaybeArray b)+traverseSmallArray f =  \ !(SmallMaybeArray ary) ->+  let+    !len = sizeofSmallArray ary+    go !ix+      | ix == len = pure $ STA $ \mary -> unsafeFreezeSmallArray (SmallMutableArray mary)+      | otherwise = let x = indexSmallArray ary ix+                    in case unsafeToMaybe x of+                      Nothing -> go (ix + 1)+                      Just v -> liftA2 (\b (STA m) -> STA $ \mary ->+                                          writeSmallArray (SmallMutableArray mary) ix (toAny b) >> m mary)+                                       (f v) (go (ix + 1))+  in if len == 0+       then pure mempty+       else SmallMaybeArray <$> runSTA len <$> go 0++newtype STA a = STA { _runSTA :: forall s. SmallMutableArray# s a -> ST s (SmallArray a) }++runSTA :: Int -> STA a -> SmallArray a+runSTA !sz = \(STA m) -> runST $ newArray_ sz >>= \ar -> m (msarray# ar)++msarray# :: SmallMutableArray s a -> SmallMutableArray# s a+msarray# (SmallMutableArray m) = m+{-# INLINE msarray# #-}++newArray_ :: Int -> ST s (SmallMutableArray s a)+newArray_ !n = newSmallArray n badTraverseValue++badTraverseValue :: a+badTraverseValue = error "traverse: bad indexing"++data ArrayStack a+  = PushArray !(SmallArray a) !(ArrayStack a)+  | EmptyStack++instance Monad SmallMaybeArray where+  return = pure+  (>>) = (*>)+  (SmallMaybeArray ary) >>= f = SmallMaybeArray $ collect 0 EmptyStack (la - 1)+    where+      la = sizeofSmallArray ary+      collect sz stk i+        | i < 0 = createSmallArray sz nothingSurrogate $ fill 0 stk+        | otherwise = let x = indexSmallArray ary i+                      in case unsafeToMaybe x of+                        Nothing -> collect sz stk (i - 1)+                        Just v -> let (SmallMaybeArray sb) = f v+                                      lsb = sizeofSmallArray sb+                                  in if lsb == 0+                                       then collect sz stk (i - 1)+                                       else collect (sz + lsb) (PushArray sb stk) (i - 1)+      fill _ EmptyStack _ = return ()+      fill off (PushArray sb sbs) smb+        | let lsb = sizeofSmallArray sb+        = copySmallArray smb off sb 0 lsb+            *> fill (off + lsb) sbs smb++instance Alternative SmallMaybeArray where+  empty = mempty+  (<|>) = (<>)+  some a | sizeofSmallMaybeArray a == 0 = mempty+         | otherwise = error "some: infinite arrays are not well defined"+  many a | sizeofSmallMaybeArray a == 0 = pure []+         | otherwise = error "many: infinite arrays are not well defined"++instance MonadPlus SmallMaybeArray where+  mzero = empty+  mplus = (<|>)++instance MonadFail SmallMaybeArray where+  fail _ = empty++zipWith :: (a -> b -> c) -> SmallMaybeArray a -> SmallMaybeArray b -> SmallMaybeArray c+zipWith f (SmallMaybeArray aa) (SmallMaybeArray ab) = SmallMaybeArray $+  createSmallArray mn nothingSurrogate $ \mc ->+    let go i+          | i < mn = do+              x <- indexSmallArrayM aa i+              y <- indexSmallArrayM ab i+              let x' = unsafeToMaybe x+                  y' = unsafeToMaybe y+              case x' of+                Nothing -> go (i + 1)+                Just va -> case y' of+                  Nothing -> go (i + 1)+                  Just vb -> writeSmallArray mc i (toAny $ f va vb) >> go (i + 1)+          | otherwise = return ()+    in go 0+  where mn = sizeofSmallArray aa `min` sizeofSmallArray ab++instance MonadZip SmallMaybeArray where+  mzip aa ab = zipWith (,) aa ab+  mzipWith f aa ab = zipWith f aa ab+  munzip :: forall a b. SmallMaybeArray (a, b) -> (SmallMaybeArray a, SmallMaybeArray b)+  munzip (SmallMaybeArray aab) = runST $ do+    let sz = sizeofSmallArray aab+    ma_ <- newSmallArray sz nothingSurrogate :: ST s (SmallMutableArray s Any)+    mb_ <- newSmallArray sz nothingSurrogate :: ST s (SmallMutableArray s Any)+    let go :: forall s. Int -> SmallMutableArray s Any -> SmallMutableArray s Any -> ST s ()+        go i ma mb = if i < sz+          then do+            tab <- indexSmallArrayM aab i+            let (a, b) = fromAny tab+                a' = unsafeToMaybe a+                b' = unsafeToMaybe b+            maybe (pure ()) (writeSmallArray ma i) a'+            maybe (pure ()) (writeSmallArray mb i) b'+            go (i + 1) ma mb+          else return ()++    go 0 ma_ mb_+    (ma1, ma2) <- (,) <$> unsafeFreezeSmallArray ma_ <*> unsafeFreezeSmallArray mb_+    return (unsafeCoerce ma1, unsafeCoerce ma2) :: ST s (SmallMaybeArray a, SmallMaybeArray b)++-- | Create a new 'SmallMutableMaybeArray' of the given size and initialize all elements with the given 'Maybe' value. newSmallMaybeArray :: PrimMonad m => Int -> Maybe a -> m (SmallMutableMaybeArray (PrimState m) a) {-# INLINE newSmallMaybeArray #-} newSmallMaybeArray i ma = case ma of@@ -52,18 +247,160 @@     x <- newSmallArray i nothingSurrogate     return (SmallMutableMaybeArray x) +instance Foldable SmallMaybeArray where+  -- Note: we perform the array lookups eagerly so we won't+  -- create thunks to perform lookups even if GHC can't see+  -- that the folding function is strict.+  foldr f = \z !(SmallMaybeArray ary) ->+    let+      !sz = sizeofSmallArray ary+      go i+        | i == sz = z+        | otherwise = let !x = indexSmallArray ary i+                      in case unsafeToMaybe x of+                        Nothing -> z+                        Just val -> f val (go (i + 1))+    in go 0+  {-# INLINE foldr #-}+  foldl f = \z !(SmallMaybeArray ary) ->+    let+      go i+        | i < 0 = z+        | otherwise = let !x = indexSmallArray ary i+                      in case unsafeToMaybe x of+                        Nothing -> z+                        Just val -> f (go (i - 1)) val+    in go (sizeofSmallArray ary - 1)+  {-# INLINE foldl #-}+  null (SmallMaybeArray a) = sizeofSmallArray a == 0+  {-# INLINE null #-}+  length (SmallMaybeArray a) = sizeofSmallArray a+  {-# INLINE length #-}+  sum = foldl' (+) 0+  {-# INLINE sum #-}+  product = foldl' (*) 1+  {-# INLINE product #-}++instance Semigroup (SmallMaybeArray a) where+  SmallMaybeArray a1 <> SmallMaybeArray a2 = SmallMaybeArray $+    createSmallArray (sza1 + sza2) nothingSurrogate $ \ma ->+      copySmallArray ma 0 a1 0 sza1 >> copySmallArray ma sza1 a2 0 sza2+    where+      sza1 = sizeofSmallArray a1; sza2 = sizeofSmallArray a2++instance Monoid (SmallMaybeArray a) where+  mempty = SmallMaybeArray emptySmallArray+  mappend = (<>)++instance IsList (SmallMaybeArray a) where+  type Item (SmallMaybeArray a) = a+  fromListN = smallMaybeArrayFromListN+  fromList  = smallMaybeArrayFromList+  toList    = Foldable.toList++smallMaybeArrayLiftEq :: (a -> b -> Bool) -> SmallMaybeArray a -> SmallMaybeArray b -> Bool+smallMaybeArrayLiftEq p (SmallMaybeArray sa1) (SmallMaybeArray sa2) = length sa1 == length sa2 && loop (length sa1 - 1)+  where+    loop i+      | i < 0 = True+      | otherwise = let x = unsafeToMaybe (indexSmallArray sa1 i)+                        y = unsafeToMaybe (indexSmallArray sa2 i)+                    in case x of+                      Nothing -> case y of+                        Nothing -> True && loop (i - 1)+                        _       -> False+                      Just x' -> case y of+                        Nothing -> False+                        Just y' -> p x' y' && loop (i - 1)+                    +instance Eq a => Eq (SmallMaybeArray a) where+  sma1 == sma2 = smallMaybeArrayLiftEq (==) sma1 sma2++instance Eq1 SmallMaybeArray where+  liftEq = smallMaybeArrayLiftEq++smallMaybeArrayLiftCompare :: (a -> b -> Ordering) -> SmallMaybeArray a -> SmallMaybeArray b -> Ordering+smallMaybeArrayLiftCompare elemCompare (SmallMaybeArray a1) (SmallMaybeArray a2) = loop 0+  where+    la1 = length a1+    la2 = length a2+    mn = la1 `min` la2+    loop i+      | i < mn = let x = unsafeToMaybe (indexSmallArray a1 i)+                     y = unsafeToMaybe (indexSmallArray a2 i)+                 in case x of+                   Nothing -> case y of+                     Nothing -> EQ `mappend` loop (i + 1)+                     _       -> LT+                   Just x' -> case y of+                     Nothing -> GT+                     Just y' -> elemCompare x' y' `mappend` loop (i + 1)+     | otherwise = compare la1 la2++instance Ord a => Ord (SmallMaybeArray a) where+  compare sma1 sma2 = smallMaybeArrayLiftCompare compare sma1 sma2++instance Ord1 SmallMaybeArray where+  liftCompare = smallMaybeArrayLiftCompare++smallMaybeArrayLiftShowsPrec :: (Int -> a -> ShowS) -> ([a] -> ShowS) -> Int -> SmallMaybeArray a -> ShowS+smallMaybeArrayLiftShowsPrec elemShowsPrec elemListShowsPrec p sa = showParen (p > 10) $+  showString "fromListN " . shows (length sa) . showString " "+    . listLiftShowsPrec elemShowsPrec elemListShowsPrec 11 (toList sa)++listLiftShowsPrec :: (Int -> a -> ShowS) -> ([a] -> ShowS) -> Int -> [a] -> ShowS+listLiftShowsPrec _ sl _ = sl++instance Show1 SmallMaybeArray where+  liftShowsPrec = smallMaybeArrayLiftShowsPrec++instance Show a => Show (SmallMaybeArray a) where+  showsPrec p sa = smallMaybeArrayLiftShowsPrec showsPrec showList p sa++smallMaybeArrayLiftReadsPrec :: (Int -> ReadS a) -> ReadS [a] -> Int -> ReadS (SmallMaybeArray a)+smallMaybeArrayLiftReadsPrec _ listReadsPrec p = readParen (p > 10) . readP_to_S $ do+  () <$ string "fromListN"+  skipSpaces+  n <- readS_to_P reads+  skipSpaces+  l <- readS_to_P listReadsPrec+  return $ smallMaybeArrayFromListN n l++instance Read1 SmallMaybeArray where+  liftReadsPrec = smallMaybeArrayLiftReadsPrec++instance Read a => Read (SmallMaybeArray a) where+  readsPrec = smallMaybeArrayLiftReadsPrec readsPrec readList++smallMaybeArrayDataType :: DataType+smallMaybeArrayDataType = mkDataType "Data.Primitive.Array.Maybe.SmallMaybeArray" [fromListConstr]++fromListConstr :: Constr+fromListConstr = mkConstr smallMaybeArrayDataType "fromList" [] Prefix++instance Data a => Data (SmallMaybeArray a) where+  toConstr _ = fromListConstr+  dataTypeOf _ = smallMaybeArrayDataType+  gunfold k z c = case constrIndex c of+    1 -> k (z fromList)+    _ -> error "gunfold"+  gfoldl f z m = z fromList `f` toList m++-- | Get the 'Maybe' value at the given index out of a 'SmallMaybeArray'. indexSmallMaybeArray :: SmallMaybeArray a -> Int -> Maybe a {-# INLINE indexSmallMaybeArray #-} indexSmallMaybeArray (SmallMaybeArray a) ix =   let (# v #) = indexSmallArray## a ix    in unsafeToMaybe v +-- | Get the 'Maybe' value at the given index out of a 'SmallMutableMaybeArray'. 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) +-- | Write a 'Maybe' value to the given index of a 'SmallMutableMaybeArray'. writeSmallMaybeArray :: PrimMonad m => SmallMutableMaybeArray (PrimState m) a -> Int -> Maybe a -> m () {-# INLINE writeSmallMaybeArray #-} writeSmallMaybeArray (SmallMutableMaybeArray marr) ix ma = case ma of@@ -84,12 +421,51 @@     then       let (# v #) = indexSmallArray## a ix        in case reallyUnsafePtrEquality# v nothingSurrogate of-            0# -> True-            _  -> go (ix + 1)+            0# -> go (ix + 1)+            _ -> True     else False +-- | Convert a 'SmallMutableMaybeArray' to an immutable one without copying.+--   The array should not be modified after the conversion. unsafeFreezeSmallMaybeArray :: PrimMonad m => SmallMutableMaybeArray (PrimState m) a -> m (SmallMaybeArray a) {-# INLINE unsafeFreezeSmallMaybeArray #-} unsafeFreezeSmallMaybeArray (SmallMutableMaybeArray ma) = do   a <- unsafeFreezeSmallArray ma   return (SmallMaybeArray a)++-- | Create a 'SmallMutableMaybeArray' from a slice of an immutable array. This operation makes a copy of+--   the specified slice, so it is safe to use the immutable array afterward.+thawSmallMaybeArray+  :: PrimMonad m+  => SmallMaybeArray a -- ^ source+  -> Int -- ^ offset+  -> Int -- ^ length+  -> m (SmallMutableMaybeArray (PrimState m) a)+thawSmallMaybeArray (SmallMaybeArray a) off len =+  fmap SmallMutableMaybeArray (thawSmallArray a off len)++-- | Given the length of the list and a list of @a@, build a 'SmallMaybeArray' from the values in the list.+--   If the given 'Int' does not match the length of the list, this function calls 'error'. You should prefer+--   this to 'maybeArrayFromList' if the length of the list has already been computed.+smallMaybeArrayFromListN :: Int -> [a] -> SmallMaybeArray a+smallMaybeArrayFromListN n l = SmallMaybeArray $+  createSmallArray n+      (error "uninitialized element") $ \sma ->+  let go !ix [] = if ix == n+        then return ()+        else error "list length less than specified size"+      go !ix (x : xs) = if ix < n+        then do+          writeSmallArray sma ix (toAny x)+          go (ix+1) xs+        else error "list length greater than specified size"+  in go 0 l++-- | Given a list of @a@, build a 'SmallMaybeArray' from the values in the list.+smallMaybeArrayFromList :: [a] -> SmallMaybeArray a+smallMaybeArrayFromList l = smallMaybeArrayFromListN (length l) l++-- | Yield the size of the 'SmallMaybeArray'.+sizeofSmallMaybeArray :: SmallMaybeArray a -> Int+sizeofSmallMaybeArray (SmallMaybeArray a) = sizeofSmallArray a+{-# INLINE sizeofSmallMaybeArray #-}
test/Main.hs view
@@ -1,2 +1,110 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE MagicHash #-}+{-# LANGUAGE UnboxedTuples #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE StandaloneDeriving #-}+{-# LANGUAGE InstanceSigs #-}+{-# LANGUAGE FlexibleContexts #-}++{-# OPTIONS_GHC -Wall -fno-warn-orphans #-}++#if __GLASGOW_HASKELL__ >= 805+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE DerivingStrategies #-}+{-# LANGUAGE DerivingVia #-}+{-# LANGUAGE TypeInType #-}+#endif++import qualified Data.Foldable as Foldable+import Data.Proxy (Proxy(..))+#if !(MIN_VERSION_base(4,11,0))+import Data.Monoid ((<>))+#endif++import Control.Monad.Zip (MonadZip)+import Control.Monad (MonadPlus)+import Data.Primitive.Array.Maybe+import Data.Primitive.SmallArray.Maybe+import GHC.Exts (IsList(..))+import Data.Functor.Classes++import Test.Tasty (defaultMain,testGroup,TestTree)+import Test.QuickCheck (Arbitrary,Arbitrary1,Gen)+import qualified Test.Tasty.QuickCheck as TQC+import qualified Test.QuickCheck as QC+import qualified Test.QuickCheck.Classes as QCC+ main :: IO ()-main = putStrLn "Test suite not yet implemented"+main = do+  defaultMain $ testGroup "properties"+    [ testGroup "MaybeArray" $ lawsToTest <$> maybeArrayLaws+    , testGroup "SmallMaybeArray" $ lawsToTest <$> smallMaybeArrayLaws+    ]++makeArrayLaws :: forall (f :: * -> *) a.+     (Monad f, MonadPlus f, MonadZip f, Foldable f, Eq1 f, Ord1 f, Show1 f, Arbitrary1 f, Traversable f)+  => (Read (f a), Show (Item (f a)), Monoid (f a), Ord (f a), Arbitrary (f a), Show (f a))+  => (IsList (f a), Show (Item (f a)), Arbitrary (Item (f a)))+  => Proxy f+  -> Proxy (f a)+  -> [QCC.Laws]+makeArrayLaws pf pfa =+  [ QCC.eqLaws pfa+  , QCC.ordLaws pfa+  , QCC.monoidLaws pfa+  , QCC.showReadLaws pfa+  , QCC.isListLaws pfa+  , QCC.functorLaws pf+  , QCC.alternativeLaws pf+  , QCC.applicativeLaws pf+  , QCC.foldableLaws pf+  , QCC.monadLaws pf +  , QCC.monadPlusLaws pf+  , QCC.monadZipLaws pf+  , QCC.traversableLaws pf+  ]++maybeArrayLaws :: [QCC.Laws]+maybeArrayLaws = makeArrayLaws proxyM1 proxyM++smallMaybeArrayLaws :: [QCC.Laws]+smallMaybeArrayLaws = makeArrayLaws proxyS1 proxyS++proxyM :: Proxy (MaybeArray Int)+proxyM = Proxy++proxyM1 :: Proxy MaybeArray+proxyM1 = Proxy++proxyS :: Proxy (SmallMaybeArray Int)+proxyS = Proxy++proxyS1 :: Proxy SmallMaybeArray+proxyS1 = Proxy++lawsToTest :: QCC.Laws -> TestTree+lawsToTest (QCC.Laws name pairs) = testGroup name (map (uncurry TQC.testProperty) pairs)++instance Arbitrary1 MaybeArray where+  liftArbitrary :: forall a. Gen a -> Gen (MaybeArray a) +  liftArbitrary elemGen = fmap fromList (QC.liftArbitrary elemGen :: Gen [a])+  liftShrink :: forall a. (a -> [a]) -> MaybeArray a -> [MaybeArray a]+  liftShrink shrf m = fmap maybeArrayFromList (fmap shrf (Foldable.toList m))++instance Arbitrary a => Arbitrary (MaybeArray a) where+  arbitrary = QC.arbitrary1+  shrink = QC.shrink1++instance Arbitrary1 SmallMaybeArray where+  liftArbitrary :: forall a. Gen a -> Gen (SmallMaybeArray a) +  liftArbitrary elemGen = fmap fromList (QC.liftArbitrary elemGen :: Gen [a])+  liftShrink :: forall a. (a -> [a]) -> SmallMaybeArray a -> [SmallMaybeArray a]+  liftShrink shrf m = fmap smallMaybeArrayFromList (fmap shrf (Foldable.toList m))++instance Arbitrary a => Arbitrary (SmallMaybeArray a) where+  arbitrary = QC.arbitrary1+  shrink = QC.shrink1+